Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Video 如何使用FFMPEG分割视频,使每个块以关键帧开始?_Video_Ffmpeg_Split_Keyframe - Fatal编程技术网

Video 如何使用FFMPEG分割视频,使每个块以关键帧开始?

Video 如何使用FFMPEG分割视频,使每个块以关键帧开始?,video,ffmpeg,split,keyframe,Video,Ffmpeg,Split,Keyframe,我们需要将一个大的WMV直播视频源分成大小相同的小块。我们制作了一个脚本,它可以很好地完成这项工作,除了一件事:视频块不是从关键帧开始的,所以在播放大多数视频块时,它们不会显示任何图像,直到最终达到原始视频的关键帧 有没有办法告诉ffmpeg使输出视频以关键帧开始 下面是我们的命令行现在的样子: ffmpeg.exe -i "C:\test.wmv" -ss 00:00:00 -t 00:00:05 -acodec copy -vcodec copy -async 1 -y "0000.wmv

我们需要将一个大的WMV直播视频源分成大小相同的小块。我们制作了一个脚本,它可以很好地完成这项工作,除了一件事:视频块不是从关键帧开始的,所以在播放大多数视频块时,它们不会显示任何图像,直到最终达到原始视频的关键帧

有没有办法告诉ffmpeg使输出视频以关键帧开始

下面是我们的命令行现在的样子:

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"

以此类推……

如果您愿意编写一些脚本,并且希望以特定的间隔生成I帧,那么一种方法就是

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

    ffprobe-显示\u流

  • 使用相同的脚本运行一系列-ss-t命令以获得所需的块

  • 然后你可以让你的脚本决定最小帧数[假设有两张相隔10帧的I图片,你真的不想在那里分块]


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

    使用
    ffprobe-show\u frames-pretty
    来识别关键帧。

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

    根据av501和d33pika的建议,我使用ffprobe查找关键帧的位置。由于ffprobe非常冗长,可能需要几秒钟甚至几分钟才能输出所有关键帧,并且无法确定我们希望从一个长视频中获得的帧范围,因此我将分为5个步骤:

  • 从原始文件导出一个视频块,大约为所需块大小的两倍

    ffmpeg -i source.wmv -ss 00:00:00 -t 00:00:06 -acodec copy -vcodec copy -async 1 -y  0001.wmv
    
    ffprobe -show_frames -select_streams v -print_format json=c=1 0001.wmv
    
  • 使用ffprobe查找关键帧的位置。选择所需块大小之后最近的关键帧

    ffmpeg -i source.wmv -ss 00:00:00 -t 00:00:06 -acodec copy -vcodec copy -async 1 -y  0001.wmv
    
    ffprobe -show_frames -select_streams v -print_format json=c=1 0001.wmv
    
  • 从ffprobe的输出中,获取关键帧之前的帧的
    pkt\u dts\u time

  • 在步骤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
    
  • 在步骤1重新启动,使用
    -ss
    [在迭代过程中在步骤3中找到的值的累积和]


  • 通过这种方式,我能够有一种高效而健壮的方法在关键帧分割视频。

    使用较新版本的
    ffmpeg
    ,可以通过使用
    ffprobe
    ffmpeg
    muxer
    来实现这一点

  • 使用
    ffprobe
    和awk尽可能近距离地识别关键帧 到所需的块长度
  • ffprobe-显示帧-选择流v:0\
    -打印格式csv[源视频]2>&1|
    grep-n帧,视频,1|
    awk'BEGIN{FS=“,”}{print$1”“$5}'|
    sed's/:frame//g'|
    awk'开始{previous=0;frameIdx=0;size=0;}
    {
    拆分($2,时间,“.”);
    电流=时间[1];
    如果(当前上一个>=[持续时间(单位:秒)]){
    a[frameIdx]=1美元;frameIdx++;大小++;上一个=当前;
    }
    }
    结束{
    str=a[0];
    
    对于(i=1;iFFMPEG的最新版本包括一个新选项“segment”,它完全符合我认为您需要的功能

    ffmpeg-i INPUT.mp4-acodec copy-f段-vcodec copy-reset\u时间戳1-map 0输出%d.mp4

    这将生成一系列编号的输出文件,这些文件根据关键帧分为若干段。在我自己的测试中,它工作得很好,尽管我没有在超过几分钟的时间内使用它,而且只使用MP4格式。

    正如官方声明的那样,在-ss timestart
    对我来说效果更好g>
    -我输入了_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
    文件上测试了这种方法。

    您使用的是最新的ffmpeg版本吗?是的,最新的:ffmpeg版本N-47062-g26c531c。我们还尝试了使用-force_key_frames:v 00:00:00或-force_key_frames:v 00:00:05,但这对输出没有影响。我相信使用-vcodec copy实际上意味着它只是将图片组复制到新文件中,但不会进行任何形式的重新编码来添加关键帧。是这样吗?
    -vcodec copy
    不会重新编码:它只执行解组和muxing。有没有办法将我的文件分割成块,以便每个块都以关键帧开始?它们的持续时间不必完全相同。但是它们必须是完全连续的。如果我在输入文件中指定-ss,它会在关键帧处剪切,但随后我看到我的视频重叠,将相同的GOP重新包含在两个连续的块中。看起来是一个很有希望的解决方案。将进行调查。我查阅了文档,但无法轻松找到方法来探测视频的一小部分(例如,仅前10秒)。因为视频相当长,它会生成几MB的输出,需要几秒钟才能生成。ffprobe中是否有选项仅输出特定流的帧,并且在特定范围内?ffprobe-show_frames-select_streams v filtered to only video frames。现在,我只需要能够指定帧的范围或时间范围。我浏览了文档,没有找到任何关于限制到视频特定时间范围的内容。因此我想我将使用ffmpeg获取块,然后调用ffprobe获取关键帧,然后调用ffmpeg在关键帧之前进行最后分割。@sboisse,
    -read\u interval
    现在允许您需要指定探测的时间或数据包间隔。例如,
    ffprobe-显示帧-读取间隔10%+20,01:30%01:45-i
    从10-30秒开始探测,然后从1:30-1:45开始探测。在您的帮助下,我也可以这样做,但是,初始dts/pts稍微移动了一点(此处为500毫秒)。文档显示