如何使用ffmpeg简单地从视频中删除重复的帧

Ske*_*eve 4 linux windows video ffmpeg duplicates

首先,尽管我已经多年(以相当有限的方式)对ffmpeg情有独钟,但我还是以我不是视频操作专家来开头。因此,我不太喜欢人们经常使用的所有语言 ...以及它如何影响我在操作中试图做的事情...但是无论如何我还是会尝试的...

我在这里检查了一些链接,例如: ffmpeg-依次删除重复的帧

...但是内容并没有真正帮助我。

我有几百个使用ffmpeg和其他类似应用程序在Windows和Linux下创建的视频剪辑。但是,它们在视频显示不动的情况下存在时间问题。

例如,假设我们有一个网站,该网站将实时视频流式传输到Web浏览器中的Flash视频播放器/插件中。例如,在这种情况下,我们谈论的是交通摄像头视频流。

运行ffmpeg的一个实例正在将(Windows)桌面的某个区域捕获到视频文件中,即:

ffmpeg -hide_banner -y -f dshow ^
      -i video="screen-capture-recorder" ^
      -vf "setpts=1.00*PTS,crop=448:336:620:360" ^
      -an -r 25 -vcodec libx264 -crf 0 -qp 0 ^
      -preset ultrafast SAMPLE.flv
Run Code Online (Sandbox Code Playgroud)

假设正在捕获的实际“显示”看起来像这样:

123456789 XXXXX 1234567 XXXXXXXXXXX 123456789 XXXXXXX
^---a---^ ^-P-^ ^--b--^ ^----Q----^ ^---c---^ ^--R--^ 
Run Code Online (Sandbox Code Playgroud)

...其中每个字符位置代表一帧(序列)。由于互联网连接状况不佳,可以长时间显示“单个框架”(“ X”字符是前一个框架的(几乎)精确副本)。因此,这意味着我们捕获的视频片段中的图像根本没有变化(无论如何用裸眼)。

我们该如何处理重复的帧?...并且如果ffmpeg的“重复项”不相同,但查看者看起来或多或少相同,我们的方法将如何改变?

如果我们简单地删除重复的帧,则视频的“步调”将丢失,以前需要花费5秒钟才能显示的视频现在只需花费一秒钟的时间,从而产生了非常不自然的运动,尽管视频中没有重复的图像。使用ffmpeg的'mp_decimate'选项似乎可以实现,即:

     ffmpeg -i SAMPLE.flv ^                      ... (i)
        -r 25 ^
        -vf mpdecimate,setpts=N/FRAME_RATE/TB DEC_SAMPLE.mp4
Run Code Online (Sandbox Code Playgroud)

我引用的参考使用一条命令,该命令显示当“ mp_decimate”帧被视为“相同”时将删除哪些帧,即:

     ffmpeg -i SAMPLE.flv ^                      ... (ii)
        -vf mpdecimate ^
        -loglevel debug -f null -
Run Code Online (Sandbox Code Playgroud)

...但是知道了(复杂格式的)信息之后,如何在不执行多次ffmpeg提取视频“片段”以供以后重新组合的情况下重新组织视频呢?

在那种情况下,我猜我们将不得不运行以下内容:

  • 用户为重复项指定“阈值持续时间”(可能仅运行1秒)
  • 确定并保存主要视频信息(fps等-假设帧率恒定)
  • 映射(重复开始的帧/时间)->否。帧数/重复时间
  • 如果重复的持续时间小于用户阈值,请不要将此时间段视为“一系列重复的帧”,然后继续
  • 提取“非重复”视频片段(上图中的a,b和c)
  • 使用原始视频的规范创建“新视频”(空)
  • 对于每个视频片段,提取片段的最后一帧,创建一个简短的视频剪辑,并重复提取刚提取的帧(持续时间=用户指定= 1秒),然后将(当前视频片段+简短剪辑)追加到“新视频”并重复

...但是就我而言,很多捕获的视频可能长达30分钟,并且有数百个10秒的暂停时间,因此使用此方法对视频进行“重建”将花费很长时间。

这就是为什么我希望使用ffmepg(带有/不带有“ mp_decimate”过滤器)以某种“可靠”和“更智能”的方式仅经过几遍就可以执行“ decimate”功能的原因……也许有一种方法甚至可以指定所需的段(例如,在文本文件中),并且当ffmpeg运行时,它会在指定的时间/帧数处停止/重新启动代码转换吗?

缺少这一点,是否有另一个应用程序(可在Windows或Linux上使用)可以执行我要的操作,而无需手动设置开始/停止点,手动提取/组合视频片段...?

我一直在尝试使用Win7-SP1下的ffmpeg N-79824-gcaee88d和Puppy Linux Slacko 5.6.4下的(我目前不记得的其他版本)来完成所有这些工作。

感谢您提供任何线索。

Gya*_*yan 5

我假设您要做的是使帧保持运动,并且最多保留1秒钟的重复帧,而丢弃其余的帧。

ffmpeg -i in.mp4 -vf
"select='if(gt(scene,0.01),st(1,t),lte(t-ld(1),1))',setpts=N/FRAME_RATE/TB"
trimmed.mp4
Run Code Online (Sandbox Code Playgroud)

选择过滤器表达式的作用是使用if-then-else运算符:

gt(scene,0.01)检查当前帧是否检测到相对于前一帧的运动。该值将必须基于手动观察进行校准,方法是查看与框架中的传感器/压缩噪声或视觉噪声相比,哪个值可以准确捕获实际活动。有关如何获取所有场景更改值的列表,请参见此处

如果框架被评估为具有运动,则then子句为st(1,t)。该函数st(val,expr)将值存储在expr编号为变量的变量中val,并且还返回该表达式值作为结果。因此,保留帧的时间戳将在该变量中继续更新,直到遇到静态帧为止。

else子句检查当前帧时间戳和存储值的时间戳之间的差异。如果差异小于1秒,则保留该帧,否则丢弃该帧。

setpts进行消毒所有被选择帧的时间戳。

编辑:我用合成的视频输入测试了我的命令,它可以正常工作。


sza*_*ary -1

可变帧速率编码是完全可能的,但我认为它的作用并不像你想象的那样。我假设您希望删除这些重复的帧以节省空间/带宽?如果是这样,它将不起作用,因为编解码器已经在这样做了。编解码器使用参考帧,并且仅对参考帧发生变化的内容进行编码。因此,重复的框架一开始几乎不占用任何空间。基本上,帧只是被编码为数据包,即复制前一帧,然后进行更改。X 帧的变化为零,因此只需几个字节即可对每个帧进行编码。