我正在按场景对视频进行编码。目前,我有两种解决方案。第一个是使用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命令。
list.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视频。
答案 0 :(得分:1)
可能的差异归因于copy
编解码器。在后一种情况下,您告诉ffmpeg复制段,但是根据您的输入时间,它无法做到这一点。
它必须先找到先前的I帧(无需参考任何先前的帧即可解码的帧),然后从此处开始。
要获得所需的内容,您需要重新编码视频(就像您在前面两个示例中所做的一样),或者更改停止在I帧处的时间。
断言我正确地解决了您的问题:
我认为问题主要在于您在时间安排上存在一些差异(如果将帧索引除以给定的时间,则我得到的是16fps至18fps)。在步骤2中进行转换时,输出视频片段时间将为24fps。 ffmpeg不会在时间轴上重新采样,因此如果您强制使用视频速率,则视频将加速或减速。
流还存在一致性问题:
通常,视频流必须以I帧开始,因此,在分割时,FFMPEG必须定位先前的I帧(使用copy
编解码器时,这会更改段的持续时间)。
在连接时,还可能存在一致性问题(即,如果要连接的段确实以I帧结尾,而下一个以I帧开头,则FFMPEG可能会丢弃其中一个,虽然我不记得现在的行为是什么)
因此,要解决您的问题,如果我是您,我将避免执行第2步(无论如何对质量都是不利的)。也就是说,我将使用ffmpeg根据png或ppm帧中的帧号(这是您的方案中唯一不是近似的唯一值)(或如果不包含的话,将其分割为管道)来分割感兴趣的段不在乎保留它们),然后通过在最后一步以预期速率设置为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"
答案 1 :(得分:0)
我建议检查输入和输出帧速率,并确保它们匹配。这可能是差异的原因。