oxideav-h264 0.1.9

Pure-Rust H.264 / AVC (ITU-T H.264 | ISO/IEC 14496-10) codec for oxideav — under spec-driven rewrite, no decode/encode functionality yet
Documentation

oxideav-h264

CI crates.io docs.rs License: MIT

Pure-Rust H.264 / AVC (ITU-T Rec. H.264 | ISO/IEC 14496-10) codec for the oxideav framework.

Status

Active spec-driven implementation built solely from the ITU-T Rec. H.264 | ISO/IEC 14496-10 specification (2024-08 edition) as the single authoritative source. The decoder reconstructs I / P / B slices (4:2:0, 4:2:2 and 4:4:4 chroma) through full intra / inter prediction, transform, deblocking and DPB output ordering on both the CAVLC and CABAC entropy paths; the encoder emits CAVLC and CABAC streams across Baseline / Main / High profiles. MBAFF (macroblock-adaptive frame/field) frame pictures decode byte-exact with frame-coded pairs (round 410: pair-interleaved deblock addressing, spec-exact §8.7.2.1 bS, Table 6-4 inter MV neighbour derivation; mbaff-interlaced BitExact gate) and with FIELD-coded pairs (round 413: §8.4.2.1 per-field reference selection with zero-copy field-view MC, §7.4.4 skipped-pair flag inference, the §9.3.3.1.x FIELD CABAC residual contexts (Tables 9-22/9-23) with §8.5.6/§8.5.7 field inverse scans, exact Table 6-4 block-level ctx probes, and the §8.7 per-MB MBAFF deblock walker incl. the dual field-mode top edge and the NOTE 3 field |Δmv| threshold; mbaff-field-pairs BitExact gate). Round 416 closed the CAVLC MBAFF tail (mbaff-field-cavlc BitExact gate: the residual walker's §9.2.1.1 nC probes now route through the exact §6.4.12.2 Table 6-4 process). §8.5.15 lossless transform-bypass (qpprime_y_zero_transform_bypass_flag=1, QP′Y == 0) decodes losslessly — identity §8.5.10..§8.5.13 legs + V/H intra residual DPCM (lossless-transform-bypass BitExact gate). PAFF (field_pic_flag == 1) decodes byte-exact end-to-end (round 416): field pictures reconstruct as half-height pictures (§7.4.2.1.1 eq. 7-26) with the §8.5.6 FIELD coefficient scan, reference lists initialise through the §8.2.4.2.2/.2.4 + §8.2.4.2.5 field process (per-field entries, alternating parity from the current field's own parity) with the §8.2.4.3 field RPLM, opposite-parity references apply the §8.4.1.4 Table 8-10 chroma-MV adjustment, per-field §8.7 deblocking uses the field-picture bS rules, and the §C.4.4 driver pairs complementary fields into full-height output frames (frame POC = Min of the two field POCs) — five PAFF fixtures (I fields, P field pairs, cross-parity reference, frame-as-field-reference, mixed frame/field switching) gate BitExact, generated by the crate's own clean-room PAFF field ENCODER (encoder::field: interlaced SPS, field slice headers, field-scan CAVLC emission, Table 8-10 chroma predictors, per-field deblock) and black-box-validated byte-identical against a stock reference binary. Round 436 closed the standing interlaced follow-ups: PAFF B field pairs decode AND encode byte-exact — non-reference B/B pairs between P/P anchors (coding order 0, 2, 1, 4, 3, …) with both the §8.4.1.2.2 spatial and the §8.4.1.2.3 temporal direct derivation on fields (colPic = the same-parity anchor field, all eq. 8-201/8-202 distances on per-FIELD §8.2.1 order counts) — which first required fixing the §8.2.5.3 sliding window to count a complementary reference field pair as ONE frame slot (per-entry counting had halved the effective DPB for field streams). §8.2.5.4 MMCO field-marking landed with per-parity DPB markings: field MMCO 1/2/3/4/6 mark individual FIELDS (pair-exception eviction rules included), the §8.2.4.2.5 interleave skips fields not marked with the matching reference class, and two encoder axes gate it end-to-end (long-term field-pair promotion via MMCO 4 + two field MMCO 3 ops with RPLM long_term_pic_num splicing, and a field MMCO 1 unmark exercising the "missing field is ignored" list fallback). The encoder field 8×8 transform scan (§8.5.7 Table 8-14 field row, pre-composed for the §7.4.5.3.3 CAVLC split + writer-remap pipeline) enables transform_8x8 in field pictures across I/P/B. All 13 new PAFF gates decode byte-exactly in our decoder and a black-box reference binary. Round 440 completed the interlaced co-located derivation and the PAFF encoder tail. Decoder: the §8.4.1.2.1 process now implements every Table 8-6/8-7/8-8 frame/field cross row (colPic as a decoded frame / decoded field / field of a decoded frame / complementary field pair; mbAddrCol1..7 with vertMvScale and the eq. 8-182 AFRM tie-break; MapColToList0 by picture identity with the field↔frame index doubling; per-FIELD eq. 8-201/8-202 distances), frame-slice reference lists collapse complementary field pairs into §8.2.4.2.1/.2.3 frame-level UNITS (re-interleaved for MC; non-paired fields excluded), and MBAFF intra prediction gathers its reference SAMPLES through the §6.4.12 Table 6-4 process (mixed field/frame pairs previously read raster-adjacent rows). All four staged JVT conformance bitstreams gate byte-exact end-to-end as hard asserts: camp_mot_picaff0_full (PAFF CABAC IBBP temporal direct, 30/30), CAPA1_TOSHIBA_B (90/90), CVPA1_TOSHIBA_B (90/90) and — round 443 — CAPAMA3_Sand_F (PAFF + MBAFF, 50/50): the §8.4.1.3 MVP neighbour probes now use the §6.4.11.7 exact sample locations, whose yN PARITY drives the Table 6-4 field-MB selection inside a field-coded neighbouring pair (the B/C/D probes at yP − 1 of a partition previously read the wrong field macroblock's motion data in mixed field/frame AFRM pictures). Encoder: implicit-weight B fields (PaffConfig::b_implicit_weight — stride-3 anchors put the two non-reference B pairs at unequal per-field POC distances so the §8.4.2.3.3 weights genuinely leave 32/32: 43/21 and 22/42 at logWD = 5, applied to luma AND chroma) and B REFERENCE fields (PaffConfig::b_reference_fields — a stride-4 layout stores a reference B pair through the sliding window and the non-reference B pairs use the coded B FIELDS as RefPicList0[0] / RefPicList1[0] — a B field as the §8.4.1.2.1 colPic — with an §8.2.4.3.1 RPLM re-splicing the previous anchor on later P fields), both self-roundtrip byte-exact and black-box-validated under spatial AND temporal direct. Round 448 closed the ChromaArrayType-0 surface — the last deferred leg of the High 4:4:4 decode row. Monochrome (4:0:0, chroma_format_idc = 0) decodes AND encodes end-to-end (High-family SPS, no §7.3.5.1 intra_chroma_pred_mode, luma-only §7.3.5.3 residual, Table 9-4(b) CBP, luma-only §8.7 deblocking, single-plane output), and separate_colour_plane_flag = 1 streams decode via the literal §8.1 three-invocation model: every coded slice routes to one of three internal monochrome sub-decoders selected by its §7.4.3 colour_plane_id, each running the complete per-plane pipeline (POC, marking, DPB, §C.4 bumping), with the three output streams re-assembled into three-plane pictures (0 → S_L, 1 → S_Cb, 2 → S_Cr) and the §8.5.9 luma-path scaling lists selected by iYCbCr = colour_plane_id. The encoder carries matching 4:0:0 and per-plane SCP legs (CAVLC + CABAC; I_16x16 + I_NxN + CABAC Intra_8x8 IDRs, P with P_Skip/P_L0_16x16, the full B mode set under spatial AND temporal direct, the §8.6.4 8x8-transform trials) plus encoder::scp::encode_scp_sequence for whole three-plane streams — 44 new gates: 4:0:0 streams byte-exact in our decoder AND a black-box reference decoder; SCP streams (which the stock reference binary rejects: "separate color planes are not supported") gated by self-roundtrip plus the §8.1 compositional identity against the black-box-validated standalone monochrome decodes. Round 451 opened the Extended-profile (88) surface: SP / SI switching pictures (§8.6) and slice data partitioning (§7.3.2.9). SP slices reconstruct through the literal transform-domain process — eq. 8-415 forward core transform of the prediction, the §8.6.1 QPY-dequant + QSY-requant chain (eqs. 8-416/8-420, chroma 8-424..8-431) or the §8.6.2 switching chain (8-432..8-441), §8.5.12 at qP = QSY/QSC (sMbFlag == 1) and Clip1(rij) output with no second prediction add — and the Table 7-12 SI macroblock type (Intra_4x4-coded, raw 0 with the offset-by-one I-type remap) decodes through the same switching path; §8.7.2.1's SP/SI bullets give every MB of such slices the intra boundary strengths. A clean-room SP/SI ENCODER (encoder::sp) emits primary SP pictures, switching SP pictures and SI pictures over an all-I_PCM IDR anchor, and the defining property is gated byte-exactly: a switching SP picture predicted from a DIFFERENT stream's decode state, and an SI picture predicted from nothing at all, both reproduce the primary SP reconstruction BYTE-FOR-BYTE through deblocking; primary SP chains are byte-exact against the encoder mirror at QP != QS and close-agreement-gated against a black-box reference decoder (which rounds negative §8.6 coefficients off the literal equations and lacks the switching semantics entirely). Data-partitioned slices (NAL types 2/3/4) decode with the category-2 elements read from partition A and every residual() (and I_PCM payload) routed to partition B (intra collective types) or C (inter) per §7.4.2.9; dual-form gates emit the SAME coded content as one NAL and as an A+B+C triple and require identical reconstruction — which flushed out a real pre-existing defect (the CAVLC I_PCM parse never committed its §9.2.1.1 nC-grid slot, desyncing any CAVLC slice mixing I_PCM with coded macroblocks). The round also gated 12-/14-bit decode (I_PCM sample-exact round-trips and Intra_16x16 DC-residual pictures byte-exact against the black-box reference decoder at both depths), arbitrary slice order (every slice-order rotation of multi-slice pictures decodes byte-identically — which exposed and fixed a §6.4.8 availability defect where a not-yet-decoded neighbour counted as same-slice) and redundant-coded-picture discard (§7.4.2.2). The Annex F/G/H/I scalable / multiview / 3D extensions remain the outstanding surface (see the coverage matrix below).

