每400毫秒录制播放摄像头时出现blob媒体资源无法解码错误
错误原因分析
你遇到的解码错误核心原因是:MediaRecorder 输出的分片 WebM 数据,仅第一个分片包含完整的文件头、编码参数等元数据,后续所有分片都只包含音视频帧裸数据,无法作为独立的媒体文件单独解码播放,所以第一个分片能正常播放,后续分片直接赋值给 video.src 就会抛出元数据错误。
除此之外你的代码还存在以下问题:
playStream、blob变量未声明,成为隐式全局变量,容易引发不可预期的错误- 每次创建
URL.createObjectURL后未释放旧的 URL,会造成内存泄漏 autoplay重复赋值无意义,不需要每次播放前设置
解决方案
场景1:仅需要实时播放摄像头画面,无分片存储需求
这是最推荐的方案,直接把摄像头流赋值给 video 元素的 srcObject 属性,无需录制再播放,延迟更低、性能更好:
async function playCamera() { try { const mediaStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true}); const video = document.querySelector('video'); video.srcObject = mediaStream; video.autoplay = true; } catch (err) { console.error('获取摄像头权限失败:', err); } }
场景2:需要同时实现每400毫秒分片存储+实时播放
这种场景需要用 MediaSource Extensions (MSE) 来实现流式播放,把分片数据按顺序喂给 MediaSource 实例,保证元数据和帧数据的连续性:
async function recordAndPlayCamera() { try { const mediaStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true}); const video = document.querySelector('video'); const mime = 'video/webm; codecs="vp8, opus"'; // 提前校验当前浏览器是否支持对应编码格式 if (!MediaSource.isTypeSupported(mime)) { throw new Error('当前浏览器不支持指定的媒体编码格式'); } // 初始化MediaSource const mediaSource = new MediaSource(); video.src = URL.createObjectURL(mediaSource); let sourceBuffer; mediaSource.addEventListener('sourceopen', () => { sourceBuffer = mediaSource.addSourceBuffer(mime); // 初始化MediaRecorder const mediaRecorder = new MediaRecorder(mediaStream, {mimeType: mime}); mediaRecorder.start(400); mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0 && sourceBuffer && !sourceBuffer.updating) { sourceBuffer.appendBuffer(e.data); } // 此处可添加自定义逻辑,将e.data存入分片列表实现分片存储 }; }); } catch (err) { console.error('初始化失败:', err); } }
注意事项
- 播放过程中如果 SourceBuffer 缓存过多,可以在合适的时机调用
sourceBuffer.remove()清理旧的缓存,避免内存占用过高 - 不同浏览器支持的编码格式有差异,可根据实际场景调整 mime 字段的编码配置
内容的提问来源于stack exchange,提问作者kasra
相关产品推荐
相关产品推荐

