Repository navigation
fix(capture-linux): cap the VAAPI QP so the first keyframe stays legible - #1269
Conversation
On AMD (VCN via Mesa's VA-API driver) the rate control budgets the first IDR of a session at about eight times the average frame, whatever the VBV size, initial fullness or peak rate. A picture that needs more gets its macroblock QP ramped up to 51 down the frame: a 866x628 terminal window take at the default 3.3 Mbit/s opened in the editor with its lower half unreadable (54 KB I-frame, QP 13 at the top, 51 below). Set qmax=30 on the VAAPI backend. ffmpeg passes it as VAEncMiscParameterRateControl::max_qp, which the firmware honours: the same frame comes out QP 13-30, 70 KB, and the first second costs the same within 2%. Vulkan and libopenh264 keep their defaults.
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
Summary
The first frame of a Linux capture encoded with VAAPI can come out with its lower half blurred and blocky. The editor opens a take on frame 0, so that is the picture the user sees first. The cause is the encoder's rate control on the first keyframe, not a partly filled PipeWire buffer. This PR caps the VAAPI QP at 30 (
qmax). It is a one-line change inopen_backend, small enough to cherry-pick ontorelease/v2.1.0.What was observed
Found during the manual e2e pass of the installed v2.1.0-rc.1
.debon Ubuntu 24.04, GNOME Shell 46 (Wayland), AMD Radeon 610M (VAAPI encode over the dmabuf path), Mesa 25.2.8.recording-1792077324409.mp4, 866×628,encoder {"video":"vaapi","rejected":[]}:ffmpeg -debug qpon frame 0 gives the per-macroblock QP:Root cause
AMD's VCN rate control, reached through Mesa's VA-API driver, gives the first IDR of a session a budget of about 8 times the average frame:
bitrate / fps.When the picture needs more than that budget, the encoder raises the QP of each macroblock row from the top down until the frame fits.
This was reproduced off-line. The input was a sharp still taken from the same file, encoded with
h264_vaapiusing the helper's exact parameters: 60 fps,-b:v 3263088,-g 30,-bf 0.bitrate/fps)qmax=30Only the bitrate moved the budget; VBV size, initial occupancy and maxrate did not.
ffmpeg's
h264_vaapidefaultsqmaxto -1.vaapi_encode_init_rate_controlthen sendsmax_qp = 0to the driver, which means a ceiling of 51 (qmax > 0 ? qmax : 0, checked in the 8.0.1 source).Fix
Backend::max_qp()returnsSome(30)for VAAPI.open_backendsets it ascodec_ctx->qmaxbeforeavcodec_open2.open_backend: the zero-copy dmabufopen_importingand the ladder's CPU-upload path. Both get the cap.Measured cost:
Same still, 60 frames:
1080p segment of the real screen take:
Where the cap binds, it trades bitrate for quality. That is the right trade for a file the editor decodes and re-encodes.
In the two real takes, about 3 % of macroblocks were above QP 30, in bursts of change.
Related issue
Refs the v2.1.0-rc.1 Linux manual e2e pass (no issue filed).
Type of change
Release impact
Desktop impact
Testing
Unit test
only_vaapi_caps_the_qp_and_the_cap_reaches_the_codec:qmax = -1.avcodec_open2.vaMapBuffer2guard refuses.Commands run:
cargo testinelectron/native/pipewire-capture: 100 passed, 1 ignored.LD_LIBRARY_PATHpointing at a libva 2.23, the VAAPI branch of the new test ran and passed, andOPENSCREEN_LINUX_ENCODE_TEST=1ladder_encodes_a_playable_mp4selectedvaapi.Through the helper's own
VideoEncoder(scratch test, not committed):Manual verification on GNOME Wayland (AMD/VAAPI)
npm run build:native:linux) and run a dev build, or the CI artifact.🤖 Generated with Claude Code
Summary by CodeRabbit