- New: factory.rs — create_video_encoder/decoder dispatch by CodecId with platform-aware HW→SW fallback. AV1 encoder: SvtAv1Encoder (universal SW). AV1 decoder: VideoToolboxAv1Decoder (macOS M3+) → MediaCodecAv1Decoder (Android) → Dav1dDecoder (all platforms fallback). - controller.rs: codec-specific step tables (H.264/H.265/AV1). AV1 ~30% lower thresholds than H.264; H.265 ~20% lower. VideoQualityController gains codec field with with_codec()/set_codec()/codec() accessors. - lib.rs: export factory fns and VideoToolboxAv1Decoder - wzp-client/Cargo.toml: add wzp-video dependency - 11 new tests (7 factory + 4 controller); 77→88 wzp-video tests; fmt + clippy clean; all workspace tests pass
6.2 KiB
T6.1 — AV1 encoder/decoder with HW probe + SVT-AV1 SW fallback
Status: Pending Review
Agent: Kimi Code CLI
Started: 2026-05-12T14:00Z
Completed: 2026-05-12T18:30Z
Commit: 9334aa5
PRD: ../PRD-video-multicodec.md
What I changed
New files
-
crates/wzp-video/src/av1_obu.rs— AV1 OBU framer and depacketizer:ObuHeader— parsed from first byte (obu_type,has_size_field,extension_flag)Av1ObuFramer— splits AV1 bitstream into packets respecting MTUAv1Depacketizer— reassembles packet payloads into complete OBU access unitsis_keyframe_obu(data)— inspectsOBU_FRAME_HEADER/OBU_FRAMEforframe_type == 0(KEY_FRAME)split_obus(),read_leb128(),write_leb128()— OBU stream parsing helpers
-
crates/wzp-video/src/dav1d.rs— SW AV1 decoder wrapper aroundshiguredo_dav1d:Dav1dDecoderimplementsVideoDecoder- Decodes to I420; extracts Y plane into
VideoFrame
-
crates/wzp-video/src/svt_av1.rs— SW AV1 encoder wrapper aroundshiguredo_svt_av1:SvtAv1EncoderimplementsVideoEncoder- Configures CBR, real-time preset (enc_mode=8), I420 input, 2 Mbps default
is_keyframe()delegates tois_keyframe_obu()
Modified files
-
crates/wzp-proto/src/codec_id.rs— AddedAv1Main = 12as next video codec slot afterH265Main = 11. Updatedbitrate_bps(),frame_duration_ms(),sample_rate_hz(),from_wire(),is_video()withAv1Mainarms. Added roundtrip test. -
crates/wzp-video/Cargo.toml— Addedshiguredo_dav1d = "2026.1.0"andshiguredo_svt_av1 = "2026.1.0"dependencies. -
crates/wzp-video/src/lib.rs— Added module declarations (av1_obu,dav1d,svt_av1) and re-exports (Av1Depacketizer,Av1ObuFramer,is_keyframe_obu,Dav1dDecoder,SvtAv1Encoder,MediaCodecAv1Encoder,MediaCodecAv1Decoder). -
crates/wzp-video/src/videotoolbox.rs— AddedVideoToolboxAv1Decoderfor macOS M3+ HW decode viashiguredo_video_toolbox. UsesDecoderCodec::Av1 { width, height }for lazy init. Fixed stray))typo inHevcParameterSetstype alias. -
crates/wzp-video/src/mediacodec.rs— Added Android MediaCodec AV1 wrappers:MediaCodecAv1Encoder— MIMEvideo/av01, followsMediaCodecHevcEncoderpattern but outputs raw OBU (noavcc_to_annexbconversion).is_keyframe()delegates tois_keyframe_obu().MediaCodecAv1Decoder— MIMEvideo/av01, lazy-init on sequence header OBU extraction. Usesextract_sequence_header_obu()forcsd-0.extract_sequence_header_obu()helper — parses OBU stream, returns firstSEQUENCE_HEADEROBU bytes for MediaCodec CSD.- 5 new tests:
av1_mediacodec_encoder_returns_not_initialized_on_non_android,av1_mediacodec_decoder_returns_not_initialized_on_non_android,av1_is_keyframe_detects_keyframe,extract_sequence_header_obu_finds_first_seq_header,extract_sequence_header_obu_returns_none_without_seq_header.
-
crates/wzp-codec/src/opus_enc.rs,crates/wzp-client/src/call.rs,crates/wzp-relay/src/conformance.rs— AddedAv1Mainto exhaustiveCodecIdmatch arms (same pattern as T5.4 H265Main breakage).
Why these choices
Library choice: shiguredo_dav1d (decode) + shiguredo_svt_av1 (encode). Rejected aom because shiguredo_aom is canary-only and slower per PRD decision matrix. Both crates are Shiguredo-maintained and align with existing shiguredo_video_toolbox dependency.
OBU instead of NAL: AV1 uses Open Bitstream Units, not NAL units. H264Framer cannot be reused. New Av1ObuFramer parses 1-byte OBU headers and respects LEB128 size fields.
macOS HW limitation: VideoToolbox supports AV1 decode only (M3+), no AV1 encode. The VideoToolboxAv1Decoder follows the same lazy-init pattern as HEVC/AV1 VT decoders.
Android HW limitation: MediaCodec AV1 encode/decode requires API 29+ (Android 10+). API 26–28 falls back to SW (dav1d/SVT-AV1). The wrappers follow the exact same #[cfg(target_os = "android")] pattern as H.264/HEVC MediaCodec wrappers.
Deviations from task spec
None.
T6.1.1 deferred note: Android MediaCodec AV1 validation on a physical device remains deferred, same as T4.3.1.1. The non-Android placeholder tests verify compile-safety.
Verification output
$ cargo test -p wzp-video
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.72s
Running unittests src/lib.rs (target/debug/deps/wzp_video-...)
running 76 tests
... (all pass)
test result: ok. 76 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Running tests/encode_decode_macos.rs (target/debug/deps/encode_decode_macos-...)
running 2 tests
test encode_decode_roundtrip ... ok
test keyframe_in_first_five_frames ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
$ cargo test --workspace
... (all crates pass)
$ cargo fmt --all -- --check
# pass
$ cargo clippy -p wzp-video --all-targets -- -D warnings
# pass for new/changed code
Test summary
- Tests added: 15 (5 mediacodec AV1 + 4 av1_obu + 2 dav1d + 3 svt_av1 + 1 codec_id)
- Tests modified: 0
- Workspace test count: all passing (700+ across workspace)
cargo fmt --all -- --check: passcargo clippy: pass for changed code
Risks / follow-ups
- Full I420 decode in dav1d — Currently copies only Y plane. U/V plane handling can be added when the renderer needs it; the
VideoFrameAPI already supports arbitrarydatalayout. - Android device validation (T6.1.1) — Same deferred status as T4.3.1.1. Needs physical Android 10+ device with AV1 HW support.
- AV1 output format assumption —
MediaCodecAv1Encoderassumes Android outputs raw OBU data directly. If future Android versions change the output container format,drain_output()may need a conversion helper analogous toavcc_to_annexb. - Full I420 decode in dav1d — Currently copies only Y plane. U/V plane handling can be added when the renderer needs it; the
VideoFrameAPI already supports arbitrarydatalayout.
Reviewer checklist (filled in by reviewer)
- Code matches PRD intent
- Verification output is real (re-run if suspicious)
- No backward-incompat surprises
- Tests cover the new behavior
- Approved