2023年6月27日发(作者:)
MediaSourceExtensionMedia Source ExtensionsMedia Source API,正式称为Media Source Extensions (MSE),提供了基于web且不依赖插件播放流媒体的功能。使⽤MSE,可以通过JavaScript创建媒体流MediaSource,并使⽤和元素播放。MSE可以让我们使⽤⼀个 MediaSource 对象来替代通常的单个媒体⽂件的 src 值给HTMLMediaElement元素。MSE 让我们能够根据内容获取的⼤⼩和频率,或是内存占⽤详情(例如什么时候缓存被回收),进⾏更加精准地控制。MSE为可扩展API构建⾃适应码率播放器的出现奠定了基础,例如DASH 、 HLS播放器。使⽤createObjectURL将MediaSource和video标签连接起来var mediaSource = new MediaSource;//(tate); // = ObjectURL(mediaSource);ntListener('sourceopen', sourceOpen);function sourceOpen(){ ObjectURL()}创建MediaSource对象,通过ObjectURL()将MediaSource对象转换为url,然后赋值给媒体元素的src。MS对象的sourceopen事件触发时,代表MS对象和媒体元素两者已经连接在⼀起,ObjectURL创建的url就没有作⽤可以销毁。Media Source API⽀持事件:sourceopen 绑定到媒体元素后开始触发sourceclosed 未绑定到媒体元素后开始触发sourceended 所有数据接收完成后触发对应的属性tate:open MSE 实例,已经绑定到了媒体元素上,等待接受数据或者正在接受数据closed MSE 实例未绑定到了媒体元素上。MS刚创建时就是该状态。ended MSE 实例,已经绑定到了媒体元素上, 并且所有数据都已经接受到了。当endOfStream()执⾏完成,会变为该状态。设置编码类型mime 字符串,创建SourceBufferfunction sourceOpen(e) {
ObjectURL(); var mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; // refers to the mediaSource instance. // Store it in a variable so it can be used in a closure. var mediaSource = ; // addSourceBuffer只能在readyState为open时调⽤ var sourceBuffer = rceBuffer(mime); // Fetch and process the video.}⾸先,前⾯的 video/mp4 代表这是⼀段 mp4 格式封装的视频,同理也存在类似 video/webm、audio/mpeg、audio/mp4 这样的mime 格式。⼀般情况下,可以通过 canPlayType 这个⽅法来判断浏览器是否⽀持当前格式。后⾯的这⼀段 codecs="…" ⽐较特别,以逗号相隔,分为两段:1. 第⼀段,‘avc1.42E01E’,即它⽤于告诉浏览器关于视频编解码的⼀些重要信息,诸如编码⽅式、分辨率、帧率、码率以及对解码器解码能⼒的要求。在这个例⼦中,**‘avc1’ **代表视频采⽤ H.264 编码,随后是⼀个分隔点,之后是 3 个两位的⼗六进制的数,这 3 个⼗六进制数分别代表:AVCProfileIndication(42)profile_compability(E0)AVCLevelIndication(1E)第⼀个⽤于标识 H.264 的 profile,后两个⽤于标识视频对于解码器的要求,只是浏览器⽤于判断⾃⾝的解码能⼒能否满⾜需求,所以不需要和视频完全对应,更⾼也是可以的。对于⼀个 mp4 视频,可以使⽤ mp4file 这样的命令⾏⼯具来查看这些参数:mp4file --dump 42.
SourceBuffer简介SourceBuffer 是由 mediaSource 创建,并直接和 HTMLMediaElement 接触。简单来说,它就是⼀个流的容器,⾥⾯提供的append(),remove() 来进⾏流的操作,它可以包含⼀个或者多个 media segments。1 添加/移除 buffer1.1 appendBufferappendBuffer可以动态地向 MediaSource 中添加视频/⾳频⽚段(对于⼀个 MediaSource,可以同时存在多个 SourceBuffer)如果视频很长,存在多个chunk 的话,就需要不停地向 SourceBuffer 中加⼊新的 chunk。这⾥就需要注意⼀个问题了,即appendBuffer 是异步执⾏的,在完成前,不能 append 新的 chunk,⽽是应该监听 SourceBuffer 上的 updateend 事件,确定空闲后,再加⼊新的 chunk:ntListener('updateend', () => { //
这个时候才能加⼊新 chunk //
先设定新chunk加⼊的位置,⽐如第20秒处 ampOffset = 20 //
然后加⼊ Buffer(newBuffer)}当然,并不是所有的 Buffer 都能随便添加给指定的 SB,这⾥⾯是需要条件和相关顺序的。该 buffer,必须满⾜ MIME 限定的类型该 buffer,必须包含 initialization segments(IS) 和 media segments(MS)在添加 Buffer 的时候,你需要了解你所采⽤的 mode 是哪种类型,sequence 或者 segments。这两种是完全两种不同的添加⽅式。1. segments:这种⽅式是直接根据 MP4 ⽂件中的 pts 来决定播放的位置和顺序,它的添加⽅式极其简单,只需要判断 updating=== false,然后,直接通过 appendBuffer 添加即可。2. sequence:如果你是采⽤这种⽅式进⾏添加 Buffer 进⾏播放的话,那么你也就没必要了解 FMP4 格式,⽽是了解 MP4 格式。因为,该模式下,SB 是根据具体添加的位置来进⾏播放的。所以,如果你是 FMP4 的话,有可能就有点不适合了。针对 sequence 来说,每段buffer 都必须有⾃⼰本⾝的指定时长,每段 buffer 不需要参考的 baseDts,即,他们直接可以毫⽆关联。那 sequence 具体怎么操作呢?简单来说,在每⼀次添加过后,都需要根据指定 SB 上的 timestampOffset。该属性,是⽤来控制具体 Buffer 的播放时长和位置的。if (!ng) { let MS = this._mergeBuffer(fer);
Buffer(MS); // **** ampOffset += on; // **** fer = [];}1.2 remove在 SB 中,简单的来说,就是移除指定的时间范围内 buffer。需要⽤到的 API 为:remove(double start, unrestricted double end);具体的步骤为:找到具体需要移除的 segment。得到其开始(start)的时间戳(以 s 为单位)得到其结束(end)的时间戳(以 s 为单位)此时,updating 为 true,表明正在移除完成之后,出发 updateend 事件1.3 abort清空当前 SB 中所有的 segment,常⽤的场景为:当⽤户移动进度条,⽽此时 fetch 已经获取前⼀次的 media segments,那么可以使⽤abort 放弃该操作,转⽽请求新的 media segments2 属性2.1 mode上⾯说过,SB(SourceBuffer) ⾥⾯存储的是 media segments(就是你每次通过 append 添加进去的流⽚段)。 有两种格式:segments: 乱序排放。通过 timestamps 来标识其具体播放的顺序。⽐如:20s的 buffer,30s 的 buffer 等。表⽰ A/V 的播放时根据你视频播放流中的 pts 来决定,该模式也是最常使⽤的。因为⾳视频播放中,最重要的就是 pts 的排序。因为,pts 可以决定播放的时长和顺序,如果⼀旦 A/V 的 pts 错开,有可能就会造成 A/V sync drift。sequence: 按序排放。通过 appendBuffer 的顺序来决定每个 mode 添加的顺序。timestamps 根据 sequence ⾃动产⽣。还需要注意,在播放的同时,你需要告诉 SB这段 segment 有多长,也就是该段 Buffer 的实际偏移量。⽽该段偏移量就是由 timestampOffset决定的。整个过程⽤代码描述⼀下就是:Buffer(t);ampOffset += on;的默认值是根据传进来的media segments决定的,当 media segments 天⽣⾃带 timestamps,那么 mode 就为 segments,否则为 sequence。所以,⼀般情况下,我们是不⽤管它的值。不过,你可以在后⾯,将 segments 设置为 sequence 这个是没⽑病的。反之,将 sequence 设置为 segments 就有问题了。代码如下:Buffer(t);ampOffset += on;如果你想⼿动更改 mode 也是可以的,不过需要注意⼏个先决条件:对应的 ng 必须为 false.如果该 parent MS 处于 ended 状态,则会⼿动将 MS readyState 变为 open 的状态。2.2 buffered返回⼀个 TimeRange 对象。⽤来表⽰当前被存储在 SB 中的 buffer。2.3 updating返回 Boolean,表⽰当前 SB 是否正在被更新。例如: appendBuffer(), appendStream(), remove() 调⽤时。3. 事件在 SB 中,相关事件触发包括:updatestart: 当 updating 由 false 变为 true。update:当 append()/remove() ⽅法被成功调⽤完成时,updating 由 true 变为 false。updateend: append()/remove() 已经结束error: 在 append() 过程中发⽣错误,updating 由 true 变为 false。abort: 当 append()/remove() 过程中,使⽤ abort() ⽅法废弃时,会触发。此时,updating 由 true 变为 false。注意上⾯有两个事件⽐较类似:update 和 updateend。都是表⽰处理的结束,不同的是,update ⽐ updateend 先触发。MediaSource简介1. isTypeSupportedisTypeSupported是静态⽅法,主要是⽤来检测 MS 是否⽀持某个特定的编码和容器盒⼦。例如:Supported('video/mp4; codecs="avc1.42E01E, mp4a.40.2"')2. addSourceBuffer⽤来返回⼀个具体的视频流 SB,接受⼀个 mimeType 表⽰该流的编码格式3. removeSourceBufferremoveSourceBuffer⽤来移除某个 sourceBuffer。⽐如当前流已经结束,那么你就没必要再保留当前 SB 来占⽤空间,可以直接移除。⽰例代码为:SourceBuffer(sourceBuffer);4. endOfStream⽤来表⽰接受的视频流的停⽌,注意,这⾥并不是断开,相当于只是下好了⼀部分视频,然后你可以进⾏播放。此时,MS 的状态变为:ended。例如: var mediaSource = this; var sourceBuffer = rceBuffer(mimeCodec); fetchAB(asssourceopenetURL, function (buf) { ntListener('updateend', function (_) { tream(); //
结束当前的接受 (); //
可以播放当前获得的流 }); Buffer(buf); });BufferssourceBuffers 是 MS 实例上的⼀个属性,它返回的是⼀个 SourceBufferList 的对象,⾥⾯可以获取当前 MS 上挂载的所有 SB。不过,只有当 MS 为 open 状态的时候,它才可以访问。具体使⽤为: var mediaSource = this; var sourceBuffer = rceBuffer(mimeCodec); fetchAB(assetURL, function (buf) { ntListener('updateend', function (_) { tream(); //
结束当前的接受 (); //
可以播放当前获得的流 }); Buffer(buf); });6. activeSourceBufferssourceBuffers 是 MS 实例上的⼀个属性,它返回的是⼀个 SourceBufferList 的对象,⾥⾯可以获取当前 MS 上挂载的所有 SB。不过,只有当 MS 为 open 状态的时候,它才可以访问7. sourceclose事件触发条件sourceclose 是在 media 元素和 MS 断开的时候,才会触发。那这个怎么断开呢?难道直接将 media 的元素的 src 直接设置为 null 就OK 了吗?MS 会这么简单么?实际上并不,如果要⼿动触发 sourceclose 事件的话,则需要下列步骤:将 readyState 设置为 closed将 on 设置为 NaN移除 activeSourceBuffers 上的所有 Buffer触发 activeSourceBuffers 的 removesourcebuffer 事件移除 sourceBuffers 上的 SourceBuffer。触发 sourceBuffers 的 removesourcebuffer 事件触发 MediaSource 的 sourceclose 事件
发布者:admin,转转请注明出处:http://www.yc00.com/web/1687822473a48189.html
评论列表(0条)