《WebKit 技术内幕》学习之十一(2):多媒体

2 视频

2.1 HTML5视频

        在HTML5规范定义中,Web开发者可以使用“video”元素来播放视频资源。视频中有个重要的问题就是视频编码格式,对此,目前标准中包含了三种编码格式,它们分别是Ogg、MPEG4和WebM。其中Ogg是由Xiph.org组织开发的一个开放标准,不需要任何授权费用,它使用Theora作为视频编码格式和Vorbis作为音频编码格式。MPEG4是MPEG工作组开发的需要授权费用的标准,它使用H.264作为视频编码格式和AAC作为音频编码格式。而WebM是由Google研发的标准,它也是完全免费自由使用的,使用VP8作为视频编码格式和Vorbis作为音频编码格式。表11-1说明4个主流浏览器是否支持这三种标准的情况。

                        表11-1 主流浏览器对HTML5中三个视频格式的支持

        从图中可以看到,除了Chrome浏览器支持所有的三种标准之外,其他浏览器可能只是支持其中的一种或者两种,这对网页的开发者造成了困扰。到底如何编写代码才能让视频在这些浏览器上都能工作呢?示例代码11-1是一种很好的解决方法,前提是前端开发者需要了解三种格式的视频文件。

示例代码11-1 使用“video”元素的HTML5代码片段

    <video width="800" height="600" controls="controls"><source src="video.webm" type="video/webm"><source src="video.mp4" type="video/mp4"><source src="video.ogg" type="video/ogg">Your browser does not support the video tag.</video>

浏览器会根据自身支持情况来决定播放哪一个,对于不支持HTML5视频规范的浏览器来说,它显示的是用户的浏览器不支持它。

HTML5提供了一些属性让开发者来使用JavaScript代码检查和操作视频。HTML5在“video”和“audio”元素之间抽象了一个基类元素,也就是“media”元素,结合它提供的能力,大致有以下几个方面的JavaScript编程接口。

首先是资源加载和信息方面的接口,开发者可以通过特定接口检查浏览器支持什么格式,如Metadata和海报(Poster)等。其次是缓冲(Buffering)处理,包括缓冲区域、进度等信息。然后是播放方面的状态,包括播放、暂停、终止等。再次是搜寻(Seeking)方面的信息,包括设置当前时间、“Timeupdate”事件,以及两个状态“Seeking”和“seeked”。最后是音量方面的设置,包括获取和设置音量、静音和音量变换等事件。

2.2 WebKit基础设施

        WebKit提供了支持多媒体规范的基础框架,如音视频元素、JavaScript接口和视频播放等。根据WebKit的一般设计思想,它主要是提供标准的实现框架,而具体的实现由各个移植来完成,因为音视频需要平台的支持。图11-1是WebKit为了达到这一目标而设计的各个类和它们之间的关系,也包括了Chromium移植的几个基础类,关系比较复杂,下面按功能来分析它们。

                                图11-1 WebKit支持视频的基础类和关系

        首先WebKit是支持规范定义的编程接口,图11-1中左侧的HTMLMediaElement和HTMLVideo-Element类是DOM树中的节点类,分别对应于W3C标准中的定义,包含众多DOM接口,这些接口可以被JavaScript代码访问。

        其次是MediaPlayer和MediaPlayerClient两个类,它们的作用非常明显。MediaPlayer类是一个公共标准类,被HTMLMediaElement类使用来播放音频和视频,它本身只是提供抽象接口,具体实现依赖于不同的WebKit移植。同时,一些播放器中的状态信息需要通知到HTMLMediaElement类,这里使用MediaPlayerClient类来定义这些有关状态信息的接口,HTMLMediaElement类需要继承MediaPlayerClient类并接收这些状态信息。根据前面的描述,规范要求将事件派发到JavaScript代码中,而这一实现就在HTMLMediaElement类完成。

        然后是不同移植对MediaPlayer类的实现,其中包括MediaPlayerPrivateInterface类和WebMediaPlayerClientImpl类。前者是除了Chromium移植之外使用的标准接口,也是一个抽象接口,由不同移植来实现。后者是Chromium移植的实现类。为什么会这样?因为Chromium将WebKit复制出Blink之后就将MediaPlayerPrivateInterface类直接移除了,而在MediaPlayer类中直接调用它。WebMediaPlayerClientImpl类会使用Chromium移植自己定义的WebMediaPlayer接口类来作为实际的播放器,而真正的播放器则是在Chromium项目的代码中来实现的。

        最后是同渲染有关的部分,这里面就是之前介绍的RenderObject树和RenderLayer树,图中的RenderMedia类和RenderVideo类是RenderObject的子类,用于表示Media节点和Video节点。图中并没有关于将MediaPlayer类解码和渲染结合起来这一部分的说明,这在Chromium实现中会介绍到。

        图11-1中关于资源获取的部分也没有绘制出来,本质上来讲,同其他资源一样,这里仍然使用ResourceDispatcher类来请求资源,但是在资源的缓冲上Chromium有特殊之处,这些后面介绍。

        图11-1是采用硬件加速机制的视频播放所使用的类,对于具体过程将在稍后介绍。当然,WebKit也支持使用软件渲染方式来播放视频,实际比硬件加速方式要简单一些。根据之前章节的描述,WebKit采用软件渲染方式不需要使用RenderLayer类、GraphicsLayer类等,当需要绘制的时候,由RenderVideo类使用HTMLMediaElement类获取MediaPlayer对象,调用它的paint方法来让MediaPlayer对象将解码后的图像绘制在当前的2D图形上下文接口中,具体软件渲染过程前面介绍过,比较容易理解,不再赘述。

