您的位置:首页 > 移动开发 > Android开发

android hwcomposer 在视频播放中的应用

2016-01-13 22:59 1156 查看
之前写了一篇博客,分析了视频如何显示的
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合成
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: