《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.mfbz.cn/a/345671.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(二)CarPlay集成开发之苹果的iAP协议

文章目录 概要协议格式鉴权流程CarPlay中的iAP2协议应用小结 概要 iAP2协议是由苹果公司定义的一种数据通信协议&#xff0c;主要用于苹果设备认证外设&#xff0c;以及与外设数据交换的一种协议 协议格式 协议格式一共分为三种类型&#xff0c;分别为握手包&#xff0c;链路…

「 典型安全漏洞系列 」06.路径遍历(Path Traversal)详解

引言&#xff1a;什么是路径遍历&#xff1f;如何进行路径遍历攻击并规避常见防御&#xff1f;如何防止路径遍历漏洞。 1. 简介 路径遍历&#xff08;Path Traversal&#xff09;是一种安全漏洞&#xff0c;也被称为目录遍历或目录穿越、文件路径遍历。它发生在应用程序未正确…

mac电脑安卓文件传输工具:Android File Transfer直装版

Android File Transfer&#xff08;AFT&#xff09;是一款用于在Mac操作系统上与Android设备之间传输文件。它允许用户将照片、音乐、视频和其他文件从他们的Android手机或平板电脑传输到Mac电脑&#xff0c;以及将文件从Mac上传到Android设备。 下载地址&#xff1a;https://w…

【立创EDA-PCB设计基础完结】7.DRC设计规则检查+优化与丝印调整+打样与PCB生产进度跟踪

前言&#xff1a;本文为PCB设计基础的最后一讲&#xff0c;在本专栏中【立创EDA-PCB设计基础】前面已经将所有网络布线铺铜好了&#xff0c;接下来进行DRC设计规则检查优化与丝印调整打样与PCB生产进度跟踪 目录 1.DRC设计规则检查 2.优化与丝印调整 1.过孔连接优化 2.泪滴…

如何做好一个信息系统项目经理,一个项目经理的个人体会和经验总结(四)

前言 说完了在 项目开发阶段 我的一些个人体会和经验总结&#xff0c;最后我们聊聊在 项目验收阶段 我们需要关注哪些方面的内容…… 项目验收阶段 系统开发告一段落后&#xff0c;就进入客户培训、系统验收阶段&#xff0c;这个阶段&#xff0c;我一般会注意以下几个问题&a…

NAT配置

目录 静态NAT配置配置抓包测试 动态NAT配置配置测试 Easy IP配置配置测试 静态NAT配置 配置 nat static global { global-address} inside {host-address } 命令用于创建静态NAT。 global参数用于配置外部公网地址。 inside参数用于配置内部私有地址。 AR1-NAT <Huawei&g…

Effective C++——关于重载赋值运算

令operator返回一个*this的引用 在重载,,*等运算符时&#xff0c;令其返回一个指向this的引用。 class MyClass {int* val; public:MyClass(int i) : val(new int(i)){}MyClass():val(new int(0)){}void print() {cout << *val << endl;}MyClass& operator(co…

基于SpringBoot Vue美食网站系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

Django入门,十分钟学会登录网页

我们假定你已经阅读了 安装 Django。你能知道 Django 已被安装&#xff0c;且安装的是哪个版本&#xff0c;通过在命令提示行输入命令 cmd黑窗口运行&#xff0c;不懂cmd百度一下 python -m django --version 如果没出现版本&#xff0c;就是没安装&#xff0c;那么用pip安装…

什么叫特征分解?

特征分解&#xff08;Eigenvalue Decomposition&#xff09;是将一个方阵分解为特征向量和特征值的过程。对于一个 nn 的方阵A&#xff0c;其特征向量&#xff08;Eigenvector&#xff09;v 和特征值&#xff08;Eigenvalue&#xff09; λ 满足以下关系&#xff1a; 这可以写…

vp9协议笔记

vp9协议笔记&#x1f4d2; 本文主要是对vp9协议的梳理&#xff0c;协议的细节参考官方文档&#xff1a;VP9协议链接&#xff08;需要加速器&#xff09; vp9协议笔记 vp9协议笔记&#x1f4d2;1. 视频编码概述2. 超级帧superframe&#xff08;sz&#xff09;&#xff1a;2. fr…

