且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用 FFMPEG:如何进行场景变化检测?带时间码?

更新时间:2023-02-06 15:56:02

结合 scene 过滤器(用于检测场景变化)和 showinfo 过滤器应该实现你想要的:

Combining the scene filter (for detecting scene changes) and the showinfo filter should achieve what you want:

ffmpeg -i input.flv  
       -filter:v "select='gt(scene,0.4)',showinfo" 
       -f null 
       - 2> ffout

此命令提取与前一帧相差超过 (gt) 0.4 的所有帧(范围从 0 到 1代码>).对于这些帧,信息是这样打印出来的(showinfo)

This command extracts all frames that differ from the previous frame by more than (gt) 0.4 (on a scale from 0 to 1). For these frames, information is printed out (showinfo) like this

[Parsed_showinfo_1 @ 0x2d85e60] n:   0 pts:2537204 pts_time:2.5372  pos:  2998114 fmt:rgb24 sar:1/1 s:1920x1200 i:P iskey:1 type:I checksum:5616582E plane_checksum:[5616582E]

现在您只需提取时间戳.我认为您对 pts_time 感兴趣.你可以这样做:

Now you only have to extract the timestamp. I think you're interested in pts_time. You could do it like this:

grep showinfo ffout | grep pts_time:[0-9.]* -o | grep [0-9.]* -o > timestamps

这将为您提供所有时间戳的列表:

This will give you the list of all timestamps:

2.5372
4.37799
6.65301
8.09344

要使这种方法起作用,您必须有一个实现场景检测的 FFmpeg 版本.此外,您必须为阈值选择一个合适的值(第一个命令中的 0.4).您可以尝试通过像这样提取不同阈值的帧(然后手动检查帧)来找到***阈值

For this approach to work, you must have a version of FFmpeg that implements the scene detection. Also, you have to select a suitable value for the threshold (0.4 in the first command). You can try to find an optimal threshold by extracting frames for different thresholds (and afterwards examine the frames manually) like this

ffmpeg -i input.flv 
       -filter:v "select='gt(scene,0.1)',showinfo" 
       -vsync 0 frames/%05d.jpg

只是为了澄清:grep [0-9.]* 不排除另一个答案中声称的整数.它匹配任何由数字和句点组成的字符序列,但它也会匹配非数字,如4.4.4".但是,ffmpeg 不应该输出这种格式错误的时间戳.

Just for clarification: grep [0-9.]* does not exclude integers as claimed in another answer. It matches any character sequence consisting of digits and periods but it would also match non-numbers like '4.4.4'. However, ffmpeg shouldn't output such ill-formed timestamps.