如何使用Media Source Buffer和碎片化MP4无需下载全段即可在指定时间启动视频
基于Media Source Extensions实现碎片化MP4指定时间点播放方案
常见属性使用误区
你之前使用的两个属性的作用和预期存在偏差,这里先做澄清:
appendWindowStart:作用是过滤本次追加的Buffer中时间戳小于该值的帧,仅对单次追加操作生效,无法直接指定视频的起始播放时间timestampOffset:作用是给所有后续追加的Buffer的时间戳整体增加固定偏移量,一般用于拼接多段时间不连续的视频分片,不适合用来实现时间跳转
实现步骤
要实现从指定时间(如10秒)起播放,按以下步骤操作即可:
- 初始化
MediaSource实例,将实例生成的对象URL绑定到video元素的src属性,等待sourceopen事件触发 - 提前确认目标时间对应的分片位置:如果是固定时长分片,直接按分片时长计算对应分片序号;如果是单文件碎片化MP4,需要先解析文件的
sidx盒子获取每个分片的时间范围和字节偏移 - 创建
SourceBuffer实例,MIME类型需要和你的MP4文件编码完全匹配 - 先向
SourceBuffer追加MP4的初始化段(包含ftyp和moov盒子),所有播放场景都必须先追加初始化段 - 从目标时间对应的分片开始,依次向
SourceBuffer追加对应的moof+mdat分片内容 - 等待第一个目标分片追加完成触发
updateend事件后,设置video.currentTime = 目标时间,再调用video.play()即可从指定时间开始播放
核心代码示例
const TARGET_START_TIME = 10; // 自定义起始播放时间,单位秒 const video = document.querySelector('video'); const mediaSource = new MediaSource(); video.src = URL.createObjectURL(mediaSource); mediaSource.addEventListener('sourceopen', async () => { // 替换为你的视频对应MIME编码 const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); // 第一步:追加MP4初始化段 const initSegment = await fetch('/video/init.mp4').then(res => res.arrayBuffer()); sourceBuffer.appendBuffer(initSegment); sourceBuffer.addEventListener('updateend', async () => { if (sourceBuffer.updating || mediaSource.readyState !== 'open') return; // 第二步:追加目标时间对应的分片 const targetSegment = await fetch(`/video/seg_${TARGET_START_TIME}.mp4`).then(res => res.arrayBuffer()); // 可选配置:自动过滤分片中早于目标时间的帧 sourceBuffer.appendWindowStart = TARGET_START_TIME; sourceBuffer.appendBuffer(targetSegment); // 分片追加完成后设置播放位置并启动播放 sourceBuffer.onupdateend = () => { if (sourceBuffer.updating) return; video.currentTime = TARGET_START_TIME; video.play(); // 此处可继续追加后续分片实现连续播放 }; }); });
注意事项
- 每次调用
appendBuffer前必须确认sourceBuffer.updating为false,否则会抛出状态错误 - 初始化段仅需追加一次,不需要随分片重复加载
- 如果需要连续播放后续内容,需要在前一个分片追加完成后再触发下一个分片的加载和追加操作
内容的提问来源于stack exchange,提问作者Mohamed Fasil
相关产品推荐
相关产品推荐

