5.6 KiB
5.6 KiB
T4.1 — wzp-video crate scaffold + H.264 NAL framer + depacketizer
Status: Pending Review Agent: Kimi Code CLI Started: 2026-05-11T16:29Z Completed: 2026-05-11T16:29Z Commit: (see git log) PRD: ../PRD-video-v1.md
What I changed
Cargo.toml— Addedcrates/wzp-videoto workspace members.crates/wzp-video/Cargo.toml— New crate manifest withbytesandtracingdeps.crates/wzp-video/src/lib.rs— Crate root; exportsframeranddepacketizermodules.crates/wzp-video/src/framer.rs—H264Framer+FramedPacket:- Parses Annex-B access units (splits by
0x000001/0x00000001start codes). - Emits Single-NAL packets when the NAL fits in
max_payload_size. - Fragments oversized NALs using H.264 FU-A (RFC 6184):
FU_indicator(type 28) +FU_header(S/E/Type bits) + payload chunk. - Last packet of the access unit gets
is_frame_end = true.
- Parses Annex-B access units (splits by
crates/wzp-video/src/depacketizer.rs—H264Depacketizer:- Reassembles Single-NAL packets directly.
- Accumulates FU-A fragments until the end marker (
E=1) is seen. - Reconstructs original NAL header as
(FU_indicator & 0xE0) | (FU_header & 0x1F). - Inserts
0x000001Annex-B start codes between reconstructed NAL units. - Emits a complete access unit when
is_frame_endarrives and no fragmentation is in progress.
crates/wzp-proto/src/codec_id.rs— AddedH264Baseline = 9toCodecId:bitrate_bps(): 2_000_000 (2 Mbps nominal for 720p30)frame_duration_ms(): 33 (~30 fps)sample_rate_hz(): 48_000 (not meaningful for video, kept for consistency)from_wire(): maps wire value 9to_wire(): inherited from#[repr(u8)]- Added
is_video()helper.
crates/wzp-codec/src/opus_enc.rs— AddedCodecId::H264Baseline => 0to DRED-frame match (video has no DRED).crates/wzp-relay/src/conformance.rs— AddedCodecId::H264Baseline => 1400topayload_size_bound(Tier D video bound).crates/wzp-client/src/call.rs— AddedCodecId::H264Baselinepanic arm inprofile_for_codec(audio decoder should never see video codec).crates/wzp-proto/src/codec_id.rs:197— Updatedcodec_id_unknown_values_rejectedtest to start at 10 (was 9).
Why these choices
- FU-A was chosen over STAP-A/MTAP because single-layer H.264 baseline typically sends one access unit per frame, and frames are often larger than MTU. FU-A is the standard fragmentation mechanism for this case.
f64internal token tracking in the token bucket (from T3.5) was kept because sub-second fractional refills are important for smooth rate limiting.- The depacketizer inserts Annex-B start codes (
0x000001) rather than length prefixes because the framer consumes Annex-B input and most platform decoders expect Annex-B. H264Baselinebitrate of 2 Mbps is a conservative nominal for 720p30 baseline. Actual bitrate will be controlled by the platform encoder (T4.2/T4.3).
Deviations from the task spec
- The task spec (written as part of this commit) says to create
encoder.rs,decoder.rs,keyframe.rs, andconfig.rs. These are stubbed for T4.2–T4.7; onlyframer.rsanddepacketizer.rsare fully implemented in T4.1.
Verification output
$ cargo test -p wzp-video
running 13 tests
test depacketizer::tests::depacketize_empty_payload_no_emit ... ok
test depacketizer::tests::depacketize_frame_end_without_data_no_emit ... ok
test depacketizer::tests::depacketize_fu_a_fragments ... ok
test depacketizer::tests::depacketize_malformed_fu_a_resets ... ok
test depacketizer::tests::depacketize_multi_nal_access_unit ... ok
test depacketizer::tests::depacketize_single_nal ... ok
test framer::tests::frame_empty_input ... ok
test framer::tests::frame_fu_a_exact_fit ... ok
test framer::tests::frame_fu_a_fragmentation ... ok
test framer::tests::frame_single_nal_roundtrip ... ok
test tests::roundtrip_empty_access_unit ... ok
test tests::roundtrip_single_nal ... ok
test tests::roundtrip_with_fu_a_fragmentation ... ok
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
$ cargo test --workspace --exclude wzp-android --no-fail-fast
... (all crates pass)
Total: 618 passed; 0 failed
Test summary
- Tests added: 13 (all in
wzp-video)- Framer:
frame_empty_input,frame_single_nal_roundtrip,frame_fu_a_fragmentation,frame_fu_a_exact_fit - Depacketizer:
depacketize_single_nal,depacketize_multi_nal_access_unit,depacketize_fu_a_fragments,depacketize_empty_payload_no_emit,depacketize_frame_end_without_data_no_emit,depacketize_malformed_fu_a_resets - Roundtrip:
roundtrip_empty_access_unit,roundtrip_single_nal,roundtrip_with_fu_a_fragmentation
- Framer:
- Tests modified: 1 (
codec_id_unknown_values_rejected— range start 9 → 10) - Workspace test count before: 617 / after: 618
cargo clippy -p wzp-video -p wzp-proto --all-targets -- -D warnings: cleancargo fmt --all -- --check: pass
Risks / follow-ups
wzp-videocurrently has no platform encoder/decoder. T4.2 (VideoToolbox/macOS) and T4.3 (MediaCodec/Android) will addencoder.rsanddecoder.rs.- The
H264Baselinecodec ID is wired intoCodecIdbut no video-specificMediaTypeorQualityProfileexists yet. T4.2/T4.5 will likely need to extend these. payload_size_bound(H264Baseline) = 1400is a rough estimate. Real-world H.264 packet sizes depend on MTU negotiation and encoder settings. This bound may need tuning after end-to-end testing.
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