使用MP4box.js时onSegment回调未触发,无法实现浏览器H264直播流播放
为什么MP4box.js的
onSegment回调没触发? 结合你的代码和场景,我梳理出几个关键问题导致了这个现象,下面逐一拆解并给出修复方案:
1. 错误的fileStart设置让MP4box无法追踪数据位置
你每次收到WebSocket数据时都把fileStart设为0,但MP4box需要知道每个传入的buffer在整个MP4文件中的绝对偏移位置。如果每次都重置为0,MP4box会反复解析文件开头,根本没法识别后续的媒体数据,自然不会生成分片。
修复方法:新增一个变量累计偏移量,每次append后更新:
var fileOffset = 0; // 用来追踪整个文件的累计偏移 ws.onmessage = function (event) { const buffer = event.data; buffer.fileStart = fileOffset; const nextOffset = mp4box.appendBuffer(buffer); fileOffset = nextOffset; // 更新为下一次的起始位置 mp4box.flush(); };
2. nbSamples设置过大,分片触发门槛太高
你设置了nbSamples: 1000,这意味着MP4box要攒够1000个媒体样本才会触发onSegment。如果你的WebSocket传输的是实时流,单次传输的样本数远小于1000,那回调肯定不会触发。
建议把这个值调小,比如20,适配实时流的小分片粒度:
var options = { nbSamples: 20 }; // 调整为更贴合实时场景的数值 mp4box.setSegmentOptions(info.tracks[0].id, null, options);
3. onSegment回调绑定时机可能滞后
你把onSegment绑在了onReady内部,虽然逻辑上没问题,但最好在初始化MP4box实例后就绑定,避免错过早期的触发信号:
mp4box = MP4Box.createFile(); // 先绑定onSegment,再处理其他回调 mp4box.onSegment = function (id, user, buffer, sampleNum) { console.log("Received segment on track "+id+" for object "+user+" with a length of "+buffer.byteLength+",sampleNum="+sampleNum); };
4. 确认WebSocket传输的是完整MP4容器,不是裸H264
虽然你说VLC能播放,但要注意:MP4box处理的是MP4容器格式,不是裸H264流。如果WebSocket只传输了H264裸码流,MP4box根本没法解析,自然不会生成分片。要确保服务端传输的是包含moov、mdat等完整结构的MP4文件,且按字节顺序逐步传输。
修复后的完整代码
var ws; var mp4box; var fileOffset = 0; // 新增:追踪文件累计偏移 function startVideo() { mp4box = MP4Box.createFile(); // 提前绑定onSegment回调 mp4box.onSegment = function (id, user, buffer, sampleNum) { console.log("Received segment on track "+id+" for object "+user+" with a length of "+buffer.byteLength+",sampleNum="+sampleNum); }; mp4box.onError = function(e) { console.log("mp4box解析失败: ", e); // 打印具体错误信息,方便调试 }; mp4box.onMoovStart = function () { console.log("开始接收文件元信息"); }; mp4box.onReady = function(info) { console.log(info.mime); var options = { nbSamples: 20 }; // 调整分片粒度 mp4box.setSegmentOptions(info.tracks[0].id, null, options); var initSegs = mp4box.initializeSegmentation(); // 这里可以把initSegs传给MSE做初始化 mp4box.start(); }; ws = new WebSocket("ws://a_websocket_server_which_serves_h264_file"); ws.binaryType = "arraybuffer"; ws.onmessage = function (event) { const buffer = event.data; buffer.fileStart = fileOffset; const nextOffset = mp4box.appendBuffer(buffer); fileOffset = nextOffset; mp4box.flush(); }; } window.onload = function() { startVideo(); }
额外调试技巧
- 在
onError里打印具体错误对象,能帮你快速定位解析问题 - 在
onmessage里打印buffer.byteLength,确认WebSocket确实在持续传输数据
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

