ffmpeg - 在分段实时 MP4 流中发送定期元数据?

标签 ffmpeg mp4 live-streaming

正如主题所建议的,我想知道是否可以在分段 MP4 直播流中定期发送有关流内容的元数据。

我使用以下命令(1)来获取碎片MP4:

ffmpeg -i rtsp://admin:12345@192.168.0.157 -c:v copy -an -movflags empty_moov+omit_tfhd_offset+frag_keyframe+default_base_moof -f mp4 ...

我的主程序从标准输出或(unix域)套接字读取此命令的片段并获取:

ftyp
moov
moof
mdat
moof
mdat
moof
mdat 
...

因此,我得到的第一个片段是 ftypmoov,它们是元数据并描述流内容。

现在,客户端程序稍后会连接到主程序。问题是,此时,ftypemoov 片段早已消失。

有没有办法(=ffmpeg 命令选项)使这项工作类似于 MPEGTS(又名 mpeg 传输流),并随流定期重新发送元数据?像这样:

ftyp
moov
moof
mdat
moof
mdat
moof
mdat 
ftyp
moov
moof
mdat
moof
mdat
moof
mdat 
...

.. or 是我在主程序中缓存ftypmoov数据包并将它们重新发送到<客户端程序何时请求流?

相关链接:What exactly is Fragmented mp4(fMP4)? How is it different from normal mp4?

每次新客户端连接时缓存和重新发送ftypmoov也不是那么简单..因为它以某种方式破坏了流(至少浏览器MSE扩展不这样做)不喜欢这样的流)。 moof 数据包中似乎有很多序列号和内容需要修改。 (+)

另一个选项是将流传递到另一个进行重新复用(并纠正 moof 数据包)的 FFmpeg 进程。由于命令 (1) 没有给出完全分离的 ftypmoovmoof 等数据包,事情变得更加复杂。

任何想法/解决方案表示赞赏。

编辑:关于(+),MSE似乎在播放带有间隙的碎片MP4时出现问题:https://bugs.chromium.org/p/chromium/issues/detail?id=516114

最佳答案

我终于能够毫无问题地将碎片 MP4 提供给浏览器 MSE 扩展。

如果开始向 MSE 扩展提供 moofmdat 数据包,而这些数据包并非在原始 ftypmoov 之后立即出现,然后..

.. 进入 MSE 扩展的第一个 moof 数据包必须是设置了名为 first_sample_flags_present 的特殊标志的 moof 数据包(有关详细信息,请参阅 ISO/IEC 14496-12:2012(E) 规范)

..否则,所有流行浏览器中的 MSE 都会卡住,并且无法播放视频(顺便说一句,从 > 1 开始的 moof 序列号根本没有问题)。

这个Python包对于分析非常有用:https://github.com/beardypig/pymp4

要获取该标志,此答案中提供了客户端 JavaScript 函数。

使用函数getBox找出盒子的类型(ftypmoovmoof、等)。

对于 moof 框,应用函数 findFirstSampleFlag 来查看 moof 框是否启用了 first_sample_flags_present

function toInt(arr, index) { // From bytes to big-endian 32-bit integer.  Input: Uint8Array, index
    var dv = new DataView(arr.buffer, 0);
    return dv.getInt32(index, false); // big endian
}

function toString(arr, fr, to) { // From bytes to string.  Input: Uint8Array, start index, stop index.
    return String.fromCharCode.apply(null, arr.slice(fr,to));
}

function getBox(arr, i) { // input Uint8Array, start index
    return [toInt(arr, i), toString(arr, i+4, i+8)]
}

function getSubBox(arr, box_name) { // input Uint8Array, box name
    var i = 0;
    res = getBox(arr, i);
    main_length = res[0]; name = res[1]; // this boxes length and name
    i = i + 8;
    
    var sub_box = null;
    
    while (i < main_length) {
        res = getBox(arr, i);
        l = res[0]; name = res[1];
        
        if (box_name == name) {
            sub_box = arr.slice(i, i+l)
        }
        i = i + l;
    }
    return sub_box;
}

function findFirstSampleFlag(arr) { // input Uint8Array
    // [moof [mfhd] [traf [tfhd] [tfdt] [trun]]]
    
    var traf = getSubBox(arr, "traf");
    if (traf==null) { return false; }
    
    var trun = getSubBox(traf, "trun");
    if (trun==null) { return false; }
    
    // ISO/IEC 14496-12:2012(E) .. pages 5 and 58-59
    // bytes: (size 4), (name 4), (version 1), (tr_flags 3)
    var flags = trun.slice(9,12); // console.log(flags);
    f = flags[2] & 4; // console.log(f);
    return f == 4;
}

关于ffmpeg - 在分段实时 MP4 流中发送定期元数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54186634/

相关文章:

video - 从 HEVC 比特流中提取 DCT 系数

ios - 如何从 iOS 设备设置 HLS 实时视频流

ffmpeg - 使用 ffmpeg 在 m3u8 列表中选择下载分辨率

php - ffmpeg 编码 mpeg

asp.net - 如何在asp.net 网站中使用wowza 媒体服务器?

ffmpeg - ffmpeg 中 rtmpproto.c 的默认超时值是多少?

ffmpeg - 为什么使用 ffmpeg 流式传输到 flv 服务器只为客户端显示黑色/空白视频?

android - 无法在 android 12 和 13 中选择/传递图库视频的选定 URI,并且无法在选定的屏幕中查看

ffmpeg转换可执行文件输出 ".MOD: no files in such directory"

json - 如何使用 YouTube API 获取特定直播视频的当前观看人数?