You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:47:38