El *_*psa 6 mp4 ffmpeg 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 ...
Run Code Online (Sandbox Code Playgroud)
我的主程序从标准输出或(unix 域)套接字读取此命令的片段并获取:
ftyp
moov
moof
mdat
moof
mdat
moof
mdat
...
Run Code Online (Sandbox Code Playgroud)
因此,我得到的第一个片段是ftyp和moov,它们是元数据并描述流内容。
现在,客户端程序稍后连接到主程序。问题是,那时ftype和moov片段早已消失。
有没有办法(= ffmpeg 命令选项)使这项工作类似于 MPEGTS(又名 mpeg 传输流),并定期与流一起重新发送元数据? 像这样:
ftyp
moov
moof
mdat
moof
mdat
moof
mdat
ftyp
moov
moof
mdat
moof
mdat
moof
mdat
...
Run Code Online (Sandbox Code Playgroud)
.. 或者是我在主程序中缓存ftyp和moov数据包并在请求流时将它们重新发送到客户端程序的唯一选择?
相关链接:Fragmented mp4(fMP4)到底是什么?和普通mp4有什么区别?
每次新客户端连接时缓存和重新发送ftyp和moov也不是那么简单..因为它以某种方式破坏了流(至少浏览器 MSE 扩展不喜欢这样的流)。moof数据包中似乎有很多序列号和内容需要修改。(+)
另一种选择是将流传递到另一个进行重新复用(并纠正moof数据包)的 FFmpeg 进程。由于命令 (1) 没有给出清晰分离的ftyp、moov、moof等数据包,事情变得更加复杂。
任何想法/解决方案表示赞赏。
编辑:关于(+),MSE 似乎在播放有间隙的碎片 MP4 时遇到问题:https://bugs.chromium.org/p/chromium/issues/detail ?id=516114
我终于能够毫无问题地将碎片 MP4 提供给浏览器 MSE 扩展。
如果开始向 MSE 扩展提供moof和mdat数据包,而这些数据包并非在原始ftyp和moov之后立即出现,那么 ..
..进入 MSE 扩展的第一个moof数据包必须是具有名为first_sample_flags_present的特殊标志集的moof数据包(有关更多信息,请参阅 ISO/IEC 14496-12:2012(E) 规范)
..否则,所有流行浏览器中的 MSE 都会冻结,并且无法播放视频(顺便说一句,从 > 1 开始的moof序列号根本没有问题)。
这个 python 包对于分析非常有用: https: //github.com/beardypig/pymp4
要获取该标志,此答案中提供了客户端 JavaScript 函数。
使用函数getBox找出框的类型(ftyp、moov、moof等)。
对于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;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3835 次 |
最近记录: |