之前写了一篇博客,分析了视频如何显示的

http://blog.csdn.net/wan8180192/article/details/50269405

以及gralloc的内存管理

http://blog.csdn.net/wan8180192/article/details/50513895


这里结合hwcomposer模块,以及视频播放的场景,对其中有一些细节,在这里再做补充一下

android中,多个surface layer要显示到屏幕上,就要合成到一起,合成方式有两种:
离线合成
先将所有图层画到一个最终层(FrameBuffer)上,再将FrameBuffer送到LCD显示。由于合成FrameBuffer与送LCD显示一般是异步的(线下生成FrameBuffer,需要时线上的LCD去取),因此叫离线合成。
在线合成
不使用FrameBuffer,在LCD需要显示某一行的像素时,用显示控制器将所有图层与该行相关的数据取出,合成一行像素送过去。只有一个图层时,又叫Overlay技术。 
由于省去合成FrameBuffer时读图层,写FrameBuffer的步骤,大幅降低了内存传输量,减少了功耗,但这个需要硬件支持。

对于这两种方式,各有优缺点,
离线合成充分利用GPU,更加灵活,不受win layer数量限制。但是功耗大,不利于移动设备。GPU如果性能不强,复杂应用场景下会出现卡顿,实时性不好
在线合成,功耗小,没有性能瓶颈,没有时延。但是不够灵活。UI layer一旦变多,需要重新借助于GPU的离线合成。 

一般来说,优先使用overlay.实在不行就用GPU

