Ffmpeg压静态帧多的影片时对动态部分丢帧过多

视频是ppt,几乎全是静态帧和少量的局部动画,还有更少的翻页动画

现在的问题是翻页动画的场景丢帧过多以至于看上去很不平滑,很卡

最开始用的参数只有-cq,发现单用cq的话会导致CFR
-c:v h264_nvenc -cq 42

后来加了-vsync vfr 强制VFR也没改善

试过-r 60或是-fv fps=60,导致文件大小翻倍,得不偿失,而且压制时间明显增加了50%不止

发现只要把源文件减掉开头第一个关键帧之前的部分就好了,太奇怪了,整个文件30分钟左右,只差这么一点?

AI回覆您:

你的问题是使用 FFmpeg 压缩以静态画面为主的影片(例如 PPT 录制的影片)时,动态部分(翻页动画)丢帧严重,导致画面不流畅。 虽然你尝试了 -vsync vfr,但效果不佳,而提高帧率 (-r 60-vf fps=60) 又会导致档案大小大幅增加。 你还发现移除影片开头一小段就能解决问题,这暗示了问题可能出在影片的编码或关键帧设定上。

以下是一些可能的解决方案和建议,从简单到复杂:

1. 尝试不同的编码器和参数:

  • x264 (CPU 编码): 虽然速度较慢,但 x264 通常能提供更好的压缩效率和画质。 你可以尝试以下参数:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset slow -x264-params "keyint=240:min-keyint=240:scenecut=0" output.mp4
  • -crf 23: 恒定品质因子 (CRF),值越小,品质越高,档案越大。 你可以根据需要调整这个值 (18-28 都是可接受的范围)。

  • -preset slow: 设定编码预设值,slow 会花费更多时间,但压缩率更高。

  • keyint=240:min-keyint=240:scenecut=0: 这部分非常重要!它强制每 240 帧 (约 4 秒,假设帧率为 60fps) 插入一个 I 关键帧,并且关闭场景切换检测 (scenecut=0)。 对于静态画面佔比很高的影片,这可以避免在静态画面中插入太多关键帧,从而提高压缩效率,并在动态部分保留更多帧。 你可以根据你的影片长度和帧率调整 keyintmin-keyint 的值。

  • x265 (CPU 编码,HEVC 编码): HEVC 编码比 H.264 更高效,但需要更强大的处理器。

ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset slow -x265-params "keyint=240:min-keyint=240:scenecut=0" output.mp4
  • -crf 28: x265 的 CRF 值,通常比 x264 高一些才能达到相同的视觉品质。
  • NVENC (GPU 编码,如果你的显卡支援): 如果你有支援 NVENC 的 NVIDIA 显卡,它可以加速编码过程。 但 NVENC 的品质可能不如 x264 或 x265。 你可以尝试调整 -cq 值。

2. 分析影片结构:

使用 ffprobe 分析你的影片,查看关键帧的位置和分布:

ffprobe input.mp4

这可以帮助你了解影片的编码方式,以及关键帧是否过于频繁地插入。 如果关键帧分布不均匀,可能是导致动态部分丢帧的原因。

3. 使用两遍编码:

两遍编码可以让编码器更好地分配比特率,提高压缩效率。 这需要更多时间,但通常能获得更好的结果。 在 x264 和 x265 中都可以使用两遍编码。 (需要额外参数,请参考 FFmpeg 文件)

4. 处理开头关键帧问题:

你提到移除开头一小段影片就能解决问题,这很奇怪。 这可能表示影片开头的编码存在问题,例如第一个关键帧的时间戳记错误。 你可以尝试使用 ffmpeg-ss 参数跳过开头一小段,然后再进行编码:

ffmpeg -ss 1 -i input.mp4 -c:v libx264 -crf 23 -preset slow output.mp4  // 跳过前一秒

(调整 -ss 的值来实验)

5. 使用 -g 参数控制 GOP 大小:

-g 参数设定 GOP (Group of Pictures) 的大小,也就是两个 I 关键帧之间的帧数。 你可以尝试设定一个较大的 GOP 大小,例如 -g 240,这与 keyint 参数的效果类似。

总结:

我建议你从 方案 1 开始尝试,先用 x264 或 x265,并使用 keyintmin-keyint 参数来控制关键帧的插入。 如果仍然无法解决问题,再尝试其他方案。 记得在尝试不同的参数时,每次只改变一个参数,以便更好地找出问题所在。 仔细观察编码过程中的日志讯息,这可能提供额外的线索。 最后,提供你的影片档案的一些资讯 (例如长度、帧率、大小) 也会帮助我更好地理解你的问题。

尝试不同的编码器

ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4

使用两遍编码

ffmpeg -y -i input.mp4 -c:v libx264 -b:v 1000k -pass 1 -an -f mp4 /dev/null && \
ffmpeg -i input.mp4 -c:v libx264 -b:v 1000k -pass 2 output.mp4
ffmpeg -ss 00:00:02 -i input.mp4 -c:v h264_nvenc -cq 42 -preset medium -vsync passthrough output.mp4

ffmpeg -i input.ppt -c:v h264_nvenc -cq 42 -vsync vfr -r 30 -c:a aac -b:a 128k -f mp4 output.mp4
2 个赞

经测试有的文件 -c copy一遍为mkv,然后再随便怎么压都没问题了
如果先转成mp4再压还是会出毛病

另一些文件无法用这种方法解决,剪掉开头一部分也无法解决。。。

猜测是因为视频在制作时用的软件输出不符合视频格式标准,或者与ffmpeg不兼容,

最后是用一个老的ffmpeg 5.0解决了,参数是之前试出来的,很奇怪但是压出来效果是最好的,尤其没有新版ffmpeg7.1乱七八糟的问题

homebridgeffmpeg 0.1.0 (ffmpeg 5.0)

压第一遍的参数,输出格式必须选择mkv,速度比mp4要快非常多
-c:v h264_nvenc -c:a libfdk_aac -vbr 4 -ac 1 -b:v 800k -r 80 -preset p7 -qmin 1 -qmax 39

第二遍调整同步,复制流,把mkv转成mp4,(后来测试 几个文件不加-async 1似乎也是一样的,生成文件md5都一样,但这是对正常文件的结果)
-async 1 -c copy

6.0和7.x使用-r 会导致压缩慢很多,所以这个参数不适合新版本
之所以要压两次也是试出来的,在压制的同时 -async是无效的,可能源文件真的有问题

其实我猜测是你的实时录制工具可能在CPU占用高时出现了一些问题,而导致视频本身结构不对!

有可能用 -c copy 一次后,重新编码mp4可能会好!
或者直接使用多次编码

1 个赞

应该就是这样,
发现有的视频拖动有问题,demux之后看到视频流的长度竟然比音频流短了50%,这也行?

问了发行人,他也不知道最初的版本是用什么软件做的,估计程序编写的时候没有考虑对算力不足的应对方案,所以执行的时候遇到算力问题就凑合把数据胡乱写了。。。

真是草台班子

:joy:我也遇到过类似的情况,如果是PPT的话,
建议使用FlashBack,它的特长就是专门录低桢率的
我也是后来换了FlashBack就没有这个问题了

1 个赞

谢谢,其实不光是ppt,还穿插和叠加了一些其他的内容。
现在我自己录课都用Geforce Experience了,从来就没遇到bug