V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
JackalZhao
V2EX  ›  问与答

FFmpeg 对视频进行分段倍速处理再输出的问题

  •  
  •   JackalZhao · 2020-09-24 13:13:15 +08:00 · 2121 次点击
    这是一个创建于 1506 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一个视频文件,要进行以下处理,[0, 13, 2 倍速] 表示从 0 到 13 帧做 2 倍速处理,按照以下列表,依次对整个视频中各个片段做不同的倍速处理后,以 H264 压制写到输入文件。希望整个过程都使用 FFmpeg 进行处理。

    [0, 13, 2 倍速]
    [13, 20, 1 倍速]
    [20, 25, 2 倍速]
    [25, 135, 1 倍速]
    [135, 164, 2 倍速]
    [164, 250, 1 倍速]
    [250, 254, 2 倍速]
    [254, 309, 1 倍速]
    [309, 354, 2 倍速]
    [354, 438, 1 倍速]
    [438, 465, 2 倍速]
    [465, 540, 1 倍速]
    [540, 625, 2 倍速]
    

    目前我实现了两种方法,但都不完美:

    1. 使用 FFmpeg 将输入视频的所有帧提取成 jpeg,依次放到一个文件夹 1,根据区间和倍速信息,将需要的帧图片移动到文件夹 2,最后将文件夹 2 的图片用 FFmpeg H264 编码合成为一个视频。缺点是:

      • 将视频的所有帧提取出来,会占用大量空间,一个 500MB 的视频提取出来后,可能会占用 30G 的硬盘空间,而且都是零散的图片文件,除了费时间,有损硬盘。
    2. 使用 openCV 将输入视频逐帧读取,根据区间和倍速信息,决定是否将这一帧写入到输出视频。缺点是:

      • 这个操作是单线程的,速度比 FFmpeg 提取照片还慢,而且写出的输出视频是未压缩的数据
      • 写出的视频还需要使用 FFmpeg 再 H264 压制一遍

      这样下来,整体还是比 FFmpeg 提取图片筛选后再压制方法一慢一些。

    所以寻求可以直接使用 FFmpeg 读取输入文件的同时按上述区间和倍速信息列表用 H264 编码写到输出文件的方法。

    14 条回复    2020-10-05 08:40:26 +08:00
    ungrown
        1
    ungrown  
       2020-09-24 16:11:41 +08:00   ❤️ 1
    分段处理的问题怎么被你转化成分帧处理了?
    1. segment 分段
    https://www.ffmpeg.org/ffmpeg-formats.html#segment_002c-stream_005fsegment_002c-ssegment
    用`segment_times `指定多个时间点,用`reset_timestamps`重置各段起始时间
    2. 各段变速
    https://trac.ffmpeg.org/wiki/How%20to%20speed%20up%20/%20slow%20down%20a%20video
    3. concat 合并
    netnr
        2
    netnr  
       2020-09-24 16:49:20 +08:00
    现在播放器支持倍数播放,在播放的时候根据当前时间动态设置倍数
    JackalZhao
        3
    JackalZhao  
    OP
       2020-09-24 17:04:29 +08:00
    @ungrown 谢谢,ffmpeg 格式这一部分的文档还没仔细看过,才使得我不知道有 segment 这种格式。我会试试的。刚刚又找了另外一种方法,ffmpeg 可以用 `-i -` 的参数,使其开始接收视频数据,也可以按帧将原始数据传给 ffmpeg,我会两种方法都试一下。
    JackalZhao
        4
    JackalZhao  
    OP
       2020-09-27 16:00:21 +08:00 via Android
    @ungrown 这个方法应该是不行。segment 是将视频分成大概等长的片段,使用关键帧作为分割点。而我这里边的片段,比如说从第五帧到第十五帧,做两倍速处理,是非常短的一个小片段,使用 segment 做分割,就可能会是从第 0 到第 90 帧都导出了。所以还是要按帧处理。
    ungrown
        5
    ungrown  
       2020-09-27 16:03:22 +08:00
    @JackalZhao #4 segment 可以带时间点的参数,第一帖里就说了,用`segment_times `指定多个时间点
    ungrown
        6
    ungrown  
       2020-09-27 16:05:30 +08:00
    segment_times times

    Specify a list of split points. times contains a list of comma separated duration specifications, in increasing order. See also the segment_time option.
    ungrown
        7
    ungrown  
       2020-09-27 16:07:57 +08:00
    就算退一万步不用 segment,还可以用-ss, -to, -t 这些参数进行分段输出(不转码,copy ),逐段变速,再合并

    无论如何都没必要按帧来处理
    JackalZhao
        8
    JackalZhao  
    OP
       2020-09-29 14:47:21 +08:00 via Android
    @ungrown 对于只有零点几秒的片段,不管是 segment 还是 ss to,都会导出最少长达 1 秒的视频片段
    ungrown
        9
    ungrown  
       2020-09-29 15:01:52 +08:00
    从来没遇到过,我自己经常弄出来零点几秒的片段,甚至只有一两帧的片段都碰到过
    可能没遇到你手头的文件吧,也可能你手里文件的时间戳不太对劲,前者的可能性更大
    如果你是在要对亚秒级的片段进行变速处理而又无法正常切割出这些片段的话,也只好对这些地方进行逐帧处理
    我知道有个库可以比较方便地处理:PyAV,你愿意的话可以试试
    换做我的话是不高兴去写这么麻烦的代码的,我宁可开非编软件,鼠标妥妥点点就完事了
    JackalZhao
        10
    JackalZhao  
    OP
       2020-09-29 21:40:14 +08:00 via Android
    @ungrown 我是要对视频自动处理,比如将静音部分 8 倍速,有人说话部分 1 倍速,具体效果见我这个视频: https://b23.tv/93Xp4e 功能已经实现,详见: https://gitee.com/haujet/QuickCut 这样的操作,用非编软件处理 20 分钟的视频需要很久,而自动剪辑的话只需要 10 分钟的压制时间。
    ungrown
        11
    ungrown  
       2020-09-29 23:09:40 +08:00
    这个应用场景好窄,啊不是,好特别
    JackalZhao
        12
    JackalZhao  
    OP
       2020-09-29 23:18:02 +08:00
    @ungrown 懒得剪,就只保留人声部分,可以轻松的把视频缩短一半以上,除去录制视频时不想要的无信息的垃圾片段,保留关键信息。
    ungrown
        13
    ungrown  
       2020-09-30 08:27:35 +08:00
    建议单就这一个功能进行完善,这会是个很有用的工具,虽然不是大众需求,虽然没有太多技术含量,但对某些行业的人可谓是革命性的效率提升工具
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5761 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 06:09 · PVG 14:09 · LAX 22:09 · JFK 01:09
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.