Chromium视频标签<video>简要介绍和学习计划

来源:互联网 发布:大数据挖掘工程师招聘 编辑:程序博客网 时间:2024/05/17 00:05

       随着互联网的发展,在网页上观看视频变得越来越流行,尤其是泛娱乐(手机直播)大行其道的今天。在HTML5之前,在网页上播放视频需要插件支持,例如Flash插件。有了HTML5之后,标签<video>使得浏览器有了播放视频的功能。与插件相比,浏览器的视频播放功能不仅在产品上体验更好,在技术上也更加稳定。本文接下来就简要介绍Chromium是如何实现<video>标签的视频播放功能的,以及制定学习计划。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

       本文以及接下来的文章,我们主要关注Chromium在Android平台上是如何实现<video>标签的视频播放功能的。我们知道,Android平台提供播放视频的API接口,也就是MediaPlayer接口。这个接口不仅可以用来播放本地媒体文件,也就用来播放网络上的流媒体文件。这可以大大简化Chromium在Android平台上支持<video>标签的工作,因为前者可以直接利用后者提供的MediaPlayer接口实现视频播放功能,如图1所示:


图1 <video>标签的实现

       从前面Chromium多进程架构简要介绍和学习计划这个系列的文章可以知道,Chromium是一个多进程架构。其中,Render进程负责加载、解析和渲染网页,Browser进程负责将Render进程渲染出来的网页内容合成到屏幕上显示。Render进程又是通过WebKit来加载和解析网页内容的。

       WebKit在解析网页内容时,每当遇到<video>标签,就会在DOM Tree中创建一个类型为HTMLMediaElement的节点。这个HTMLMediaElement节点又会在内部创建一个WebMediaPlayerClientImpl对象。这个WebMediaPlayerClientImpl对象在WebKit内部就描述为一个播放器,用来为<video>标签提供视频播放功能。

       WebMediaPlayerClientImpl类是由WebKit提供的,它本身不实现视频播放功能,因为视频播放是一个平台相关的功能。我们知道,WebKit是平台无关的,所有平台相关的功能都需要由它的使用者实现。在Chromium中,WebKit的使用者即为运行在Render进程中的Content模块。Content模块提供了一个WebMediaPlayerAndroid类,用来向WebKit提供视频播放功能。

       WebKit层的每一个WebMediaPlayerClientImpl对象在Content层都有一个对应的WebMediaPlayerAndroid对象。这些WebMediaPlayerAndroid对象就相当于是在Render进程内部实现的播放器。每一个播放器都关联有一个ID,它们被另外一个称为RendererMediaPlayerManager的对象管理。通过这种方式,就可以在一个网页上同时支持多个<video>标签,也就是可以同时播放多个视频。

       我们知道,Render进程运行在一个沙箱中,也就是它是一个受限进程。播放网络上的视频需要访问网络,以及使用系统的解码器等资源。因此,Render进程也没有实现视频播放功能,而是通过Browser进程进行播放。因此,对于Render进程中的每一个WebMediaPlayerAndroid对象,在Browser进程中都会有一个对应的WebMediaPlayerBridge对象。这些WebMediaPlayerBridge对象就相当于在Browser进程内部实现的播放器。这些播放器被另外一个称为BrowserMediaPlayerManager的对象管理,使得Browser进程可以同时创建多个播放器,以支持在一个网页上同时播放多个视频。

       WebMediaPlayerBridge类本身也不实现播放器功能。在Android平台上,WebMediaPlayerBridge类将通过SDK提供的MediaPlayer接口来实现视频播放功能。SDK是在Java层提供MediaPlayer接口的,而WebMediaPlayerBridge类是实现在C++层的,因此后者在使用前者时,需要通过JNI使用。

       总结来说,在Android平台上,Chromium会通过SDK接口MediaPlayer为网页中的每一个<video>标签创建一个播放器。播放器负责从网络上下载视频内容,并且进行解码。解码后得到的视频画面需要作为网页的一部分进行显示。从前面Chromium网页渲染机制简要介绍和学习计划这个系列的文章可以知道,在Chromium中,网页是Render进程进行渲染的,并且当前需要渲染的内容来自于网页的CC Active Layer Tree。这意味着要将播放器解码出来的视频画面交给网页的CC Active Layer Tree处理。

       播放器解码出来的视频画面是通过SurfaceTexture接口交给网页的CC Active Layer Tree处理的,如图2所示:


图2 <video>标签的视频画面渲染方式

       在Android平台上,SurfaceTexture是一个完美的接口。一方面它支持跨进程传输数据,另一方面传输的数据可以作为纹理使用。在我们这个情景中,MediaPlayer运行在Browser进程中,CC Active Layer Tree运行在Render进程中,并且是通过OpenGL进行渲染的。因此,SurfaceTexture非常适合将前者的输出作为后者的输入,并且通过OpenGL以纹理的方式渲染出来。

       具体来说,就是CC Active Layer Tree会为每一个<video>标签创建一个类型为VideoLayerImpl的节点。这个节点的内容就来自于播放器解码出来的视频画面。这些视频画面最终又是通过纹理来描述的。从前面Chromium网页渲染机制简要介绍和学习计划这个系列的文章可以知道,CC Active Layer Tree其它节点的内容,最终也是描述为纹理进行渲染的。因此,Chromium可以轻松地将播放器解码出来的视频画面作为网页的一部分进行显示。

       在Android平台上,Chromium还为<video>标签提供了全屏播放功能。全屏播放与非全屏播放可以进行无缝切换,它是怎么实现的呢?我们通过图3来说明,如下所示:


图3 <video>标签的全屏播放功能实现

       在<video>标签全屏播放的情况下,我们是看不到网页的其它内容的。这使得Chromium可以使用一种简单的方式实现<video>标签的全屏播放功能。当<video>标签全屏播放的时候,Browser进程会在浏览器窗口上创建一个全屏的SurfaceView,然后将这个SurfaceView底层的Surface取出来,设置为MediaPlayer的解码输出。这样就可以将MediaPlayer的解码输出全屏显示在屏幕上了。这时候由于网页是不可见的,Render进程不需要对它进行渲染。

       接下来,我们结合源码,按照三个情景深入分析Chromium对<video>标签的支持:

       1. 为<video>标签创建播放器的过程。

       2. 渲染<video>标签视频画面的过程。

       3. 全屏播放<video>标签视频的过程。

       学习了这三个情景之后 ,我们就会对HTML5中的<video>标签有更深刻的了解,敬请关注!更多的信息也可以关注老罗的新浪微博:http://weibo.com/shengyangluo。

1 0