No external decoder source is consulted while writing this implementation — only the spec PDF. Conformance is verified by behavioural diff: our decoder is run against synthetic and public-domain real-world streams and the YUV output is compared against an independent reference decoder run separately. The staged fixture corpus (tests/docs_corpus.rs) decodes each fixture byte-for-byte against its expected.yuv. As of round 416 the corpus holds 36 fixtures and all 36 targets gate BitExact over their full frame counts; round 440 added four staged upstream JVT conformance bitstreams (docs/video/h264/conformance/) and as of round 443 all four gate byte-exact as hard asserts (camp_mot_picaff0_full 30/30, CAPA1_TOSHIBA_B 90/90, CVPA1_TOSHIBA_B 90/90, CAPAMA3_Sand_F 50/50) — every profile/tool combination staged (Baseline/Main/ High/High10/High422/High444; 8- and 10-bit; 4:2:0/4:2:2/4:4:4; CAVLC + CABAC; I/P/B with temporal + spatial direct, explicit + implicit weighted prediction, multi-ref, multi-slice, non-flat scaling matrices, 8×8 transform, MBAFF interlaced frame- AND field-coded pairs (CABAC and CAVLC), PAFF field pictures (I/P, cross-parity references, picture-adaptive frame/field switching), lossless transform-bypass, Annex-B + avcC framing) decodes byte-exactly.

The spec PDF itself can't be redistributed (ITU-T copyright) so it lives in the private OxideAV/docs repo at video/h264/T-REC-H.264-202408-I.pdf. Clone that repo next to your oxideav checkout if you're an internal contributor; otherwise the document is freely downloadable from https://www.itu.int/rec/T-REC-H.264 (pick the 2024-08 edition).

Specification coverage

