How to split a video using FFMPEG so that each chunk starts with a key frame?

video ffmpeg split keyframe

47133 观看

6回复

2819 作者的声誉

We need to split a large live WMV video feed in small chunks all of the same size. We made a script that works fine doing this, except for one thing: the video chunks don't start with a key frame, so when playing most video chunks they don't display any image until a key frame from the original video is eventually reached.

Isn't there a way to tell ffmpeg to make the output video to start with a key frame?

Here is how our command lines look right now:

ffmpeg.exe -i "C:\test.wmv" -ss 00:00:00 -t 00:00:05 -acodec copy -vcodec copy -async 1 -y  "0000.wmv"
ffmpeg.exe -i "C:\test.wmv" -ss 00:00:05 -t 00:00:05 -acodec copy -vcodec copy -async 1 -y  "0001.wmv"

and so on...

作者: sboisse 的来源 发布者: 2012 年 12 月 22 日

回应 6


3

5808 作者的声誉

如果您愿意进行一些脚本编写并希望以特定的时间间隔进行构图,则一种方法是

  1. 运行ffprobe并从输出中收集I帧的位置

    ffprobe -show_streams

  2. 使用相同的脚本运行一系列-ss -t命令以获取所需的块。

然后,您可以让脚本决定最小帧数(例如,彼此之间10帧之内有两张I图片,您真的不想在这里分块)。

另一种方法是使用gstreamer的multisfilesink并将模式设置为关键帧[但是,它将在每个关键帧处分块,因此可能不理想]

作者: av501 发布者: 2012 年 12 月 23 日

6

1783 作者的声誉

使用ffprobe -show_frames -pretty <stream>找出关键帧。

作者: d33pika 发布者: 2012 年 12 月 23 日

19

2819 作者的声誉

这是我可以使用的解决方案:

根据av501和d33pika的建议,我使用ffprobe查找关键帧在哪里。因为ffprobe非常冗长,并且可能花费几秒钟甚至几分钟来输出所有关键帧,并且无法确定冗长视频中我们想要的帧范围,所以我继续执行5个步骤:

  1. 从原始文件中导出视频块,大约为所需块大小的两倍。

    ffmpeg -i source.wmv -ss 00:00:00 -t 00:00:06 -acodec copy -vcodec copy -async 1 -y  0001.wmv
    
  2. 使用ffprobe查找关键帧的位置。在所需块大小之后选择最接近的关键帧。

    ffprobe -show_frames -select_streams v -print_format json=c=1 0001.wmv
    
  3. 从ffprobe的输出中获取pkt_dts_time关键帧之前的帧。

  4. 在步骤1的导出块上的ffmpeg,指定相同的输入和输出文件,并指定-ss 00:00:00-t[在步骤3中找到的值]。

    ffmpeg -i 0001.wmv -ss 00:00:00 -t 00:00:03.1350000 -acodec copy -vcodec copy -async 1 -y 0001.wmv
    
  5. 使用-ss[在迭代中在步骤3中找到的值的总和] 重新启动步骤1 。

通过这种方式,我能够以一种有效而强大的方式在关键帧处分割视频。

作者: sboisse 发布者: 2012 年 12 月 23 日

12

121 作者的声誉

使用较新版本的ffmpeg,可以通过使用ffprobe和ffmpeg段多路复用器来实现。

1.使用ffprobe和awk标识关键帧,使其尽可能接近所需的块长度。

ffprobe -show_frames -select_streams v:0 -print_format csv **[SOURCE_VIDEO]** 2>&1 | grep -n frame,video,1 | awk 'BEGIN { FS="," } { print $1 " " $5 }' | sed 's/:frame//g' | awk 'BEGIN { previous=0; frameIdx=0; size=0; } { split($2,time,"."); current=time[1]; if (current-previous >= **[DURATION_IN_SECONDS]**){ a[frameIdx]=$1; frameIdx++; size++; previous=current;} } END { str=a[0]; for(i=1;i<size;i++) { str = str "," a[i]; } print str;}'

哪里

  • [SOURCE_VIDEO] =您要分段的视频的路径
  • [DURATION_IN_SECONDS] =所需的段长度(以秒为单位)

输出是关键帧的逗号分隔字符串。

2.使用上面输出的关键帧作为ffmpeg的输入。

ffmpeg -i [SOURCE_VIDEO]-编解码器副本-map 0 -f段-segment_frames [OUTPUT_OF_STEP_1] [SEGMENT_PREFIX] _%03d。[SOURCE_VIDEO_EXTENSION]

哪里

  • [SOURCE_VIDEO] =您要分段的视频的路径
  • [OUTPUT_OF_STEP_1] =关键帧的逗号分隔字符串
  • [SEGMENT_PREFIX] =段输出的名称
  • [SOURCE_VIDEO_EXTENSION] =源视频的扩展名(例如mp4,mkv)
作者: Steek 发布者: 2013 年 7 月 16 日

29

1872 作者的声誉

决定

The latest builds of FFMPEG include a new option "segment" which does exactly what I think you need.

ffmpeg -i INPUT.mp4 -acodec copy -f segment -vcodec copy -reset_timestamps 1 -map 0 OUTPUT%d.mp4

这将产生一系列带编号的输出文件,这些文件将根据“关键帧”分为多个段。在我自己的测试中,它运行良好,尽管我没有用过超过几分钟的时间并且仅以MP4格式使用它。

作者: Tim Bull 发布者: 2014 年 1 月 30 日

29

1768 作者的声誉

如官方的FFMPEG文件所述,对我来说,指定-ss timestart before 更好-i input_file.ext,因为它可以将(或据我所知)将生成的视频的开头设置为在指定时间戳之前找到最接近关键帧

将您的示例更改为:

ffmpeg.exe -ss 00:00:00 -i "C:\test.wmv" -t 00:00:05 -acodec copy -vcodec copy -async 1 -y  "0000.wmv"

我已经测试了在.flv.mp4文件上使用此方法。

作者: Sopalajo de Arrierez 发布者: 2015 年 10 月 17 日
32x32