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目录)

[cpp]  view plain copy
  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 plain copy
  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)

你可能感兴趣的:(Android用surface直接显示yuv数据(一))