MediaSource加载Uint8Array无报错但视频无法播放问题排查
问题分析与解决方案
核心问题
你的代码存在几个关键问题,导致视频无法正常播放:
1. SourceBuffer MIME类型缺失编码参数
MediaSource API要求必须指定具体的音视频编码格式,只写video/mp4不足以让浏览器解析流数据。
2. 普通MP4不支持MediaSource流式拼接
单独能播放的MP4是非碎片化MP4,而MediaSource仅支持碎片化MP4(fMP4)——这种格式的文件结构是专为流式传输设计的。
3. 分片追加的异步逻辑错误
appendBuffer是异步操作,你直接递归调用get会导致多个分片同时写入,触发updating状态冲突,数据无法正确加载。
4. 分片索引范围错误
服务器有13个文件,索引应该是0到12,但原代码要等i===14才重置,会请求不存在的13.mp4和14.mp4。
修复后的完整代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Video</title> </head> <body> <div class="content"> <h1>My Video</h1> <video id="video" width="640" height="480" autoplay muted controls></video> <script> 'use strict'; const video = document.querySelector('video'); let currentIndex = 0; const totalChunks = 13; // 服务器上的分片总数 const mediaSource = new MediaSource(); let sourceBuffer; if (!window.MediaSource) { alert('当前平台不支持MediaSource API'); } video.src = window.URL.createObjectURL(mediaSource); mediaSource.addEventListener('sourceopen', () => { // 替换为你的视频实际编码格式,示例为h.264视频+aac音频 const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; sourceBuffer = mediaSource.addSourceBuffer(mimeCodec); // 监听分片追加完成事件,再加载下一个分片 sourceBuffer.addEventListener('updateend', () => { if (currentIndex < totalChunks) { loadNextChunk(); } else { // 所有分片加载完成,标记流结束 mediaSource.endOfStream(); } }); // 启动第一个分片加载 loadNextChunk(); }); function loadNextChunk() { const url = `${currentIndex}.mp4`; const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'arraybuffer'; xhr.onload = () => { if (xhr.status !== 200) { alert(`请求${url}失败,状态码:${xhr.status}`); return; } // 仅当sourceBuffer未在更新时,才追加数据 if (!sourceBuffer.updating) { sourceBuffer.appendBuffer(new Uint8Array(xhr.response)); currentIndex++; } }; xhr.send(); } </script> </div> </body> </html>
关键修复说明
- 补全MIME编码参数:通过
codecs明确视频(avc1开头对应h.264)和音频(mp4a开头对应AAC)的编码格式,可通过ffprobe 原视频文件查看实际编码。 - 转换为碎片化MP4:用FFmpeg将每个普通MP4分片转为fMP4,命令示例:
ffmpeg -i input.mp4 -movflags frag_keyframe+empty_moov+cmaf output_fmp4.mp4 - 异步分片加载逻辑:通过
updateend事件确保上一个分片写入完成后,再加载下一个,避免状态冲突。 - 修正索引范围:根据13个文件设置
totalChunks=13,索引从0到12,避免请求不存在的文件。
验证步骤
- 用FFmpeg将所有MP4分片转成碎片化格式。
- 替换代码中的
mimeCodec为你视频的实际编码信息。 - 确保服务器上的分片文件名是
0.mp4到12.mp4。 - 重新运行代码,视频即可正常播放。
内容的提问来源于stack exchange,提问作者Remi Demers
相关产品推荐
相关产品推荐

