AMD VAAPI(780M / radeonsi)极速、流畅档不遵守 maxrate:实测超目标 2–4 倍,且两档输出几乎相同 #33
Description
摘要:AMD Radeon 780M(radeonsi)上,UU_VIDEO_ENCODER=vaapi 的极速(1M)与流畅(2M)两档几乎不生效——实测码率分别是目标的 4.3 倍和 2.4 倍,而两档之间只差 0.06%。CPU(libx264)路径没有这个问题。目前参数是 -rc_mode VBR -qmin <cq>,看起来在这套驱动组合下是按质量走的,没有遵守 -maxrate。
环境
- GPU:AMD Radeon 780M Graphics(Phoenix1,
1002:15bf),amdgpu 驱动 - Mesa
26.2.2-arch1.1,vainfo:Mesa Gallium driver 26.2.2-arch1.1 for AMD Radeon 780M Graphics (radeonsi, phoenix, ACO, DRM 3.64, 7.2.5-3-omarchy) - libva 2.24.1 / VA-API 1.24;
VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice可用 - 内核 7.2.5-3-omarchy,Arch Linux
- 主机 v0.1.28,
UU_VIDEO_ENCODER=vaapi,无回退(日志encoder=h264_vaapi)
复现
用 v0.1.28 的固定输入探针消除桌面内容变量:
ffmpeg -f lavfi -i "testsrc2=size=2560x1600:rate=60:duration=1" \
-c:v libx264 -qp 0 -pix_fmt yuv420p clip.mp4
UU_PROBE_INPUT=clip.mp4 UU_PROBE_LOOP=1 UU_PROBE_FRAMES=180 UU_PROBE_QUALITY=N \
UU_VIDEO_ENCODER=vaapi uuremote-server desktop-video-probe out.h264输出逐字节可重复(同档重复跑 sha256 相同,CPU 与 VAAPI 都是),所以下表是精确值而非统计结果。
数据
2560x1600@60,180 帧(= 3.000 s),输入 10.7 MB 无损 testsrc2。
| 档 | cq | 目标 | VAAPI 实际 | VAAPI 字节 | CPU 实际 | CPU 字节 |
|---|---|---|---|---|---|---|
| 1 极速 | 30 | 1M | 4,346 kbit/s | 1,807,446 | 828 | 310,763 |
| 2 流畅 | 26 | 2M | 4,708 | 1,808,488 | 1,551 | 581,735 |
| 3 高清 | 21 | 8M | 5,626 | 2,358,783 | 6,125 | 2,297,045 |
| 4 蓝光 | 17 | 20M | 13,618 | 5,745,156 | 15,439 | 5,789,773 |
| 5 自动 | 18 | — | 14,573 | 6,076,902 | 31,629 | 11,860,877 |
目标确实传下去了:
Fixed input probe: source=2560x1600 output=2560x1600 fps=60 cq=30 maxrate=1000k encoder=h264_vaapi
Fixed input probe: source=2560x1600 output=2560x1600 fps=60 cq=26 maxrate=2000k encoder=h264_vaapi
要点
- 1 档与 2 档输出只差 1,042 字节(0.06%),关键帧亮度偏移逐位相同——两档在 VAAPI 下产生的是同一个编码结果,
-qmin从 30 变成 26 没有体现出来。 - 两档都远超目标(4.3× / 2.4×)。用户想靠降档省流量时,在 AMD VAAPI 上省不下来;CPU 路径同一输入是 828 / 1,551,贴着目标走。
- 高档位 VAAPI 反而比 CPU 小(4/5 档 14.6 vs 31.6 Mbit/s),方向和
gpu_encoder_requested()只读环境变量、不探测显卡,AMD 机器上每次建流都白跑一次 NVENC #10 里「VAAPI 输出字节少约 44%」一致。所以不是整体偏高或偏低,而是低档位的码率控制没有生效。
期望
低档位能接近 -maxrate(即 CPU 路径的行为)。固定输入探针随时可以复测,改了参数之后欢迎让我们对比。
English summary: On AMD Radeon 780M (Mesa 26.2.2 radeonsi), UU_VIDEO_ENCODER=vaapi ignores the 1M/2M viewer presets: measured 4.3x / 2.4x the target bitrate, while tiers 1 and 2 produce a 0.06%-different output with identical IDR offsets. libx264 on the same fixed input hits 828 / 1,551 kbit/s. Reproducible byte-for-byte with the v0.1.28 UU_PROBE_INPUT probe.
Activity
VallierDev commentedon Oct 17, 2026
谢谢整理成独立 issue(#31、#32 是重复提交,已关闭)。
1、2 档输出几乎逐字节相同,让我怀疑这不是码率控制没生效,而是两档都已经撞到 QP 上限 51:testsrc2 在 2560x1600@60 下细节和运动都极高,硬件编码器在最大 QP 时可能也压不到 1–2 Mbit/s,而 libx264 的压缩效率更高。可否帮忙跑一个对照(与生产相同的 profile/GOP,只把码率控制换成固定 QP 51):
qp51.h264也在 1.8 MB 左右:是硬件编码器在这种内容下的下限,降低码率只能靠降低帧率或分辨率(我们可以考虑低档位在 VAAPI 下自动降分辨率)。另外,用普通桌面内容(终端/网页)跑 1、2 档的结果也很有参考价值,那才是实际使用中的码率。
Thanks (closed #31/#32 as duplicates). Tiers 1/2 being nearly byte-identical suggests both hit the QP 51 ceiling rather than ignoring maxrate. Could you run the CQP 51 command above? ~1.8 MB means it's the hardware floor for this content (only fps/resolution can go lower); much smaller means VBR really ignores maxrate and we'll change the low-tier rate control. Numbers on ordinary desktop content would also help.
ferstar commentedon Oct 21, 2026
复测与排查记录(不是修复,记录已排除的方向)。
环境:Ryzen 7 8845H,核显 Radeon 780M(PCI ID
1002:1900,HawkPoint1,与报告中的1002:15bfPhoenix1 不同);本机 X11 会话,/dev/dri/renderD128可用。版本为当前pr80分支。复现(固定输入探针,与报告一致):2560x1600,180 帧,进程路径
h264_vaapi,tier 1 为 1807446 字节、tier 2 为 1808488 字节,与报告完全相同。进程路径,去掉/改动参数(6 秒非循环素材,目标 750k,字节数):
-qmin):约 4.1–5.5 Mbps-qmin:字节数不变-qmax 51:不变-rc_mode CBR:与 VBR 完全相同(2945761)-rc_mode CQP -global_quality 35:约 14 Mbps,更严重结论:进程路径上
-qmin/-qmax/CBR 都不改变低档位码率,FFmpeg 的 CBR 在这个驱动上似乎没有生效。in-process 路径(
--features inproc-av,桌面 1920x1200,60 fps,300 帧,单次测量)rc_mode=CBR生效)max_qp=51结论:
max_qp和 HRD buffer 都无法让低档位收敛。HRD 缩小会让高档位明显偏低。目前看来:问题不在
-qmin/-qmax/rc_mode/HRD 这些参数上。下一步需要驱动侧信息,例如 libva trace 中每帧实际下发的 RC 参数与驱动返回的 QP,或 Mesa radeonsi 对VAEncMiscParameterRateControl的处理。这部分还没做。测试未改动任何代码,相关实验均已撤销。
VallierDev commentedon Oct 21, 2026
感谢 @ferstar 这么细的排查。进程管线上
-qmin、-qmax和 CBR 都不改变低档码率,这个结论很有用。#80 已合并(21c01d2)。PR 里说 sequence 参数提交顺序修正后,in-process H.264 1M 档降到了 0.97 Mbps,这和你这里表格中 VBR 2.4 Mbps 对不上。想确认一下这组数据用的是哪个提交:a4a58c4 之前还是之后?如果之后也超标,麻烦附上测试素材和命令,我们按素材对比。另外,FFmpeg 的 h264_vaapi 是不是也有同样的参数顺序问题,也值得查一下:可以用
LIBVA_TRACE看它每帧实际下发的 RC 参数。video: auto uses NVENC then CPU, or CPU only; drop auto VAAPI paths
ferstar commentedon Oct 23, 2026
三件事都在另一块 AMD 集显(Cezanne / radeonsi renoir,Mesa 26.2.5-arch1.1,libva 2.24.0,ffmpeg n9.0.2,代码 = origin/main 21c01d2(#80 合并)加两个纯文档提交 19397dd,即含 a4a58c4)上补完了。
1. 之前那组 2.4 Mbps 是 a4a58c4 之前测的
时间线可以确认:a4a58c4 是 2026-10-21 21:23 UTC 推进 PR 分支的,我那条评论 21:45 UTC 发表,中间只隔 22 分钟,那套矩阵只可能基于我自己当晚的 push(最后一次是 50fd458)。所以 VBR 2.4 / CBR 2.6 那组数字是顺序修复之前的行为。
2. 合并后代码在第二块 AMD 集显上复测
固定输入(进程管线),与 #33 报告同素材同命令——Cezanne 几乎逐项复现 780M 的数字:
tier 1/2 只差 0.096%,和 780M 的 0.06% 同一现象,与具体 GPU 无关。
in-process(当前 main):Xvfb 1920x1200 + ffplay 1280x720 testsrc2 窗口(复现 PR 的动态场景),每档 1200 帧:
in-process tier 1 命中目标,PR 的 0.97 在第二块集显上成立;修复前 tier1≈tier2≈2.4 的形态消失。进程管线在这个中等复杂度场景也只有 1.3×,与 PR 表里 HawkPoint1 的 1.48 一致——进程管线的病态 4.3× 超标只出现在 2560x1600 testsrc2 这种极限内容上(两块卡都是)。
3. FFmpeg h264_vaapi 没有参数顺序问题;超标是 radeonsi VBR 的问题
LIBVA_TRACE(tier 1、60 帧、GOP 30)显示 FFmpeg 在每个 IDR(2 次)按 sequence → RateControl → HRD → FrameRate → Picture → Slice 提交,非 IDR 帧不带 misc——与 a4a58c4 修复后 in-process 引擎的顺序一致,顺序没有问题。RC 内容也确实传到了驱动:tier 1
bits_per_second=1000000, target_percentage=75, window_size=125, min_qp=30, max_qp=0, initial_qp=0, mb_rate_control=2;tier 2 为bits_per_second=2000000, min_qp=26,其余相同。两档 trace 不同、输出却几乎相同 → 参数已正确下发,是 radeonsi 无视了目标码率。同素材 CQP 阶梯(你上一条给的命令,此前没实际跑过)推翻了 QP 51 硬件下限假说:
VCN 在 QP 51 明明能压到 1.58 Mbps,VBR 却停在 4.28(≈ CQP 41–42 的水平):复杂内容下 radeonsi VBR 的有效 QP 上限远低于 51,
-qmax 51/CBR 都救不了(前一条已验证)。这一半值得报给 Mesa/radeonsi。复现
XShm 上传路径(Xvfb 无 DRI3);DRI3 零拷贝在 #80 验收时已单独验证过。低档位进程管线的缓解(复杂内容自动降分辨率,或引导 AMD 用户用 inproc-av)数据都在上面,你们定方向。
ferstar commentedon Oct 23, 2026
补充一个数据点,把上面的归因闭环:极限内容下 in-process 同样躲不过 VBR 天花板。
把 in-process 引擎直接喂同款内容(Xvfb 2560x1600 + 全屏 ffplay testsrc2@60,live 抓屏走 XShm 上传,日志确认
pipeline=in-process,tier 1):也就是说 radeonsi VBR 的有效 QP 上限(≈41–42)对任何 VAAPI 客户端一视同仁,与引擎、参数顺序都无关——码率控制的责任完全在驱动侧。inproc-av + a4a58c4 解决的是「正常内容下目标码率被整体忽略」;极限内容下的低档超标两条路径都会有,缓解只能靠低档自动降分辨率(QP 44 都能到 2.25M,降分辨率后 1M 可达)或 CPU 编码。
复现(in-process 极限场景):
(此分辨率下 Xvfb+XShm 采集约 17 fps,600 帧约 35 s;1200 帧会撞探针 55 s 超时窗口,属采集节奏,不是引擎问题。)
ferstar commentedon Oct 23, 2026
勘误 + 结论反转:VBR 没有无视目标;tier 1/2 是钉在 QP 51 的硬件下限上。前两条评论里的 CQP 对照全部作废。
错误原因:我的 CQP 对照命令没加
-stream_loop -1,60 帧素材只编出 60 帧(ffprobe 核实每个对照输出都是 60 帧),我却按 180 帧 3 秒折算码率,数值全部恰好低了 3 倍。第一楼给的对照命令在 60 帧素材上有同样的坑(-frames:v 180实际只输出 60 帧,593 KB 与探针的 1.8 MB 完全不可比)。对照必须加循环:修正后的数据(180 帧,Cezanne):
VBR tier 1 输出与 CQP 51 只差 0.12%:tier 1/2 都顶在 QP 51 的硬件下限,testsrc2@2560x1600@60 在 VCN 上就是压不进 ~4.75M。第一楼的「QP 51 下限」判断是对的,我此前的「推翻」收回。radeonsi 的 VBR 在这里没有问题——tier 3(6.0M < 8M 目标)在正常贴目标走,LIBVA_TRACE 里那些参数(1M/2M 目标、顺序)也都如实生效,只是目标低于硬件下限时输出就停在下限。x264 同内容能到 828k 是软件编码器的效率优势。之前评论里「报 Mesa」的建议也相应撤回。
不受帧数错误影响、仍然成立的部分(帧数均为探针自报):
max_qp = 44会挡住低档到达硬件下限——只把 max_qp 改成 51 实测 4.16 → 2.60 Mbps。这个值来源于旧代码的硬编码,建议改成 51,我可以提个一行的 PR;抱歉前两条的对照数据误导,一条勘误留言比我私下更正有用。
VallierDev commentedon Oct 23, 2026
谢谢补测和勘误,结论很清楚:
max_qp = 44(c_engine/vaapi_engine.c,随 feat(vaapi): in-process zero-copy VAAPI H.264/HEVC (DRI3 + VPP + VCN) #80 引入)会让码率在到达这个下限之前就被挡住。同意改成 51,欢迎提这个一行的 PR。PR 描述里请附上你实测的 4.16 → 2.60 Mbps(live 2560x1600,tier 1),以及正常内容下 tier 1/2/3 改动前后的对照,确认高档不受影响。
min_qp、initial_qp保持不变。低档在复杂内容下自动降分辨率是另一个方向,我们会单独评估,不放进这个 PR。
🤖 Generated with Claude Code
VallierDev commentedon Oct 23, 2026
@ferstar 的
max_qp44 → 51(#102)已随 v0.2.30 发布。复杂画面下,in-process VAAPI 低档现在能压到 VCN QP 51 下限对应的码率;中高档不受影响。低档在复杂画面下自动降分辨率仍单独评估。
🤖 Generated with Claude Code