使用 FFmpeg 时删除顺序重复的帧

Posted

技术标签:

【中文标题】使用 FFmpeg 时删除顺序重复的帧【英文标题】:Remove sequentially duplicate frames when using FFmpeg 【发布时间】:2016-09-02 11:30:45 【问题描述】:

有没有办法使用ffmpeg 检测视频中的重复帧?

我尝试使用-vf 标志和select=gt(scene\,0.xxx) 进行场景更改。但是,它不适用于我的情况。

【问题讨论】:

【参考方案1】:

我在这里尝试了解决方案,但当您需要修剪视频并保留音频时,它们似乎都不起作用。有一个 mpdecimate_trim repo 做得很好。它基本上列出了所有要丢弃的帧(使用mpdecimate),然后创建一个复杂的过滤器,通过拆分视频并仅包括没有重复帧的部分来修剪视频中的所有这些帧(和相应的音频)。

不过,我确实不得不调整代码中的一些选项。例如,在mpdecimate_trim.py 中,我不得不更改这一行:

dframes2 = get_dframes(ffmpeg(True, "-vf", "mpdecimate=hi=576", "-loglevel", "debug", "-f", "null", "-").stderr)

我不得不更积极地检测重复,所以我将mpdecimate 选项更改为mpdecimate=hi=64*32:lo=64*24:frac=0.05

【讨论】:

【参考方案2】:

我也遇到了这个问题,上面 Gyan 的出色回答让我开始了,但结果是音频不同步,所以我不得不探索更多选择:

mpdecimate 与 decimate 过滤器

mpdecimate 是我在 SO 和互联网上找到的标准推荐,但我认为它不应该是首选 它使用启发式算法,因此它可能会跳过一些重复的帧 您可以使用 frac 参数调整检测,但如果可以的话,您可能希望避免这种额外工作 它实际上不应该工作 with mp4 container (source),但我使用的是 mkv 所以这个限制不适用于我的案例,但很高兴知道它 decimate 精确地删除帧,但它仅对周期性出现的重复项有用

检测到的帧率与实际帧率

因此您的多媒体文件包含重复帧,最好确保检测到的帧速率与实际帧速率匹配

ffprobe in.mkv会输出检测到的FPS;它可能看起来像这样

Stream #0:0: Video: h264 (Main), yuvj420p(pc, bt709, progressive), 1920x1080, SAR 1:1 DAR 16:9, <strong>25 fps</strong>, 25 tbr, 1k tbn, 50 tbc (default)

如果您在媒体播放器中打开媒体in.mkv,可以找到实际帧率,可以让您一次步进一帧;然后计算将播放时间提前 1 秒所需的步骤,在我的情况下是 30 fps

对我来说并不意外,因为每第 6 帧都是重复的(5 个好帧和 1 个重复),所以在 25 个好帧之后也有 5 个重复

什么是N/FRAME_RATE/TB

除了使用FRAME_RATE 变量之外,N/FRAME_RATE/TB 与以下来自 ffmpeg 文档 (source) 的示例相同

将固定速率设置为每秒 25 帧:setpts=N/(25*TB)

What is video timescale, timebase, or timestamp in ffmpeg? 中完美解释了其背后的数学原理

它基本上计算每一帧的时间戳并将其与时基TB 相乘以提高精度

FRAME_RATE 变量与文字 FPS 值(例如 25)

这就是了解检测到的和实际的 FPS 很重要的原因 如果检测到的 FPS 与您的实际 FPS 匹配(例如,两者都是 30 fps),您可以愉快地在 N/FRAME_RATE/TB 中使用 FRAME_RATE 变量 但如果检测到的 FPS 不同于您必须自行计算 FRAME_RATE 在我的情况下,我的实际 FPS 是每秒 30 帧,我每隔 6 帧删除一次,所以目标 FPS 是 25,这导致 N/25/TB 如果我使用FRAME_RATE(我实际上尝试过),它会检测到错误的 25 帧 fps,即FRAME_RATE=25,通过mpdecimate 过滤器运行它,该过滤器将每 6 次删除一次框架,它会更新为FRAME_RATE=20.833 所以N/FRAME_RATE/TB 实际上是N/20.833/TB 这是完全错误的

使用或不使用setpts

所以setpts 过滤器已经变得相当复杂,尤其是因为重复帧可能会造成 FPS 混乱 好消息是您实际上可能根本不需要 setpts 过滤器

这是我使用的效果很好

@987654330@ -i in.mkv -vf @987654331@ out.mkv

@987654332@ -i in.mkv -vf @987654333@=cycle=6,@987654334@=N/25/TB out.mkv

