ffmpeg - 如何在编解码器复制时从关键帧精确地开始剪切?

ffmpeg - 如何在编解码器复制时从关键帧精确地开始剪切?

使用 -ss 作为输入选项与 -c:v copy 一起使用可能不准确,因为 ffmpeg 被迫仅在 i 帧上使用/分割。不过,如果可能的话,它会将流的开始时间调整为负值以补偿这一点。基本上,如果您指定“第 157 秒”,并且直到第 159 秒才有关键帧,开始时将包含两秒的音频(没有视频),然后从第一个关键帧开始。因此,分割和进行编解码器复制时一定要小心。

为了避免这种情况,我首先尝试找到所需帧的时间戳-ss,然后-to 通过构建所有附近帧的图块。我已经使用

ffmpeg -i "INPUT.mkv" -ss 09:55 -t 3 -vf "drawtext=fontfile=I\\:\Misc\\\\~Software\\\\~OS\\\\I386\\\\arial.ttf: fontsize=60: text='F%{n}\(%{pict_type}\)\@%{pts\:hms}': x=(w-tw)/2: y=h-(2*lh): fontcolor=white: box=1: boxcolor=0x00000000@1,scale=320:-1,tile=layout=12x10" tiles%03d.png

根据它们,所需的关键帧应该从 00:09:56.012 开始,而所需的最后一个帧应该在 00:10:00.224。但是,使用这些时间戳进行剪切时创建的片段

ffmpeg -i "INPUT.mkv" -map 0:0 -map 0:4 -map 0:5 -map 0:6 -ss 09:56.012 -to 00:10:00.224 -vcodec copy -acodec copy J01.mkv

从非关键帧(仅声音)开始,并在错误的位置结束。相比之下,在 Avidemux 中剪切相同的片段即使将视频和音频输出设置设置为Copy(IIUC、不重新编码和从非关键帧开始)也可以正常工作。Avidemux 中显示的时间戳也不同(-ss 09:56.346 -to 10:00.558vs -ss 09:56.012 -to 10:00.224)。

我也尝试过通过 pkt_dts_time 进行剪切(https://stackoverflow.com/questions/14005110/),但这也不起作用。

ps 另一个与我尝试执行的操作(与上述 Avidemux 类似)的过程是,在 Sony Vegas 中,放大时间线,直到可以从一帧移动到另一帧,然后将场景切换后的第一帧(也是关键帧)设置为起点,将同一场景的最后一帧(之后是下一个不需要的关键帧)设置为终点,然后进行渲染。在 Avidemux 中也可以执行类似的操作,同时复制视频和音频流。

编辑 1:这是版本日志-copyts:pastebin . com /Cxzrc8Er。我还应该做其他的吗?


编辑2:这是的结果"PATHTO\ffprobe.exe" -select_streams v -show_entries packet=pts_time,flags -of compact -read_intervals 580%600 "INPUT.mkv" | findstr K

packet|pts_time=578.160000|flags=K
packet|pts_time=581.205000|flags=K
packet|pts_time=583.499000|flags=K
packet|pts_time=585.042000|flags=K
packet|pts_time=588.671000|flags=K
packet|pts_time=594.885000|flags=K
packet|pts_time=596.012000|flags=K

我也尝试了其他 2 个视频的整个命令组合(平铺、以此方式列出帧、以两种不同方式剪切片段),结果类似。使用您建议的命令在终端中列出的关键帧时间与我制作的平铺中的关键帧时间相匹配;并且通常使用我的方法剪切会在开头留下一小段冻结部分(~1s),有时会在结尾留下几个不需要的帧,而使用您的方法剪切会在开头留下更长的空白视频流。

我还找到了一个更好的视频片段用于实验,因为它可以更直观地确定有多少想要的帧丢失了,又有多少不需要的帧被添加了 (imgur.com /a /DTzmt,相关部分可以在 bit.ly /Kmnz112f1 下载)。您的解决方案也更好地适用于它。

另外,只是为了确认一下:你的意思是 -ss 09:56.013而不是 -ss 09:56.012在您原来的解决方案中?而且,我猜它通常适用于您正在剪辑的视频,而它不适用于我的视频,这很不寻常,对吗?


答案1

尝试

ffmpeg -ss 09:56.013 -i "INPUT.mkv" -map 0:0 -map 0:4 -map 0:5 -map 0:6 -to 00:10:00.224 -vcodec copy -acodec copy -avoid_negative_ts make_zero J01.mkv

答案2

一个解决方案可能是:

  1. 剪切片段的前 5 秒(即您想要剪切的位置)
  2. 使用与输入相同的编解码器对其进行编码
  3. 将其用作第 1 层
  4. 将带编解码器的剪辑复制copy为第 2 层
  5. 将第 1 层覆盖在第 2 层上。

这可能比仅仅复制还要慢。

另一个解决方案是找到第一个关键帧,然后连接两个剪辑:

  • 一个从剪辑开始到关键帧,使用相同的编解码器进行编码
  • 其他从关键帧到剪辑结束,使用编解码器copy

我还没有尝试过。

相关内容