FFMPEG:如何在不打乱时间的情况下将 VFR 转换为 CFR

FFMPEG:如何在不打乱时间的情况下将 VFR 转换为 CFR

我得到了一个用 iOS 模拟器录制的视频

xcrun simctl io booted recordVideo raw.mov

该视频的帧率可变

  Stream #0:0[0x1](und): Video: hevc (Main) (hvc1 / 0x31637668), yuv420p(tv, bt709/bt709/iec61966-2-1), 1242x2688, 2268 kb/s, 32.84 fps, 600 tbr, 600 tbn (default)

使用任何命令将视频转码为 CFR 视频时,时间安排都会混乱。

例如:

ffmpeg -i raw_ios_recording.mov -filter:v fps=60 -fps_mode:v cfr -vsync 1 -copytb 0 out.mp4

但是将视频转码为 CRF 的任何其他变化/排列都会产生相同的伪影。

(例如ffmpeg -i in.mov out.mp4)。

我想知道这是 FFmpeg 中的一个错误还是我误解了什么?

以下是一个发生故障的视频的示例(我无法将其上传到视频共享网站,因为它会改变视频):

https://storage.googleapis.com/app_recorder_releases/raw_ios_recording.mov

转码后的版本如下:

https://storage.googleapis.com/app_recorder_releases/ios_simulator_recording_converted_to_60_fps.mp4

请注意打开第一个应用程序时的时间完全不对。

答案1

这些伪影看起来像视频编码(压缩)伪影,而不是帧速率转换伪影。

帧率转换也适用于视频重新编码/转码(这是我们无法避免的)。
任何重新编码操作都会降低视频质量,并添加一些伪影(除非编解码器是“无损”的,并且输出文件很大)。

MP4 文件的默认 FFmpeg 编解码器通常是 H.264,但您的视频编解码器out.mp4是 H.263,导致视频质量较差。
请注意,输入的视频编解码器是 H.265 (HEVC)。

我们可以选择 H.265 (HEVC) 编解码器,-crf 17以便(例如)获得更好的质量:

ffmpeg -y -i raw_ios_recording.mov -filter:v fps=60 -fps_mode:v cfr -copytb 0 -c:v libx265 -crf 17 -tag:v hvc1 out.mp4


如果你的 FFmpeg 版本不支持libx265,你可以更新 FFmpeg,或者使用hevc_videotoolbox假设您使用的是 Mac。

如果质量仍然不够好,我们可能会尝试添加-pix_fmt yuv444p参数和/或减少crf

ffmpeg -y -i raw_ios_recording.mov -filter:v fps=60 -fps_mode:v cfr -copytb 0 -c:v libx265 -crf 10 -tag:v hvc1 -pix_fmt yuv444p out.mp4


更新:

修复视频时间:

为了修复时间,我们可能必须通过添加-fflags +igndts参数来忽略 DTS 时间戳:

ffmpeg -y -fflags +igndts -i raw_ios_recording.mov -filter:v fps=60 -fps_mode:v cfr -copytb 0 -c:v libx265 -crf 17 -tag:v hvc1 out.mp4


使用FFprobe命令:ffprobe -show_packets raw_ios_recording.mov我们可以看到存在负的DTS时间戳:

dts_time=-1.283333
dts_time=-0.818333
dts_time=-0.813333
dts_time=-0.805000
dts_time=-0.800000
dts_time=-0.798333
...

我不知道为什么会有这么多负面 DTS,以及 FFmpeg 如何处理它们。
似乎忽略所有 DTS 时间戳会生成具有正确时间的视频。

相关内容