2.3 Chromium视频机制

2.3.1 资源获取

        因为视频资源相对其他资源而言,一般比较大,当用户播放视频的时候,需要连续性播放以获得较好的体验,但是网络可能并不是一直都稳定和高速,所以资源的获取对用户体验很重要,需要使用缓存机制或者其他机制来预先获取视频资源。

        图11-2是Chromium中的缓存资源类。BufferedDataSource类表示资源数据,它是一个简单的数据表示类,内部包含一个较小的内存空间(32K),实际的缓冲机制由BufferedResourceLoader类完成,前面章节介绍了资源的加载机制,BufferedResourceLoader类也是使用该机制来获取数据,只是它会使用一定的内存空间来保存这些视频数据。在Chromium的设置中,最小的缓存空间是2M内存,最大的缓存空间是20M内存,并没有使用磁盘来缓存视频资源。

                             图11-2 Chromium的视频资源缓存类

        上面这些都是浏览器为视频或者音频所做的工作,看起来一切都与网页开发者无关,真是这样的吗?当然不是,W3C组织提供了Media Source规范,开发者可以使用Media Source接口来进行音视频数据流的缓冲,这样可以按照实际需求来处理数据。还是来看一个JavaScript代码的例子,如示例代码11-2所示。

示例代码11-2 一个使用MediaSource接口的代码片段

    var mediaSource = new MediaSource();var avideo = document.querySelector('avideo');avideo.src = window.URL.createObjectURL(mediaSource);mediaSource.addEventListener('sourceopen', function(e) {var sourceBuffer =mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');sourceBuffer.append(aChunk);}, false);

这段代码的基本思想是,Web开发者使用“video”元素的“src”属性设置自定义的数据流。不同于传统文件等数据流方式,示例代码11-2使用MediaSource对象来创建一个URL对象,然后往对象中不断地加入音视频数据。结合前面关于播放控制的JavaScript接口和事件,开发者可以将数据流同多媒体播放器播放进度很好地结合起来,从而达到根据实际需求来实现自适应的数据流的目的。

2.3.2 基础设施

        前面介绍了WebKit中支持规范的相关类等基础设施,这里介绍Chromium中支持硬件加速机制的视频播放所需的基础设施。图11-3是一个总体架构图,基于Chromium的多进程结构。

                        图11-3 Chromium多进程结构的媒体播放器设施

        根据多进程架构的设计原则,Chromium的媒体播放器的实现应该在Renderer进程,而对于资源的获取则是在Browser进程。当然,前面介绍的WebKit基础设施需要每个移植的具体实现,所以,WebKit的Chromium移植部分提供了桥接接口,并且实现则是在Chromium代码中来完成的。Chromium支持媒体播放器的具体实现相当复杂,而且涉及到不同的操作系统,目前Chromium在不同操作系统上实现的媒体播放器也不一样。首先看一看Chromium基础类,为了方便理解这些类和图11-1中类之间的关系,图11-4标注了一些WebKit中同Chromium直接相关的类。

                                        图11-4 Chromium支持视频的基础类和关系

        图11-4的上半部分是WebKit和WebKit的Chromium移植中的相关类,它们同样出现在图11-1中,而下半部分是Chromium中使用硬件加速机制来实现视频播放的基础设施类。而从左右分开来看,左边部分是播放器的具体实现类,右边部分则是支持视频在合成器中工作的相关类。

        首先看一看这些类和对象的创建过程。WebMediaPlayerClientImpl类是WebKit在创建HTMLMediaElement对象之后创建MediaPlayer对象的时候,由MediaPlayer对象来创建的。当视频资源开始加载时,WebKit创建一个WebMediaPlayer对象,当然就是Chromium中的具体实现类WebMediaPlayerImpl对象,同时WebMediaPlayerClientImpl类也实现了WebMediaPlayerClient类,所以WebMediaPlayerImpl在播放视频的过程中需要向该WebMediaPlayerClient类更新各种状态,这些状态信息最终会传递到HTMLMediaElement类中,最终可能成为JavaScript事件,如前面介绍播放进度事件等。之后,WebMediaPlayerImpl对象会创建一个WebLayerImpl对象,还会同时创建VideoLayer对象,根据合成器的设计,Chromium还有一个LayerImpl树,在同步的时候,VideoLayer对象对应的VideoLayerImpl对象会被创建。之后Chromium需要创建VideoFrameProviderClientImpl对象,该对象将合成器的Video层同视频播放器联系起来并将合成器绘制一帧的请求转给提供视频内容的VideoFrameProvider类,这实际上是调用Chromium的媒体播放器WebMediaPlayerImpl,因为它就是一个VideoFrameProvider类的实现子类。

        然后是Chromium如何使用这些类来生成和显示每一帧的。当合成器调用每一层来绘制下一帧的时候,VideoFrameProviderClientImpl::AcquireLockAndCurrentFrame()函数会被调用,然后该函数调用WebMediaPlayerImpl类的GetCurrentFrame函数返回当前一帧的数据。VideoLayerImpl类根据需要会将这一帧数据上传(或者是拷贝等)到GPU的纹理对象中。当绘制完这一帧之后,VideoLayerImpl调用VideoFrame-ProviderClientImpl::PutCurrentFrame来通知播放器这一帧已绘制完成,并释放掉相应的资源。同时,媒体播放器也可以通知合成器有一些新帧生成,需要绘制出来,它会首先调用播放器的VideoFrameProvider::DidReceiveFrame()函数,该函数用来检查当前有没有一个VideoLayerImpl对象,如果有对象存在,需要设置它的SetNeedsRedraw标记位,这样,合成器就知道需要重新生成新的一帧。

        最后是上述有关视频播放对象的销毁过程。有多种情况使Chromium需要销毁媒体播放器和相关的资源,如“video”元素被移除或者设置为隐藏等,这样视频元素对应的各种层对象,以及WebKit和Chromium中的这些设施就会被销毁。

        WebMediaPlayerImpl类是多媒体播放器的具体实现类。在Chromium项目中,随着工程师增加了对Android系统(这里不涉及iOS系统话题,那是另外的故事)的支持,Chromium既能支持桌面系统也能支持移动系统,而这两者对视频和音频的支持很不一样,所以在不同系统上WebMediaPlayerImpl是如何实现和工作的,也很不一样。下面,依次了解桌面系统和Android系统中支持视频播放的过程。

2.3.3 桌面系统

        在桌面系统中,Chromium使用了一套多媒体播放框架,而不是直接使用系统或者第三方库的完整解决方案。图11-5是Chromium在桌面系统中采用的多媒体播放引擎的工作模块和过程,来源于网页http://www.chromium.org/developers/design-documents/video,这里稍微做了些修改,这一框架称为多媒体管线化引擎,图中主要的模块是多路分配器(Demuxer)、音视频解码器、音视频渲染器。这些部分主要被WebMediaPlayerImpl类调用。

                                                图11-5 Chromium的多媒体管线化引擎

        在处理音视频的管线化过程中,需要解码器和渲染器来分别处理视频和音频数据。它们均采用一种叫做“拉”而不是“推”的方式进行,也就是说由视频或者音频渲染器根据声卡或者时钟控制器,按需要来请求解码器解码数据,然后解码器和渲染器又向前请求“拉”数据,直到请求从视频资源文件读入数据。根据之前的多进程架构和Chromium的安全机制,整个管线化引擎虽然在Renderer进程中,但是由于Renderer进程不能访问声卡,所以图中渲染器需要通过IPC将数据或者消息同Browser进程通信,由Browser进程来访问声卡。

        虽然FFmpeg多媒体库拥有上述管线化过程的能力,但是其实Chromium并不是将其作为一个黑盒来使用,而是分别使用FFmpeg的不同模块来实现自己的管线化引擎,目的是由自身来控制这一整个过程。

        Chromium使用并行FFmpeg解码技术,也就是说FFmpeg能够在帧这个层面上并行解码,当然这不是针对所有格式的视频文件,目前主要针对H.264这个格式的视频。根据Chromium官方的实验结果,在多核机器上,性能能够得到较大幅度的提升。

        FFmpeg多媒体库只是在桌面系统上被使用,而在Android上则是另外一种情况了。

2.3.4 Android系统

        在Android系统上,情况变得很不一样,因为Chromium使用的是Android系统所提供的android.media.MediaPlayer类,也就是使用系统提供的音视频的渲染框架。在减少了管线化引擎带来复杂性的同时,Chromium却额外引入了一些复杂性,接下来一起来看看。

Android中的Chromium彻底抛弃了FFmpeg,直接使用系统自带的多媒体功能,因而,Android系统支持什么样的视频和音频格式,Chromium就只能支持什么样的相应格式。同时,由于Android多媒体框架的优点,使得视频元素仍然能够同HTML5中的其他技术一起工作,这点很重要。

1.Android媒体播放框架

        Android中使用一个名为“MediaService”的服务进程来为应用程序提供音频和视频的播放功能,图11-6所示的是一个Android的多媒体框架概念图。对于每一个使用多媒体播放功能的应用程序来说,“MediaService”服务是透明的。因为Android系统提供了使用“MediaService”的封装接口,这些接口隐藏了“MediaService”服务内部的细节,应用程序只是使用了简单的播放接口。

                                        图11-6 Android多媒体框架

        MediaService能够为多个播放器提供服务,对于播放器来说,它主要设置两个参数,其一是输入的URL,其二是输出结果的绘制目标。图11-7描述了Android的播放器类和相关类,以及它们之间的关系。

                                        图11-7 Android的MediaPlayer相关类

        所以,当应用程序需要使用播放器的时候,Chromium可以创建MediaPlayer类的对象,调用setDataSource函数来设置待播放视频文件,并调用setSurface来设置视频结果绘制的目标——SurfaceTexture对象,这是一个GL的纹理对象。因为实际的解码和绘制是在MediaService进程中完成的,这需要该纹理对象能够被多个不同的GL上下文对象所访问,支持多个GL上下文对象访问的GL经理对象的类型就是:GL_TEXTURE_EXTERNAL_OES。

        根据上面的描述,读者可以看到Chromium使用Android系统提供的音视频播放功能。这表示Chromium使用Android系统的音视频解码器,所以Chromium是依赖于Android系统支持的音视频编码格式,而不像Chromium的桌面版独立于操作系统支持的音视频编码格式。

2.Chromium的视频解决方案

        在Android系统上,因为Chromium使用系统的多媒体框架,所以它没有自己的管线化引擎,主要的工作还是将Chromium的架构同Android多媒体框架结合起来以完成对网页中视频和音频的播放。

        图11-8是Chromium在Android系统上支持音频和视频播放的播放器主要类,因为Chromium的多进程架构,所以这里面包括两大部分,首先是右侧的Renderer进程中的相关类。根据前面Chromium的桌面版上支持多媒体的相关类,笔者可以看到WebKit::WebMediaPlayer类和WebMediaPlayerClient类来自于WebKit的Chromium移植,这两个类在所有平台上的定义都是一样的。下面介绍Chromium的Android版支持多媒体播放的不同之处。

                                        图11-8 Android系统上的播放器基础设施

        上图中右侧的Renderer进程,从上向下看首先是WebMediaPlayerAndroid类,它同之前的WebMediaPlayerImpl类相似,表示的是Android系统上网页中的播放器,同video元素是一一对应的。与桌面系统上不一样的是,Android系统使用Renderer-MediaPlayerManager类来管理所有的WebMediaPlayerAndroid对象,这是因为一个网页中可能包含多个播放器实例。而WebMediaPlayerProxyAndroid则是同Browser进程来通信的,因为真正的Android播放器是在Browser进程中的,这里主要请求Browser进程创建实际的Android的MediaPlayer类并设置播放文件的信息。

        图11-8中左侧则是实际的播放器,在JNI(Java Native Interface)之上的是Java类,如同前面介绍的,该播放器就是使用Android系统中的android.media.MediaPlayer及其相关类来工作的。从下向上看,首先是BrowserMediaPlayerManager类,该类不仅负责同Renderer进程的播放器类进行通信,而且自身又是一个播放器的管理类,它包含当前全部网页中的所有播放器对象,因为可能会有多个Renderer进程,所以只能通过播放器的唯一标记来区分这些播放器。BrowserMediaPlayerManager类管理称为MediaPlayerAndroid类的多个对象,而MediaPlayerAndroid的子类MediaPlayerBridge则是具体实现类,该子类能够与Java层中相同名字类通过JNI调用来控制Android系统的播放器类,图中已经表明这一关系。请读者记住,这里的所有类都是工作在Browser进程的主线程。

        上面的过程基本上就是如何在网页中创建一个播放器的过程,从右向左,直到图11-8中左侧上面的android.media.MediaPlayer对象被创建完成,与此同时Chromium获取网页中设置的视频文件的URL字符串,然后传递并设置该URL字符串到Android的媒体播放器中。

        输入是有了,那么输出呢?播放器将解码之后的结果输出到什么目标上呢?在Android上,如前面所述,Chrome使用SurfaceTexture对象作为输出目标。创建和使用SurfaceTexture对象的过程是如何进行的呢?当Chromium调用WebMediaPlayerAndroid类的play函数时,该函数发起请求从Renderer进程到Browser进程来创建输出目标,也就是SurfaceTexture对象,图11-9描述了这一过程中使用到的主要类和它们之间的关系。

                                图11-9 媒体播放器的视频结果基础设施

        下面依次了解右侧的Renderer进程部分。从上往下看,最上面的是StreamTexture-FactoryImpl类,顾名思义,该类就是创建目标结果存储空间的类,它被WebMedia-PlayerAndroid类使用来创建所需要的结果存储对象StreamTexture。因为实际的对象是在Browser进程中被创建的,所以Renderer进程中的StreamTextureProxy类就是一个代理类,最后的请求通过GPUChannelHost类来传递给Browser进程。

        在Browser进程中,负责处理上述请求的是GPU线程,该线程由StreamTextureManager-Android类来处理所有创建StreamTexture对象的请求。StreamTexture对象的直接使用者是GPU线程。Renderer进程需要区分和标识这些StreamTexture对象,具体的方法是使用整形标记符来表示Browser进程中的各个StreamTexture对象。StreamTexture和StreamTextureManager是基础抽象类,在Android系统上,StreamTextureAndroid和StreamTextureManagerAndroid是实际的实现类。Stream-TextureAndroid表示的是C++端的桥接类,它包含一个SurfaceTexture对象,该对象会在Java端创建一个android.graphics.SurfaceTexture对象,Chromium设置该对象到MediaPlayer对象作为播放器的输出目标。

        当视频播放器将解码后的结果写入到SurfaceTexture中后,播放器需要告诉Chromium浏览器这一信息,因为Chromium浏览器需要执行合成操作,而合成器在Renderer进程中,同之前创建SurfaceTexture对象的调用过程正好相反,这里需要使用回调机制,这就是Java层SurfaceTextureListener类的作用,该回调类注册Java层的回调对象到创建好的SurfaceTexture对象,当该对象被写入新帧的时候,Chromium首先是从Browser进程中的Java层将这一回调动作通过JNI到C++层的SurfaceTextureListener类的FrameAvailable函数,该函数经过StreamTextureAndroid和StreamTextureManagerAndroid类最后发送到Renderer进程,Renderer进程的调用过程如图11-10所示。

                                                图11-10 视频帧的合成过程

        上面的过程同桌面系统是一致的,在这之后的合成过程相信读者都知道了吧?没错,读者可以回忆一下第8章中对于它们的详细介绍,视频只是众多层中的一层,合成过程仍然是之前所描述的那样。

        网页中的视频播放有两种模式,其一是嵌入式模式,其二是全屏模式,这两种模式在对解码后结果的处理上是不一样的。图11-11描述了全屏模式创建视频结果的绘制目标的相关类和过程。

                                图11-11 全屏模式下的输出目标创建过程

        当某个播放器进入全屏模式的时候,Chromium使用ContentVideoView类来管理,该类会创建一个SurfaceView对象并将对象传递给C++端的ContentVideoView类,因为总是只有一个播放器是全屏模式,而且BrowserMediaPlayerManager管理所有的MediaPlayer对象,所以该管理类能够知道哪个对象是全屏播放模式,并将该SurfaceView对象设置到相应的MediaPlayer对象中去。

        关于多媒体播放器,还有一点非常有趣,那就是播放器的控制器(Controls),它是用来控制播放的开始、停止、快进、声音控制等操作的,网页的开发者在“video”元素中加入属性“controls”就可以调用默认的控制器,浏览器就可以为网页绘制出一个默认的控制器,当然开发者也能够定义自身的控制器,因为浏览器已经提供了相应的JavaScript接口。当使用默认控制器的时候,浏览器是如何绘制控制器的呢?方法就是使用第4章的影子DOM技术,此处介绍的DOM树结构不会出现在网页的DOM树中,这样就可以使用HTML5的CSS技术来绘制所需的控制器,非常方便而且易于维护。

2.4 字幕

        对于视频技术,还有一个重要的组成部分,那就是字幕的支持。庆幸的是,W3C组织已经开始定义支持字幕的“track”元素,而字幕文件采用的格式是WebVTT格式,该格式看起来比较直观,简单的例子就是时间戳区间加上相应的字幕文字,有兴趣的读者可以去W3C官网上查看一下。示例代码11-3是一个使用字幕的视频元素,实际上,因为语言的问题,每个“video”元素可以有多个“track”元素,每个“track”元素可以用来表示一种语言。

示例代码11-3 使用字幕的视频元素代码

    <video controls="controls"><source src="video.mp4" type="video/mp4"><track src="captions.vtt" kind="subtitles" srclang="en"  label="English"></track></video>

        字幕文件的解释工作不依赖各个WebKit移植,WebCore模块完整地支持了“track”元素解析、字幕文件解析等功能。图11-12是WebKit支持字幕功能的主要类,笔者逐次来分析它们。

                                                图11-12 WebKit中支持字幕的基础设施

        “track”本身是一个HTML元素,所以它在DOM中有相应的节点元素,这就是图中的HTMLTrackElement类。根据规范,“track”元素有一个重要的属性,那就是“src”,该属性指定了字幕文件的URL。WebKit使用LoadableTextTrack类来负责解析字幕文件并使用TextTrack类来存储解析后的结果。目前WebKit只支持WebVTT格式的字幕,使用WebVTTParser解析器来解释它们,关系不是很复杂。

        下面一部分是提供接口,这里的接口依然是WebKit的Chromium移植所定义的接口,不同的移植所定义的接口可能不一样。接口依然是两个类,WebInbandTextTrack和WebInbandText-TrackClient类,且是公开接口,WebInbandTextTrack类由Chromium实现,由WebKit调用。而WebInbandTextTrackClient类则由WebKit实现,实现类就是InbandTextTrackPrivateImpl,它实现WebInbandTextTrackClient的接口,然后调用解析后的字幕并返回给Chromium。这一过程由InbandTextTrackPrivateClient类和InbandTextTrack类完成,这里类的关系有些复杂,WebKit/Blink今后最好能简化一下。

        上面这些动作需要将一些消息传递给JavaScript代码,因为规范提供了JavaScript接口,开发者可以让JavaScript代码控制或者获取字幕信息,这些不再介绍。下面是Chromium中的支持框架,图11-13描述了Chromium是如何将WebKit中的字幕信息桥接到多媒体管线化引擎中去的。

                                图11-13 Chromium中支持字幕的基础设施

        在Chromium中,WebMediaPlayerImpl类创建继承类的对象,并设置WebInband-TextTrackClient对象到该对象。根据之前的介绍可知,该对象实际上是InTextTrack,它包含解析后的字幕内容,这样TextTrackImpl就可以获得字幕的内容,而TextTrack对象会被多媒体的管线化引擎所调用并渲染在视频的结果中。

2.5 视频扩展

        在视频领域,还有很多方面在不停地向前发展,包括Media Source接口、音视频资源保护等,这些称为Media的扩展。

        接下来讨论的是对音视频资源的保护,也就是版权保护的问题,通俗一点就是如何避免被非法拷贝和使用。在HTML5中,目前没有成熟方案的原因有两种。一种说法是编码格式应该自行解决该问题,而不是需要HTML5额外提供解决方案。但是,就目前而言,主流的三种方式都没有解决加密等保护问题,所以事实上这的确是一个问题。另外一种就是目前标准组织没有继续坚持之前的想法,开始了其他方面的研究和工作,这就是“Encrypted Media Extensions”,它目前还在草案阶段,主要用来保护播放内容的安全,具体请查看W3C官方网站上的文档。

        而关于Media Source扩展,其主要目的是提供接口来让JavaScript代码能够生成多媒体流,典型的应用场景是自适应流,其主要接口是MediaSource和SourceBuffer。每个MediaSource对象可以包含多个SourceBuffer对象,每个SourceBuffer包含一个数据流,如视频流或音频流,Chromium已经开始提供一些支持。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/245296.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

字符串匹配(BF KMP)详解 + 刷题

目录 &#x1f33c;前言 BF 算法 KMP 算法 &#xff08;1&#xff09;前缀函数 -- O(n^3) &#xff08;2&#xff09;前缀函数 -- O(n^2) &#xff08;3&#xff09;前缀函数 -- O(n) &#xff08;4&#xff09;辅助理解 &#x1f40b;P1308 -- 统计单词数 …

Linux:使用for+find查找文件并cp到其他目录,文件名带有空格

一、场景描述 在终端窗口中&#xff0c;用shell命令&#xff0c;批量拷贝文件到指定目录。 我是在Windows系统上&#xff0c;通过git bash终端来执行shell命令的。 二、实现过程 命令1 for filepath in find /d/LearningMaterials/数学/数学/高中/一数/偏基础&#xff08;基…

年销180万辆的特斯拉,护城河却在崩塌

文&#xff5c;刘俊宏 2023年率先开启汽车价格战的马斯克&#xff0c;伤敌一百自损八千&#xff1f; 在1月25日的特斯拉2023Q4财报电话会上&#xff0c;特斯拉CEO马斯克对中国公司的竞争力如此感叹道&#xff0c;“要是没有贸易壁垒&#xff0c;他们将摧毁&#xff08;destroy…

EXECL 单元格字符串链接 CONCAT :应用:将一行数据转为json

源&#xff1a; 目标 函数表示 CONCAT("data", CHAR(10), "{", CHAR(10), " ", "ulAlarmId : ", A5, CHAR(10), " ", "ulAlarmLevel : ", D5, CHAR(10)," ", "bBo…

《剑指 Offer》专项突破版 - 面试题 28 : 展平多级双向链表(C++ 实现)

题目连接&#xff1a;LCR 028. 扁平化多级双向链表 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 在一个多级双向链表中&#xff0c;节点除了有两个指针分别指向前后两个节点&#xff0c;还有一个指针指向它的子链表&#xff0c;并且子链表也是一个双向链表&…

怎么给wordpress网站底部页脚添加备案号和链接?

以前“WordPress后台 >> 常规”最底部是有一个ICP备案号的&#xff0c;我们只需要填写备案号并保存更改即可让WordPress自带主题底部显示ICP备案号&#xff0c;但是现在新版本的WordPress已经没有了这个ICP备案号选项&#xff0c;而且也无法直接添加公安联网备案号&#…

常见の算法

前言本文主要使用Java 什么&#xff0c;是快乐星球#&#xffe5;%……什么是算法&#xff1f; 算法是一组完成任务的指令。任何代码片段都可视为算法&#xff0c;但我们主要介绍常见算法 一、引入——二分查找 二分查找是一种算法&#xff0c;其输入是一个有序的元素列表。如…

web安全学习笔记【09】——算法2

基础[1] 入门-算法逆向&散列对称非对称&JS源码逆向&AES&DES&RSA&SHA #知识点&#xff1a; 1、Web常规-系统&中间件&数据库&源码等 2、Web其他-前后端&软件&Docker&分配站等 3、Web拓展-CDN&WAF&OSS&反向&负载…

socket以及字节序

1. socket 介绍&#xff1a; 简介&#xff1a; 所谓 socket&#xff08; 套接字&#xff09;&#xff0c;就是对网络中不同主机上的应用进程之间进行双向通信的 端点的抽象。 一个套接字就是网络上进程通信的一端&#xff0c;提供了应用层进程利用网络协议交换数据的机制。从所…

字符金字塔(C语言刷题)

个人博客主页&#xff1a;https://blog.csdn.net/2301_79293429?typeblog 专栏&#xff1a;https://blog.csdn.net/2301_79293429/category_12545690.html 题目描述 请打印输出一个字符金字塔&#xff0c;字符金字塔的特征请参考样例 输入描述: 输入一个字母&#xff0c;保…

[BSidesCF 2020]Had a bad day

先看url&#xff0c;发现可能有注入 http://655c742e-b427-485c-9e15-20a1e7ef1717.node5.buuoj.cn:81/index.php?categorywoofers 试试能不能查看index.php直接?categoryindex.php不行&#xff0c;试试伪协议 把.php去掉试试 base64解码 <?php$file $_GET[category];…

Kali如何启动SSH服务并实现无公网ip环境远程连接

文章目录 1. 启动kali ssh 服务2. kali 安装cpolar 内网穿透3. 配置kali ssh公网地址4. 远程连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 简单几步通过[cpolar 内网穿透](cpolar官网-安全的内网穿透工具 | 无需公网ip | 远程访问 | 搭建网站)软件实现ssh 远程连接kali! …

Termux结合内网穿透实现无公网ip远程SFTP传输文件

目录 前言 1. 安装openSSH 2. 安装cpolar 3. 远程SFTP连接配置 4. 远程SFTP访问 4. 配置固定远程连接地址 结语 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊Termux结合内网穿透实现无公网ip远程SFTP传输文件&#xff0c;希望大家能…

模拟队列

输入样例&#xff1a; 10 push 6 empty query pop empty push 3 push 4 pop query push 6输出样例&#xff1a; NO 6 YES 4 import java.util.Scanner;public class Main{public static void main(String[] args) {Scanner sc new Scanner(System.in);int m sc.nextInt();…

nodejs学习计划--(六)包管理工具

包管理工具 1. 介绍 包是什么 『包』英文单词是 package &#xff0c;代表了一组特定功能的源码集合包管理工具 管理『包』的应用软件&#xff0c;可以对「包」进行 下载安装 &#xff0c; 更新 &#xff0c; 删除 &#xff0c; 上传 等操作 借助包管理工具&#xff0c;可以快…

蓝桥杯备赛 week 3 —— 高精度(C/C++,零基础,配图)

目录 &#x1f308;前言&#xff1a; &#x1f4c1; 高精度的概念 &#x1f4c1; 高精度加法和其模板 &#x1f4c1; 高精度减法和其模板 &#x1f4c1; 高精度乘法和其模板 &#x1f4c1; 高精度除法和其模板 &#x1f4c1; 总结 &#x1f308;前言&#xff1a; 这篇文…

不合格机器人工程讲师再读《悉达多》-2024-

一次又一次失败的经历&#xff0c;让我对经典书籍的认同感越来越多&#xff0c;越来越觉得原来的自己是多么多么的无知和愚昧。 ----zhangrelay 唯物也好&#xff0c;唯心也罢&#xff0c;我们都要先热爱这个世界&#xff0c;然后才能在其中找到自己所热爱的事业。 ----zh…

Find My卡片正成为消费电子香饽饽,伦茨科技ST17H6x可以帮到您

今年CES许多公司发布支持苹果Find My的卡片产品&#xff0c;这种产品轻薄可充电&#xff0c;放在钱包、背包或者手提包可以防丢查找&#xff0c;在智能化加持下&#xff0c;防丢卡片使得人们日益关心自行车的去向。最新的防丢卡片与苹果Find My结合&#xff0c;智能防丢&#x…

【MIdjourney】一些材质相关的关键词

1.多维剪纸(Multidimensional papercut) "Multidimensional papercut"&#xff08;多维剪纸&#xff09;是一种剪纸艺术形式&#xff0c;通过多层次的剪纸技巧和设计来创造出立体感和深度感。这种艺术形式通常涉及在不同的纸层上剪裁不同的图案&#xff0c;并将它们…

Oracle 经典练习题 50 题

文章目录 一 CreateTable二 练习题1 查询"01"课程比"02"课程成绩高的学生的信息及课程分数2 查询"01"课程比"02"课程成绩低的学生的信息及课程分数3 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩4 查询平均成绩小于…