加载MediaRecorder旧Blob时MediaSource SourceBuffer报错问题
解决思路:让MediaRecorder生成的Blob可独立播放并支持回溯
1. 先搞定MediaRecorder的片段完整性问题
MediaRecorder默认录出的是增量媒体片段,没有完整的文件容器元数据(比如MP4的核心结构信息),单独播放自然无法解析。试试这么处理:
- 每次分段录制结束时,必须调用
MediaRecorder.stop(),此时dataavailable事件返回的Blob才带有完整元数据,能独立播放。如果怕直播断流,停录后立刻重启新的Recorder继续:let recorder; function startNewSegment() { if (recorder) recorder.stop(); // 优先用MP4格式,兼容性最强 recorder = new MediaRecorder(stream, { mimeType: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"' }); recorder.ondataavailable = (e) => { if (e.data.size > 0) { // 存储带完整元数据的Blob到IndexedDB saveToDB(e.data); } }; recorder.start(); // 示例:每5分钟生成一个独立片段 setTimeout(startNewSegment, 5 * 60 * 1000); }
2. 修复IndexedDB存储Blob的序列化坑
直接存Blob到IndexedDB容易出现序列化损坏,取出来的Blob就废了。换成存储ArrayBuffer:
// 存储时转成ArrayBuffer async function saveToDB(blob) { const buffer = await blob.arrayBuffer(); const db = await openMyDB(); // 自行实现的打开IndexedDB方法 const tx = db.transaction('recordings', 'readwrite'); await tx.store.add({ id: Date.now(), data: buffer, type: blob.type }); await tx.done; } // 读取时转回Blob async function getBlobFromDB(id) { const db = await openMyDB(); const item = await db.get('recordings', id); return new Blob([item.data], { type: item.type }); }
3. 回溯播放时彻底重置所有资源
别试图复用旧的MediaSource、SourceBuffer或Video元素,直接全量重建:
async function playBack(id) { // 清理旧资源 if (window.mediaSource) { mediaSource.endOfStream(); window.mediaSource = null; } const video = document.getElementById('backtrack-video'); video.src = ''; video.load(); // 新建MediaSource并关联Video const mediaSource = new MediaSource(); window.mediaSource = mediaSource; video.src = URL.createObjectURL(mediaSource); mediaSource.addEventListener('sourceopen', async () => { const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); const blob = await getBlobFromDB(id); const buffer = await blob.arrayBuffer(); sourceBuffer.appendBuffer(buffer); sourceBuffer.addEventListener('updateend', () => { if (!sourceBuffer.updating && mediaSource.readyState === 'open') { mediaSource.endOfStream(); video.play(); } }); }); }
4. 先验证Blob本身的有效性
如果单独加载Blob都不行,先排查Blob是否损坏:
const testVideo = document.createElement('video'); testVideo.src = URL.createObjectURL(你的Blob实例); testVideo.onloadedmetadata = () => { console.log('Blob有效,时长:', testVideo.duration); }; testVideo.onerror = () => { console.error('Blob损坏,无法解析'); }; // 可临时添加到页面查看实际播放效果 document.body.appendChild(testVideo);
另外,尽量避开webm格式,部分浏览器对分段webm的元数据支持较差,优先用MP4更稳妥。
内容的提问来源于stack exchange,提问作者simondx
相关产品推荐
相关产品推荐

