Android用surface直接显示yuv数据(二)

论坛 期权论坛 脚本     
匿名网站用户   2020-12-19 17:01   221   0

研究了一段时间Android的surface系统,一直执着地认为所有在surface或者屏幕上显示的画面,必须要转换成RGB才能显示,yuv数据也要通过颜色空间转换成RGB才能显示。可最近在研究stagefright视频显示时发现,根本找不到omx解码后的yuv是怎么转换成RGB的代码,yuv数据在render之后就找不到去向了,可画面确确实实的显示出来了,这从此颠覆了yuv必须要转换成RGB才能显示的真理了。

稍微看一下AsomePlayer的代码,不难发现,视频的每一帧是通过调用了SoftwareRenderer来渲染显示的,我也尝试用利用SoftwareRenderer来直接render yuv数据显示,竟然成功了,这是一个很大的突破,比如以后摄像头采集到的yuv,可以直接丢yuv数据到surface显示,无需耗时耗效率的yuv转RGB了。



上一篇文章主要是参照AwesomePlayer直接用SoftwareRenderer类来显示yuv,为了能用到这个类,不惜依赖了libstagefright、libstagefright_color_conversion等动态静态库,从而造成程序具有很高的耦合度,也不便于我们理解yuv数据直接显示的深层次原因。

于是我开始研究SoftwareRenderer的具体实现,我们来提取SoftwareRenderer的核心代码,自己来实现yuv的显示。

SoftwareRenderer就只有三个方法,一个构造函数,一个析构函数,还有一个负责显示的render方法。构造方法里有个很重要的地方native_window_set_buffers_geometry这里是配置即将申请的图形缓冲区的宽高和颜色空间,忽略了这个地方,画面将用默认的值显示,将造成显示不正确。render函数里最重要的三个地方,一个的dequeBuffer,一个是mapper,一个是queue_buffer。

  1. native_window_set_buffers_geometry;//设置宽高以及颜色空间yuv420
  2. native_window_dequeue_buffer_and_wait;//根据以上配置申请图形缓冲区
  3. mapper.lock(buf->handle,GRALLOC_USAGE_SW_WRITE_OFTEN,bounds,&dst));//将申请到的图形缓冲区跨进程映射到用户空间
  4. memcpy(dst,data,dst_y_size+dst_c_size*2);//填充yuv数据到图形缓冲区
  5. mNativeWindow->queueBuffer;//显示

以上五步是surface显示图形必不可少的五步。

有了以上分析,我们直接上代码:(yuv数据下载地址点击打开链接,放到sdcard)

