作者:quink
来源:Fun With FFmpeg
原文:https://mp.weixin.qq.com/s/rYwVP0YUsD2t87invJXDCw
1. 传统mp4不是掉电安全的
众所周知,mp4文件生成过程中,如果异常退出,比如程序崩溃,设备异常掉电等,生成的不完整的mp4文件是无法使用的。也许特定条件可以抢救一下,比如只有视频轨,我对通用的修复不完整mp4文件的方案不抱希望。
mp4(超)简化结构如下,mdat是音视频数据,moov是全局描述+索引信息。
2. fmp4掉电安全
实际上,前一段描述不准确:mp4中的fmp4是掉电安全的。传统的mp4有一个全局的索引信息,丢了全局索引,不知道音视频数据如何分割。全局的索引信息对fmp4来说是可选项,没有全局索引的fmp4也可以播放,只是seek困难。
我们可以用如何方式模拟实时录制成fmp4:
ffmpeg -re -i ~/Movies/cctv.mp4 -c copy -movflags cmaf /tmp/test.mp4
运行过程中kill掉
killall -9 ffmpeg
你会发现生成的mp4可以播放。注意这里是kill -9 SIGKILL,如果你用killall ffmpeg,ffmpeg会捕获signal SIGTERM后正常退出,不能模拟异常退出。
fmp4简化结构示意如下:
moov里有全局的表述,标记了有几个音频轨、视频轨信息等等,但是不包含音视频数据的位置信息。moof + mdat是一个片段,fmp4可以看成一个moov头加N个片段。moof里描述了对应的mdat的音视频数据信息,有多少个sample(音视频帧)、sample的大小、在文件中的位置等等。尾巴掉了,不影响前面数据正常播放。
这里省略了fmp4的全局索引描述信息。fmp4至少有两种全局索引描述方式:sidx和mfra。和本文无关,不深入探讨了。
3. 我全都要
fmp4虽然有掉电安全的优点,也有缺点,主要是本地播放兼容性不如传统的mp4。如果我既要fmp4的掉电安全,又要传统mp4的兼容性,怎么办呢?
很简单,先生成fmp4,如果正常结束,在结束的时候做个变身,把fmp4变成传统mp4。变身过程示意如下。
先给fmp4加个带全局索引的moov尾巴:
再调整fmp4原来的moov,把它变成一个大的mdat。虚线部分是原来的moof和mdat,被包在新的mdat里,属于不可见信息了。如此生成的文件,对于播放器来说是传统mp4,只是内部有一些空洞/无效数据(旧的moof等。因为mp4访问音视频数据是靠moov的索引,这些无效数据不影响音视频数据正常读取。
4. 说说简单,代码呢?
请看FFmpeg:
https://github.com/FFmpeg/FFmpeg/commit/6ec22731ae7
用法简单,把前面的命令增加一个hybrid_fragmented
./ffmpeg -re -i ~/Movies/cctv.mp4 -c copy -movflags cmaf+hybrid_fragmented /tmp/test.mp4
然后你用killall -9 ffmpeg杀进程,会发现生成了一个fmp4,如果进程正常退出,生成的是传统的mp4。
让我们感谢Martin Storsjö实现的这个功能.
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。