尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SVT-VP9:用并行架构让VP9转码在至强上从按分钟排队变为按核并行

SVT-VP9:用并行架构让VP9转码在至强上从按分钟排队变为按核并行 简介面向视频编码及转码开发者的 SVT-VP9 编码器源码包基于 C 语言实现是 VP9 兼容编码器库的核心。该版本针对英特尔至强可扩展处理器深度优化支持 VOD 与实时编码场景可在多路至强处理器间分布式处理提升转码效率。资源共 359 个文件含 145 个 C 源码、169 个头文件、11 个汇编优化文件如 x86inc.asm、intrapred_sse2.asm以及文档、补丁、构建脚本和配置文件压缩包约 1.12MB结构清晰。包内提供 10 个密度质量预设和三种调优模式视觉优化、PSNR/SSIM 基准、VMAF 基准便于针对画质指标实验。已有 1723 人学习下载。对研究 VP9 编码、SIMD 汇编优化、至强多核调度或视频转码二次开发的读者可获取完整源码、构建文件与优化思路适合具备 C/汇编基础的开发者参考。1. SVT-VP9 到底解决了什么不是又一个 VP9 编码器而是把转码从「按分钟排队」变成「按核数并行」视频平台把存量 H.264 库转成 VP9最头疼的不是画质是速度。用传统的 libvpx 在 32 核至强上跑 1080p单路也就 7-8fps一条 90 分钟的片子要大半个晚上。换到 SVT-VP9 这个开源的软件编码器后同样一台机器能跑到 100fps 以上一条片子几分钟出片。SVT-VP9 全称 Scalable Video Technology for VP9是开放媒体联盟AOM维护的开源项目针对英特尔至强处理器做了深度的指令集与线程调度优化并支持把编码任务拆到多路处理器上并行。它要解决的不是“再写一个 VP9 编码器”而是让 VP9 批量转码真正吃满至强上的每一个核。适合正在搭 VOD 转码管线、或者手里有大量闲置至强资源的团队。2. 为什么 SVT-VP9 在至强上能跑满核从架构理解它的性能账2.1 可扩展视频技术多核并行、多路并行的两级拆分逻辑SVT 这个缩写里的 Scalable 不是营销词。VP9 编码在单条视频里天然有可并行的结构128x128 的 superblock 可以划分成多个 tile每帧也能按行做波前并行。libvpx 把这些并行点暴露给了多线程但它的做法是偏保守的粗粒度并行在 8 核机器上效果尚可到了 16 核以上扩展曲线很快变平。SVT-VP9 的做法是把编码器内部重新拆成流水线式的任务队列从帧级初始化、拉取参考帧、运动估计、模式决策、变换量化到熵编码每个阶段都是独立任务线程池里的工作线程动态去取任务而不是简单的一帧一个线程。这套架构最大的好处是编码不再是“一个大活人跑完所有流程”而是“一条流水线上几十个工位同时干不同环节的活”。如果某个环节比如运动估计特别重队列调度器会为它多分配线程别的环节空着就等待。所以 SVT-VP9 在预设 8 甚至更高预设下依然能把大多数核喂满。拆开看是三级的并行结构单路内的并行一帧里按行分组每行一组任务后一行要等前一行算出参考数据这里用波前并行每帧内部有多个线程在推进不同行段。多路间的并行不同帧之间可以同时开多个编码线程只要参考关系允许。这一点和 x265 的 frame threading 是同一个思路但 SVT-VP9 把 GOP 划分和任务优先级绑在一起配合 lookahead让并行度和编码质量损失更可控。跨节点并行单机核数不够时通过 dpi 参数把不同 GOP 派给不同机器编码最后再拼接。这部分留到最后一章说。从实操角度理解这个架构能帮你判断一件事为什么“把 preset 调到 0”会让 CPU 利用率反而难看。preset 越低编码决策越复杂每个任务耗时更长线程间的依赖和等待就越多流水线越难填满preset 高时任务切得碎线程调度更灵活。所以如果机器核很多但 preset 设得很低性能不一定好看。这是很多人第一次接触 SVT-VP9 时的认知误区。2.2 至强处理器的 AVX-512 和超大 L3 缓存为什么默认参数就偏向服务器SVT-VP9 不是随便一个开源的 VP9 编码器它的汇编优化层把大量热点函数用 x86 SIMD 指令改写特别是针对至强的 AVX2 和 AVX-512 做了专门的代码路径。运动估计里最耗计算的是 SAD 和 SSE也就是把两帧的像素块做绝对差求和。这类计算非常适合用 SIMD 一次处理 32 个字节。AVX-512 相比 AVX2 吞吐量翻倍在 8 位像素数据上提升非常直接。如果你对比同一段源码在普通桌面 CPU 和至强上的行为你会发现至强跑 SVT-VP9 的加速比比跑 libvpx 要高不少——因为 libvpx 的汇编层并没有对 AVX-512 做这么深的适配。内存端的作用同样不可忽略。编码器的 lookahead 窗口和参考帧列表要缓存好几帧原始数据4K 分辨率下一帧 YUV 就是 12MB 左右几十帧窗口就是几百 MB。至强的大 L3 缓存能装下更多常用参考数据线程切换时的 cache miss 少很多。双路至强更夸张每颗 CPU 有独立的内存控制器带宽接近翻倍。SVT-VP9 的多实例编码在这个场景下比单实例吃多核要舒服得多因为每个实例固定访问自己那部分内存减少跨 CPU 的缓存一致性开销。这里要提一个常见做法如果机器是双路至强跑 SVT-VP9 时最好用 numactl 把进程钉在同一个 NUMA 节点上跨节点访问内存带宽虽然够用但延迟高。真实业务里我一般固定每个编码容器只绑一个 CPU socket多开几个容器比让一个进程跨两个 socket 要稳定得多。2.3 SVT-VP9 对比 libvpx 和 x265为什么说它是「吞吐优先」的编码器先澄清一个易混点x265 不是 VP9 编码器是 H.265/HEVC。但在做转码方案选型时x265 经常被拿来和 VP9 比较因为 HEVC 和 VP9 是同一代的高压缩率编码压缩率接近播放端生态则各自有支持阵营。如果你用 VP9绕不开的对比对象其实是 libvpx。libvpx 是 Google 官方 VP9 编码器这么多年一直在维护质量也稳定。但它的并行架构是集码型的多线程主要作用在 tile 和 row 的并行到 16 核以上很难继续线性扩展。我实测过 32 核机器上 libvpx 只能用到十几个核1080p 的编码速度大概在 8-15fps这还是在 preset 拉到最快的前提下。SVT-VP9 在同样的机器上、同样画质档位速度可以到 100fps 以上两者的吞吐差了一个数量级。x265 这边情况有所不同。x265 也有 wavefront 并行和 frame threading高核数下的扩展性比 libvpx 好但 x265 整体优化更倾向通用 CPU对 AVX-512 的依赖不如 SVT-VP9 激进。在纯编码效率上x265 的同码率主观质量比 libvpx 和 SVT-VP9 略微好一点但优势不大大约在 2%-5% 的码率区间。而 SVT-VP9 的价值在于相同硬件下你可以一次性跑更多路转码。做对比时不要只看单路压缩率。转码业务有一个更重要的指标单位时间能转出多少分钟的视频。拿 10 分钟的 1080p 素材分别在 libvpx 和 SVT-VP9 上编到同样的码率看编码耗时和 PSNR。SVT-VP9 在 PSNR 低 0.3-0.5dB 的情况下编码速度快 5-15 倍这个交换对 VOD 批量转码来说是划算的。当然如果业务对 PSNR 有硬指标比如科研或医疗影像那还是老老实实用 libvpx 或者 SVT-VP9 的 preset 0-2 档。3. 从源码把 SVT-VP9 跑起来编译、安装与最小编码命令3.1 编译安装CMake 构建与 -j 参数的取舍SVT-VP9 是典型的 CMake 工程源码根目录下有一个 Build 目录官方建议在 Build 目录下做构建。把仓库 clone 下来后步骤很简单。git clone https://github.com/AOMediaCodec/SVT-VP9.git cd SVT-VP9/Build cmake .. -DCMAKE_BUILD_TYPERelease make -j 32 sudo make install sudo ldconfigCMAKE_BUILD_TYPE 不设的话默认也是 Release但显式写出来能避免后续调试时发现编译器优化等级不对。make -j 的数值不是越大越好我见过有人在 128 核机器上直接 make -j 128结果编译器同时起 128 个进程内存峰值冲到 200GB把机器干到 OOM。稳妥做法是用 nproc 先看核数再留几个核给系统比如 32 核机器就 -j 28。编译依赖方面需要 gcc、cmake、nasm/yasm汇编器和 pthread。如果没有 nasmcmake 会自动禁用汇编优化编出来的库性能缩水严重这是最容易忽略的一点。装好依赖后make install 会把动态库放到 /usr/local/lib所以最后一步 ldconfig 跑一下不然运行时提示找不到 libSvtVp9Enc.so。提示装完之后用 SvtVp9EncApp --help 验证。如果系统提示找不到命令检查 /usr/local/bin 是否在 PATH 里。3.2 最小编码命令一个 1080p 的 VP9 转码实例SvtVp9EncApp 的输入很挑剔只接受 YUV 裸流不接受 mp4、mkv 这些封装格式。所以要先把源文件转成 YUV。ffmpeg -i input.mp4 -c:v rawvideo -pix_fmt yuv420p -f rawvideo input_1920_1080.yuv转出来的 YUV 文件巨大一部 90 分钟的 1080p 电影大约 300GB。所以实际操作里很少把整片转成 YUV而是按片段转、编完就删。如果不想占磁盘可以用命名管道FIFO把 ffmpeg 输出直接喂给编码器但要注意管道另一端的消费速度跟不上时ffmpeg 会阻塞等待这在批处理脚本里要处理好。编码命令SvtVp9EncApp -i input_1920_1080.yuv -w 1920 -h 1080 -b output.ivf -preset 8 -lp 32这里 -preset 8 是 VOD 场景常见的折中点速度快画质损失不大。-lp 32 表示用 32 个逻辑处理器并行如果机器只有 16 核线程开多了反而有调度开销。输出是 ivf 裸流要封装成 webm 再给播放器用ffmpeg -i output.ivf -c:v copy -c:a libopus -f webm output.webm这条把编码好的 VP9 流原样拷贝进 webm 容器音频用 opus在网页播放和字幕支持上都顺。注意 -w 和 -h 必须和 YUV 实际分辨率一致不一致时编码器读出来的画面是撕开的或者直接报错。另一个细节是 -pix_fmt yuv420pSVT-VP9 默认吃 420 的 8 位 YUV如果你想上 10 位要确认编译时开了高精度选项并且输入要转成 yuv420p10le。3.3 把 SVT-VP9 接进 FFmpeg为什么大多数生产环境走的是 ffmpeg 而不是原生 CLI原生 CLI 只做纯视频编码实际转码管线绕不开音频、字幕、封装、裁剪这些活。所以生产环境里最常见的做法是绕过 SvtVp9EncApp直接用 FFmpeg 调 libsvt_vp9。前提是 FFmpeg 编译时带了 --enable-libsvt-vp9。ffmpeg -version | grep libsvt_vp9没看到这个输出就说明没编进去。网上不少所谓的“FFmpeg 集成教程”实际用的是 libvpx 的 vp9 编码器参数完全不一样坑就在这。编了 SVT-VP9 支持之后命令非常像用 libvpxffmpeg -i input.mp4 -c:v libsvt_vp9 -preset 8 -b:v 2M -c:a libopus -f webm output.webm-preset 和 -tune 这些参数会透传给 SVT-VP9 编码器但命名上和原生 CLI 略有差异比如原生 CLI 里的 -lp 在 FFmpeg 里没有直接对应的选项它默认按 CPU 核心数分配线程也可以设置 -threads 参数去覆盖。注意如果 ffmpeg 运行时提示 Unknown encoder libsvt_vp9要么重新编译 ffmpeg 打开这个库要么直接用 SvtVp9EncApp。FFmpeg 带来的额外好处是不用再手工转 YUV读 mp4、mkv、TS 直接输入还能做切段、加音轨、控制输出封装省掉大量中间文件。但要注意FFmpeg 的 libsvt_vp9 封装对参数暴露不全像 dpi 分布式编码这种FFmpeg 里未必有对应选项真要多节点分发还是回到 SvtVp9EncApp 更可控。4. 把吞吐量拉满前先学会读它的参数表4.1 preset 的边界0 是质量上限11 是吞吐上限8 是折中点SVT-VP9 的 preset 表示“速度-质量”的权衡数字越大编码越快、压缩率越差。不同版本范围略有差异文档上写 0 到 11部分版本到 12。preset 0 单帧要参考的候选模式最多运动搜索的范围最大每个块都要做几十次模式决策速度慢到可以按帧算preset 8 开始模式决策砍掉大半运动搜索步长拉大preset 11 基本只做少量候选模式边界细节和快速运动的损失会比较明显。怎么选做最终出片的 VOD我一般选 preset 5-8。preset 8 在多数内容上比 preset 0 只高几个百分点的码率但速度快十倍以上。preset 5 对通缉片源质量高的片段有用比如动画或屏幕录制。直播或实时转码preset 10-11 更合适延迟低CPU 占用低接受画质损失。preset 3 以下适合做“离线精修”比如一个片子要压很多遍、每一遍都追求极致压缩率。这类场景很少因为 VP9 的增量空间用完以后preset 0 和 5 的码率差通常在 5% 以内不值得为它多烧几十倍 CPU。还有一个经常被忽略的点preset 会影响码率控制器的行为。preset 越高lookahead 能计算的信息越少VBR 模式的实际码率偏离目标码率的幅度会变大。比如同样设 -tbr 2Mpreset 8 输出码率可能在 1.95M 到 2.1M 之间preset 11 就可能跑到 2.4M。所以如果你的业务对输出码率有硬上限不能只调码率参数还要考虑 preset 带来的波动。反向经验不要一上来就预设“质量优先”先把源拉到 preset 8 跑一遍看结果能不能满足业务指标。能过就上不能过再降到 6 或 5。转码项目的成本大头是机器时间preset 每降一档机器成本翻倍甚至更多。4.2 tune 决定优化目标VQ、PSNR 与 SSIM 分别适合什么业务tune 参数控制编码器在率失真决策里优先优化的指标。tune 0VQ视觉质量模式默认。它不盲目追某个数学指标而是按人眼感知模型分配码率比如对平坦区域的噪声更敏感对纹理复杂区域的细节更宽容。适合最终给人看的内容。tune 1PSNR 优化。编码器会把更多算力放在提高 PSNR 数值上。适合做客观指标对比、或实验室里做算法评测因为这些场景只看 PSNR不看观感。tune 2SSIM 优化。SSIM 衡量结构相似度相比 PSNR 更接近人眼的感受。有些 CDN 服务商要求转码后 SSIM 不低于某个阈值这时必须选 tune 2。实际使用中tune 1 跑出来的画面往往噪声少但细节糊tune 2 在结构边缘上更锐利。生产里 VOD 出片用 tune 0 就够了除非合同里写了客观指标。给运营商交付的视频转码验收条款常常写“PSNR 不低于多少 dB”这种就用 tune 1指标好看没争议。4.3 控制编码质量的三个码率参数target-bitrate、max-bitrate 与 CQPSVT-VP9 有三种码率控制模式对应参数是 rcrc 0CQP恒定量化参数。指定 -qp比如 -qp 32画质基本恒定码率随内容波动。类似 x264 的 crf适合“我不关心码率只关心每帧质量一致”的场景。做存档母版时常用。rc 1VBR指定 -tbrtarget bitrate。编码器尽量贴近目标码率但复杂场景允许向上波动。适合 VOD、文件点播是默认选择。rc 2CBR指定 -tbr 和 -mbrmax bitrate。严格限制码率上限适合网络带宽固定的场景比如直播、广电级传输。CBR 会让复杂场景画质波动大简单场景浪费码率所以文件业务别用。命令里对应的参数如下SvtVp9EncApp -i input.yuv -w 1920 -h 1080 -b output.ivf -rc 1 -tbr 2000k -preset 8-tbr 的单位可以是 kkbps也可以是数字2M 写成 2000k 或者 2000000 都行。如果不设 -tbr编码器默认是 CQP 模式全部按量化参数跑。FFmpeg 里的映射是 -b:v 对 VBR 的 -tbr-rc 和 -qp 直接透传。换码率控制模式时很多人忘了把原来为 CBR 调的 lookahead 降回来。CBR 对 lookahead 的需求高CQP 其实不需要那么大的窗口白白吃内存。我用 CQP 时会把 lookahead 压到 30-60用 CBR 或 VBR 才开到 120。这几个参数之间是联动的单独调一个往往看不出效果要放在一起权衡。这也是为什么每次调整参数组我都会在中段和高复杂度的片子上各验证一遍避免只在一个片源上调出来的参数换片就废。5. SVT-VP9 排查与避坑5 个常见翻车点的现象、原因、解法SVT-VP9 整体上是个稳定的编码器但它把一半的复杂度藏在了参数组合里。新手最容易踩的坑恰恰是那些看起来无害的默认值。下面这几条是我在自建转码服务时反复见过的按出现频率排序。每条都按现象、原因、解决三步写可以直接对着排查。5.1 快速运动场景出现块状马赛克现象转码后的视频在镜头快速移动、爆炸、烟火这类高信息量场景里出现明显块状马赛克静止画面却正常。原因preset 设得太高导致运动搜索和模式决策被大幅裁剪参考帧选得不准也可能输入 YUV 是隔行扫描编码器内部没做去交错直接当逐行处理画面里就混入了交错伪影看起来像“碎块”。解决先把 preset 降到 8 以下试编码同一段素材马赛克明显缓解。如果还在检查输入源。用 ffprobe -show_streams 看 field_order 字段如果是 tt 或 bb说明源是隔行转 YUV 前加 yadif 滤镜做 deinterlace。SVT-VP9 本身不支持隔行输入必须确保 YUV 是 progressive。5.2 32 核机器 CPU 利用率只剩 30%现象top 看到 SvtVp9EncApp 进程占用不到一半核机器明显“没吃饱”。原因lp 参数默认按当前机器核心数分配但很多发行版在容器里 nproc 不准确也可能是多路至强下线程被调度到了两个 NUMA 节点跨节点缓存命中率低线程互相等内存。解决先 nproc 确认逻辑核数显式用 -lp 设满。多路机器用 numactl 把进程绑在一个 socket。还遇到过一种情况是 BIOS 关掉了超线程逻辑核只剩物理核这时 -lp 按默认值设成了物理核数量没跑满超线程。用 mpstat -P ALL 1 能看到每个核的占用分布如果集中在某几个核就是 NUMA 绑定问题。5.3 4K 编码时内存飙高进程被 OOM kill现象编码器在 8K 或 4K 素材上跑到一半系统日志出现 Out of memory进程被内核杀掉。原因lookahead 默认值偏大窗口内有几十帧原始 YUV 和重建帧4K 下每帧就是 12MB 级别组合起来轻松吃掉几十 GB。多实例叠加后内存直接爆掉。解决把 lookahead 从默认值降到 60 或更低代价是码率控制精度下降但内存占用能降到原来的三分之一。用 systemd 或 cgroup 给编码进程设内存上限超限就排队而不是让内核随机杀进程。如果你开了多个编码实例先算一下单实例峰值内存分辨率字节数乘以 lookahead 加参考帧数再乘以实例数超过物理内存就别硬上。5.4 FFmpeg 输出的 webm 播放器打不开现象ffmpeg 压制完成VLC 打开黑屏浏览器也播不了ffprobe 报没有视频流。原因最常见的是 ffmpeg 编译没带 libsvt_vp9退回去用了 libvpx 或压根没选到 VP9 编码器。另外VP9 放进 mp4 的兼容性不如 webm很多播放器对 mp4 内的 VP9 不认而 webm 是 VP9 的原生主场。解决先 ffmpeg -version 确认有 libsvt_vp9再用 -c:v libsvt_vp9 指定。输出文件格式改成 -f webm播放端用 Chrome、Firefox 这类原生支持 VP9 的浏览器。如果还不行检查编码过程中是不是一堆 failed to decode 日志那是硬盘空间满了半途而废。用 ffprobe -show_entries streamcodec_name 看输出流的编码名确认不是 vp8 或 h264。5.5 设置了目标码率 2M出来却是 4M现象-rc 1 -tbr 2000k 转码完ffprobe 一看平均码率 3800kbps差得离谱。原因VBR 模式允许码率波动复杂场景很激进如果 lookahead 不够码率控制器看不到后面的复杂内容容易过早把码率拉高。解决改用 rc 2 CBR 并设 -mbr 上限或者把 lookahead 调到 120 让码率控制器有更长视野。检查音频是不是也占了码率ffprobe 看包大小时要单独看视频流。做验收时用 ffprobe -select_streams v -show_entries streambit_rate 验证视频码率别把音视频混一起算。6. 生产环境里的两个进阶验证从单机到多节点的横向扩展6.1 用 dpi 参数把编码分发到多台至强标题里说的“在多个至强处理器之间分布视频编码处理”就是通过 dpi 参数实现的。dpi 表示当前实例的分布式点索引dp 表示参与编码的总节点数。思路是按 GOP 边界把视频切成多个片段每台机器编其中一段最后再用 ffmpeg 的 concat 拼接。节点 0SvtVp9EncApp -i seg0.yuv -w 1920 -h 1080 -b seg0.ivf -preset 8 -dpi 0 -dp 4节点 1SvtVp9EncApp -i seg1.yuv -w 1920 -h 1080 -b seg1.ivf -preset 8 -dpi 1 -dp 4合并时确保所有段的 GOP 大小、分辨率、色彩空间一致否则链接处会有跳动ffmpeg -i seg0.ivf -i seg1.ivf -i seg2.ivf -i seg3.ivf -filter_complex concatn4:v1 -c:v copy merged.ivf切分点要落在关键帧上常见做法是用 ffmpeg 按 segment_time 切段并开启关键帧对齐避免拼接处画质塌陷。这个方案适合一台机器核数不够的团队但要注意各节点之间的进度同步。如果某一段特别复杂它会拖慢整条流水线所以切段时尽量按内容复杂度均匀分配而不是机械地按时长切。6.2 用一组基准数据验证值不值得上选一段 10 分钟 1080p 公开素材比如 Blender 的电影片段或标准测试序列固定目标码率 2M分别在 libvpx 和 SVT-VP9 上转码记录 fps、PSNR 和产出文件码率。常见做法是写一个脚本循环跑几组 preset把结果整理成一张表编码器、preset、fps、PSNR、实际码率。我手上这台双路至强上libvpx 在最快速档也只有 9fpsSVT-VP9 preset 8 到 152fpsPSNR 只差了 0.4dB。如果你现在的管线还是 libvpx值得做一次同样的对比再决定换不换。这个习惯救过我一次。有一次升级到新版本后同样的参数下 PSNR 掉了 0.2dB肉眼几乎看不出但客观指标就是不过。查了半天发现新版默认的 tune 变了显式设 -tune 1 后恢复正常。从那以后我把所有编码参数都写死在脚本里不依赖任何默认值。这类黑匣子级的变化只能靠基准数据兜底。希望帮到你。本文还有配套的精品资源点击获取
返回列表