ffmpeg - 删除顺序重复的帧

时间:2016-05-07 12:25:36

标签: ffmpeg duplicates

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

我尝试使用-vf标记select=gt(scene\,0.xxx)进行场景更改。但是,它对我的​​情况不起作用。

3 个答案:

答案 0 :(得分:47)

使用mpdecimate过滤器,其目的是删除与前一帧没有太大差异的帧,以降低帧速率。"

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

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

  • 生成删除了重复项的视频

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

Th setpts过滤器表达式为FRAME_RATE fps的视频生成平滑的时间戳。请参阅What is video timescale, timebase, or timestamp in ffmpeg?

的时间戳说明

答案 1 :(得分:12)

我也遇到了这个问题,吉安(Gyan)的出色回答让我起步,但是其结果是音频不同步,所以我不得不探索更多选择:

mpdecimatedecimate过滤器

  • mpdecimate是我在SO和互联网上找到的标准建议,但我认为它不应该是首选
    • 它使用启发式方法,因此可能并且会跳过一些重复的帧
    • 您可以使用frac参数来调整检测,但这是您可能需要避免的额外工作
    • 这实际上不是应该工作的with mp4 containersource),但是我使用的是mkv,所以此限制不适用于我的情况,但请注意
  • decimate可以精确删除帧,但仅对定期出现的重复有用。

检测到的实际帧速率

  • 因此,如果您的多媒体文件具有重复的帧,则最好确保检测到的帧速率与实际帧速率匹配。
  • ffprobe in.mkv将输出检测到的FPS;可能看起来像这样

    Stream #0:0: Video: h264 (Main), yuvj420p(pc, bt709, progressive), 1920x1080, SAR 1:1 DAR 16:9, 25 fps, 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符合您的实际FPS(例如,两者均为 30 fps ),则可以在FRAME_RATE中使用N/FRAME_RATE/TB变量
  • 但是如果检测到的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过滤器
  • 这是我用来获得好的结果

    的方法

    ffmpeg -i in.mkv -vf mpdecimate out.mkv

    ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv

  • 但以下内容使我去同步的音频

    ffmpeg -i in.mkv -vf mpdecimate,setpts=N/FRAME_RATE/TB out.mkv

    ffmpeg -i in.mkv -vf mpdecimate,setpts=N/25/TB out.mkv

    ffmpeg -i in.mkv -vf decimate=cycle=6 out.mkv

  • 如您所见

    • mpdecimatedecimate的工作方式不同
    • mpdecimate在没有setpts过滤器的情况下对我来说效果更好
    • decimate需要使用setpts过滤器,此外,我还需要避免使用FRAME_RATE变量,而应使用N/25/TB,因为未正确检测到实际的FPS

关于asetpts的注释

  • 它与setpts的工作相同,只是音频
  • 它并没有真正为我解决取消同步音频的问题,但是您想使用类似-af asetpts=N/SAMPLE_RATE/TB
  • 的音频
  • 也许您应该根据删除的重复帧的比例来调整SAMPLE_RATE,但是在我看来,这是多余的工作,尤其是当我的视频开始时音频是同步的时,这样做会更好使用将保持这种状态的命令,而不是稍后再修复

tl; dr

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

ffmpeg -i in.mkv -vf mpdecimate out.mkv

ffmpeg -i in.mkv -vf decimate=cycle=6,setpts=N/25/TB out.mkv

({cycle=6,因为每第6帧都是重复的,而N/25/TB是因为删除重复的帧后,视频将具有25 fps(避免使用FRAME_RATE变量);请调整使用范围情况)

答案 2 :(得分:0)

我在这里尝试了解决方案,但当您需要修剪视频并保留音频时,它们似乎都不起作用。有一个 mpdecimate_trim 存储库做得很好。它基本上列出了要删除的所有帧(使用 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