如何在浏览器中播放通过WebRTC数据通道传输的基线H264帧流
问题根源
MediaSource的video/mp4类型SourceBuffer 不支持直接接收裸H264 NAL帧,必须输入符合**碎片化MP4(fMP4)**格式的分片,包含moov、moof、mdat这些标准MP4容器结构,你直接喂裸H264帧会触发格式错误,导致MediaSource自动关闭。- 你的FFmpeg参数配置错误:
-f rawvideo是输出裸YUV像素数据的格式,不是H264码流格式,你当前拿到的H264数据属于未封装的异常输出,格式本身不符合MediaSource要求。
解决方案(改动最小,推荐)
1. 修改FFmpeg参数
把输出格式调整为标准fMP4分片,开启零延迟配置,修改后的参数如下:
[ "-rtsp_transport", "tcp", "-i", `${rtspCamURL}`, "-framerate", "15", "-c:v", "libx264", "-vprofile", "baseline", "-b:v", "600k", "-bufsize", "600k", "-pix_fmt", "yuv420p", '-tune', 'zerolatency', "-preset", "ultrafast", // 以下为新增/修改的参数 "-g", "15", // 每秒1个关键帧,降低首开和卡顿延迟 "-f", "mp4", "-movflags", "+frag_keyframe+empty_moov+default_base_moof+omit_tfhd_offset", "-" ]
参数说明:
-f mp4指定输出MP4格式+frag_keyframe每个关键帧生成一个独立可解码的fMP4分片+empty_moov输出流开头先发送moov封装头,不需要等待整个文件生成+default_base_moof生成符合MediaSource规范的容器结构
2. 调整后端逻辑
不需要自己拆分NAL帧、手动加分隔符了,FFmpeg输出的流开头是完整的moov头,之后每块都是独立的fMP4分片,直接按FFmpeg输出的字节块通过DataChannel发送即可。
3. 调整前端逻辑
你原来的前端基础逻辑不需要大改,只需要增加缓冲区队列,避免sourceBuffer正在处理数据时重复append触发错误,修改后的参考代码:
const remoteStream = new MediaSource(); myVideoElement.src = window.URL.createObjectURL(remoteStream); const bufferQueue = []; let sourceBuffer = null; // 当remoteStream.readyState === "open"时调用 remoteStream.addEventListener('sourceopen', () => { sourceBuffer = remoteStream.addSourceBuffer('video/mp4; codecs="avc1.4d002a"'); // 增加错误监听方便排查问题 sourceBuffer.addEventListener('error', e => console.error('SourceBuffer错误', e)); remoteStream.addEventListener('error', e => console.error('MediaSource错误', e)); }) // 每次从WebRTC数据通道接收到新帧时调用 function onFrame(frame) { bufferQueue.push(new Uint8Array(frame)); tryAppendBuffer(); } function tryAppendBuffer() { // sourceBuffer正在处理数据 或 队列为空时直接返回 if (!sourceBuffer || sourceBuffer.updating || bufferQueue.length === 0) return; const buf = bufferQueue.shift(); try { sourceBuffer.appendBuffer(buf); // 当前分片处理完成后继续处理队列中的缓存 sourceBuffer.addEventListener('updateend', tryAppendBuffer, { once: true }); } catch (e) { console.error('appendBuffer失败', e); } }
替代方案(更低延迟)
如果不想用fMP4封装,你可以使用浏览器原生WebCodecs API直接解码裸H264 NAL帧,解码后渲染到Canvas上,这种方案端到端延迟会比MediaSource方案低100~300ms,但是需要浏览器支持WebCodecs(2022年之后发布的主流浏览器版本均已支持)。
内容的提问来源于stack exchange,提问作者Thabet Sabha
相关产品推荐
相关产品推荐

