feat(codec): use SVT-AV1 for AV1 encoding on 64-bit targets

Encode AV1 with SVT-AV1 v4.2.0 (rtc + low delay + CBR) instead of libaom
on all 64-bit targets; 32-bit targets keep aom. Decoding is unchanged and
the wire format is still AV1, so old peers are unaffected.

- vcpkg overlay port pinned to v4.2.0: static build, LTO off (mixed
  toolchain safety), MSVC >= 1950 inline workaround, no forced llvm
  binutils
- low delay contract: one packet out per picture in, blocking get_packet
- bitrate and frame rate change on the fly via RATE_CHANGE_EVENT /
  FRAME_RATE_CHANGE_EVENT; VideoQoS pushes its pacing rate through the
  new EncoderApi::set_fps, applied only after a successful send
- fall back to aom for i444 (svt-av1 is 4:2:0 only), for unsupported
  resolutions and on encoder init failure
- test_av1 now gates auto AV1 on the encoder actually used, the cached
  verdict is re-keyed (SVT-Y/SVT-N) so upgrades re-measure
- unit tests: per-frame packet contract, aom cross-decode of the
  bitstream, on-the-fly event acceptance

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012Wf7v1KJM6mbhiYxWSz4PH
This commit is contained in:
rustdesk
2026-07-23 01:50:57 +08:00
parent 1c2dd71891
commit 1ac684db0d
11 changed files with 770 additions and 29 deletions

View File

@@ -1023,12 +1023,28 @@ fn get_encoder_config(
},
keyframe_interval,
}),
CodecFormat::AV1 => EncoderCfg::AOM(AomEncoderConfig {
width: c.width as _,
height: c.height as _,
quality,
keyframe_interval,
}),
CodecFormat::AV1 => {
let aom = EncoderCfg::AOM(AomEncoderConfig {
width: c.width as _,
height: c.height as _,
quality,
keyframe_interval,
});
// Prefer svt-av1 for AV1 encoding, keep aom for i444 (svt-av1 is 4:2:0
// only) and for resolutions svt-av1 cannot handle.
#[cfg(target_pointer_width = "64")]
if scrap::svt_av1::SvtAv1Encoder::support(c.width as _, c.height as _)
&& !Encoder::use_i444(&aom)
{
return EncoderCfg::SVTAV1(scrap::svt_av1::SvtAv1EncoderConfig {
width: c.width as _,
height: c.height as _,
quality,
keyframe_interval,
});
}
aom
}
_ => EncoderCfg::VPX(VpxEncoderConfig {
width: c.width as _,
height: c.height as _,
@@ -1326,6 +1342,9 @@ fn check_qos(
) -> ResultType<()> {
let mut video_qos = VIDEO_QOS.lock().unwrap();
*spf = video_qos.spf();
// encoders whose rate control budgets per frame need the real pacing rate,
// implementations no-op when the value is unchanged
encoder.set_fps(video_qos.fps());
if *ratio != video_qos.ratio() {
*ratio = video_qos.ratio();
if encoder.support_changing_quality() {