如何根据 CSV 中的时间戳使用 FFmpeg 加速视频?

如何根据 CSV 中的时间戳使用 FFmpeg 加速视频?

关于使用 FFmpeg 加速视频,已经存在一些问题,例如这个

我的问题是:是否还有一种方法可以指定多个部分,并通过外部 CSV 来加速。

我的 CSV 如下所示:

start, end
00:00:03.296, 00:00:14.372,
00:00:16.388, 00:00:33.635,
00:00:33.693, 00:00:39.428,
00:00:39.460, 00:00:50.355,
00:00:50.355, 00:01:17.892,
00:01:17.892, 00:01:19.845,
00:01:19.845, 00:01:47.616,

这些是应加速 10 倍的精确部分(每行一个部分,两个时间戳定义每个部分的开始和结束)。其余部分应保持原始播放速度。

有什么办法可以做到这一点?

答案1

我们可以使用以下方式设置每个视频帧所需的 PTS 时间戳:设定点用精心设计的嵌套if表达式进行过滤。

以下答案只是一个“概念证明”,假设您具备以编程方式创建所需更复杂表达式的知识。该解决方案假设输入视频具有固定的帧速率,并且可以轻松地从输入帧号计算输入时间戳。

注意:
通过设置时间戳来加速视频的某些部分会创建可变帧率 (VFR) 视频,这可能无法在所有视频播放器中正常播放。
通过将整个视频加速 10 倍来创建固定帧率视频可能会更好,并在原始速率的部分中将每个帧复制 10 次。
请注意,使用通过 OpenCV 读取帧并使用 OpenCV 写入(或更好地管道到 FFmpeg)的 Python 脚本,复制帧相对简单。


假设我们有以下输入文件(40 帧,1fps):

ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=40 -c:v libx264 -g 1 input.mp4

输入视频的时间戳为:

 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,

假设我们想要在范围 [0, 19] 和 [30, 39] 内加速,并获取以下输出时间戳:

 0,    1,    2,    3,    4,    5,    6,    7,    8,    9,
10, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9,
11,   12,   13,   14,   15,   16,   17,   18,   19,   20,
21, 21.1, 21.2, 21.3, 21.4, 21.5, 21.6, 21.7, 21.8, 21.9,

我们可以使用以下FFmpeg命令:

ffmpeg -y -r 100 -i input.mp4 -fps_mode:v passthrough -vf "setpts='(if(lt(N,10), N, if(lt(N,20), ((N-10)/10)+10, if(lt(N,30), 11+(N-20), 21+(N-30)/10))))/TB'" -c:v libx264 -g 1 output.mp4

  • -r 100用于将数据包持续时间设置为 10 毫秒(短数据包持续时间允许更高的时间戳分辨率)。
  • -fps_mode:v passthrough- 将每个输入帧从输入传递到输出(由于速率为 100 fps,因此不会重复帧)。
  • -vf "setpts='(if(lt(N,10), N, if(lt(N,20), ((N-10)/10)+10, if(lt(N,30), 11+(N-20), 21+(N-30)/10))))/TB'"- 使用if表达式和一些数学运算来调整时间戳。
    表达式if适用于 if(条件,如果为真则为值,如果为假则为值)。
    N是输入帧号,从零开始计数。
    if(lt(N,10), N, ...将 PTS 设置N为前 10 帧...
    /TB除以时间基准的秒数。
  • -g 1- 将 GOP 大小设置为 1 以进行测试(将其删除)。使用 FFprobe 时,它​​保持 PTS 排序。

使用 FFprobe 验证输出时间戳:
ffprobe -select_streams v:0 -of default=noprint_wrappers=1 -show_entries packet=pts_time output.mp4

输出符合预期:

pts_time=0.000000
pts_time=1.000000
pts_time=2.000000
pts_time=3.000000
pts_time=4.000000
pts_time=5.000000
pts_time=6.000000
pts_time=7.000000
pts_time=8.000000
pts_time=9.000000
pts_time=10.000000
pts_time=10.100000
pts_time=10.190000
pts_time=10.300000
pts_time=10.400000
pts_time=10.500000
pts_time=10.600000
pts_time=10.700000
pts_time=10.800000
pts_time=10.900000
pts_time=11.000000
pts_time=12.000000
pts_time=13.000000
pts_time=14.000000
pts_time=15.000000
pts_time=16.000000
pts_time=17.000000
pts_time=18.000000
pts_time=19.000000
pts_time=20.000000
pts_time=21.000000
pts_time=21.100000
pts_time=21.200000
pts_time=21.300000
pts_time=21.400000
pts_time=21.500000
pts_time=21.600000
pts_time=21.700000
pts_time=21.800000
pts_time=21.900000

演示输出的动画 GIF:
在此处输入图片描述
(使用 创建ffmpeg -y -i output.mp4 -filter_complex "[0:v]split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -r 1 output.gif

相关内容