在实际代码中,可以看到SurfaceFlinger::doComposeSurfaces中, 有以下处理,
switch (cur->getCompositionType()) {                    case HWC_OVERLAY: {   ////overlay 方式,采用HWC硬件来合成                        const Layer::State& state(layer->getDrawingState());                        if ((cur->getHints() & HWC_HINT_CLEAR_FB)                                && i                                && layer->isOpaque() && (state.alpha == 0xFF)                                && hasGlesComposition) {                            // never clear the very first layer since we're                            // guaranteed the FB is already cleared                            layer->clearWithOpenGL(hw, clip);                        }                        break;                    }                    case HWC_FRAMEBUFFER: {   ///非overlay方式,采用GPU来合成,后续调用的是openGL                        layer->draw(hw, clip);                        break;                    }                    case HWC_FRAMEBUFFER_TARGET: {   /////异常处理。FRAMEBUFFER_TARGET不应该出现在这个流程里。FRAMEBUFFER_TARGET是合成是使用的目标buffer。                        // this should not happen as the iterator shouldn't                        // let us get there.                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%d)", i);                        break;                    }                }

其中:
HWC_FRAMEBUFFER_TARGET:该Layer是3D合成的目标Layer
HWC_FRAMEBUFFER:hwcomposer无法处理此Layer,该Layer需要走GPU合成流程,用OpenGL绘制
HWC_OVERLAY:该Layer为硬件合成器所处理,不需要OpenGLES去渲染

结合视频播放的场景,这里打印了部分主要的log, 打出来的基本都是函数名。 在log的基础上分析一下。
显示视频帧,exynos上主要有两个路子:
1,利用GPU。
  采用GPU做渲染以实现缩放,色彩空间转换,以及与其他APP UI layer的composer合成。
  这里的合成,实际上就是offline离线合成.
  
2,采用display controller 模块。
  display controller会利用exynos的FIMC模块来完成缩放,色彩空间转换,
  利用exynos 4412的5个win layer, 将视频单独一个win layer,与其他win layer的APP UI合成。
  这实际上是online在线合成。 这种合成方式,也叫做overlay方式
  exynos的display controller实际上相当于高通的MSM平台上的MDP,这两个模块,通俗意义上可以被称作hwcomposer/HWC
 
 
1,先介绍下离线合成场景下的显示过程:  
##########################tiled 和linear 转换 :解码完毕之后,exynos解出来的是很变态的YUV420 tiled格式。后面要显示,就要转成常见的linear格式,目前的实现采用了 NEON软件方法实现
E/libcsc  ( 1660):  csc_convert
E/libcsc  ( 1660):  conv_sw
E/libcsc  ( 1660):  HAL_PIXEL_FORMAT_YCbCr_420_SP
E/libcsc  ( 1660):  HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED


##########################OMX 把YUV数据queuebuffer
E/AwesomePlayer( 1660): status_t err = mNativeWindow->queueBuffer //这里queuebuffer的操作是gralloc利用MALI的UMP/ION内存管理机制分配得到的图形缓冲区,不是framebuffer
E/Surface ( 1660): Surface::hook_queueBuffer
E/SurfaceFlinger( 1652): Layer::onFrameAvailable
E/SurfaceFlinger( 1652): handlePageFlip
E/SurfaceFlinger( 1652): latchBuffer //把YUV数据绑定到openGL纹理,


##########################VSYNC到来,开始用GPU合成,主要是在doComposeSurfaces里面,实际上就是GPU读取YUV数据作为纹理,进行渲染。渲染完了放在了framebuffer里面
E/SurfaceFlinger( 1652): handleMessageRefresh
E/SurfaceFlinger( 1652): doComposition
E/SurfaceFlinger( 1652): doDisplayComposition
E/SurfaceFlinger( 1652): doComposeSurfaces
E/SurfaceFlinger( 1652): hasGlesComposition
E/Surface ( 1652): Surface::hook_dequeueBuffer   
E/Surface ( 1652): Surface::dequeueBuffer   //这里dequeuebuffer的操作是gralloc申请到的framebuffer
E/SurfaceFlinger( 1652): count 2
E/SurfaceFlinger( 1652): else clip.isEmpty
E/SurfaceFlinger( 1652): onDraw
E/SurfaceFlinger( 1652): drawWithOpenGL 0,0,1280,720,1280,720,  //进行纹理渲染。
E/SurfaceFlinger( 1652): count 2
E/SurfaceFlinger( 1652): else clip.isEmpty
E/SurfaceFlinger( 1652): onDraw
E/SurfaceFlinger( 1652): drawWithOpenGL 0,0,800,480,800,480, //这是干啥?哪位大侠知道?暂且认为是在做composer


##########################渲染,合成之后调用swapBuffers,把渲染完的数据hook_queueBuffer,这里的buffer都是framebuffer了。然后调用mFbDev->post,也就是framebuffer HAL的fb_post,画到屏幕上。
E/SurfaceFlinger( 1652): hw->swapBuffers
E/SurfaceFlinger( 1652): DisplayDevice::swapBuffers
E/SurfaceFlinger( 1652): eglSwapBuffers  //eglSwapBuffers最终调用了openGL,maliDDK中的代码,也就是调用了调用了libmali.so,其内部调用了NativeWindow->queueBuffer,这部分代码没有开源,不做分析
E/Surface ( 1652): Surface::hook_queueBuffer
E/SurfaceFlinger( 1652): FramebufferSurface::onFrameAvailable
E/SurfaceFlinger( 1652): HWComposer::fbPost
E/SurfaceFlinger( 1652): mFbDev->post


##########################下面好像都没有实质工作。都是在处理fence之类的
E/SurfaceFlinger( 1652): mDisplaySurface->advanceFrame
E/SurfaceFlinger( 1652): DisplayDevice::flip
E/SurfaceFlinger( 1652): SurfaceFlinger::postFramebuffer
E/SurfaceFlinger( 1652): hw->onSwapBuffersCompleted
E/SurfaceFlinger( 1652): else currentLayers[i]->onLayerDisplayed
E/SurfaceFlinger( 1652): Layer::onLayerDisplayed
E/SurfaceFlinger( 1652): else currentLayers[i]->onLayerDisplayed
E/SurfaceFlinger( 1652): Layer::onLayerDisplayed


综上:离线合成的方法实际上就是: 
decoder---->UMP/ION graphicbuffer 1
                                                                    -------->GPU--------->framebuffer----->screen
APP UI ---->UMP/ION graphicbuffer 2

2,在线合成的尚未调试完毕,具体细节后面会补充:
其主要思路就是
decoder-->FIMC---------------------------------->framebuffer for win1
                                                                                                                -------->display controller----->screen
APP UI -->ION graphicbuffer ---->GPU----->framebuffer for win2
可以看到HWC在合成时,overlay方式的视频不需要直接和非Overlay方式的APP UI layer同步,它只要和这些非Overlay层合成的最终结果同步就可以了。
非Overlay层合成的最终结果放在了FramebufferTarget中。
GPU渲染完非Overlay的层后,通过queueBuffer()将GraphicBuffer放入FramebufferSurface对应的BufferQueue,然后FramebufferSurface::onFrameAvailable()被调用。它先会通过nextBuffer()->acquireBufferLocked()从BufferQueue中拿一个GraphicBuffer,接着调用HWComposer::fbPost()->setFramebufferTarget(),其中会把刚才acquire的GraphicBuffer设到HWC的Layer list中的FramebufferTarget slot中,然后进行HWC合成

更多相关文章

  1. Android(安卓)Wifi模块分析(三)
  2. Android中dispatchDraw分析
  3. Android四大基本组件介绍与生命周期
  4. Android(安卓)Service AIDL
  5. Android调用天气预报的WebService简单例子
  6. android打电话发短信
  7. android 拨打紧急号码,通话时开启免提功能实现
  8. Android调用.NET Webservice报org.ksoap2.serialization.SoapPri
  9. android 自定义view

随机推荐

  1. android 选择本地图片并预览
  2. Android的OpenGL学习笔记(1)
  3. Android 条码扫描程序源码
  4. android中将中文以粗体显示
  5. Android程序横竖屏切换
  6. 对比onSaveInstanceState和onRestoreInst
  7. Android(安卓)getIdentifier获取资源ID
  8. 关于LinearLayout布局中,子控件平分宽度
  9. android获取3G或wifi流量信息
  10. Android使用selector改变和文本框文字的