mediasource api 不提供自动码率切换(abr),需自行实现检测、决策与切换逻辑,配合多码率分段资源(如 fmp4+dash)、sourcebuffer 管理及带宽/缓冲区等状态评估。

MediaSource API 本身不提供码率自动切换(ABR)逻辑,它只是为 JavaScript 提供了将媒体数据动态写入 <video></video> 的底层能力。真正的自适应码率切换需要你自行实现检测、决策和切换流程,配合分段视频(如 MP4 fragments 或 ISO BMFF)和 MSE(Media Source Extensions)协同工作。
核心前提:准备多码率分段资源
YouTube 类 ABR 的基础是服务端提供同一内容的多个质量层级(如 360p/720p/1080p),每层切分为小段(通常 2–10 秒),格式为支持 MSE 的 fragmented MP4(ISO BMFF)或 WebM。不能直接用普通 MP4 文件——必须可按时间轴增量 append。
常见做法:
- 使用 DASH(MPD 清单)或 HLS(m3u8 + ts/fmp4)作为元数据描述各码率分段地址与时序
- 推荐优先采用 fMP4 + DASH 方案:兼容性好、浏览器 MSE 支持成熟、便于随机 seek 和带宽预估
- 确保所有码率分段起始点对齐(common presentation time),否则切换时可能出现音画不同步或卡顿
构建 MediaSource 流水线并监听关键事件
初始化 MediaSource 后,需监听 sourceopen 创建 SourceBuffer,并持续管理其状态:
示例关键代码片段:
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
<p>mediaSource.addEventListener('sourceopen', () => {
// 根据 MIME 类型创建 SourceBuffer(注意:audio 和 video 需分开)
const sb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64001f"');
sb.mode = 'segments'; // 推荐使用 segments 模式,便于按时间范围移除旧数据</p><p>// 监听更新完成,用于触发下一段加载
sb.addEventListener('updateend', () => {
if (sb.updating) return;
scheduleNextSegment(); // 自定义逻辑:决定下一段要加载哪个码率
});
});
</p>
实现 ABR 决策逻辑(核心环节)
ABR 算法本质是根据实时网络与播放状态,选择“当前最稳妥能播得流畅”的码率。无需追求最高清,而要避免 rebuffer。
你需要持续采集并评估以下信号:
-
网络吞吐量估算:记录最近 N 段(如 3–5 段)的下载耗时与字节数,计算瞬时带宽(
bytes / durationMs),建议加滑动平均滤波 -
缓冲区水位:通过
video.buffered.end(0) - video.currentTime获取剩余可播秒数;低于 2 秒应降码率,高于 10 秒可试探升码率 -
卡顿次数与解码延迟:监听
waiting事件(进入缓冲等待)并计数;也可观察video.getVideoPlaybackQuality()中的droppedVideoFrames - 设备能力约束:例如屏幕宽度
简单启发式策略示例:
function selectBitrate() {
const bandwidth = estimateBandwidth(); // 单位 bps
const bufferLevel = getBufferLevel(); // 单位 秒
const maxAllowed = getMaxBitrateForDevice();
<p>if (bufferLevel 8 && bandwidth > currentBitrate * 1.3) return Math.min(nextHigherBitrate, maxAllowed);
return currentBitrate;
}
</p>
安全切换码率(避免中断与错帧)
切换不是简单换 URL,而是要保证时间连续、解码器平滑过渡:
- 在
SourceBuffer.updating === false且video.readyState >= 3时执行 - 先调用
sourceBuffer.remove(start, end)清除即将被替换的那部分(例如当前播放位置后 2 秒内的旧码率数据) - 立即 fetch 新码率的下一段(注意对齐 PTS),append 到
SourceBuffer;确保新段的moof中baseMediaDecodeTime与上一段末尾连续 - 若使用 DASH,可借助开源库如 video.js + VHS 或 dash.js,它们已封装健壮的 ABR 引擎和 MSE 适配
⚠️ 注意:不要在 updatestart 或 updating === true 时调用 appendBuffer 或 remove,会抛异常。
调试与兜底建议
实际部署中建议加入:
- 强制码率开关(供 QA 测试)
- 失败重试机制(某段加载失败时降码率重取)
- 日志上报:记录每次码率变更原因(带宽下降?卡顿触发?用户手动切换?)
- 降级方案:若 MSE 不可用(如 iOS Safari 旧版),回退到原生 HLS
不复杂但容易忽略:ABR 效果高度依赖分段对齐精度、服务器响应一致性、以及首帧加载优化(比如预加载第一段并设置 video.preload = "metadata")。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











