我正在从单个文件输入 (.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
我无法重现您的问题。设置:
- 最新的 Zeranoe 静态构建
- Win10专业版
- Intel i5-4210U CPU(4 核,无 HT)
- 8GB DDR3 内存
- 读/写至内部 1TB Mushkin Reactor SSD
- 复现视频:http://ftp.halifax.rwth-aachen.de/blender/demo/movies/ToS/ToS-4k-1920.mov(
-ss 00:01:00.000 -to 00:01:25.000
因为渲染整个东西显然会花很长时间)
我在 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
值,看看是否会产生任何差异。