【问题标题】:FFmpeg - How to trim with high precision?FFmpeg - 如何高精度修剪?
【发布时间】:2016-10-12 00:12:40
【问题描述】:

我非常坚持 FFmpeg 修剪视频的方式,所以如果有人能帮助我,我将不胜感激。 基本上,我想做的是:我有一个视频序列,我希望它在某一秒钟内停止,将图像冻结几秒钟(如暂停),然后从同一帧再次再现。我可以说我正在处理三个视频:A.mp4(视频序列的第一部分)、B.mp4(冻结的图像)和 C.mp4(第二部分)视频序列的一部分)。此外,我还使用 filter_complex 进行叠加。

从静态图像生成视频的部分不是问题,我主要关心的是找到准确修剪和连接视频的方法。从其他帖子和来源中,我发现 FFmpeg 从那些是关键帧的帧中修剪,可以强制执行。但是,我得到的结果并不合适,因为我的视频 A 以与 C 开头的帧不同的帧结束。

我使用的命令如下:

ffmpeg -y -i VideoSequence.mp4 -c:v libx264 -pix_fmt yuv420p \
-force_key_frames "expr: gte(t,n_forced * 15)" -t 30 VideoOut.mp4

[请注意,Filter Complex 中的所有内容都是关于叠加的,效果很好]

据我所知,生成的视频应该每 15 秒有一个关键帧。现在,我想将视频分成两部分(“15 秒前”和“15 秒后”):

ffmpeg -y -ss 00:00:01 -i VideoOut.mp4 -t 14 -c copy A.mp4

ffmpeg -y -ss 00:00:15 -i VideoOut.mp4 -t 5 -c copy C.mp4 

如前所述,我希望 A.mp4 的结尾与 C.mp4 的开头“匹配”(以帧精度),但我获得的结果远非完美。

非常感谢您,任何形式的帮助将不胜感激!

【问题讨论】:

  • 这是真正的 ffmpeg 还是 libav-tools 的 Debian 包装器,什么版本?
  • 您能否也删除与问题无关的任何内容,例如-filter_complex,以提供minimal reproducible example
  • @OrangeDog 已编辑。感谢您的建议。顺便说一句,它是真正的 ffmpeg 版本 N-81696-gd38dff8e。
  • 不,这是构建时 git repo 的 HEAD。那这不是正式版吗?不用我去搜索发布历史,你知道它最接近什么吗?
  • 您了解 MPEG 的工作原理吗?关键帧是一个完整的帧,它在关键帧之间进行插值。所以如果我们想在非关键帧的帧处进行剪切,我们必须使用解码器生成帧,然后将其作为人工关键帧插入。

标签: ffmpeg


【解决方案1】:

假设您的最终目标是我希望它在某一秒内停止,将图像冻结几秒(如暂停),然后从同一帧再次重现。,当前方法,具有多个视频生成,是不必要的浪费。

这是在一个命令中执行此操作的方法,假设视频为 25 FPS。

ffmpeg -i original.mp4 -filter_complex
       "[0]split[a][b];
        [a]trim=1:15,loop=75:1:349,setpts=N/FRAME_RATE/TB[pre];
        [b]trim=15,setpts=N/FRAME_RATE/TB[post];
        [0]atrim=1:15,asetpts=N/SR/TB[apre];
        [0]atrim=15,asetpts=N/SR/TB[apost];
        [pre][apre][post][apost]concat=a=1[v][a]"
       -map "[v]" -map "[a]" paused.mp4

这是过滤图中发生的事情:

首先,视频被分成两个相同的流。然后从第 2 秒开始到第 15 秒结束修剪第一个流。在循环过滤器中,从(最后一帧)#349 开始的1 帧循环了 75 帧。然后时间戳被规范化,因为修剪或循环过滤器不会这样做。第二个拆分流被修剪为从第 16 秒开始,其时间戳重置,两个流使用 concat 连接。如果您需要在联合流的顶部覆盖某些内容,请在 concat 之后插入 overlay 过滤器。

【讨论】:

  • 我还有一个问题:如果您不想暂停一帧,而是想显示另一幅图像(即相同的图像,但带有一些线条和颜色),您会怎么做?谢谢!
  • 在concat之后,添加overlay过滤器,使用enable='between(t,14,17)'将新图像覆盖在暂停部分的顶部
【解决方案2】:

由于您没有定义帧速率,我认为问题可能是您的关键帧没有准确插入您想要的位置。而不是每 15 帧强制一个,只需插入您需要的两个:

-force_key_frames 00:00:01,00:00:15

或者,如果您只关心拆分是否干净而不是拆分的确切位置,您可以使用分段复用器:

-f segment -segment_time 14 out%03d.mp4

关于这个documentation的另一个想法:

-ss 位置(输入/输出)
当用作输入选项时(-i 之前),在此输入文件中查找位置。请注意,在大多数格式中,不可能精确搜索,因此 ffmpeg 将搜索到 position 之前最近的搜索点。当转码和-accurate_seek 启用(默认)时,搜索点和位置之间的这个额外段将被解码并丢弃。在进行流复制或使用-noaccurate_seek时,会被保留。

当用作输出选项时(在输出文件名之前),解码但丢弃输入,直到时间戳到达位置。

因此,移动 -ss 应该没有任何区别,但值得一试,尤其是对于没有准确搜索的旧版本。

【讨论】:

  • 感谢您的时间@OrangeDog。但是,它似乎不起作用:第一次修剪正确执行,但第二部分的开头与第一个部分的结尾重叠(音频和视频)。我试过在-i之前和之后放置-ss,但在这两种情况下,结果都不正确。
  • 正如我所说,我不认为 -ss 会有所作为,但关键帧落在哪里。
  • 另外两个想法呢?
  • 关于 -force_key_frames 的那个不起作用。带有 -segment 的第二个效果很好!但是,正如@Mulvya 在他的回答中指出的那样,不生成中间文件并在 filter_complex 中执行所有操作更为明智。无论如何,非常感谢你
猜你喜欢
  • 1970-01-01
  • 2019-06-06
  • 2015-09-10
  • 1970-01-01
  • 2015-10-27
  • 1970-01-01
  • 2015-06-05
  • 2014-03-21
  • 2017-03-28
相关资源
最近更新 更多