【码农新闻】浏览器上有趣的 Console 命令,VSCode 插件 FreeWindow......

目录 【码农新闻】浏览器上有趣的 Console 命令,VSCode 插件 FreeWindow...... 浏览器上有趣的 Console 命令VSCode 插件 FreeWindow拖拽竟然还能这样玩!阮一峰 ES6 教程总结学习网站总结与整理买临期食品的年轻人,在向“吃喝内卷”低头文章所属专区 码农新闻 欢迎各位编程大…

100T数据存进服务器分几步?

大家好&#xff0c;我是豆小匠。 这期来聊聊数据存储相关的问题&#xff0c;包括&#xff1a; 容量评估。技术选型。容灾处理。 另外&#xff0c;文末赠送免费定制红包封面哦&#xff01; 1. 容量评估 通过对容量&性能的评估&#xff0c;可以把业务需求转化成技术语言描…

Mysql数据库DQL查询语言之表连接(联合查询)

表连接 关系字段&#xff1a;两表中有关联关系的字段 \关系字段&#xff1a;两表之间存在关系的字段 什么是表连接&#xff1f; 当我们的查询结果需要从多张表中获取时&#xff0c;此时应该让表之间建立连接&#xff0c;同时获取数据 内连接 特点&#xff1a;同时对连接双方做…

SpringBoot集成mybatis时idea控制台中文乱码问题解决

在application.yml中配置好映射文件打印数据库日志文件时&#xff0c;控制台出现乱码的情况解决如下 问题 在执行查询操作的时候&#xff0c;查询时可以查看是没有问题的&#xff0c;但是控制台乱码了 解决 在File-Setting-Editor-File Encodings中设置如图所示就可以了 现在…

打 jar 包运行 在windows 平台控制台和日志 乱码解决

--拒絕鷄巴囉嗦&#xff0c;直接解決問題 我们在Windows下运行jar包时&#xff0c;常常会出现乱码&#xff0c;主要分为dos窗口输出的日志中出现乱码和程序返回数据出现乱码。 dos窗口输出的日志中出现乱码 执行如下命令&#xff0c;将控制台输出编码改为UTF8&#xff1a; ch…

c++文件操作(2)-- 按照指定格式读写文件

目录 按照指定格式写文件 代码说明: 按照指定格式读文件 -- 解析一定格式的字符串 代码说明&#xff1a; 注意&#xff1a; 问: 为什么使用getline()? 按照指定格式写文件 在实际开发中&#xff0c;我们以一定的格式写入文件当中。 其实就是使用stringstream类对…

【vite】找不到模块“vite”或其相应的类型声明

今天在用vite搭建项目时&#xff0c;在vite.config.ts文件中 ts报错找不到模块“vitejs/plugin-vue”或其相应的类型声明。 原因&#xff1a;项目中缺少了相应的依赖包或 TypeScript 类型声明。可以按照以下步骤进行检查&#xff1a; 1. 确保安装了相应的依赖包 如果在pack…

Unity中URP下获取额外灯数量

文章目录 前言一、SimpleLit下额外灯数量的获取1、在 SimpleLit 下&#xff0c;先获取了额外灯的数量2、对其进行循环计算每一个额外灯3、GetAdditionalLightsCount在这里插入图片描述 二、GetAdditionalLightsCount实现了什么1、_AdditionalLightsCount.x2、unity_LightData.y…

Tarjan 算法(超详细!!)

推荐在 cnblogs 上阅读 Tarjan 算法 前言 说来惭愧&#xff0c;这个模板仅是绿的算法至今我才学会。 我还记得去年 CSP2023 坐大巴路上拿着书背 Tarjan 的模板。虽然那年没有考连通分量类似的题目。 现在做题遇到了 Tarjan&#xff0c;那么&#xff0c;重学&#xff0c;开…
最新文章