我得到了一个用 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 时间戳会生成具有正确时间的视频。