如何在不重新编码的情况下使用 ffmpeg 删除帧?

How to remove a frame with ffmpeg without re-encoding?

我正在用 C++ 制作一个数据交换程序,我需要找到一种方法来从视频中删除一个帧(具体来说,序列跳转之后的 p 帧)而不重新编码视频。我目前正在使用 h.264,但也希望能够使用 VP9 和 AV1 来实现。

我有一种解决方法,但由于一个令人沮丧的原因(稍后提到)它不起作用。我可以将原始视频转换为两个中间视频 - 一个只有序列跳跃前的 i 帧,一个有两帧后的 p 帧。然后我创建了一个包含以下内容的 concat.txt 文件:

file video.mkv
file video1.mkv

和运行 ffmpeg -y -f concat -i concat.txt -c copy output.mp4。这产生了预期的输出,虽然当然没有我想要的那么高效,因为它需要创建中间文件并从磁盘读取 .txt 文件(在这个项目中性能非常重要)。

但更糟糕的是,我无法使用 ffmpeg 生成中间视频,我不得不使用 avidemux。我在 ffmpeg -y -ss 00:00:00 -i video.mp4 -t 0.04 -codec copy video.mkv 上尝试了各种变体,但该命令似乎对长度为 1-2 帧的视频确实有问题 - 虽然它适用于更长的视频没问题。我最好的猜测是有一些内部检查器可以确保输出视频没有损坏(不幸的是,这正是我想要的!)。

也许有一种方法可以解决这个问题,或者更好的是,首先有一个更优雅的解决方案。

谢谢!

如果你知道目标帧的PTS或数据偏移量或包索引,那么你可以使用噪声比特流过滤器。这是codec-agnostic.

ffmpeg -copyts -i input -c copy -enc_time_base -1 -bsf:v:0 noise=drop=eq(pos\,11291) out

这将丢弃存储在输入文件中偏移量 11291 处的第一个视频流中的数据包。在 http://www.ffmpeg.org/ffmpeg-bitstream-filters.html#noise

查看其他可用变量