FFMPEG 多输出性能(单实例与多实例)

FFMPEG 多输出性能(单实例与多实例)

我正在从单个文件输入 (.mp4) 创建多个编码流。输入流没有音频。每个编码流都是通过裁剪输入的不同部分然后在 32 核系统上使用相同比特率进行编码而创建的。

以下是我正在尝试的场景,如 ffmpeg wiki 中所述,用于创建多个输出。 https://trac.ffmpeg.org/wiki/Creating%20multiple%20outputs

场景 1(使用单个 ffmpeg 实例)

ffmpeg -i 输入.mp4 \

-filter:v crop=iw/2:ih/2:0:0 -c:v libx264 -b:v 5M out_1.mp4 \

-filter:v crop=iw/2:ih/2:iw/2:0 -c:v libx264 -b:v 5M out_2.mp4 \

-filter:v crop=iw/2:ih/2:0:ih/2 -c:v libx264 -b:v 5M out_3.mp4

在这种情况下,我假设 ffmpeg 只会解码一次输入,并将其提供给所有裁剪过滤器。如果不正确,请纠正我。

场景 2(使用多个 ffmpeg 实例,因此使用三个独立的进程)

ffmpeg -i 输入.mp4 -filter:v crop=iw/2:ih/2:0:0 -c:v libx264 -b:v 5M out_1.mp4

ffmpeg -i 输入.mp4 -filter:v crop=iw/2:ih/2:iw/2:0 -c:v libx264 -b:v 5M out_2.mp4

ffmpeg -i 输入.mp4 -filter:v crop=iw/2:ih/2:0:ih/2 -c:v libx264 -b:v 5M out_3.mp4

在我的例子中,我实际上需要通过裁剪输入视频的不同部分来编码更多数量的流。我在这里展示三个只是为了使这个例子更简单。

现在,就 fps 性能而言,我发现方案 2 表现更好。它还最大程度地利用了 CPU(超过 95% 的 CPU 利用率)。方案 1 的 fps 较低,CPU 利用率低得多(接近 65%)。此外,在这种情况下,随着我增加要编码的流的数量,CPU 利用率不会线性增加。当我从一个流增加到两个流时,它几乎变成了 1.5 倍。但此后增量非常低(可能为 10%,如果流更多,增量甚至更低)。

我的问题是: 我想使用单实例 ffmpeg,因为它可以避免多次解码,而且我的输入可能大到 4K 甚至更大。我应该怎么做才能获得更好的 CPU 利用率(> 90%),从而有望获得更好的 fps?此外,为什么 CPU 利用率不随要编码的流数量线性增加?为什么单实例 ffmpeg 的性能不如多实例?在我看来,使用单个 ffmpeg 实例,所有编码并不是真正并行运行的。

编辑: 如果事情不太清楚,以下是我可以重现和解释该问题的最简单的方法。请记住,这只是为了了解该问题的实验目的。

单实例:ffmpeg -y -i input.mp4 -c:v libx264 -x264optsthreads=1 -b:v 1M -f null - -c:v libx264 -x264optsthreads=1 -b:v 1M -f null - -c:v libx264 -x264optsthreads=1 -b:v 1M -f null -

多个实例:ffmpeg -y -i input.mp4 -c:v libx264 -x264optsthreads=1 -b:v 1M -f null - | ffmpeg -y -i input.mp4 -c:v libx264 -x264optsthreads=1 -b:v 1M -f null - | ffmpeg -y -i input.mp4 -c:v libx264 -x264optsthreads=1 -b:v 1M -f null -

请注意,我将 x264 限制为单线程。在单实例的情况下,我希望 ffmpeg 为每个 x264 编码生成 1 个编码线程并并行执行它们。但我看到只有一个 CPU 核心被充分利用,这让我相信一次只有一个编码会话在运行。另一方面,在多实例的情况下,我看到三个 CPU 核心被充分利用,我猜这意味着所有三个编码都在并行运行。

我真的希望一些专家能够介入并帮助解决这个问题。

答案1

一个不太明显的问题是,根据您的输入/输出或过滤器ffmpeg可能需要在内部进行像素格式转换,并且在某些情况下,如果在每个流上单独进行,这在使用并行输出时会成为瓶颈。

我们的想法是,如果可能的话,进行一次像素格式转换,例如:

-filter_complex '[0:v]format=yuv420p, split=3[s1][s2][s3]' \
-map '[s1]' ... \
-map '[s2]' ... \
-map '[s3]' ... \

应用于所有输出的相同过滤器也应仅使用一次。某些过滤器可能需要特定的像素格式。

对于其他原因,请参见底部的小注释维基百科

并行编码

在同一个 FFmpeg 进程中多次输出和重新编码通常会减慢到列表中“最慢的编码器”的速度。一些编码器(如 libx264)以“线程化和后台”的方式执行编码,因此它们可以有效地实现并行编码,但是音频编码可能是串行的并成为瓶颈等。似乎如果您确实有任何串行编码,FFmpeg 会将其视为“真正的串行”,因此您的 FFmpeg 可能不会使用所有可用内核。

答案2

我自己也注意到了这一点,视频缓冲区大小较低/默认。

尝试将 bufsize 增加到 50M 或文件大小的一半(以较小者为准)。

还要注意,bufsize 参数以 k 为单位表示,因此它类似于 -bufsize 50000k

答案3

我无法重现您的问题。设置:

我在 Powershell 中的代码:

# Measure time of FFMPEG process
$time = Measure-Command{
    ffmpeg -ss 00:01:00.000 -i .\ToS-4k-1920.mov `
    -to 00:00:25.000 -c:v libx264 -b:v 5M -y .\out_1.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_2.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:ih/2" -c:v libx264 -b:v 5M -y .\out_3.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_4.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_5.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_6.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_7.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_8.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_9.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_10.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_11.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_12.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:0" -c:v libx264 -b:v 5M -y .\out_13.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_14.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:0:ih/2" -c:v libx264 -b:v 5M -y .\out_15.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_16.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_17.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_18.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_19.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_20.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_21.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_22.mp4 `
    -to 00:00:25.000 -c:v libx264 -b:v 5M -y .\out_23.mp4 `
    -to 00:00:25.000 -vf "crop=iw/2:ih/2:iw/2:0" -c:v libx264 -b:v 5M -y .\out_24.mp4
}

Write-Host "Time spent: $time"

结果:

  • $time:00:05:52.7747482
  • ffmpeg 的速度:speed=0.0711x

我认为这两个价值观都是合理的。

即使 24 个并行输出也没有出现任何问题 - 整个过程中 CPU 保持在 95% 左右,几乎没有使用 SSD(<5%)并且使用了 ~75% 的 RAM(空闲时,使用了 ~30%)。(通过任务管理器手动检查值)

因此,这里有一些可能性:

  • 您正在使用旧版本的 FFmpeg
  • 其他东西(HDD、RAM)成为瓶颈
  • 你的文件有问题 - 我认为不太可能
  • 你的 CPU 出了问题 - 这不太可能,正如你所说,当使用多个 ffmpeg 实例时,它会满负荷工作)
  • 在您的代码中尝试不同的-threads值,看看是否会产生任何差异。

相关内容