正确修复使用旧版 x264 编码的视频

vid*_*guy 6 h.264 ffmpeg

由于旧版 x264 中的一个错误,h.264 视频流具有以下三个属性:

  1. 使用 x264 build 150 或更早版本编码
  2. 使用 4:4:4 色度子采样
  3. 比特流不包含 x264 版本信息

许多视频播放器将无法正常播放。新版本的视频播放器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 中的错误可能是在这里引入的。)

cxr*_*ers 3

感谢您提出这个问题,它也帮助我了解了我遇到的问题的本质。我有一个似乎有效的解决方案。

就我而言,我使用 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”。