我使用ffmpeg libx264来编码从x11实时捕获的720p屏幕,其fps为30。 当我使用 -tune zerolatency 参数时,每个帧的平均编码时间可以与配置文件基线一样大到12毫秒。
在研究了ffmpeg x264源代码后,我发现导致如此长编码时间的关键参数是切片线程,它由-tune zerolatency启用。使用-x264-params slic-threads = 0禁用后,编码时间可低至2ms
禁用切片线程后,CPU使用率将为40%,而启用时仅为20%。
有人可以解释有关此切片线程的详细信息吗?特别是在实时编码中(假设没有帧被缓冲以进行编码。仅在捕获帧时进行编码)。
答案 0 :(得分:11)
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
主要区别似乎是帧线程增加了帧延迟,因为需要使用不同的帧,而在基于切片的线程的情况下,所有线程都在同一帧上工作。在实时编码中,它需要等待更多帧到达以填充管道而不是离线。
普通线程,也称为基于帧的线程,使用巧妙的交错帧系统进行并行处理。但它需要付出代价:如前所述,每个额外的线程都需要一层延迟。基于切片的线程没有这样的问题:每个帧被分成片,每个片在一个核上编码,然后将结果打包在一起以形成最终帧。由于各种原因,它的最高效率要低得多,但它至少允许一些并行性而不会增加延迟。
Sliceless threading: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
是有意义的,因为您需要尽快发送一个帧,而不是有效地编码它们(性能和质量明智)。
相反,使用太多线程会影响性能,因为维护它们的开销可能会超过潜在的收益。