为啥切片线程对使用 ffmpeg x264 的实时编码影响如此之大?
Posted
技术标签:
【中文标题】为啥切片线程对使用 ffmpeg x264 的实时编码影响如此之大?【英文标题】:Why sliced thread affect so much on realtime encoding using ffmpeg x264?为什么切片线程对使用 ffmpeg x264 的实时编码影响如此之大? 【发布时间】:2016-02-10 23:28:09 【问题描述】:我正在使用 ffmpeg libx264 以 30 fps 对从 x11 实时捕获的 720p 屏幕进行编码。 当我使用 -tune zerolatency 参数时,每帧的平均编码时间可以大到 12ms 与配置基线。
研究了ffmpeg x264源代码,发现导致编码时间如此长的关键参数是sliced-threads,它通过-tune zerolatency启用。使用 -x264-params sliced-threads=0 禁用后,编码时间可以低至 2ms
如果禁用分片线程,CPU 使用率为 40%,而启用时仅为 20%。
有人能解释一下这个切片线程的细节吗?特别是在实时编码中(假设没有缓冲帧进行编码。仅在捕获帧时进行编码)。
【问题讨论】:
你使用的是默认的preset
吗?如果你使用-preset ultrafast
会发生什么?
以上两种情况都使用超快。
这是一个有趣的问题。您是否使用最新版本的ffmpeg
和libx264
以及在什么操作系统/CPU 上。另外,你是如何测量的?
不是最新的,我源上的最后一次提交是2014年2月23日,而libx264是2014年2月11日(抱歉源代码是从另一个人那里得到的,我只能得到细节来自 git log)主机操作系统是 ubuntu 14.04,CPU 是 Xeon(R) CPU E5-2630 v3。我使用了 -benchmark_all 选项并将所有输出数据转储到文件中,然后使用脚本计算平均编码时间。
x264/doc/threads.txt
表示部分编码器是串行的,并且基于切片的线程不能很好地扩展。由于您有 8 个内核,我认为它会产生 8 个切片线程。您可以覆盖 --threads 4
或 --slices
/ --slices-max
看看会发生什么。这与您的问题类似:mailman.videolan.org/pipermail/x264-devel/2010-April/… 不过我不认为这是调度程序,您的内核是最新的。
【参考方案1】:
documentation 表明基于帧的线程比基于切片的线程具有更好的吞吐量。它还指出,由于部分编码器是串行的,后者不能很好地扩展。
veryfast
配置文件的加速与编码线程(非实时):
threads speedup psnr
slice frame slice frame
x264 --preset veryfast --tune psnr --crf 30
1: 1.00x 1.00x +0.000 +0.000
2: 1.41x 2.29x -0.005 -0.002
3: 1.70x 3.65x -0.035 +0.000
4: 1.96x 3.97x -0.029 -0.001
5: 2.10x 3.98x -0.047 -0.002
6: 2.29x 3.97x -0.060 +0.001
7: 2.36x 3.98x -0.057 -0.001
8: 2.43x 3.98x -0.067 -0.001
9: 3.96x +0.000
10: 3.99x +0.000
11: 4.00x +0.001
12: 4.00x +0.001
主要区别似乎是帧线程增加了帧延迟,因为它需要不同的帧来处理,而在基于切片的线程的情况下,所有线程都在同一帧上工作。在实时编码中,它需要等待更多帧到达以填充管道,而不是离线。
普通线程,也称为基于帧的线程,使用巧妙的交错帧系统进行并行处理。但这是有代价的:如前所述,每个额外的线程都需要多一帧的延迟。基于切片的线程没有这样的问题:每一帧都被分割成切片,每个切片在一个核心上编码,然后将结果拼接在一起形成最终帧。由于各种原因,它的最大效率要低得多,但它至少允许一些并行性而不会增加延迟。
发件人:Diary of an x264 Developer
Sliceless 线程:以 2 个线程为例。 开始编码帧#0。完成一半后,开始编码第 1 帧。线程 #1 现在只能访问其参考帧的上半部分,因为其余部分尚未编码。所以它必须限制运动搜索范围。但这可能没问题(除非你在一个小帧上使用很多线程),因为很少有这么长的垂直运动向量。过了一会儿,两个线程都编码了一行宏块,所以线程 #1 仍然可以使用运动范围 = +/- 1/2 帧高度。稍后,线程#0 完成了第 0 帧,然后移动到第 2 帧。线程 #0 现在获得运动限制,线程 #1 不受限制。
发件人:http://web.archive.org/web/20150307123140/http://akuvian.org/src/x264/sliceless_threads.txt
因此,启用 sliced-threads
和 -tune zereolatency
是有意义的,因为您需要尽快发送帧,而不是有效地对其进行编码(性能和质量方面)。
相反,使用太多线程会影响性能,因为维护它们的开销可能会超过潜在收益。
【讨论】:
“在实时编码中,它需要等待更多帧到达以填充管道,而不是离线。”这是在谈论帧线程对吗?切片或帧线程会增加解码时间吗?线程数呢?谢谢 是的,我说的是帧线程,因为它适用于不同的帧。默认情况下它是帧线程(#threads = 1.5 * cores),这就是为什么您在启用切片时看到较低值的原因。线程过多 (16) = 开销过多。关于解码时间,似乎使用切片可以使解码器利用多线程并更快地解码(例如:蓝光需要4个切片)。 我想知道的另一件事是,如果不使用 b 帧,为什么编码器会等待后面的帧而不是只使用前面的帧。 查看我的更新答案。每个额外的线程都会增加 1 帧延迟,因为它需要用于运动估计。 非常感谢您的耐心和详细的回答。这对我帮助很大。以上是关于为啥切片线程对使用 ffmpeg x264 的实时编码影响如此之大?的主要内容,如果未能解决你的问题,请参考以下文章