1. 程式人生 > >Android用surface直接顯示yuv資料(一)

Android用surface直接顯示yuv資料(一)

轉自:http://blog.csdn.net/tung214/article/details/36887041

研究了一段時間Android的surface系統,一直執著地認為所有在surface或者螢幕上顯示的畫面,必須要轉換成RGB才能顯示,yuv資料也要通過顏色空間轉換成RGB才能顯示。可最近在研究stagefright視訊顯示時發現,根本找不到omx解碼後的yuv是怎麼轉換成RGB的程式碼,yuv資料在render之後就找不到去向了,可畫面確確實實的顯示出來了,這從此顛覆了yuv必須要轉換成RGB才能顯示的真理了。

    稍微看一下AsomePlayer的程式碼,不難發現,視訊的每一幀是通過呼叫了SoftwareRenderer來渲染顯示的,我也嘗試用利用SoftwareRenderer來直接render yuv資料顯示,竟然成功了,這是一個很大的突破,比如以後攝像頭採集到的yuv,可以直接丟yuv資料到surface顯示,無需耗時耗效率的yuv轉RGB了。

    程式碼原創,貼出來與大家分享:Android 4.4平臺 (其中yuv資料的地址可以從這裡下載點選開啟連結,放到/mnt/sdcard目錄)

  1. #include<include/SoftwareRenderer.h>
  2. #include <cutils/memory.h>
  3. #include <unistd.h>
  4. #include <utils/Log.h>
  5. #include <binder/IPCThreadState.h>
  6. #include <binder/ProcessState.h>
  7. #include <binder/IServiceManager.h>
  8. #include <gui/Surface.h>
  9. #include <gui/SurfaceComposerClient.h>
  10. #include <gui/ISurfaceComposer.h>
  11. #include <ui/DisplayInfo.h>
  12. #include <android/native_window.h>
  13. #include <media/stagefright/MetaData.h>
  14. usingnamespace android;  
  15. bool getYV12Data(constchar *path,unsigned char
     * pYUVData,int size){  
  16.     FILE *fp = fopen(path,"rb");  
  17.     if(fp == NULL){  
  18.         printf("read %s fail !!!!!!!!!!!!!!!!!!!\n",path);  
  19.         returnfalse;  
  20.     }  
  21.     fread(pYUVData,size,1,fp);  
  22.     fclose(fp);  
  23.     returntrue;  
  24. }  
  25. int main(void){  
  26.     // set up the thread-pool
  27.     sp<ProcessState> proc(ProcessState::self());  
  28.     ProcessState::self()->startThreadPool();  
  29.     // create a client to surfaceflinger
  30.     sp<SurfaceComposerClient> client = new SurfaceComposerClient();  
  31.     sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(  
  32.             ISurfaceComposer::eDisplayIdMain));  
  33.     DisplayInfo dinfo;  
  34.     //獲取螢幕的寬高等資訊
  35.     status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);  
  36.     printf("w=%d,h=%d,xdpi=%f,ydpi=%f,fps=%f,ds=%f\n",   
  37.         dinfo.w, dinfo.h, dinfo.xdpi, dinfo.ydpi, dinfo.fps, dinfo.density);  
  38.     if (status)  
  39.         return -1;  
  40.     //建立surface,有些系統可能報錯,dinfo.w和dinfo.h也可以寫成固定值
  41.     sp<SurfaceControl> surfaceControl = client->createSurface(String8("showYUV"),  
  42.             dinfo.w, dinfo.h, PIXEL_FORMAT_RGBA_8888, 0);  
  43. /*************************get yuv data from file;****************************************/
  44.     printf("[%s][%d]\n",__FILE__,__LINE__);  
  45.     int width,height;  
  46.     width = 320;  
  47.     height = 240;  
  48.     int size = width * height * 3/2;  
  49.     unsigned char *data = new unsigned char[size];  
  50.     char *path = "/mnt/sdcard/yuv_320_240.yuv";  
  51.     getYV12Data(path,data,size);//get yuv data from file;
  52. /*********************配置surface*******************************************************************/
  53.     SurfaceComposerClient::openGlobalTransaction();  
  54.     surfaceControl->setLayer(100000);//設定Z座標
  55.     surfaceControl->setPosition(100, 100);//以左上角為(0,0)設定顯示位置
  56.     surfaceControl->setSize(width, height);//設定視訊顯示大小
  57.     SurfaceComposerClient::closeGlobalTransaction();  
  58.     sp<Surface> surface = surfaceControl->getSurface();  
  59.     printf("[%s][%d]\n",__FILE__,__LINE__);  
  60. /****************************************************************************************/
  61.     sp<MetaData> meta = new MetaData;  
  62.     meta->setInt32(kKeyWidth, width);  
  63.     meta->setInt32(kKeyHeight, height);  
  64.     /*指定yuv格式,支援以下yuv格式 
  65.      * OMX_COLOR_FormatYUV420Planar: 
  66.      * OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: 
  67.      * HAL_PIXEL_FORMAT_YV12: 
  68.      * 其他的貌似會轉換成OMX_COLOR_Format16bitRGB565 
  69.      */
  70.     meta->setInt32(kKeyColorFormat, HAL_PIXEL_FORMAT_YV12);  
  71.     //setRect不要也可以,我也不知道設定了有什麼用,原理是什麼,但是設定,引數一定要正確
  72.     meta->setRect(  
  73.                     kKeyCropRect,  
  74.                     0,//left
  75.                     0,//top
  76.                     width -1,//right
  77.                     height -1);//bottom
  78.     printf("[%s][%d]\n",__FILE__,__LINE__);  
  79.     SoftwareRenderer* sr = new SoftwareRenderer(surface,meta);//初始化
  80.     printf("[%s][%d]\n",__FILE__,__LINE__);  
  81.     sr->render(data,size,NULL);//關鍵在這裡,顯示到螢幕上
  82.     delete[] data;  
  83.     printf("[%s][%d]\n",__FILE__,__LINE__);  
  84.     IPCThreadState::self()->joinThreadPool();//可以保證畫面一直顯示,否則瞬間消失
  85.     IPCThreadState::self()->stopProcess();  
  86.     return 0;  
  87. }  

Android.mk 如果你有完整編譯過的Android編譯環境,那沒問題,如果是NDK,可能有點麻煩,因為其中很多靜態動態庫。

  1. LOCAL_PATH:= $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3. LOCAL_SRC_FILES:= \  
  4.     main.cpp  
  5. LOCAL_STATIC_LIBRARIES := \  
  6.     libstagefright_color_conversion  
  7. LOCAL_SHARED_LIBRARIES := \  
  8.     libcutils \  
  9.     libutils \  
  10.     libbinder \  
  11.     libui \  
  12.     libgui \  
  13.     libstagefright\  
  14.     libstagefright_foundation  
  15. LOCAL_C_INCLUDES := \  
  16.     frameworks/native/include/media/openmax \  
  17.     frameworks/av/media/libstagefright  
  18. LOCAL_MODULE:= showYUV  
  19. LOCAL_MODULE_TAGS := tests  
  20. include $(BUILD_EXECUTABLE)