main.cpp

  1. #include<cutils/memory.h>
  2. #include<unistd.h>
  3. #include<utils/Log.h>
  4. #include<binder/IPCThreadState.h>
  5. #include<binder/ProcessState.h>
  6. #include<binder/IServiceManager.h>
  7. #include<media/stagefright/foundation/ADebug.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<system/window.h>
  14. #include<ui/GraphicBufferMapper.h>
  15. //ANativeWindow就是surface,对应surface.cpp里的code
  16. usingnamespaceandroid;
  17. //将x规整为y的倍数,也就是将x按y对齐
  18. staticintALIGN(intx,inty){
  19. //ymustbeapowerof2.
  20. return(x+y-1)&~(y-1);
  21. }
  22. voidrender(
  23. constvoid*data,size_tsize,constsp<ANativeWindow>&nativeWindow,intwidth,intheight){
  24. sp<ANativeWindow>mNativeWindow=nativeWindow;
  25. interr;
  26. intmCropWidth=width;
  27. intmCropHeight=height;
  28. inthalFormat=HAL_PIXEL_FORMAT_YV12;//颜色空间
  29. intbufWidth=(mCropWidth+1)&~1;//按2对齐
  30. intbufHeight=(mCropHeight+1)&~1;
  31. CHECK_EQ(0,
  32. native_window_set_usage(
  33. mNativeWindow.get(),
  34. GRALLOC_USAGE_SW_READ_NEVER|GRALLOC_USAGE_SW_WRITE_OFTEN
  35. |GRALLOC_USAGE_HW_TEXTURE|GRALLOC_USAGE_EXTERNAL_DISP));
  36. CHECK_EQ(0,
  37. native_window_set_scaling_mode(
  38. mNativeWindow.get(),
  39. NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
  40. //Widthmustbemultipleof32???
  41. //很重要,配置宽高和和指定颜色空间yuv420
  42. //如果这里不配置好,下面deque_buffer只能去申请一个默认宽高的图形缓冲区
  43. CHECK_EQ(0,native_window_set_buffers_geometry(
  44. mNativeWindow.get(),
  45. bufWidth,
  46. bufHeight,
  47. halFormat));
  48. ANativeWindowBuffer*buf;//描述buffer
  49. //申请一块空闲的图形缓冲区
  50. if((err=native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
  51. &buf))!=0){
  52. ALOGW("Surface::dequeueBufferreturnederror%d",err);
  53. return;
  54. }
  55. GraphicBufferMapper&mapper=GraphicBufferMapper::get();
  56. Rectbounds(mCropWidth,mCropHeight);
  57. void*dst;
  58. CHECK_EQ(0,mapper.lock(//用来锁定一个图形缓冲区并将缓冲区映射到用户进程
  59. buf->handle,GRALLOC_USAGE_SW_WRITE_OFTEN,bounds,&dst));//dst就指向图形缓冲区首地址
  60. if(true){
  61. size_tdst_y_size=buf->stride*buf->height;
  62. size_tdst_c_stride=ALIGN(buf->stride/2,16);//1行v/u的大小
  63. size_tdst_c_size=dst_c_stride*buf->height/2;//u/v的大小
  64. memcpy(dst,data,dst_y_size+dst_c_size*2);//将yuv数据copy到图形缓冲区
  65. }
  66. CHECK_EQ(0,mapper.unlock(buf->handle));
  67. if((err=mNativeWindow->queueBuffer(mNativeWindow.get(),buf,
  68. -1))!=0){
  69. ALOGW("Surface::queueBufferreturnederror%d",err);
  70. }
  71. buf=NULL;
  72. }
  73. boolgetYV12Data(constchar*path,unsignedchar*pYUVData,intsize){
  74. FILE*fp=fopen(path,"rb");
  75. if(fp==NULL){
  76. printf("read%sfail!!!!!!!!!!!!!!!!!!!\n",path);
  77. returnfalse;
  78. }
  79. fread(pYUVData,size,1,fp);
  80. fclose(fp);
  81. returntrue;
  82. }
  83. intmain(void){
  84. //setupthethread-pool
  85. sp<ProcessState>proc(ProcessState::self());
  86. ProcessState::self()->startThreadPool();
  87. //createaclienttosurfaceflinger
  88. sp<SurfaceComposerClient>client=newSurfaceComposerClient();
  89. sp<IBinder>dtoken(SurfaceComposerClient::getBuiltInDisplay(
  90. ISurfaceComposer::eDisplayIdMain));
  91. DisplayInfodinfo;
  92. //获取屏幕的宽高等信息
  93. status_tstatus=SurfaceComposerClient::getDisplayInfo(dtoken,&dinfo);
  94. printf("w=%d,h=%d,xdpi=%f,ydpi=%f,fps=%f,ds=%f\n",
  95. dinfo.w,dinfo.h,dinfo.xdpi,dinfo.ydpi,dinfo.fps,dinfo.density);
  96. if(status)
  97. return-1;
  98. //创建surface
  99. sp<SurfaceControl>surfaceControl=client->createSurface(String8("testsurface"),
  100. dinfo.w,dinfo.h,PIXEL_FORMAT_RGBA_8888,0);
  101. /*************************getyuvdatafromfile;****************************************/
  102. printf("[%s][%d]\n",__FILE__,__LINE__);
  103. intwidth,height;
  104. width=320;
  105. height=240;
  106. intsize=width*height*3/2;
  107. unsignedchar*data=newunsignedchar[size];
  108. constchar*path="/mnt/sdcard/yuv_320_240.yuv";
  109. getYV12Data(path,data,size);//getyuvdatafromfile;
  110. /*********************配置surface*******************************************************************/
  111. SurfaceComposerClient::openGlobalTransaction();
  112. surfaceControl->setLayer(100000);//设定Z坐标
  113. surfaceControl->setPosition(100,100);//以左上角为(0,0)设定显示位置
  114. surfaceControl->setSize(width,height);//设定视频显示大小
  115. SurfaceComposerClient::closeGlobalTransaction();
  116. sp<Surface>surface=surfaceControl->getSurface();
  117. printf("[%s][%d]\n",__FILE__,__LINE__);
  118. /**********************显示yuv数据******************************************************************/
  119. render(data,size,surface,width,height);
  120. printf("[%s][%d]\n",__FILE__,__LINE__);
  121. IPCThreadState::self()->joinThreadPool();//可以保证画面一直显示,否则瞬间消失
  122. IPCThreadState::self()->stopProcess();
  123. return0;
  124. }

Android.mk (这次依赖的库少了很多)

  1. LOCAL_PATH:=$(callmy-dir)
  2. include$(CLEAR_VARS)
  3. LOCAL_SRC_FILES:=\
  4. main.cpp
  5. LOCAL_SHARED_LIBRARIES:=\
  6. libcutils\
  7. libutils\
  8. libbinder\
  9. libui\
  10. libgui\
  11. libstagefright_foundation
  12. LOCAL_MODULE:=MyShowYUV
  13. LOCAL_MODULE_TAGS:=tests
  14. include$(BUILD_EXECUTABLE)

转载请注明出处http://blog.csdn.net/tung214/article/details/37651825

感谢这篇文章总结:http://blog.csdn.net/crazyman2010/article/details/41750623


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP