编码器并行架构 4K 60fps 视频编码,如果单线程要 200ms / 帧,就只能跑到 5fps;想跑实时,必须靠帧级并行、片级并行、Tile / WPP、SIMD、GPU 和集群把吞吐堆起来。
本文速览 章节 阅读重点 一句话结论 0. 三种并行方式 先建立帧级、片级、数据级并行的分类框架。 编码器并行不是一种技术,而是一组不同粒度的组合拳。 1. 帧级并行(x264 默认) 理解为什么多帧可以排队编码,以及为什么不能无限加速。 通用、无压缩损失,但受 B 帧和参考关系限制。 2. 切片并行(Slice) 理解一帧拆成多个 slice 后为什么低延迟。 延迟低、隔离好,但压缩率会下降。 3. WPP(Wavefront Parallel Processing) 理解 H.265 为什么能做“波前”行级并行。 比 slice 更保压缩率,是 H.265 常用并行方式。 4. Tile 并行(H.265 / AV1) 理解 4K / 8K 为什么常按矩形 tile 分块。 更适合超高清和并行解码,AV1 里尤其重要。 5. lookahead 单独线程 理解编码前瞻分析为什么能独立跑。 lookahead 不直接编码像素,但会影响码率控制和质量。 6. SIMD 优化 理解单线程内部如何用 CPU 向量指令并行。 SIMD 是编码器性能地基,通常默认开启。 7. GPU 编码器并行 理解 NVENC / 多 GPU 如何提升转码吞吐。 硬编靠专用单元和多卡横向扩展,不等同于 CUDA 算法并行。 8. 服务端集群转码 理解单机和集群如何调度软编、硬编任务。 业务吞吐靠“单机并行 + 集群调度”一起解决。 9. 实测并行加速比 看线程数增加后为什么收益逐渐递减。 最佳线程数通常接近物理核心数,不是越多越好。 10. 调试:看哪一步慢 学会用 benchmark 和 profiler 找瓶颈。 不测就调参,基本靠猜。 11. 自研编码器要考虑 建立自研编码器并行设计清单。 自研要同时考虑线程、SIMD、缓存、NUMA 和调度。 12. 总结 汇总各类并行方式和调参顺序。 先 SIMD,再线程,再按场景加 slice / tile / GPU。
0. 三种并行方式 编码器并行先按“切分粒度”理解,后面所有实现都可以归到这三类:
并行方式 切分对象 典型名字 代表编码器 / 标准 适用场景 主要代价 帧级并行 多帧同时进入编码流水线。 Frame Parallelism x264 / x265 / SVT-AV1 都会用。 通用离线转码、点播转码、普通实时编码。 受参考帧、B 帧、lookahead 约束,不能无限并行。 切片并行 一帧拆成多个 slice,每个 slice 独立编码。 Slice Parallelism H.264 常见,直播低延迟场景会用。 直播、RTC、弱网传输、低延迟编码。 slice 边界不能跨片预测,压缩率下降。 数据块并行 一帧拆成 CTU 行、tile、superblock 等区域。 WPP / Tile Parallelism H.265 WPP / Tile,AV1 Tile。 4K / 8K、超高清、并行解码和并行编码。 需要标准和码流结构支持,调度更复杂。
核心判断 :帧级并行追求吞吐,slice 并行追求低延迟和隔离,WPP / Tile 更偏向在大分辨率下用满多核。
1. 帧级并行(x264 默认) 1.1 原理 帧级并行的核心是:不同帧处在编码流水线的不同阶段,多个线程像工厂流水线一样同时工作。
时间片 Frame N Frame N+1 Frame N+2 说明 T0 分析 等待 等待 第一帧先进入分析阶段。 T1 运动估计 分析 等待 下一帧开始分析,前一帧继续往后走。 T2 变换 / 量化 运动估计 分析 多帧同时占用不同线程。 T3 熵编码 变换 / 量化 运动估计 流水线稳定后吞吐提升。
特点 解释 优点 不改变单帧内部结构,通常没有额外压缩损失。 默认行为 x264 的--threads auto会根据 CPU 核数和分辨率自动估算线程数。 关键限制 帧间参考、B 帧重排、lookahead 依赖会限制最大并行深度。
1.2 x264 参数 参数 示例值 含义 建议 --threads8手动指定编码线程数。 服务器固定资源时可显式指定。 --threadsauto按 CPU 核数、分辨率等自动估算。 默认推荐,先让 x264 自己选。 --lookahead-threads1前瞻分析线程数。 通常 1 个足够,过多未必收益明显。
1.3 局限 局限 为什么会限制加速 典型现象 B 帧依赖前后帧 B 帧需要参考过去帧和未来帧。 线程再多也要等待参考关系满足。 帧间编码依赖前帧状态 参考帧、码率控制、lookahead 会串起多帧。 很难做到几十帧完全并行。 扩展效率非线性 同步、缓存竞争、串行阶段都会吃掉收益。 4 核可能接近 3.5x,但不是严格 4x。
2. 切片并行(Slice) 2.1 原理
每个 slice 可以独立编码和独立传输,适合低延迟场景。
设计点 解释 切分方式 一帧按行或区域拆成多个 slice。 线程模型 每个 slice 可以分配给一个线程。 依赖关系 slice 之间尽量不互相依赖。 输出形态 一个 frame 内包含多个可独立处理的 slice 数据。
2.2 优点 优点 具体含义 适用场景 并行度直接 slice 之间依赖少,可以多个线程同时编码。 多核 CPU 上的低延迟编码。 延迟低 不依赖多帧 lookahead 才能启动。 直播、RTC、互动场景。 网络隔离好 丢一个 slice 不一定影响整帧所有区域。 SFU 转发、弱网传输、分片恢复。
2.3 缺点 缺点 原因 典型影响 压缩率下降 slice 边界不能跨片预测。 4 slice 可能比 1 slice 大约多 5%,具体取决于内容和参数。 边界质量风险 边界附近预测信息减少。 复杂纹理、快速运动场景更容易损失效率。 参数要匹配线程数 slice 数和线程数不匹配会浪费线程或增加开销。 --slices 4通常配合接近 4 个编码线程。
2.4 x264 参数 参数 示例值 含义 使用建议 --slices4每帧切成 4 个 slice。 直播低延迟常用,数量不要盲目过大。 --threads4编码线程数。 通常和 slice 数接近,避免线程空转。 --tunezerolatency低延迟调优。 直播 / RTC 场景常和 slice 配合使用。
2.5 直播 SFU 用法 目标 推荐配置 原因 降低编码延迟 --slices 4 --threads 4 --tune zerolatencyslice 可并行编码,zerolatency减少缓冲和重排序等待。 降低弱网影响 多 slice 输出 网络丢一个 slice 时,不一定拖垮同帧其他 slice。 控制压缩损失 slice 数别过大 slice 越多边界越多,压缩效率越容易下降。
3. WPP(Wavefront Parallel Processing) 3.1 H.265 引入 WPP 把一帧拆成 CTU 行,下一行不必等上一行完全结束,只需要等上一行领先几个 CTU 后就能启动,形成“波前”。
行 启动时机 并行状态 直观理解 Row 0 最先启动。 跑在最前。 第 0 行先开始编码。 Row 1 等 Row 0 领先若干 CTU 后启动。 跟在 Row 0 后面。 像波浪一样追着上一行跑。 Row 2 等 Row 1 领先若干 CTU 后启动。 再晚一点启动。 多行逐步形成并行。 更多行 按同样规则延后启动。 分辨率越高可用行越多。 4K / 8K 更容易用满多核。
3.2 优点 优点 说明 对比 slice 压缩率更高 行之间仍保留一定预测关系。 通常比完全独立 slice 更省码率。 行级并行 多个 CTU 行可以错峰同时编码。 比纯帧级并行更能利用单帧内部并行度。 适合高分辨率 分辨率越高,CTU 行越多。 4K / 8K 场景收益更明显。
3.3 x265 参数 参数 示例 含义 建议 --wpp默认开启 启用 Wavefront 并行。 通常保持默认。 --frame-threads4帧级并行线程数。 和 WPP 共同提升吞吐。 --pmode开启 并行模式决策。 追求速度时可尝试。 --pme开启 并行运动估计。 高分辨率或慢 preset 下更值得测试。
4. Tile 并行(H.265 / AV1) 4.1 原理 Tile 把一帧切成矩形区域,每个 tile 更像一个独立小画面。和 slice 相比,tile 是二维矩形划分,更适合超高清并行。
2×2 Tile 示例 左列 右列 上排 Tile 0 Tile 1 下排 Tile 2 Tile 3
特性 说明 矩形切分 比按行 slice 更灵活,适合大画面区域并行。 相对独立 每个 tile 可独立处理,便于编码和解码并行。 标准支持 H.265 支持 tile,AV1 对 tile 的使用更常见。
4.2 应用 场景 推荐思路 原因 4K HDR / 8K 视频 使用多 tile,例如--tiles 4x2表示 8 个 tile。 超高清单帧太大,必须拆块提升并行度。 8K 解码 编码时就考虑 tile 友好。 单核解 8K 很难实时,多 tile 方便并行解码。 AV1 编码 更重视 tile 数和 tile 布局。 AV1 生态里 tile 常用于并行编码 / 解码和大分辨率处理。
5. lookahead 单独线程 5.1 x264 设计 lookahead 不直接输出编码帧,而是提前分析未来帧,帮助码率控制、B 帧决策、mb-tree 等模块做更优决策。
线程 工作内容 和主编码线程的关系 主编码线程 编码当前Frame N。 消费 lookahead 提前准备好的分析结果。 lookahead 线程 分析未来帧,例如Frame N+10。 尽量提前跑,避免主编码线程等待。 并发收益 编码和分析分离。 前瞻分析不阻塞当前帧编码。
5.2 参数 参数 示例值 含义 使用建议 --lookahead-threads1lookahead 使用的线程数。 默认 1,通常够用。 --rc-lookahead60前看 60 帧做码率控制和决策。 越大越利于质量 / 码控,但延迟和内存更高。
6. SIMD 优化(单线程内的并行) 6.1 x264 SIMD SIMD 是“单线程内部的并行”:一个 CPU 指令同时处理多个像素或多个残差值。
模块 SIMD 常用位置 指令集 / 平台 典型收益 DCT / IDCT 变换和反变换。 SSE2 / SSE4 / AVX / AVX2 / AVX-512 / ARM NEON。 大幅降低变换耗时。 SAD / SATD 运动估计代价计算。 x86 asm、ARM NEON asm。 运动搜索速度提升明显。 像素滤波 去块滤波、插值、像素加权。 SSE / AVX / NEON。 高频调用路径,收益稳定。 典型源码 common/x86/dct-a.asm、common/arm/dct-a.S。x264 汇编优化文件。 热点函数常见 5-10x 级别提升。
6.2 检测 CPU 能力 CPU 能力通常在初始化阶段检测,然后选择对应的 SIMD 实现。
int cpu= x264_cpu_detect ( ) ; if ( cpu& X264_CPU_AVX2) { // Use AVX2 implementation. } 检测结果 选择策略 注意事项 支持 AVX2 / AVX-512 优先走更宽的 x86 向量实现。 AVX-512 可能受频率下降影响,要以实测为准。 支持 ARM NEON 移动端和 ARM 服务器走 NEON 实现。 Android / iOS 上 NEON 基本是性能底座。 不支持高级 SIMD 回退到较低级指令或 C 实现。 功能可用,但性能可能明显下降。
7. GPU 编码器并行 7.1 NVENC NVENC 是 NVIDIA GPU 上的专用硬件编码器,不是简单把 x264 算法搬到 CUDA core 上跑。
项 说明 硬件位置 GPU 上的专用编码单元。 和 CUDA core 的关系 通常不直接占用 CUDA core 做传统编码计算。 并行来源 编码器硬件内部并行 + 多路 session 并发。 用户主要调什么 codec、GPU 编号、preset、码率、B 帧、lookahead 等高层参数。
ffmpeg 参数 示例 含义 -c:vh264_nvenc使用 H.264 NVENC 硬件编码器。 -gpu0指定使用第 0 张 GPU。 -presetp4选择 NVENC 内部速度 / 质量档位。
7.2 多 GPU 并行 多 GPU 的核心是“任务级并行”:每张卡独立处理一部分转码任务。
GPU 示例命令片段 输出流 并行关系 RTX A4000 #0 ffmpeg -gpu 0 ...stream0独立占用第 0 张卡。 RTX A4000 #1 ffmpeg -gpu 1 ...stream1独立占用第 1 张卡。 RTX A4000 #2 ffmpeg -gpu 2 ...stream2独立占用第 2 张卡。 RTX A4000 #3 ffmpeg -gpu 3 ...stream3独立占用第 3 张卡。
结论 说明 总并发约等于单卡并发 × GPU 数量 前提是 PCIe、磁盘、网络、解码侧和 mux 侧不先成为瓶颈。 多卡不是单路视频变快 4 倍 通常是 4 路任务同时跑,而不是一条视频自动拆到 4 张卡上。
8. 服务端集群转码 8.1 单机多任务 单机上通常同时跑软编和硬编:CPU 负责 x264 / x265,GPU 负责 NVENC / QSV / AMF 等硬编。
资源 示例配置 并行方式 典型并发 CPU 16 核 CPU 多个 x264 medium 任务,每任务 1 个或少量线程。 约 16 路软编任务。 GPU 1 张 NVIDIA T4 多个 NVENC session。 约 8 路硬编任务,取决于驱动、卡型和参数。 单机总吞吐 16 核 CPU + 1 张 T4 软编 + 硬编混跑。 示例约 24 路并发。
8.2 集群 集群转码的重点不是某一个编码参数,而是任务调度策略。
调度维度 策略 示例 任务来源 Kafka / MQ 排队,转码 worker 消费任务。 100 台机器从队列中抢任务。 硬编优先级 有 GPU 且任务时效要求高时优先硬编。 直播 ASAP、短视频快速出片。 软编兜底 GPU 忙或画质要求高时使用 CPU 软编。 归档转码、慢速高质量转码。 资源隔离 按 CPU 核数、GPU session、内存、磁盘 IO 限流。 防止单机超卖导致所有任务变慢。 任务紧急度 按 SLA 分队列或打优先级。 直播优先,离线归档慢慢跑。
9. 实测并行加速比 测试条件:1080p 30fps、60s 视频、x264 medium、CRF 23。
线程数 总耗时 速度倍率 CPU 利用率 现象 1 300s 1.0x 100% 单核满载,最慢。 2 165s 1.8x 95% 加速明显,但已有同步开销。 4 95s 3.2x 90% 接近常见高性价比区间。 8 60s 5.0x 80% 继续变快,但效率下降。 16 50s 6.0x 50% 瓶颈开始转向串行阶段和依赖。 32 50s 6.0x 30% 不再加速,线程过多只增加调度开销。
结论 :编码器最佳并行度通常接近 CPU 物理核心数;超过后收益递减,甚至可能变慢。
10. 调试:看哪一步慢 10.1 x264 bench 先用 benchmark 看整体编码吞吐和阶段耗时。
./x264--bench input.y4m示例输出可以按阶段理解:
encode: 25 fps analyse: 35 fps me: 28 fps encode_thread: 55 fps输出项 关注点 调优方向 encode总编码速度。 判断是否满足实时或转码 SLA。 analyse分析阶段速度。 调整 preset、subme、lookahead 等。 me运动估计速度。 关注 SIMD、搜索范围、参考帧数量。 encode_thread编码线程吞吐。 判断线程数和并行效率。
10.2 perf top 再用 profiler 看 CPU 时间花在哪些函数上。
sudo perftop -p $( pidof ffmpeg) 典型热点可能长这样:
x264_pixel_satd_8x8_avx2 35% x264_me_search_ref 20%热点类型 说明 可能动作 像素 / SATD / SAD 函数 运动估计和代价计算很热。 确认 SIMD 是否开启,检查 CPU 指令集选择。 运动搜索函数 搜索范围、参考帧、preset 影响明显。 降低 preset、减少 refs、缩小搜索范围。 熵编码 / CABAC 串行性较强。 线程加速有限,考虑参数或硬编。 内存拷贝 / cache miss 数据布局或线程竞争可能有问题。 优化对齐、减少 false sharing、改善缓存局部性。
11. 自研编码器要考虑 自研编码器不是只开几个线程就完事,至少要把下面这些基础设施想清楚。
设计项 要考虑什么 为什么重要 多线程框架 pthreads、TBB、线程池、任务队列。决定任务如何切分、调度、同步和回收。 SIMD intrinsics 或 asm。 DCT、SAD、滤波、像素操作都是热点。 双层并行 帧级并行 + slice / tile / CTU 行并行。 单一粒度很难同时兼顾吞吐和低延迟。 内存对齐 cache line 对齐、避免 false sharing。 多线程下错误的数据布局会拖垮性能。 缓存友好 按块访问、减少随机访问、提升局部性。 编码器大量访问参考帧和像素块。 NUMA 亲和 多 CPU 服务器绑定线程和内存节点。 跨 NUMA 访问会让多线程扩展性变差。
业界少有人从零自研全套编码器,更多是基于x264 / x265 / SVT-AV1 做工程化集成和参数优化。
12. 总结 并行方式 切分粒度 典型适用场景 压缩损失 典型参数 / 代表技术 帧级并行 多帧 通用转码、点播、普通实时编码。 约 0%,主要是调度方式变化。 --threads auto。切片并行 一帧多个 slice 直播 / RTC / 低延迟。 可能约 +5%,取决于内容和 slice 数。 --slices 4 --threads 4。WPP CTU 行波前 H.265 高分辨率编码。 通常较小,常低于 slice。 --wpp、--frame-threads。Tile 一帧多个矩形块 4K / 8K、AV1、并行解码。 取决于 tile 数和内容,可能约几个百分点。 --tiles 4x2。SIMD 单线程内向量并行 所有编码器热点函数。 0%,纯性能优化。 SSE / AVX / NEON。 GPU 硬编 硬件编码单元 / 多 session 大规模转码、直播云服务。 取决于硬编器和参数。 h264_nvenc、hevc_nvenc。集群转码 多机器任务级并行 海量离线 / 在线转码。 由具体编码器决定。 Kafka / MQ + worker 调度。
推荐调参顺序:
优先级 动作 典型做法 原因 1 确认 SIMD 已开启。 检查 CPU capability 和编译选项。 SIMD 是最基础的免费性能。 2 先用帧级并行。 --threads auto或接近物理核心数。通用、压缩损失小。 3 直播低延迟再加 slice。 --slices 4 --tune zerolatency。用压缩率换延迟和隔离。 4 4K / 8K 再考虑 WPP / tile。 H.265 用 WPP,AV1 / 超高清用 tile。 单帧太大时必须挖掘帧内并行。 5 大规模业务再上 GPU / 集群。 NVENC 多 session,多机队列调度。 解决整体吞吐,不只解决单路速度。
金句 :一段 4K 60fps 视频,单核可能要 1 小时,多核 + SIMD + 合理并行可能 5 分钟搞定。编码器并行不是“锦上添花”,而是“能不能跑实时”的生死线。