如何从原视频及其剪辑转码后的视频中提取同一帧以进行画质对比?
我太懂你这种困惑了——明明算好了对应时间段,提取出来的帧却不一样,大概率是时间戳对齐偏差和ffmpeg参数使用逻辑的问题,咱们一步步把它解决:
先搞懂问题根源
你用-ss参数跳转时间点的时候,有没有注意它在-i前后的区别?
- 如果
-ss放在-i前面:ffmpeg会先跳到离指定时间最近的关键帧再开始处理,速度快但不精确,很可能跳过了你要的那帧; - 如果
-ss放在-i后面:ffmpeg会先完整读取文件,再精确跳到指定时间点,虽然慢一点,但能保证拿到你要的帧。
另外,转码后的视频可能存在时间基准偏移的问题,导致你以为的00:00:09和原视频的00:40:09并不是同一帧。
最靠谱的解决方案:用帧编号提取(完全精准)
时间戳容易因为帧率、编码格式出现偏差,直接用帧的顺序编号提取是最稳妥的:
先获取原视频的帧率和总帧数,算出目标帧的编号
执行这个命令拿到原视频的帧率和总帧数:ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate,nb_frames -of default=noprint_wrappers=1:nokey=1 Original.mkv比如你的原视频帧率是
23.98fps,那00:40:09对应的总秒数是40*60+9=2409秒,帧编号大概是2409*23.98≈57767(注意ffmpeg里帧编号从0开始,计算时可以稍微调整下)。算出转码后视频对应的帧编号
你是从原视频的00:40:00开始剪辑的,这时候对应的原视频帧编号是40*60*23.98≈57552,那转码后视频的目标帧编号就是57767-57552=215。提取帧的命令
原视频提取:ffmpeg -i Original.mkv -vf "select=eq(n\,57767)" -vframes 1 -q:v 1 original.png转码后视频提取:
ffmpeg -i Original-x265.mkv -vf "select=eq(n\,215)" -vframes 1 -q:v 1 original-x265.png
用时间戳的优化方案(相对精准)
如果你还是想用时间戳,那要保证两边都用精确跳转,同时转码时强制时间戳从0开始:
重新转码时加上时间戳校准参数
ffmpeg -ss 00:40:00 -i Original.mkv -t 00:10:00 -c:v libx265 -crf 20 -c:a copy -avoid_negative_ts make_zero Original-x265.mkv-avoid_negative_ts make_zero会让转码后的视频时间戳从0开始,避免时间偏移。用精确方式提取帧
原视频提取:ffmpeg -i Original.mkv -ss 00:40:09 -accurate_seek -frames:v 1 -q:v 1 original.png转码后视频提取:
ffmpeg -i Original-x265.mkv -ss 00:00:09 -accurate_seek -frames:v 1 -q:v 1 original-x265.png-accurate_seek确保ffmpeg精确跳到指定时间点,而不是就近的关键帧。
额外提醒
x265编码时可能会有微小的帧对齐调整,所以帧编号提取的方式永远是最可靠的,完全不受时间戳和编码格式的影响。
备注:内容来源于stack exchange,提问作者Unni

