webview chromium v48 h5 video上屏过程详解

发布于 2019-09-26 作者 风铃 68次 浏览 版块 前端

前段时间网上有同学问h5 video不显示图像问题。我好像误导别人了。最近刚好有机会看这块,就仔细梳理了下。
这篇博客分为两部分,第一部分是h5 video 播放器的实现结构,第二部分是h5 video上屏过程的详细剖析。
这部分比想象中复杂,不过梳理清楚这块,对于chromium系统如何跨线程使用texture会有更深的认识,花些精力还比较值得。
第一部分h5 video播放器的实现结构

    
图中我们可以看到h5 video播放是桥接到java层调用android系统mediaplayer完成的。
第二部分h5 video视频流上屏过程
首先需要明确一点,在webview方案chromium v48版本中,video元素视频流的合成与
网页上其他内容的合成是统一的,并不是单独处理的。区别只在于video元素单独占用的GraphicsLayercc端对应的是VideoLayer.
而网页上常规内容占用的GraphicsLayercc端对应的是PictureLayer.网页上如果由2dcanvas元素,其在cc端对应的是TextureLayer.
video元素在blink端的对应层GraphicsLayer,cc端的对应层VideoLayer之间的关系建立过程如图:

    
VideoLayer创建并被关联到GraphicsLayer的时机在:
WebMediaPlayerAndroid::OnVideoSizeChanged().
video元素单独占用的GraphicsLayer和网页上的其他层一样,遍历blinkrenderlayer tree会被访问到。
我把video视频源上屏的过程分成4个步骤:
步骤1:承载video内容的texture被创建的过程;
步骤2:步骤1中创建的承载video内容的textureh5 video视频流相关联的过程,只有建立了关联,h5
    videodecode之后才会被送到1中的texture中;
步骤3:h5 video texture被绘制之前的准备工作;
步骤4:绘制texture内容到webview对应的后端存储上,从chromium内核角度看,就相当于上屏操作了。
下面详细看这4个步骤的实现:
步骤1:承载video内容的texture被创建的过程

    
这个过程主要做三件事情:
1).创建承载video内容的texture,图中路径1标示的过程;
2).创建SurfaceTexture封装1)中的texture,图中路径2标示的过程,
SurfaceTexture会在步骤2中关联到android mediaplayer上,
这样mediaplayer输出目标就变成了SurfaceTexture封装的texture;
3).1)中创建的承载video内容的texture封装进mailbox.供绘制线程在绘制videoLayerImpl内容时使用,
图中路径3标示的过程,承载video内容的texture需要在另一个gl线程中使用,所以这里把它封装进mailbox.
我们知道,chromium系统跨线程使用texture的方式是通过如下这对接口:
ProduceTextureDirectCHROMIUM/CreateAndConsumeTextureCHROMIUM.
ProduceTextureDirectCHROMIUM:在一个线程中将texture封装进mailbox;
CreateAndConsumeTextureCHROMIUM:在消耗texture的线程中将texturemailbox中取出;
和这两个接口配套使用的mailbox,syncpoint,是实现texture跨线程使用的基础设施,以后有时间单独总结下。
步骤2:步骤1中创建的承载video内容的textureh5 video视频流相关联的过程
步骤1中我们讲了承载video内容的texture被封装进了SurafceTexture,
这个SurfaceTexture封装了android系统javagraphics模块中的SurfaceTexture.
所以我们创建的承载video内容的texture最终是封装进了android系统的SurfaceTexture.
下面先看下android.graphics.SurfaceTexture类的说明(官网翻译来的)
-------------------------------------------------------------------------------------------------------------------------------------------------------------
SurfaceTexture
imagestream捕获帧,作为openGL ES图像纹理。
image stream可能来自camera预览或者视频解码。
当指定camera或者媒体播放器对象的输出目的地时,SurfaceTexture可以代替SurfaceHolder使用。
使用SurfaceTexture代替SurfaceHolder,会导致来自image stream的帧被送到SurfaceTexture对象,
而不是设备的显示系统。
updateTexImage()被调用时,SurfaceTexture创建时指定的texture的内容会被更新为image
    stream中的最新image.这可能导致stream中的某些帧被跳过。
当从texture进行纹理采样时,需要先使用变换矩阵变换纹理坐标,变化矩阵通过getTransformMatrix(float[])获得。
每次updateTexImage()被调用,变换矩阵都有可能发生变化,所以每次texture
    image更新时都需要重新申请变换矩阵。这个矩阵将传统的2D OpenGL ES texture坐标,
(s,t,0,1)形式的列向量,s,t[0,1]范围内,变换为streamedtexture中合适的取样位置。
这种变换弥补了任何引起image stream源与传统的OpenGL ES texture不同的特性。
比如,从image的左下角取样,可以通过使用queried matrix变换列向量(0,0, 0, 1)来弥补,
image右上角取样则可以通过变换(1,1, 0, 1)来完成。
texture对象使用GL_TEXTURE_EXTERNAL_OES目标,
通过OpenGL ES的扩展GL_OES_EGL_image_external来定义。这限制了texture的使用方式。
每次texture被绑定,只能绑定到GL_TEXTURE_EXTERNAL_OES目标,而不是GL_TEXTURE_2D目标。
另外,任何从texture采样的OpenGL ES 2.0 shader必须声明对GL_OES_EGL_image_external的使用。
比如,一个类似这样的声明:"#extension GL_OES_EGL_image_external :require".
这样的shader也必须使用samplerExternalOES这样的采样器类型来访问textrue.
SurfaceTexture对象可以在任何线程创建。updateTexImage()只能在拥有texture对象的OpenGL ES context所在的线程创建。
frame-availble callback可以在任何线程调用。所以直接在frame avaible callback中调用updateTexImage()需要格外小心。
-------------------------------------------------------------------------------------------------------------------------------------------------------------
使用SurfaceTexture类就是为了改变MediaPlayer的输出目的地。
封装了video textureSurfaceTextrueMediaPlayer绑定的过程如下图:
步骤2完成后,mediaplayer播放的视频流就被重定向到1中创建的texture中了。
步骤3:h5 video texture被绘制之前的准备工作
这个准备工作主要是将包含video texturemailbox传递到StreamVideoDrawQuad中。
这样,在绘制StreamVideoDrawQuad时,就可以通过mailbox取得video texture并绘制。
这个过程如下图所示:

    
路径1的三步作用如下:
1.1)VideoFrame得到mailbox;
1.2)mailobx封装进ResourceProvider::Resource;
1.3)ResourceProvider::Resource封装进VideoLayerImpl::FrameResource;
路径21.2中的ResourceProvider::Resource封装到StreamVideoDrawQuad
VideoLayerImpl被绘制时,绘制的就是StreamVideoDrawQuad。现在StreamVideoDrawQuad中已经包含了
videotexturemailbox信息。
步骤4:绘制texture内容到webview对应的后端存储上
这个过程我们分解为4个小步骤来看:
4.1)在当前渲染线程由mailbox得到video texture;
4.2)绑定video texture;
4.3)更新video texture的内容为最新,参考上文SurfaceTexture类,UpdateTexImage接口的说明;
4.4)绘制video texture;
整个过程如下图所示:

    
最后的一点说明,webview chromium v51video视频上屏过程和48版本又不一样了。51版本上的实现流程还没分析过,有时间看下。
收藏
暂无回复