<source>标签在DASH/HLS等流媒体中完全失效,因其仅支持静态资源切换,而MSE接管后会忽略所有动态src更新;切换必须基于SourceBuffer的append/remove操作,并严格遵循时间戳对齐、缓冲区检查与多轨道同步等约束。

HTML 原生的 <source> 标签和 src 属性只适用于静态资源切换,无法支撑 DASH/HLS 等复杂流媒体场景下的实时码率决策、缓冲区管理或无缝分段加载——这些必须绕过原生标签,改用 MSE(Media Source Extensions)手动控制。
为什么 <source> 在流媒体切换中完全失效
浏览器解析 <source> 是在 load 阶段一次性完成的:一旦 MediaSource 附加到 <video>,所有后续的 <source> 更新(包括 JS 修改 src 或动态插入新 <source>)都会被忽略。这不是 bug,而是 MSE 设计使然——它接管了整个解复用与喂数据流程,原生 src 路由机制被彻底旁路。
- 现象:
video.src = 'new-hls-url'后调用load(),但播放器卡住或报DOMException: The element has no supported sources - 根本原因:MSE 模式下,
video.src必须是URL.createObjectURL(mediaSource)生成的 blob URL;任何直接赋值非 blob URL 都会清空当前 MediaSource 并中断流水线 - 兼容性陷阱:Safari 对
MediaSource的duration设置敏感,若未提前设好或设错,seek会失败,导致切换后无法跳转到原位置
切换必须基于 SourceBuffer 的 append + remove 操作
真实流媒体切换不是“换链接”,而是“换数据流”:你需要在 updateend 事件触发后,清除旧 SourceBuffer 中残留数据,再向新 SourceBuffer(或同一 buffer 清空后重写)写入目标码率的 fMP4 分片。
- 关键约束:
SourceBuffer.appendBuffer()要求传入的 ArrayBuffer 必须是 ISO BMFF 格式,且时间戳(moof中的traf)需严格对齐;错位会导致音画不同步或 decode error - 安全移除旧数据:
sourceBuffer.remove(start, end)的end必须 ≤ 当前sourceBuffer.buffered.end(0),否则抛InvalidStateError - 多轨道处理:音视频必须分属不同
SourceBuffer(audio/mp4和video/mp4),切换时需同步操作两者,否则出现单声道或黑屏
手动 ABR 切换时最易忽略的三个状态点
ABR 不是“测速 → 换链接”,而是一套闭环状态机。漏掉任一环节,切换就会卡在 loading 或反复 rebuffer。
立即学习“前端免费学习笔记(深入)”;
-
video.buffered:必须检查buffered.length > 0且buffered.end(0) - video.currentTime > 2才敢触发降码率,否则新分片还没来得及填缓冲区就切了,立刻卡顿 -
sourceBuffer.updating:在updateend外部直接调appendBuffer()会报错;必须等该 flag 变为false再调度下一段 - 网络响应头:
Content-Range和Accept-Ranges: bytes缺一不可,否则 Safari 会拒绝加载分片,静默失败无提示
真正棘手的不是“怎么切”,而是“什么时候能切、切完能不能播”。所有逻辑都得卡在 updateend、canplay、timeupdate 这几个事件缝里做判断,稍有延迟或竞态,用户感知就是一顿一卡。别碰 <source>,那只是给 MP4/WebM 静态文件准备的。



















