由于旧版 x264 中的一个错误,h.264 视频流具有以下三个属性:
许多视频播放器将无法正常播放。新版本的视频播放器mpv有专门的选项
--vd-lavc-assume-old-x264
Run Code Online (Sandbox Code Playgroud)
专门解决这个问题(见:https : //mpv.io/manual/master/)。
在FFmpeg 错误跟踪器上,建议将适当的 SEI.h264 添加到视频流(我猜是包含 x264 版本信息)。我不想依赖此类黑客,所以我的问题是:是否有一种“正确”的方式(理想情况下使用 ffmpeg)来修复文件,就好像它们首先是用新的(固定)版本的 x264 编码的一样?
显然我想保持(或多或少)视频质量和文件大小。如果需要重新编码,那么除了修复旧 x264 实现的错误行为外,它应该什么都不改变。(更多信息:错误报告给出了一个损坏文件的示例。据推测,旧 x264 中的错误可能是在这里引入的。)
感谢您提出这个问题,它也帮助我了解了我遇到的问题的本质。我有一个似乎有效的解决方案。
就我而言,我使用 Ubuntu 存储库中的 ffmpeg。能够解码我的 libx264 文件的最后一个版本是 2.8.6。升级到 2.8.14 或 2.8.15 后,我遇到了您描述的解码问题。我不想重新编码我的旧视频,我只是想修复标头,以便 ffmpeg 可以正确识别原始编码期间引入的错误,并正确播放它们。
因此,首先我下载了包含最新版本 ffmpeg v4 的静态二进制文件。我将此二进制文件链接到ffmpeg4我的系统上,以便我可以控制我正在使用的版本。我们需要一些2.8之后引入的新功能(不太确定是什么时候)。如果您已经安装了较新版本的 ffmpeg,只需使用它并在下面的命令中替换ffmpeg4为。ffmpeg
现在,从损坏的视频中提取原始比特流(将其称为 BROKEN.mkv)。
ffmpeg4 -i BROKEN.mkv -vcodec copy -an -bsf:v h264_mp4toannexb raw.h264
Run Code Online (Sandbox Code Playgroud)
我不确定 h264_mp4toannexb 标志是否必要,它可能会为此格式自动插入。
现在,将比特流放入新的 mp4 容器中,并修复 SEI 标头中有关旧有缺陷的 x264 版本的信息。
ffmpeg4 -r 30 -i raw.h264 -avoid_negative_ts 1 -bsf:v h264_metadata='sei_user_data=dc45e9bde6d948b7962cd820d923eeef+x264 - core 150' -c copy FIXED.mp4
Run Code Online (Sandbox Code Playgroud)
比特流不包含时间戳信息,因此您将在这里收到大量警告。我还发现我必须手动将帧速率设置为 30fps ( -r 30),否则它会猜测 25 到 30fps 之间的一些可变帧速率。我不知道如何正确提取时间戳或将它们正确混合到新容器中。如果您有解决办法,请告诉我!很多人推荐-fflags +genpts,但这似乎对我没有任何作用。最后,我添加了-avoid_negative_ts 1为了使第一帧的时间戳为非负数。
最后,这是可选的,如果您想将结果放入 MKV 容器中,您可以这样做
ffmpeg4 -i FIXED.mp4 -c copy FIXED.mkv
Run Code Online (Sandbox Code Playgroud)
为什么要先转换为 MP4,然后再转换为 MKV?看起来 MKV 容器会简单地拒绝在没有时间戳的情况下继续进行,但 MP4 会这样做并只是发出警告。然后您可以转换为 MKV 而不会出现警告。
完成所有这些之后,我有了可用的 MP4 和 MKV 文件。然而,我检查了一些帧,发现有一些细微的变化(亮度变化约为 2 个级别)。我不明白为什么会发生这种情况,因为这应该是无损的。如果您对如何做得更好有任何建议,请告诉我。
编辑:我注意到 MP4 容器中的一些时间戳为负数,从 -0.066667s 开始。转移到 MKV 容器后,所有负时间戳都变为零。添加-output_ts_offset 0.066667到命令修复了这个问题并让它们从零开始。我不明白为什么它从 -0.066667 开始。
编辑 2:删除负时间戳的更好方法是在编码 mp4 时使用“-avoid_negative_ts 1”。
| 归档时间: |
|
| 查看次数: |
1644 次 |
| 最近记录: |