但以下给了我去同步的音频

@987654335@ -i in.mkv -vf @987654336@,@987654337@=N/FRAME_RATE/TB out.mkv

@987654338@ -i in.mkv -vf @987654339@,@987654340@=N/25/TB out.mkv

@987654341@ -i in.mkv -vf @987654342@=cycle=6 out.mkv

如你所见

mpdecimate 和 decimate 工作方式不同 没有setpts 过滤器,mpdecimate 对我来说效果更好 虽然decimate 需要setpts 过滤器,而且我需要避免使用FRAME_RATE 变量并改用N/25/TB,因为没有正确检测到实际的FPS

注意asetpts

它的作用与 setpts 的作用相同,但用于音频 它并没有真正为我修复不同步音频,但您想使用类似 -af @987654351@=N/SAMPLE_RATE/TB 的东西 也许你应该根据删除重复帧的比例来调整SAMPLE_RATE,但在我看来,这似乎是额外的不必要的工作,尤其是当我的视频在开始时音频同步时,所以最好使用命令将保持这种状态,而不是稍后修复它

tl;博士

如果通常推荐的命令 @987654352@ -i in.mkv -vf @987654353@,@987654354@=N/FRAME_RATE/TB out.mkv 对您不起作用,请尝试以下操作:

@987654355@ -i in.mkv -vf @987654356@ out.mkv

@987654357@ -i in.mkv -vf @987654358@=cycle=6,@987654359@=N/25/TB out.mkv

cycle=6 因为每 6 帧都是重复的,N/25/TB 因为删除重复后视频将有 25 fps(避免使用 FRAME_RATE 变量);根据您的用例进行调整)

【讨论】:

mp4 需要 setpts,因为它是一个恒定帧速率复用器。在我的命令中添加 -vsync vfr 并删除 setpts 以在保存到 mp4 时保持具有相同时间戳的去重帧 Add -vsync vfr and remove setpts in my command @Gyan --- 这正是我为mpdecimate 的用例所做的,特别是我删除了setpts 过滤器,我什至不需要-vsync vfr。都在tl;dr 部分。 The setpts is needed with mp4 because it is a constant frame rate muxer @Gyan --- 这很有趣,但也请注意,虽然我能够从 mpdecimate 过滤器用例中删除 setpts 过滤器(如您所建议的那样),但我 对于decimate 用例,必须 使用setpts。两者都是mkv。猜对了吗?! 在尝试ffmpeg -i in.mkv -vf [mpdecimate][] out.mkv 时,我得到[AVFilterGraph @ ...] Bad (empty?) label found in the following: "[]". Error reinitializing filters! Failed to inject frame into filter network: Invalid argument. Error while processing the decoded data for stream #0:0 错误。 嗨@Tijmen,感谢您指出问题!我调查了一下,似乎有一个edit to the original answer 破坏了 ffmpeg 命令。正如我从您的评论中看到的,您使用了损坏的命令。具体来说,您使用的命令ffmpeg -i in.mkv -vf [mpdecimate][] out.mkv 有缺陷,正确的命令是ffmpeg -i in.mkv -vf mpdecimate out.mkv(注意没有方括号)。现在都修好了。【参考方案3】:

使用mpdecimate 过滤器,其目的是“丢弃与前一帧差别不大的帧以降低帧速率。”

这将生成一个控制台读数,显示过滤器认为哪些帧是重复的。

ffmpeg -i input.mp4 -vf mpdecimate -loglevel debug -f null -

生成删除重复项的视频

ffmpeg -i input.mp4 -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mp4

setpts 过滤器表达式为FRAME_RATE FPS 的视频生成平滑的时间戳。在What is video timescale, timebase, or timestamp in ffmpeg?查看时间戳的解释

【讨论】:

这就是我要找的。谢谢! 我做到了,效果很好,谢谢。作为奖励,mp4 文件显着减少了兆字节,尽管它只刮掉了几帧。 FRAME_RATE要换成帧率吗? @MarkNeu 不,它引用了 ffmpeg 检测到的 FPS @Suuuehgi 它适用于纯视频文件。使用音频,跳过 setpts 过滤器并添加 -vsync vfr

以上是关于使用 FFmpeg 时删除顺序重复的帧的主要内容,如果未能解决你的问题,请参考以下文章

视频的帧类型与帧存储

还有另一种方法可以将ffmpeg中的帧导出到texture2d吗?我的代码在Windows中运行但不在Linux上运行

删除单链表保留顺序中的重复项

.net core多个重复任务执行顺序

python删除列表中的重复元素并保持相对顺序不变

删除顺序数组的重复数字