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

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

[plain] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. LOCAL_PATH:= $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3.   
  4. LOCAL_SRC_FILES:= \  
  5.     main.cpp  
  6.   
  7. LOCAL_STATIC_LIBRARIES := \  
  8.     libstagefright_color_conversion  
  9.       
  10. LOCAL_SHARED_LIBRARIES := \  
  11.     libcutils \  
  12.     libutils \  
  13.     libbinder \  
  14.     libui \  
  15.     libgui \  
  16.     libstagefright\  
  17.     libstagefright_foundation  
  18.       
  19. LOCAL_C_INCLUDES := \  
  20.     frameworks/native/include/media/openmax \  
  21.     frameworks/av/media/libstagefright  
  22.   
  23.       
  24. LOCAL_MODULE:= showYUV  
  25.   
  26. LOCAL_MODULE_TAGS := tests  
  27.   
  28. include $(BUILD_EXECUTABLE)
發佈了16 篇原創文章 · 獲贊 20 · 訪問量 94萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章