ffmpeg - 场景检测和连接使我的视频更长(FFMPEG)

标签 ffmpeg video-encoding

我正在按场景编码视频。此刻,我有两个解决方案可以做到这一点。第一个是使用 Python应用程序,它给了我代表场景的帧列表。像这样:

285
378
553
1145
...

第一个场景从第 1 帧开始到第 285 帧,第二个场景从第 285 帧开始到第 378 帧,依此类推。所以,我制作了一个 bash 脚本来编码所有这些场景。基本上它的作用是获取当前和以前的帧,然后将它们转换为时间,最后运行 ffmpeg 命令:
begin=$(awk 'BEGIN{ print "'$previous'"/"'24'" }') 
end=$(awk 'BEGIN{ print "'$current'"/"'24'" }') 
time=$(awk 'BEGIN{ print "'$end'"-"'$begin'" }') 

ffmpeg -i $video -r 24 -c:v libx265  -f mp4 -c:a aac -strict experimental -b:v 1.5M -ss $begin -t $time "output$count.mp4" -nostdin

这很完美。第二种方法是使用 ffmpeg 本身。我运行这个命令并给我一个列表 .像这样:
15.75
23.0417
56.0833
71.2917
...

我再次制作了一个对所有这些时间进行编码的 bash 脚本。在这种情况下,我不必转换为时间,因为我得到的是时间:
time=$(awk 'BEGIN{ print "'$current'"-"'$previous'" }') 
ffmpeg -i $video -r 24 -c:v libx265  -f mp4 -c:a aac -strict experimental -b:v 1.5M -ss $previous -t $time "output$count.mp4" -nostdin

在所有这些解释之后,问题就来了。一旦所有场景都被编码,我需要连接它们,为此我要做的是创建一个包含视频名称的列表,然后运行 ​​ffmpeg 命令。

列表.txt
file 'output1.mp4'
file 'output2.mp4'
file 'output3.mp4'
file 'output4.mp4'

命令:
ffmpeg -f concat -i list.txt -c copy big_buck_bunny.mp4

问题是“连接”视频比原始视频长 2.11 秒。原始持续 596.45 秒,编码持续 598.56。我将每个视频时长加起来,得到 598.56。所以,我认为问题出在编码过程中。两个视频具有相同的帧数。我的目标是获取有关编码过程的指标,当我运行 VQMT 来获取 PSNR 和 SSIM 时,我得到了奇怪的结果,我认为这是针对这个问题的。

顺便说一句,我正在使用 big_buck_bunny 视频。

最佳答案

可能的差异是由于 copy编解码器。在后一种情况下,您告诉 ffmpeg 复制段,但它不能根据您的输入时间执行此操作。
它必须首先找到之前的 I 帧(可以在不引用任何先前帧的情况下解码的帧)并从这里开始。

要获得所需的内容,您需要重新编码视频(就像您在前两个示例中所做的那样)或更改时间以在 I 帧处停止。

要断言我正确地解决了您的问题:

  • 您有一个源视频(以可变帧速率编码,接近 18fps)
  • 您想通过 ffmpeg 拆分源视频,将帧速率强制为 24 fps。
  • 然后你想连接每个段。

  • 我认为问题主要在于您在时间上存在一些差异(如果我将帧索引除以您给出的时间,我会在 16fps 到 18fps 之间得到)。当您在步骤 2 中转换它们时,输出视频片段时间将为 24fps。 ffmpeg 不会在时间轴上重新采样,所以如果你强制一个视频速率,视频会加速或减速。
    还有流的一致性问题:
    通常,视频流必须以 I 帧开始,因此在分割时,FFMPEG 必须定位前一个 I 帧(使用 copy 编解码器时,这会改变片段的持续时间)。

    当您连接时,您还可能遇到一致性问题(也就是说,如果您要连接的段确实以 I 帧结束,而下一个以 I 帧开始,FFMPEG 可能会丢弃任何一个,尽管我不'不记得现在的行为是什么)

    所以,为了解决你的问题,如果我是你,我会避免第 2 步(无论如何这对质量不利)。也就是说,我将使用 ffmpeg 根据帧号(这是您的方案中的唯一值 而不是 近似值)在 png 或 ppm 帧中(或者如果你不这样做,则为管道) t 关心保留它们),然后通过在最后一步对它们进行编码来连接所有帧,并将预期速率设置为 totalVideoTime/totalFrameCount .

    您将获得更小、更高质量的最终视频。

    如果由于某种原因你不能按照我说的做,至少对于 concat 输入,你应该使用 ffconcat 格式:
    ffconcat version 1.0
    file segment1
    duration 12.2
    file segment2
    duration 10.3
    

    如果每个片段更长,这将为您提供预期的持续时间

    要按帧数选择(而不是时间,因为时间很难在可变帧率视频上正确),您应该使用 select像这样过滤:
    -vf select=“between(n\,start_frame_num\,end_frame_num),setpts=STARTPTS"

    关于ffmpeg - 场景检测和连接使我的视频更长(FFMPEG),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55423785/

    相关文章:

    windows - ffmpeg 录制屏幕并将视频文件以 .mpg 格式保存到磁盘

    ffmpeg - 将时间码复制到输出文件 ffmpeg 或 ffmbc

    linux - 保存 V4L2 摄像机输出

    c++ - 如果 extern "C"包含与 Qt 库冲突怎么办?

    c# - 为什么此方法不重定向 .exe [ffmpeg] 的输出?

    php - 从带有转换的图像 unix 命令行创建视频

    ffmpeg - 在 x264 中实现的 CRF 算法

    修剪后的 ios 视频然后在非 ios 设备上播放音频/视频不同步

    OpenCV VideoWriter 不写入 Output.avi

    ffmpeg 创建多个输出视频,在 gt(scene,x) 上分割