Spec area Clause Status
NAL parsing (Annex B + AVCC) §7.3.1, §7.4.1, §B.1 + ISO/IEC 14496-15 §5.2.4.1.1 parsed (strict §7.3.1 dispatch on nal_unit_type ∈ {14, 20, 21}: parse_nal_unit reads the leading svc_extension_flag / avc_3d_extension_flag and parses the matching extension header per §F.7.3.1.1 (SVC, 3 bytes), §G.7.3.1.1 (MVC, 3 bytes — surfaces non_idr_flag, priority_id, view_id, temporal_id, anchor_pic_flag, inter_view_flag, reserved_one_bit), or §I.7.3.1.1 (3D-AVC, 2 bytes); emulation-prevention scoping honoured (extension bytes verbatim, only the post-extension RBSP fed through the 00 00 03 stripper). The avcC parser parses the §5.2.4.1.1 High-family extension trailer (chroma_format, bit_depth_luma_minus8, bit_depth_chroma_minus8, SPS-Ext NAL list) for profile_idc ∈ {100, 110, 122, 144, 244}, surfaced via avcc_* accessors)
Sequence Parameter Set §7.3.2.1 parsed (VUI + scaling_list fully integrated)
Subset Sequence Parameter Set (Annex F SVC / G MVC / H MVCD) §7.3.2.1.3, §G.7.3.2.1.4, §G.14.1, §H.7.3.2.1.4, §H.14.1 parsed (subset_seq_parameter_set_rbsp() for NAL unit type 15: the embedded seq_parameter_set_data() reuses the §7.3.2.1.1 parser, then the per-profile branch dispatches on profile_idc. Profiles 118 / 128 / 134 get the full §G.7.3.2.1.4 seq_parameter_set_mvc_extension() — per-VOIdx view_id[], anchor + non-anchor inter-view dependency lists, per-level operation points, and the profile-134 MFC tail — plus the optional §G.14.1 mvc_vui_parameters_extension(). MVCD profiles 138 / 135 get the full §H.7.3.2.1.4 seq_parameter_set_mvcd_extension() — per-VOIdx view_id[] + depth_view_present_flag / texture_view_present_flag (surfacing NumDepthViews), the depth_view_present_flag-gated anchor + non-anchor reference loops, per-level operation points with per-target-view applicable_op_depth_flag / applicable_op_texture_flag + applicable_op_num_texture_views_minus1 / applicable_op_num_depth_views — plus the optional §H.14.1 mvcd_vui_parameters_extension() (per-op depth/texture target-view flags + §E timing/HRD reuse) and the texture-view §G.14.1 VUI tail. SVC profiles 83 / 86 get the full §F.7.3.2.1.4 seq_parameter_set_svc_extension() — inter_layer_deblocking_filter_control_present_flag, extended_spatial_scalability_idc (0..=2), the ChromaArrayType-gated chroma_phase_x_plus1_flag / chroma_phase_y_plus1 with §F.7.4.2.1.4 inference, the ESS==1 seq_ref_layer_* geometrical-resampling offsets (se(v) + ref-layer chroma phase), and the seq_tcoeff_level_prediction_flag / adaptive_tcoeff_level_prediction_flag / slice_header_restriction_flag tail — plus the optional §F.14.1 svc_vui_parameters_extension() (per-entry dependency/quality/temporal id + §E.2.1 timing + §E.1.2 NAL/VCL HRD reuse). The MVCD+3D-AVC profile 139 still surfaces as the typed Mvcd3dNotParsed variant (the trailing Annex I seq_parameter_set_3davc_extension() is unimplemented) with the base SPS parsed. Subset SPSs are stored in a table separate from ordinary SPSs per §7.4.1.2.1)
Coded slice MVC extension (Annex G, NAL 20) §G.7.3.2.13, §G.7.4.1.2.1, §G.7.4.1.1 header parsed (NAL unit type 20 with svc_extension_flag == 0 decodes as a §G.7.3.2.13 slice_layer_extension_rbsp() MVC body, reusing the base §7.3.3 slice_header() parser with the §G.7.4.1.1 IdrPicFlag adaptation and the §G.7.4.1.2.1 subset-SPS id-space resolution. Event::SliceExtension surfaces the parsed header + MVC fields. §G.8 inter-view-predicted reconstruction not yet wired)
Sequence Parameter Set Extension §7.3.2.1.2 parsed (seq_parameter_set_extension_rbsp() for NAL unit type 13: seq_parameter_set_id, aux_format_idc (range-checked 0..=3), and — when aux_format_idc != 0 — the auxiliary-coded-picture / alpha-blending block (bit_depth_aux_minus8 range-checked 0..=4, alpha_incr_flag, and the bit_depth_aux_minus8 + 9-bit u(v) alpha_opaque_value / alpha_transparent_value per §7.4.2.1.2), plus additional_extension_flag. Stored keyed by the supplemented SPS id (the ordinary SPS id space) and surfaced via Event::SpsExtensionStored + Decoder::sps_extension; auxiliary-picture reconstruction is not wired, matching §7.4.2.1.2's "not required for conformance")
Picture Parameter Set §7.3.2.2 parsed (FMO + scaling_list fully integrated; 4:4:4 via parse_with_chroma_format)
scaling_list body §7.3.2.1.1.1 integrated into SPS + PPS
VUI parameters (+ HRD) §E.1 integrated into SPS
AUD + SEI framing + filler + end-of-seq/stream §7.3.2.3..7 parsed
Slice header §7.3.3 parsed (incl. RPLM, pred_weight_table, dec_ref_pic_marking)
Slice data + macroblock layer §7.3.4, §7.3.5 parsed (I/P/B; 4:2:0 + 4:2:2 + 4:4:4; I_PCM honours BitDepth{Y,C} from the SPS on both CAVLC and CABAC paths, incl. §9.3.1.2 post-PCM arithmetic-engine re-init; 4:4:4 P/B inter reconstruction now wired. MBAFF (mb_adaptive_frame_field_flag == 1, field_pic_flag == 0): the §7.3.4 MB-pair walker reads mb_field_decoding_flag per pair and decodes both MBs without CABAC desync — neighbour-MB addressing for §9.3.3.1.1.* context modeling routes through the exact §6.4.12.2 Table 6-4 process (mb_address::mbaff_neigh_location); all-frame MBAFF pairs reconstruct through the §6.4.1 field/frame y-stride path, and the §8.3.1.1/§8.3.2.1 intra-prediction-mode neighbour derivation now routes through the same §6.4.10/Table 6-4 pair-interleaved addressing (an MBAFF I-frame previously decoded at ~9 dB owing to raster neighbour mis-resolution; ~54 dB after the fix, see tests/integration_mbaff_interlaced_conformance.rs). PAFF (field_pic_flag == 1) field pictures now decode: each field reconstructs as a half-height picture (§7.4.2.1.1 eq. 7-26 PicHeightInMbs = FrameHeightInMbs / (1 + field_pic_flag)) with the §7.3.4 walk + §6.4 raster neighbours in field-local coordinates, and the §C.4.4 decoder driver pairs complementary opposite-parity fields (same frame_num) into one full-height output frame via interleave_fields (top → even rows, bottom → odd; frame POC = Min(Top,Bottom)FieldOrderCnt per eq. 8-1), emitting a trailing unpaired field as a standalone half-height frame at IDR/EOF. Round 410 made MBAFF frame pictures with frame-coded pairs byte-exact end-to-end (mbaff-interlaced gates BitExact): the deblock walker's pair-interleaved pixel_to_mb_addr, the spec-exact §8.7.2.1 bS derivation (both-in-frame-MBs bS=4 bullet, real mixedModeEdgeFlag, field-picture bS=3 horizontals), the §8.7 increasing-mbAddr (pair-interleaved) deblock processing order, and the §6.4.12.2/Table 6-4 inter MV-prediction neighbour fetch with §8.4.1.3.2 eq. 8-217..8-220 field/frame adjustment. Round 413 completed the MBAFF FIELD-coded-pair inter subsystem end-to-end (per-field references §8.4.2.1 with zero-copy field-view MC + Table 8-10 chroma MV offset, §7.4.4 skipped-pair flag inference, FIELD CABAC residual contexts (Tables 9-22/9-23 + field ctxIdxOffsets), §8.5.6/§8.5.7 field inverse scans, exact Table 6-4 block-level ctx probes, §8.7 per-MB MBAFF deblock walker with the NOTE 3 field
FMO (slice groups) decode §7.3.2.2, §8.2.2, §8.2.3, §6.4.8 implemented (all 7 slice_group_map_types; r453 wired NextMbAddress through the slice-data / reconstruction / picture-stamping walkers so FMO streams decode instead of being rejected — gated by the encoder's own FMO streams at every map type)
Monochrome / separate-colour-plane decode §7.4.2.1.1, §7.4.3, §8.1, §8.5.9 implemented (r448 — ChromaArrayType 0: 4:0:0 pictures decode luma-only end-to-end with single-plane output; separate_colour_plane_flag = 1 streams decode via the §8.1 three-invocation model — per-colour_plane_id routing to three monochrome sub-decoders, plane-triple reassembly into 4:4:4-shaped output, §8.5.9 iYCbCr = colour_plane_id scaling-list selection, no chroma-QP offset per the §7.4.2.2 NOTE; a non-conforming single-plane stream is bounded by a pairing cap surfaced as decode errors)
Top-level decoder driver §7.4.1.2.1 implemented (events: SPS/PPS stored, AUD, Slice, SEI, end markers, slice data partitions, Ignored)
SP / SI slice decode §7.4.5 Tables 7-12/7-13, §8.6, §8.5.12 (eqs. 8-331/8-333), §8.7.2.1 implemented (r451 — P macroblocks of SP slices, P_Skip included, reconstruct via §8.6.1 (sp_for_switch_flag == 0: eq. 8-416 QPY dequant-and-add, eq. 8-420 QSY re-quantisation, chroma DC 8-427..8-431) or §8.6.2 (switching: 8-432..8-441); the SI macroblock type parses per Table 7-12 and reconstructs via §8.6.2 with Intra_4x4/Intra_Chroma prediction; QSY per eq. 7-33, QSC via §8.5.8; §8.5.12 runs at qP = QSY/QSC and the samples are Clip1(r) with no second prediction add; §8.7.2.1 gives every MB of SP/SI slices the intra bS strengths. The bit-exact switching identity is gated three ways (primary §8.6.1 vs switching-SP vs SI, byte-equal through deblocking). CAVLC-only (A.2.3); 4:2:0, 8-bit
Redundant coded pictures §7.4.2.2, §7.4.1.2 implemented (r451 — slices with redundant_pic_cnt > 0 are discarded per the "may discard" allowance instead of overwriting the primary picture's macroblocks; gated with a deliberately-different redundant IDR slice decoding byte-identically to the primary-only stream)
Arbitrary slice order (ASO) §A.2.1 / §A.2.3, §6.4.8, §7.4.1.2.4 implemented (r451 — a Baseline/Extended picture may open at any first_mb_in_slice; slices deposit at their own MB addresses, the §6.4.8 availability treats not-yet-decoded neighbours as unavailable (a raster-order-invisible defect fixed by the ASO gates), the §8.7 deblock runs once over the assembled picture, and the finalize-time full-coverage check drops never-completed pictures instead of emitting zero-luma frames. Gated: every slice-order rotation of I16x16-DC-residual and I_PCM multi-slice pictures decodes byte-identically; other profiles keep the first-slice-covers-MB-0 strictness rejection)
Slice data partitioning (NAL 2/3/4) §7.3.2.9, §7.4.2.9 implemented (r451 — partition A parses slice_header + slice_id and drives the category-2 slice-data walk; partitions B/C attach by slice_id (redundant-picture partitions discarded) and serve every residual() read — intra collective types + I_PCM payloads from B (alignment relative to B's own bitstream), inter from C; missing-required-partition and orphan-partition streams surface decode errors; CAVLC-only per A.2.3. Dual-form gates decode the same content in single-NAL and A+B+C form byte-identically)
I-slice reconstruction (Picture + MB grid + intra + deblock) §8 / §6.4 implemented (I_PCM, Intra_4x4, Intra_8x8, Intra_16x16, chroma; §8.3.4.5 4:4:4 I_NxN chroma reconstruction at ChromaArrayType==3 — Cb/Cr "coded like luma" per §7.3.5.3, reusing the per-block luma pred modes with neighbour samples at BitDepthC)
P/B-slice reconstruction (MC + ref store + MV wiring) §8.4 implemented (P_Skip, P_L0_*, P_8x8; B_Skip, B_Direct, B_L0/L1/Bi_16x16/16x8/8x16; flat scaling; §8.4.2.2 ChromaArrayType==3 4:4:4 inter — the Cb/Cr planes are motion-compensated identically to luma per eq. 8-221/8-222 (mvCLX == mvLX) + eq. 8-235..8-238 (full-resolution integer position, quarter-sample fracs, §8.4.2.2.1 luma 6-tap kernel on each chroma plane via mc_chroma_partition_444), with the §8.4.2.3 default / explicit / implicit weighted-sample combine reusing the chroma weight tables; the §8.5.5 "coded like luma" inter chroma residual is added by reconstruct_inter_chroma_residual_444 (cbp_luma-gated 4x4 / 8x8 blocks, inter chroma scaling lists Table 7-2 i=4/5 + i=9/11, no chroma DC Hadamard))
DPB output ordering (POC-ordered delivery + bumping) §C.4 implemented
Reference picture marking (sliding window + MMCO) §7.3.3.3, §8.2.5 implemented (round 436: field-complete — the §8.2.5.3 sliding window counts frames / complementary field pairs / non-paired fields as single units with the second-field exemption, and the §8.2.5.4 MMCO field forms mark individual FIELDS via per-parity DPB markings: MMCO 1/2 by field PicNum / LongTermPicNum, MMCO 3/6 with the pair-exception eviction rules and long-term pair completion, MMCO 4 per-field by LongTermFrameIdx; encoder emits §7.3.3.3 adaptive op lists + §7.3.3.1 RPLM lists for the black-box-validated PAFF marking axes)
Reference picture list construction §8.2.4 implemented (frame init §8.2.4.2.1/.2.3; field init §8.2.4.2.2/.2.4/.2.5 — the §8.2.4.2.5 parity-alternation interleave emits one RefFieldEntry per field, starting with the current field's parity, skipping absent-parity frames, appending leftover same-parity fields in frame order; per-field PicNum eq. 8-30/8-31. Field lists are built + unit-tested independently of the field-coded reconstruction wiring)
Reference picture list modification (RPLM) §7.3.3.1, §8.2.4.3 implemented (frame dpb_key lists; field RefFieldEntry lists via modify_ref_pic_list_field — short-term idc 0/1 resolve picNumLX eq. 8-34..8-36 with field CurrPicNum/MaxPicNum then splice the field whose eq. 8-30/8-31 PicNum matches, long-term idc 2 by field LongTermPicNum eq. 8-32/8-33)
Picture order count derivation (types 0/1/2) §8.2.1 implemented (eq. 8-3 / 8-4 / 8-5 / 8-12 in i64 with PocError::Overflow surfaced through try_from)
Intra prediction (4x4 / 8x8 / 16x16 / chroma) §8.3 implemented (all modes)
Inter prediction — fractional interpolation + weighted pred §8.4.2 implemented (luma 6-tap, chroma bilinear for 4:2:0 / 4:2:2; at ChromaArrayType==3 the chroma planes use the luma 6-tap kernel per §8.4.2.2 eq. 8-235..8-238; default + explicit + implicit weighted)
Inter prediction — MV derivation (MVpred, P/B skip, spatial + temporal direct) §8.4.1 implemented
Transform decode + reconstruction §8.5 implemented (4x4 / 8x8 / Hadamard DC / chroma DC)
Deblocking filter §8.7 implemented (edge-level filter + bS derivation; §8.7.2 eq. (8-450) 4:4:4 chroma deblock at ChromaArrayType==3 filters the Cb/Cr planes with the luma filtering process, full-resolution, sharing the luma MB edge geometry + bS with the chroma QPC per side)
CAVLC entropy decode §9.2 tables + primitives (parse_residual_block_cavlc validates the §7.3.5.3.1 call-contract triples before reading bits)
CABAC entropy decode — engine §9.3.1 / §9.3.3.2 implemented (init + DecodeDecision/Bypass/Terminate)
CABAC entropy decode — per-element binarisations + ctxIdx §9.3.2 / §9.3.3.1 implemented (mb_skip/mb_type/sub_mb_type/mvd/ref_idx/mb_qp_delta/cbp/cbf/sig_coeff/coeff_abs/sign/end_of_slice + intra pred mode flags; the §9.3.1.1 init tables are transcribed over the full 0..=1023 ctxIdx range — r391 diffed 460..=1023 against the spec text after the mis-transcription fix). r388 chroma-format fixes: eq. (9-22) NumC8x8 chroma-DC contexts (4:2:2), the cat-4 wrap-by-16 above-neighbour (4:2:2), and real §9.3.3.1.1.9 cat-5/9/13 CBF cond terms (4:4:4 8x8) — pinned against x264 High 4:2:2 / High 4:4:4 8x8 streams
Scaling matrices §7.3.2.1.1.1 / §8.5.9 SPS + PPS scaling_list() parse with Table 7-2 fall-back rules A/B; r388 added the missing §8.5.6 inverse zig-zag (scan-order list → raster weightScale) so non-flat matrices dequantise correctly (x264 cqm=jvt 4x4 + 8x8 streams byte-exact)
SEI payloads §D.2 + §G.13.2 + §H.13.2 + §I.13.2 53+ payload types parsed, covering buffering_period / pic_timing / pan_scan_rect / filler / user_data (registered ITU-T T.35 + unregistered, incl. a typed ATSC1 'GA94' / 'DTG1' envelope sub-parser) / recovery_point / dec_ref_pic_marking_repetition / spare_pic / the 2003-draft sub-sequence family / film_grain_characteristics (incl. separate-colour-description bit-depth accessors) / frame_packing_arrangement / display_orientation / the HDR family (mastering_display, content_light_level, alternative_transfer_characteristics, ambient_viewing_environment, content_colour_volume, colour_remapping_info, tone_mapping_info) / the full 360 projection family (equirect / cubemap / sphere / region-wise packing / omni viewport) / sei_manifest / sei_prefix_indication / shutter_interval_info / and the Annex G/H/I multiview + 3D-AVC family (multiview_scene_info, multiview_acquisition_info with sign-exponent-mantissa camera params, multiview_view_position, non_required_view_component, view_dependency_change — §G.13.1.7 anchor/non-anchor inter-view-reference update flags, per-view loop bounds taken from the active MVC subset SPS via SeiContext::mvc_view_ref_counts — operation_point_not_present, base_view_temporal_hrd, three_dimensional_reference_displays_info, depth_representation_info, depth_timing, depth_sampling_info, constrained_depth_parameter_set_identifier, alternative_depth_info with global-view-and-depth camera params). Every parser enforces the spec's range bounds + anti-OOM pre-allocation caps; a deterministic malformed-input sweep + a sei_payload cargo-fuzz target pin panic-freedom across all dispatch arms. Remaining payload types fall through to SeiPayload::Unknown

Encoder coverage

The encoder emits both CAVLC and CABAC elementary streams; every coded stream is cross-checked bit-exact against an independent reference decoder run separately. Round 420 added rate control (CBR + capped VBR) and a registry encoder factory — the codec registry now carries h264_encoder::make_encoder next to the decoder, with a typed option schema (rc=auto/cqp/cbr/vbr, qp, bitrate, max_bitrate, buffer_size, gop, cabac, bframes). Round 443 extended rate control to B pictures (see the table row).

Round 475 — registry layouts, idr_pic_id, avcC. The registry encoder accepts every layout the crate's High-family encoder codes: Yuv420P / Yuv422P / Yuv444P / Gray8 at 8 bit and the *P10Le / *P12Le / Gray10Le / Gray12Le variants (declared on the registry descriptor so the Layer-2 gateway ladder sees them). 8-bit 4:2:0 input (grey coded as 4:2:0 with constant chroma) keeps the Baseline / Main session — IDR / P / B, rate control, streams byte-identical to earlier releases (integration_registry_bit_identity pins them). Every other layout rides encoder::deep::DeepSession under the §A.2.4 – §A.2.7 minimum profile (High 100 / High 10 110 / High 4:2:2 122 / High 4:4:4 Predictive 244): IDR + P pictures (Intra_16x16, P_Skip / P_L0_16x16 / Intra_16x16 fallback), CAVLC or CABAC, fixed QP (rc=cqp; no B pictures and no rate control on this path), transform_8x8, deblock, and lossless=true (transform bypass at QP′Y = 0, profile 244, reconstruction equal to the source). profile=auto|baseline|main|high|high10|high422|high444 picks the profile explicitly (one that does not admit the layout is refused; an explicit High-family profile routes 8-bit 4:2:0 input through the High-family encoder). Every IDR access unit carries a §7.4.3 idr_pic_id that advances per IDR (0, 1, 2, … mod 65536), so an all-intra gop=1 sequence never reads as redundant slices of one picture. format=annexb (default: start codes, in-band SPS / PPS, empty extradata) or format=avcc (4-byte length-prefixed samples without parameter sets / filler; extradata = the ISO/IEC 14496-15 §5.3.2.1 AVCDecoderConfigurationRecord from the avcc module — builder + parser + sample framing). Gates: every layout × CAVLC / CABAC decodes in our decoder within the lossy bound and byte-identically in a black-box reference decoder; lossless 4:2:2 / 4:4:4 / 10- / 12-bit / grey exact in both; avcC extradata + samples decode identically to the Annex B stream. Intra_4x4 at > 8 bit (intra_4x4, default on; DeepSession::with_intra_4x4): §8.3.1 block-sequential prediction at 8 / 10 / 12 / 14 bit with the §8.3.1.1 predicted-mode coding, the §8.5.15 V / H DPCM under transform bypass and the §8.3.4.5 4:4:4 chroma planes, CAVLC + CABAC, competing with Intra_16x16 per macroblock on Σ (SAD + mode bits · λ) — bit-exact in our decoder and byte-exact in the reference decoder across 8 layouts × both entropy coders, lossy and lossless; lossless 12-bit 4:4:4 shrinks 49572 → 33308 B, lossy 10-bit 4:2:0 3588 → 3446 B at equal PSNR (QP 26). Measured (64x48 synthetic, 3 pictures, CAVLC, bytes / min luma PSNR): 4:2:2 8-bit 3389 B / 45.2 dB at QP 20, 2009 B / 38.4 dB at QP 28, 1048 B / 30.8 dB at QP 36; 4:2:0 10-bit 2429 / 45.6, 1479 / 38.2, 858 / 30.9; 4:4:4 12-bit 4970 / 45.7, 3009 / 38.1, 1492 / 30.9. Not yet on this path: 4:0:0 (chroma_format_idc = 0) coding for grey input, Intra_8x8 and Intra_NxN inside P pictures at > 8 bit, B pictures and rate control for the High-family layouts.

Coding tool Scope Notes
Rate control (r420, B pictures r443) CBR + capped VBR, CAVLC + CABAC GOPs — IDR/P chains AND I B..B P mini-GOP structures (SessionConfig::b_frames / registry bframes, 0..=16); MB-row delta-QP on every slice kind and both entropy paths Non-normative feedback controller (encoder::rate_control): complexity-times-quantiser-step model (§8.5.9 doubles-every-6 anchor) over an Annex C-style leaky-bucket CPB, per-frame QP via §7.4.3 slice_qp_delta (single PPS; §9.3.1.1 CABAC ctx init at the resulting SliceQP_Y), VBV hard-cap re-encode retry, §7.3.2.7 filler NALs in CBR, and Encoder::encode_p_rate_adaptive MB-row modulation riding §7.4.5 mb_qp_delta (coded-residual-only emission + skip/cbp==0 inheritance mirrored decoder-exactly, deblock chain included). Measured (80x64 synthetic matrix, post-warmup): CBR drift-corrected payload error 0.0% across smooth / texture / scene-cut signals with channel (payload+filler) conservation 0.0%; capped-VBR payload error ≤ 1.5%; RD check — CBR lands on the fixed-QP anchor curve (43.94 dB vs 43.93 dB interpolated at equal rate). Registry encoder factory (h264_encoder) with rc/qp/bitrate/max_bitrate/buffer_size/gop/cabac/bframes options. B pictures (r443): the controller models three frame kinds — per-kind complexity EWMAs feed a GOP-mix-normalised budget split that conserves the per-frame budget for any structure and settles a λ-scaled QP hierarchy (equal step I/P, non-reference B a constant +2 QP); the session buffers display order and emits mini-GOPs anchor-first with truncated pre-IDR tails, pic_timing.dpb_output_delay covers the one-frame reorder latency, and MB-row delta-QP modulation runs on the B paths too (encode_b_rate_adaptive / encode_b_cabac_rate_adaptive). Measured (b_frames = 2, post-warmup): CBR payload error 2.8% CAVLC / 1.1% CABAC, capped-VBR 0.04%; mean QPs I 17.0 ≤ P 18.0 < B 20.2; the CBR B-GOP encode lands 1.2 dB ABOVE the fixed-QP B-GOP anchor curve at equal rate. All rate-controlled streams (reordering, SEI + filler included) decode byte-exactly in our decoder and a black-box reference decoder
P slices CAVLC + CABAC Integer + quarter-pel ME, P_Skip / P_L0_16x16 / P_8x8 (per-8x8 4MV), Intra_16x16 fallback; multi-reference (r453): per-MB ref_idx_l0 te(v) election over the active list with refIdx-aware §8.4.1.3 mvp and §8.7.2.1 reference-identity deblock keys
B slices CAVLC + CABAC Explicit B_L0/L1/Bi_16x16 / 16x8 / 8x16, per-cell mixed B_8x8, B_Skip, B_Direct_16x16 / 8x8 (§8.4.1.2.2 spatial + §8.4.1.2.3 temporal direct), default + explicit weighted bipred
MV derivation §8.4.1.3 mvp median + C→D substitution, P_Skip MV, spatial/temporal direct mirrored on the encoder side
4:2:2 chroma High 4:2:2 (profile_idc=122) §8.5.11.2 4x2 chroma DC Hadamard, §8.3.4 8x16 chroma intra. Decode of P / B-slice 4:2:2 inter is wired: §8.4.1.4 eq. 8-221/8-222 chroma MV (mvCLX = mvLX, SubHeightC=1) + §8.4.2.2 eq. 8-231..8-234 vertical 1/4-pel (yIntC += mvCLX[1]>>2, yFracC = (mvCLX[1]&3)<<1), the §8.4.2.3 default / explicit / implicit weighted combine, and the §8.5 8x16 (eight 4x4) inter chroma residual all run at full chroma height (reconstruct::tests::{mc_chroma_422_*, p_l0_16x16_422_*, b_bi_16x16_422_*}). Encoder 4:2:2 covers IDR + P + B under both entropy coders (r391 CABAC, r397 CAVLC)
4:4:4 chroma High 4:4:4 Predictive (profile_idc=244), IDR Intra_16x16 + Intra_4x4 §7.3.5.3 / §8.3.4.1 chroma "coded like luma" (per-plane 16x16 DC Hadamard + 4x4 AC); §8.3.4.5 I_NxN Cb/Cr reuse the per-block luma Intra_4x4 pred modes — the High 4:4:4 all-intra I_4x4 path now decodes bit-exact (integration_high444_i4x4_bitexact, gated on the intra-only-high444 high-QP picture). I_8x8 4:4:4 (intra_8x8_zero_residual_dc_reconstructs_444_chroma), P 4:4:4 inter (p_l0_16x16_444_* — eq. 8-235..8-238 luma-6-tap chroma MC), and B 4:4:4 inter (b_bi_16x16_444_default_averages_full_resolution_chroma — §8.4.2.3 bipred combine on full-res chroma) all decode. separate_colour_plane_flag=1 landed r448 (decode via the §8.1 three-invocation sub-decoders; per-plane SCP encoder + encoder::scp::encode_scp_sequence)
4:0:0 monochrome + separate colour planes (r448) High (100) 4:0:0; High 4:4:4 Predictive (244) with separate_colour_plane_flag=1, per-plane EncoderConfig::colour_plane_id ChromaArrayType 0 luma-only coding on every path: I_16x16 / I_NxN (write_i4x4_mb_mono) / CABAC Intra_8x8 IDRs, P (P_Skip / P_L0_16x16), the full B mode set (B_Skip / B_Direct_16x16 spatial + temporal, 16x16 rows, 16x8 / 8x16 partitions), §8.6.4 8x8-transform trials, CAVLC + CABAC. encoder::scp::encode_scp_sequence assembles three per-plane encoders into whole separate_colour_plane streams (shared SPS/PPS, per-AU plane-ordered slices, IDR+P chains and IDR-B-P mini-GOPs). 4:0:0 streams byte-exact vs the black-box reference decoder; SCP gated by the §8.1 compositional identity
SP / SI switching pictures + data partitioning (r451) Extended (88), encoder::sp — primary SP (sp_for_switch_flag=0), switching SP (=1), SI pictures, single-NAL and §7.3.2.9 partitioned emission Primary SP: all-P_L0_16x16 zero-motion pictures whose residual inverts the eq. 8-416/8-428 dequants in the transform domain, §8.6-mirror recon, final quantised coefficient arrays retained as switching targets. Switching SP / SI: per block cr = c_target − Q_QS(T(pred)) so the decoder's eq. 8-433/8-437 sums reproduce the primary picture's reconstruction BIT-EXACTLY from a different reference (or from Intra DC prediction with no reference); chroma DC rides eq. 8-440's additive level with the eq. 8-431 scale shown integral for QSC >= 6. I_PCM IDR anchor; mixed SP+I_PCM pictures and SI pictures also emit in data-partitioned dual form (A+B+C / A+B) byte-decode-identical to their single-NAL form
10 / 12 / 14-bit (r456 encoder::deep) High 10 (110), High 4:2:2 (122), High 4:4:4 Predictive (244) — u16 sources at 4:2:0 / 4:2:2 / 4:4:4, CAVLC and CABAC I (Intra_16x16) + P (P_Skip / P_L0_16x16 / Intra_16x16 fallback), 8x8 transform (4:2:0 / 4:2:2), deblocking, lossless qpprime_y_zero_transform_bypass §7.4.2.1.1 bit_depth_luma_minus8, §8.5.8 eq. 8-309 QP_Y (now 52 + 2*QpBdOffsetY addend — round 349 fixed the >8-bit-only off-by-QpBdOffsetY bug that collapsed the dequant scale), §8.5.12 dequant at qP'=qP+QpBdOffsetY(=12), 1<<(bd-1)=512 predicted DC default, LE-u16 yuv420p10le plane packing — all wired end-to-end (corpus_10_bit_high10_emits_full_range: every sample legal 10-bit 0..1023, luma genuinely spans the >8-bit range; reconstruct::next_qp_y spec-value tests at 8/10/12-bit). Round 410: the 10-bit-high10 fixture reference was regenerated (the old file was 50% conceal-fill) and the whole picture gates byte-exact, as do the new 5-frame 10-bit-high10-inter (I/P/B), 10-bit-high422 and 10-bit-high444 GOP fixtures — the residual "right-column divergence" was the defective reference, not the decoder. The 10-bit 4:2:2 path needed one real fix: §8.5.11.2 eq. 8-328 chroma-DC dequant used qP where the spec says qPDC. r451 — 12-/14-bit decode gated: the SPS writer emits caller-selected bit depths and integration_high_bit_depth builds its own streams (all-I_PCM pictures — exact LE-u16 sample round-trips at ranges beyond the 10-bit ceiling — and Intra_16x16 DC pictures with coded luma/chroma DC residual through §8.5.10/§8.5.11/§8.5.12 at qP′ = 36/50), byte-exact against the black-box reference decoder at BOTH depths r456 — the high-bit-depth ENCODER: every stage runs the decoder's bit-depth-aware processes (QP′ = QP + QpBdOffset forward/inverse scaling extended past 51, §8.5.8 chroma QP with the −QpBdOffsetC clip, 1 << (BitDepth − 1) intra DC defaults, Clip1 at depth, §8.4.2.2 interpolation at depth, §8.7 deblocking with α/β/tC0 scaled by 1 << (BitDepth − 8)), QP_Y down to −QpBdOffsetY; lossless coding (SPS bypass flag at QP′Y == 0: §8.5.10/§8.5.11/§8.5.12 identities + §8.5.15 V/H DPCM on luma, chroma and 4:4:4 planes) reconstructs the source sample-for-sample (lossless_interop withholds the DPCM-triggering V/H modes: the black-box reference decoder skips the §8.5.2 step 3 / §8.5.4 step 3 Intra_16x16 + chroma DPCM — DC/Plane agree, V/H disagree, V/H agree once the DPCM is withheld — while our decoder is spec-literal). 14 gates (10/12/14-bit × 4:2:0/4:2:2/4:4:4 × CAVLC/CABAC, 8x8 transform, negative QP, lossless at 8..=14-bit) bit-exact in our decoder + byte-exact in the black-box reference decoder + PSNR-checked vs the source. A real defect fell out: the shared 4:2:2 chroma DC quantiser ran at qP instead of eq. 8-327's qP,DC = qP + 3 (every 4:2:2 stream since r27 carried chroma ~10 dB below luma; fixed, 30 → 42 dB), and the decoder's CABAC coeff_abs_level_minus1 escape cap (14 leading ones, 8-bit-sized) rejected legal 12-/14-bit levels up to 2^21 — now 20. Fuzz: mbaff_cabac_roundtrip + deep_roundtrip round-trip targets
Intra fallback in P / B Intra_16x16 Per-MB Lagrangian RDO against the inter winner (EncoderConfig::intra_in_inter); a 4:2:0-only mode choice (I_NxN / I_PCM fallback deferred)
Trellis quantisation (RDOQ) §9.3.3.1.3 + §8.5.12 CABAC paths. Default: the spatial-domain D + λ·R one-step-toward-zero lite pass on inter luma 4×4 (EncoderConfig::trellis_quant, opt-in on Intra_16x16 luma + chroma AC). Full trellis (r453, EncoderConfig::trellis_full, opt-in): Viterbi over every last-significant position and {0, |q|−1, |q|} per coefficient with the eq. 9-23/9-24 numDecodAbsLevelEq1/Gt1 context state, bin costs from the §9.3.1.1 initial states + Table 9-44 probabilities, sample-domain re-check against open-loop and lite. Measured (textured-motion P+B, QP 20..=36): P+B payload −1.1 % at ≤ 0.1 dB, QP-32 P slice −8 %; one QP-34 B slice grew 4 bytes vs open-loop, so lite stays default. Informative only — bitstream syntax unchanged
8x8 transform (High profile) EncoderConfig::transform_8x8 — CAVLC and CABAC I/P/B at every chroma format (r397 closed the CAVLC 4:2:2/4:4:4 inter legs) §8.6.4 forward 8x8 transform + §8.5.13.1 quantiser (MF8x8 = round(2^18 / normAdjust8x8) at qBits8 = 22 + qP/6), Table 8-14 8x8 zig-zag, §7.4.5.3.3 four-4x4 CAVLC split. SPS auto-promotes to High (100); PPS codes the §7.3.2.2 tail (transform_8x8_mode_flag = 1). Intra: per-MB 3-way RDO (I_16x16 / I_4x4 / I_8x8 — all 9 §8.3.2 Intra_8x8 modes with the §8.3.2.1 eq. 8-73 pred-mode derivation mirrored encoder-side). Inter: per-MB 8x8-vs-4x4 luma-residual trial on P_L0_16x16 and every coded B shape; the §7.3.5 second-gate flag is coded on all qualifying writers. §8.7 deblock mirrors the 8x8 internal-edge skip. CABAC (r385): encode_idr_cabac trials Intra_8x8 (§9.3.3.1.1.10 transform_size_8x8_flag at ctxIdxOffset 399 + §7.3.5.3.3 blockCat-5 64-coefficient residuals, Table 9-43 significance maps, CBF suppressed at 4:2:0); encode_p_cabac / encode_b_cabac code the second-gate flag on every coded MB with cbp_luma > 0 and emit blockCat-5 residuals when the 8x8 trial wins. 4:2:2 (r385): the 3-way RDO runs at High 4:2:2 (profile 122, write_i8x8_mb_chroma + the mandatory I_NxN zero-flag). 4:4:4 (r385): all-Intra_8x8 IDR with §8.3.4.5 chroma-coded-like-luma 8x8 (per-plane §9.2.1.1 nC via derive_nc_plane_luma_like); a decoder fix landed alongside — the CAVLC 4:4:4 8x8 Cb/Cr plane residual is now §7.4.5.3.3-interleaved at parse (previously scrambled). All paths bit-exact self-roundtrip + black-box reference-decoder interop (integration_i8x8_encoder.rs 12 gates + integration_i8x8_cabac.rs 6 gates). r388: CABAC 4:2:2 IDR (8-coefficient ChromaDCLevel under the eq. (9-22) NumC8x8=2 contexts, 2x4 chroma-AC grid, transform_8x8 allowed) and CABAC 4:4:4 Intra_8x8 (blockCat-9/13 chroma residuals, explicit cat-5/9/13 coded_block_flag with the §9.3.3.1.1.9 neighbouring-8x8-block cond terms) landed, plus the 4:4:4 I_16x16-vs-Intra_8x8 RDO (CAVLC: two-way trial with 3-plane SSD + real bits; CABAC: luma-cost trial) with real per-plane nC on the mixed-shape streams. r391: the 4:4:4 I_4x4 leg landed — the CAVLC 4:4:4 IDR trial is now two-way I_16x16 / Intra_4x4 (three-way + Intra_8x8 under transform_8x8); §8.3.4.5 chroma-as-luma 4x4 emit with per-plane §9.2.1.1 nC, both transform-size flag values in one stream, dual-decoder bit-exact (integration_i4x4_444_encoder.rs)
Scaling matrices (r388 + r391) EncoderConfig::scaling_matrix ∈ {Flat, SeqDefault, PicDefault, SeqCustom, PicCustom} — CAVLC + CABAC, I/P/B at 4:2:0 §7.3.2.1.1.1 Table 7-3/7-4 default quantisation matrices signalled at sequence level (SPS seq_scaling_matrix_present_flag, every list UseDefaultScalingMatrixFlag via delta_scale = -8) or picture level (§7.3.2.2 PPS tail); the forward quantiser divides by the §8.5.9 weightScale (_w variants) and the local recon runs the decoder's scaled inverse across I_16x16 / I_4x4 / I_8x8. A decoder fix landed first: the §8.5.6 inverse zig-zag from scan-order scaling lists to raster weightScale was missing entirely, so every non-flat matrix (x264 cqm=jvt streams) previously dequantised garbled. Both directions pinned bit-exact against the black-box reference decoder (integration_scaling_matrix.rs 21 gates + 2 cqm-jvt decode gates). r391: non-flat matrices run on P/B slices (inter weightScale on the 4x4 + 8x8 inter luma and inter chroma quantisers; the intra-fallback MBs use the intra lists) and under CABAC (I/P/B at 4:2:0), and custom user-supplied list values are coded through the real §7.3.2.1.1.1 delta_scale chain (wrap-aware; SPS/PPS parse-back recovers the exact values) — integration_scaling_matrix_pb.rs (5 gates) + integration_scaling_matrix_cabac.rs (5 gates)
Chroma-AC CAVLC nC (r388 fix) all CAVLC writers (I/P/B, 4:2:0 + 4:2:2) The historical nC = 0 shortcut desynchronised every spec decoder on dense chroma (nC selects the §9.2.1.1 coeff_token table); the encoder now derives per-block chroma-AC nC from the CavlcNcGrid with in-MB progressive TotalCoeff commits (integration_chroma_nc.rs)
CABAC 4:2:2 / 4:4:4 P + B (r391) encode_p_cabac / encode_b_cabac at every chroma format 4:2:2: §8.4.1.4 half-width/full-height chroma MC (mvC.y = mvL.y·2 in 1/8-pel), §8.5.11.2 4x2-Hadamard inter chroma chain under the NumC8x8=2 contexts, §8.7 deblock at chroma_array_type=2. 4:4:4: chroma motion-compensated like luma (§8.4.2.2.1 6-tap per plane, mvC = mvL) and coded like luma — blockCat-8/12 full 4x4 inter residuals or blockCat-5/9/13 8x8 with explicitly coded CBF under transform_8x8, CBP quadrant bits merged across the three planes. r397 completed the B mode set at 4:2:2/4:4:4: B_Skip / B_Direct_16x16 (spatial §8.4.1.2.2, uniform gate) and the 16x8 / 8x16 partitions (Table 7-14 raw 4..=21, per-partition §8.4.1.3 mvps + §9.3.3.1.1.7 contexts); B_8x8 stays a 4:2:0-only mode choice. 9 GOP gates bit-exact through both decoders (integration_cabac_pb_chroma_formats.rs). A decoder fix landed first: twelve §9.3.1.1 Table 9-30/9-31/9-32 P/B-column (m, n) init values (ctxIdx 805/849, 975..980, 1005..1010 — the cat-6..8/10..12 coeff_abs_level families) were mis-transcribed, desynchronising every CABAC 4:4:4 P/B decode at the first inter chroma abs-level bin; the full 460..1023 range is now diffed against the spec table text and a 3-frame black-box 4:4:4 P stream pins it (cabac_444_p_slices_reference_stream_decodes_bit_exact)
CAVLC 4:2:2 / 4:4:4 P + B + full chroma-format matrix (r397) encode_p / encode_b at every chroma format Every (entropy coder × chroma format × slice type) cell now encodes: multi-format encode_p (shared emit_inter_mb_tail, ChromaWriteKind::Yuv444Inter, Table 9-4(b) inter CBP, derive_plane_nc_444_inter), encode_b_mb_multifmt (B_Skip / B_Direct_16x16 spatial + temporal, explicit 16x16, 16x8 / 8x16 partitions with build_chroma_rect_pred_fmt per-format chroma-rect MC), and non-flat scaling matrices at 4:2:2 / 4:4:4 (weighted §8.5.11.2 chain via quantize_chroma_dc_422_w, weighted 4:4:4 plane chains, §7.3.2.2 PPS 12-list loop). Decoder fixes alongside: the 4:4:4 inter chroma 8x8 scaling-list sub-index (spec 9/11 → 3/5; non-flat streams previously dequantised those blocks flat) and the CABAC B_Skip deblock L1 identity. 32 new dual-decoder GOP gates (integration_cavlc_pb_chroma_formats.rs, integration_scaling_matrix_chroma_formats.rs, extensions to integration_cabac_pb_chroma_formats.rs)
Interlaced: PAFF + MBAFF (r416 / r436 / r440 / r453 / r456) encoder::field (field pictures) + encoder::mbaff (MBAFF frames, CAVLC) + encoder::mbaff_cabac (MBAFF frames, CABAC, r456), Main, 4:2:0 PAFF: field_pic_flag = 1 I/P/B field pairs, §8.2.4.2.5 field lists, cross-parity references with the §8.4.1.4 Table 8-10 chroma adjustment, field MMCO/RPLM, per-field §8.7 deblock. MBAFF (r453): mb_adaptive_frame_field_flag = 1 frame pictures with per-pair mb_field_decoding_flag (AllFrame / AllField / content-adaptive / checkerboard policies), §6.4.1 eq. 6-9/6-10 field-MB interleave + §8.5.6 field scan, neighbour derivation through the decoder's §6.4.12.2 Table 6-4 process for samples, §9.2.1.1 TotalCoeff and §8.4.1.3.2 motion cells with the eq. 8-217..8-220 frame↔field MV/refIdx scaling, §8.4.2.1 same-parity field-of-frame MC with ref_idx_l0 te(v) over the doubled field list, §7.4.4 skipped-pair flag inference mirrored (fully-skipped pairs re-encoded under the inferred flag), §8.7 MBAFF deblock. I pictures Intra_16x16, P pictures the full P mode set. 9 gates bit-exact in our decoder + byte-exact in the black-box reference decoder. CABAC MBAFF (r456): the same MBAFF picture structure under entropy_coding_mode_flag = 1, every §9.3.3.1.1.x ctxIdxInc resolved through the decoder's own §6.4.10 / Table 6-4 grid (CabacNeighbourGrid + its cond-term helpers) — mb_field_decoding_flag ctxIdx 70..=72 from the neighbouring pairs, mb_skip_flag contexts under the §7.4.4 inferred flag (the pair flag rides the first coded MB and retro-patches a skipped top), eq. 9-12 refIdxZeroFlag thresholds + eq. 9-15/9-16
Weighted prediction (r26 / r440 / r453) B explicit (weighted_bipred_idc = 1) + implicit (PAFF, idc 2); P explicit (r453, EncoderConfig::explicit_weighted_pred) P: PPS weighted_pred_flag = 1, per-slice §7.3.3.2 pred_weight_table() (luma, chroma_weight_l0_flag = 0), §8.4.2.3.2 eq. 8-274 weighting of every inter predictor incl. P_Skip before the residual / skip decision, motion search on the weighted reference, slice-wide least-squares (weight, offset) at logWD = 5 elected on ≥ 1 % co-located SSD gain (fade detection) else luma_weight_l0_flag = 0. Measured (five-frame global fade, QP 26): P payload 6684 → 960 bytes at equal PSNR (37.56 → 37.55 dB). 3 gates bit-exact in both decoders
Multi-reference + long-term references + MMCO + RPLM (r453) encoder::multiref — Baseline, CAVLC 4:2:0, up to 16 active references §8.2.4.2.1 RefPicList0 (short-term by descending PicNum, long-term by ascending LongTermPicNum) mirrored from an encoder-side §8.2.5 buffer: sliding window, §7.4.3.3 long_term_reference_flag on the IDR, MMCO 4 + 6 long-term assignment of a P picture (with MMCO 1 eviction on overflow), MMCO 2 unmarking, RPLM long_term_pic_num splicing to index 0 — marking applied after the picture is coded; §7.3.3 num_ref_idx_active_override; per-MB quarter-pel election over every active reference. 4 gates (3 active refs electing the two-frames-back reference, long-term IDR anchor, MMCO mark + unmark, RPLM) bit-exact in both decoders
Multi-slice, FMO, ASO, redundant slices, constrained intra (r453) encoder::slices — Baseline, CAVLC 4:2:0 §7.3.2.2 slice group map types 0..=6 in the PPS (slice_group_change_cycle in the headers for 3..=5), MbToSliceGroupMap derived with the decoder's §8.2.2 code, raster slices of mbs_per_slice MBs per group, per-slice neighbour-state restart + explicit §6.4.8 same-slice availability mask for the intra predictors (top / left / top-left individually), constrained_intra_pred_flag = 1 dropping inter neighbours for the Intra_16x16 fallback in P slices, reverse-order slice emission (ASO), redundant_pic_cnt = 1 re-encodes at QP + 6. 12 gates bit-exact in our decoder; the multi-slice / constrained-intra / slice-boundary streams also byte-exact in the black-box reference decoder (which lacks FMO and ASO and does not discard redundant slices)
SEI writers (r430 / r453) encoder::sei buffering_period + pic_timing (HRD rate-controlled sessions) and recovery_point (r453, SessionConfig::recovery_point_sei) on every IDR access unit (recovery_frame_cnt = 0, exact_match_flag = 1), round-tripped through the decoder's §D.1 parsers

Goals

  • Spec-faithful: every clause of §7, §8, §9 implemented from the spec text. Comments cite the clause number being implemented.
  • Pure Rust: no unsafe outside what the std-lib already requires; no C dependencies.
  • No external decoder code: nothing copied from any reference implementation. Conformance is verified by output diff against an independent reference decoder, not by code reading.
  • Pluggable into the existing oxideav Decoder / Encoder trait surface (decoder AND encoder factories are registered with the codec registry; both stay directly callable per the dual-API convention).

Benchmarks

Criterion benches live under benches/:

  • inter_pred_bench — §8.4.2 luma + chroma fractional interpolation (scalar / chunked / default 6-tap kernels, 4x4 / 8x8 / 16x16 blocks).
  • transform_bench — §8.5 inverse 4x4 and 8x8 transforms at QP 26.
  • decode — end-to-end H264CodecDecoder over five in-process corpora: 64x64 + 128x96 Baseline IDR, IDR+4×P Baseline chain, IDR+P+B Main GOP, and a 64x64 High 4:2:2 IDR. All streams are synthesised from oxideav-h264's own encoder so the bench needs no on-disk fixtures.
  • encode — sibling to decode, driving the public encoder entry points across seven in-process variants: Baseline CAVLC IDR (64x64 + 128x96), Baseline IDR + 4×P chain (real per-MB integer ME), Main IDR + P + B GOP (§8.4.1.2.2 spatial-direct + bipred), CABAC IDR + IDR + P (encode_idr_cabac / encode_p_cabac with the trellis-quant refinement on), and High 4:2:2 IDR. Reports both per-frame (Throughput::Elements, ≈ frames-encoded per second) and per-source-byte (Throughput::Bytes, MiB/s of raw planar input absorbed). The encoded-stream byte count is a compression-efficiency metric and stays in the integration tests rather than the bench.

Run with cargo bench --bench decode -- --quick or cargo bench --bench encode -- --quick for fast smokes, or omit --quick for the full Criterion report.

Profiles + features in scope

The long-term target is a complete implementation of ITU-T Rec. H.264 | ISO/IEC 14496-10 — every profile and every coding tool in the spec. We're starting from the subset in widespread use and widening out from there:

Phase Profiles Bit depths Chroma Coding
1 (now) Baseline (66), Main (77), High (100) 8 4:2:0 Frame + PAFF + MBAFF (decode r413/r416, encode r416/r453)
2 + High10 (110), High 4:2:2 (122) + 10-bit + 4:2:2 done
3 + High 4:4:4 Predictive (244), Extended (88) — SP/SI + data partitioning done r451 + 12 / 14-bit (decode gated r451, encode + lossless r456) + 4:4:4, 4:0:0, separate colour planes (done r448) Full coverage
4 + Annex F SVC, Annex G MVC, Annex H 3D-AVC, Annex I 3D-AVC depth all all all

Intermediate profiles (High 10 Intra, CAVLC 4:4:4 Intra, etc.) land opportunistically as the pieces they need go in. Nothing in the spec is considered out-of-scope forever — the table is a phasing plan, not a scope fence.

License

MIT — see LICENSE.