You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(recordings): set explicit rate control on VAAPI playback transcode - #629
The HEVC → H.264 playback-compatibility transcode in recording_transcode.c encodes with h264_vaapi but passes no rate-control options, so the driver falls back to its default quality level (No quality level set; using default (20), hidden by -loglevel error) with no bound on bitrate.
This adds -rc_mode CQP -qp 24 to the VAAPI invocation.
Why CQP and not -b:v/-maxrate: some VAAPI drivers support only CQP. On an Intel HD 630 (Kaby Lake, iHD), -b:v 6M -maxrate 6M fails outright with Driver does not support any RC mode compatible with selected options (supported modes: CQP) and the encoder refuses to open. CQP is the mode drivers support most widely. If a driver rejects it anyway, the existing software fallback still produces the cache, so the worst case is the same as today's VAAPI-failure path.
The software (libx264) path is unchanged; x264 already defaults to CRF 23.
Measured
10 s clip copied straight from a 2560x1920 HEVC camera, transcoded with the exact old and new argument lists on an HD 630:
size
bitrate
HEVC source
1.7 MB
1.4 Mbit/s
before (no rate control)
10.4 MB
8.3 Mbit/s
after (CQP, qp 24)
6.3 MB
5.0 Mbit/s
That's 40% smaller. On busier scenes the gap is larger: the same unbounded-quality setting in a live hardware republish on this host produced ~21 Mbit/s, enough to make the recordings player stall. With qp 24 it dropped to ~10-13 Mbit/s and playback was smooth.
Tests
New test_vaapi_transcode_sets_explicit_rate_control puts a wrapper ffmpeg on PATH (same technique as the existing concurrency tests, now sharing an install_ffmpeg_wrapper() helper). The wrapper records the VAAPI invocation's arguments and exit status, then passes through to the real encoder. Checking the exit status proves the driver actually accepted the options; the request could otherwise succeed quietly via the software fallback. The test is skipped when /dev/dri/renderD128 is absent, so it is a no-op on CI.
Failed before the fix (VAAPI encode is missing -rc_mode CQP), passes after.
test_recording_transcode: 17/17 on a VAAPI host.
Full ctest otherwise unchanged from main. Unrelated pre-existing failures on current main: test_url_utils (test_url_apply_credentials_replaces_existing_credentials expects %3A, gets %3a) and the two argv-driven SOD tools (test_sod_unified, test_sod_voc), which print usage when run with no arguments.
No architecture-specific code; only an argument list changes.
Investigated, implemented and tested by Claude (Anthropic) via Claude Code, working with @davlaw.
The HEVC playback-compatibility transcode encoded with h264_vaapi and no
rate-control options, so the driver used its default quality level
("No quality level set; using default (20)") with no bound on bitrate.
Pass -rc_mode CQP -qp 24. CQP rather than -b:v/-maxrate because some
drivers (e.g. Intel HD 630) support only CQP and refuse to open the
encoder for bitrate modes. A driver that rejects CQP still falls through
to the existing software path.
Measured on a 10 s 2560x1920 HEVC camera clip: 8.3 -> 5.0 Mbit/s
(10.4 -> 6.3 MB, -40%).
The new test wraps ffmpeg on PATH to record the VAAPI invocation's
arguments and exit status, so it also proves the driver accepted the
options rather than the cache being produced by the software fallback.
It is skipped on hosts without a render node.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Address review feedback on the VAAPI rate-control regression test:
- Probe the baseline VAAPI HEVC-decode / H.264-encode pipeline (without
rate-control options) and skip when it fails, rather than gating only on
the render node path existing. Production falls back to software on hosts
with an inaccessible node, FFmpeg built without VAAPI, or a GPU lacking
HEVC decode, so the test should not fail there; the probe also isolates
the final status assertion to the new options themselves.
- Assert -qp is exactly 24 instead of any positive value, so an accidental
QP change is caught.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add recording transcode coverage to CI and GPU-independent tests
tests/unit/test_recording_transcode.c:639
This regression is not exercised by CI. test_recording_transcode is absent from both explicit build and ctest allowlists in .github/workflows/integration-test.yml:69-123; moreover, this case is ignored on GPU-less runners. Please add the target to those allowlists and split out a hardware-independent wrapper test that verifies the production argv, retaining the driver-backed check as an optional smoke test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The HEVC → H.264 playback-compatibility transcode in
recording_transcode.cencodes withh264_vaapibut passes no rate-control options, so the driver falls back to its default quality level (No quality level set; using default (20), hidden by-loglevel error) with no bound on bitrate.This adds
-rc_mode CQP -qp 24to the VAAPI invocation.Why CQP and not
-b:v/-maxrate: some VAAPI drivers support only CQP. On an Intel HD 630 (Kaby Lake, iHD),-b:v 6M -maxrate 6Mfails outright withDriver does not support any RC mode compatible with selected options (supported modes: CQP)and the encoder refuses to open. CQP is the mode drivers support most widely. If a driver rejects it anyway, the existing software fallback still produces the cache, so the worst case is the same as today's VAAPI-failure path.The software (
libx264) path is unchanged; x264 already defaults to CRF 23.Measured
10 s clip copied straight from a 2560x1920 HEVC camera, transcoded with the exact old and new argument lists on an HD 630:
CQP,qp 24)That's 40% smaller. On busier scenes the gap is larger: the same unbounded-quality setting in a live hardware republish on this host produced ~21 Mbit/s, enough to make the recordings player stall. With
qp 24it dropped to ~10-13 Mbit/s and playback was smooth.Tests
New
test_vaapi_transcode_sets_explicit_rate_controlputs a wrapperffmpegonPATH(same technique as the existing concurrency tests, now sharing aninstall_ffmpeg_wrapper()helper). The wrapper records the VAAPI invocation's arguments and exit status, then passes through to the real encoder. Checking the exit status proves the driver actually accepted the options; the request could otherwise succeed quietly via the software fallback. The test is skipped when/dev/dri/renderD128is absent, so it is a no-op on CI.VAAPI encode is missing -rc_mode CQP), passes after.test_recording_transcode: 17/17 on a VAAPI host.ctestotherwise unchanged frommain. Unrelated pre-existing failures on currentmain:test_url_utils(test_url_apply_credentials_replaces_existing_credentialsexpects%3A, gets%3a) and the two argv-driven SOD tools (test_sod_unified,test_sod_voc), which print usage when run with no arguments.No architecture-specific code; only an argument list changes.
Investigated, implemented and tested by Claude (Anthropic) via Claude Code, working with @davlaw.
🤖 Generated with Claude Code