必须使用MSE实现自定义分片播放与低延迟直播;需在sourceopen事件后创建SourceBuffer,正确设置MIME类型并校验updating状态,严格管理时间戳与缓冲区以避免卡顿。

直接用 标签无法播放自定义分片(比如 fMP4)、无法控制加载时机、也不能实现低延迟直播——必须走 MSE 路线。MSE 不是“可选增强”,而是现代 Web 流媒体的基础设施层。
MediaSource 创建后立即绑定 src,但别急着 appendBuffer
浏览器对 MediaSource 状态非常敏感:readyState 必须为 "open" 才能调用 addSourceBuffer();而 sourceopen 事件才是安全起点。常见错误是:创建 MediaSource 后立刻 addSourceBuffer(),或在 sourceopen 外部写入数据,导致 InvalidStateError。
- 必须用
URL.createObjectURL(mediaSource)绑定到video.src,不能用字符串路径 -
mediaSource.addEventListener('sourceopen', ...)是唯一可靠的初始化入口 - 若页面已存在
video元素,需先清空src再重新赋值,否则旧资源残留可能阻塞新流
SourceBuffer MIME type 必须匹配实际分片格式
addSourceBuffer() 的 MIME 参数不是摆设。填错会导致 appendBuffer() 静默失败,或报 TypeError: Failed to execute 'appendBuffer' on 'SourceBuffer': The buffer passed is empty(实际不空,只是解码器拒收)。
- fMP4 分片用
video/mp4; codecs="avc1.64001f"(H.264 baseline)或av01.0.04M.08(AV1) - 别照抄示例里的
avc1.42E01E——它对应 H.264 Constrained Baseline,老编码器才用;新转码服务(如 FFmpeg -c:v libx264 -profile:v main)输出的是avc1.640020级别 - 音频必须显式声明:如
audio/mp4; codecs="mp4a.40.2";混流时需两个SourceBuffer,且时间戳严格对齐
appendBuffer 前必须检查 updating 状态
SourceBuffer.updating 是布尔值,表示上一次 appendBuffer() 是否还在处理中。强行再写会触发 InvalidStateError,尤其在 WebSocket 持续推送或 fetch 并发请求时极易发生。
- 每次调用前加判断:
if (!sourceBuffer.updating) { sourceBuffer.appendBuffer(data); } - 监听
updateend事件比轮询updating更可靠,适合做分片调度队列 - 遇到
error事件时,sourceBuffer.abort()是恢复手段,但必须等updateend后再重试,否则仍报错
直播场景下时间戳和缓冲区管理是卡顿根源
MSE 不自动做 PTS/DTS 对齐,也不帮你丢帧或跳段。如果服务端推送的 fMP4 片段时间戳不连续(比如从 10s 直接跳到 15s),或客户端追加太慢导致缓冲区断档,video 就会卡住、黑屏、甚至触发 stalled 事件。
- fMP4 init segment 必须含
moov,且每个 media segment(m4s)的moof+mdat必须携带准确track fragment decode time - 用
sourceBuffer.buffered查当前缓冲区间,结合video.currentTime判断是否要预加载下一片(别等播到头才发起请求) - 移动端尤其注意:iOS Safari 对
buffered的精度较低,建议预留至少 3 秒缓冲余量
真正难的不是调通第一个 appendBuffer(),而是让时间戳、分片边界、缓冲水位、网络抖动全部对齐——这些细节不会报错,但会让画面卡顿、音画不同步、seek 失败,且很难复现。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











