Repository navigation
v0.0.3
Other
- §6.5.1 tile sizes helper; README full-stream front-end map
- complete sequence header + every-frame-type frame header with reference state (§7.20/§7.21), set_frame_refs, setup_shear, tile groups
- every-frame-type uncompressed header with cross-frame state, §8.6.1 quantizers, §8.8.1 filter levels, superframes
- full-stream front end — complete slice segment header, POC / RPS marking / ref lists, scaling lists
- full-stream front end for hardware bridges — complete slice header, POC, frame-store DPB, scaling lists
- edition 2024, MSRV 1.95
- iterator-shape the VPS dependency-closure loops for clippy 1.95
- complete VPS walk (7.3.2.3) + byte-exact writer — multi-layer dependency block, OLS modes 0/1/2 with 7.4.3.3 derivations, PTL list, per-OLS DPB + timing/HRD; VPS fixed point in fuzz
- H.266 SPS/PPS complete + byte-exact writers, HEVC typed SEI encode incl. BP/PT, AV1 sequence-header + VP9 keyframe writers, fuzz fixed-point roster
- H.266 SPS/PPS + HEVC typed-SEI/BP/PT + AV1 sequence-header + VP9 header fixed points in parsers target; av1 timing_info zero-clock guard
- keyframe uncompressed-header writer, byte-exact on the IVF fixture; fix 4-bit misparse (refresh_frame_context pair + raw frame_context_idx were skipped) and re-pin fixture expectations
- sequence-header OBU writer, byte-exact on the keyframe fixture; lossless timing/colour-description retention + 6.4.2 identity-branch fix
- typed SEI encoders + HRD-coupled BP/PT decode+encode against a SeiHrdContext (D.2.2/D.2.3 — IRAP CPB params, alt delays, use_alt extension slot, decoding-unit lists)
- complete PPS walk (7.3.2.5) + byte-exact writer — tile grid + rectangular-slice layout via replayed 6.5.1 derivations, chroma/deblocking blocks, bounded by Table A.2 limits
- complete SPS walk (7.3.2.4) + byte-exact writer — subpics, DPB, HRD, RPL templates, chroma-QP tables, range extension, opaque VUI block
- H.266 writer-surface cell — OPI/DCI/APS/AUD/SEI byte-exact, SPS/PPS writers still gated on structural parses
- OPI + DCI parse + byte-exact writers on a lossless profile_tier_level/GCI walk; fuzz fixed points
- HEVC writer + H.266 APS/SEI fixed points in parsers target; fix two H.266 SEI truncation soundness holes (zero-fill decode, ue-at-end phantom read); reject reserved max_sub_layers 7
- SEI framing (7.3.6) + complete Annex-D payload set — BP/PT/DUI with context, nesting, SLI, manifest, prefix indication, CREI; decode + byte-exact encode
- APS family (7.3.2.6) — ALF + LMCS + scaling-list payloads, parse + byte-exact writers, spec-range enforcement
- byte-exact VPS/SPS/PPS writers on a lossless parse (PTL constraint/sub-layer bits, raw ST-RPS coding, ordering tables, cprms flags retained); fixture-pinned
- complete VPS walk (7.3.2.1) — layer sets, timing info, HRD list with cprms inheritance
- extend parsers target to SEI/metadata/framing + fixed-point invariants; README refresh
- SEI module (7.3.5 framing + HDR payloads) + fuzz-found CtbLog2SizeY shift-overflow fix
- Annex-B <-> length-prefixed framing converters
- metadata OBU family (5.8) — parse + write for all five registered types
- full SPS/PPS walk — scaling lists, PCM, ST-RPS (7.4.8 derivation), LT-RPS, VUI/HRD, tiles, range extensions
- byte-exact SPS/PPS writers (parse->write pinned on both fixtures)
- SEI family — sei_rbsp/sei_message framing + 5 typed payload decoders
- full SPS/PPS walk — scaling lists (7.3.2.1.1.1) + VUI/HRD (Annex E)
- untrack Cargo.lock (+anchored .gitignore); neutral wording in provenance comments
- add CI / crates.io / docs.rs / MIT-license badges
- refresh to current status, drop per-round changelog cruft
- add parsers fuzz target; fix H.264/HEVC SPS log2_max panic
- AV1 §4.10.3 uvlc() + §4.10.4 le(n) — §4.10 descriptor family complete
- AV1 §4.10.6 su(n) signed integer descriptor
- ns(n) — AV1 §4.10.7 non-symmetric unsigned
- peek_bits_u64 — 64-bit non-advancing peek
- access unit delimiter parse + write
- neutral wording in ivf.rs module doc
- write_header + write_frame + write_all — muxer inverse of the demuxer
- shared ebsp_to_rbsp + new rbsp_to_ebsp inverse
- SPS-context picture-header parser (ph_pic_order_cnt_lsb + ph_recovery_poc_cnt) plus three new SPS fields
- structural picture-header prefix parser (7.3.2.7 / 7.3.2.8)
- i(n), te(v), signed_magnitude, read_bytes + write inverses
Changed
- edition 2024, MSRV 1.95.
Added
- h264: full-stream front end for hardware decode bridges.
h264::slice::parse_slice_headerwalks the complete §7.3.3 slice
header for I/P/B/SP/SI slices (ref_pic_list_modification,
pred_weight_table with §7.4.3.2 inferred defaults, dec_ref_pic_marking
incl. every MMCO, field / MBAFF fields, QP / deblocking) and records
whereslice_data()starts (RBSP bits and the escaped in-NAL bit
offset).h264::stream::H264Parserkeeps SPS/PPS tables, yields
per-NAL events and detects the first slice of each primary picture
(§7.4.1.2.4).h264::pocderives picture order counts of types 0/1/2
(§8.2.1) with their cross-picture state and the MMCO 5 rebasing.
h264::dpb::Dpbis a frame-store DPB: picture numbers (§8.2.4.1),
P/B list initialisation for frames and fields incl. the §8.2.4.2.5
parity interleave, list modification (§8.2.4.3), IDR / sliding-window
/ MMCO 1–6 marking (§8.2.5), gaps in frame_num with non-existing
frames (§8.2.5.2) and field pairing into one store.
h264::scalinggives the scaling lists in effect (Table 7-2 fall-back
rules A/B, Tables 7-3/7-4 defaults, Table 8-13/8-14 scans).
H264Spsgainsmax_frame_num/max_pic_order_cnt_lsb/
pic_width_in_mbs/frame_height_in_mbs/chroma_array_type/
crop_rect;nal::emulation_prevention_bytes_before/
rbsp_offset_to_ebspmap RBSP offsets back into escaped NAL units.
Verified field by field againsttrace_headerson B-pyramid, weighted
(luma + chroma), MBAFF, PAFF (long-term, MMCO 1, B fields, mixed
frame/field), multi-ref, CAVLC-B and scaling-matrix streams, the DPB
contents after every reference picture againstffmpeg -debug mmco,
and POC order against container presentation order. - hevc: full-stream front end.
hevc::slice::parse_slice_segment_header
walks the complete §7.3.6.1 header for single-layer, non-SCC streams
— inline or SPS-indexed short-term RPS (inline inter-set prediction
withdelta_idx_minus1), long-term pictures with eq. 7-52
accumulation,ref_pic_lists_modification(),pred_weight_table()
with the §7.4.7.3 derived weights / offsets, collocated / TMVP, QP
offsets, deblocking overrides, entry points, header extension,
byte_alignment()— completes dependent segments from their
independent segment, and reports the slice-data byte offset, the
emulation prevention bytes inside the header and the inline RPS bit
size.hevc::stream::HevcParserkeeps VPS/SPS/PPS tables and yields
per-NAL events.hevc::dpb::HevcDpbderives NoRaslOutputFlag and
RASL skipping (§8.1.3), PicOrderCntVal (§8.3.1), the five RPS lists
with DPB marking (§8.3.2) and RefPicList0/1 (§8.3.4).
hevc::scalingresolves the scaling lists in effect (Tables 7-5/7-6,
list prediction, DC values, eq. 7-50 chroma 32x32, §6.5.3 scan).
Verified againsttrace_headerson x265 open-GOP B-pyramid (CRA +
RASL, WPP, two slices), weighted + scaling-list, Main 10, tiles,
multi-slice and WPP streams, and POC against presentation order.
hevc::slice::tile_sizes_in_ctbsgives the §6.5.1 tile column
widths / row heights. - vp9:
vp9::frame— the uncompressed header of every frame type
(key, inter withframe_size_with_refs(), intra-only incl. the
profile 0 colour inference,show_existing_frame) parsed against a
Vp9Statethat carries reference slot sizes / colour, loop filter
deltas and segmentation features across frames with the §7.2
setup_past_independence()resets; the header reports the values in
force. Adds the §8.6.1dc_q/ac_qtables (8/10/12-bit, checked
against the spec text) withget_qindex()/get_dc_quant()/
get_ac_quant(), the §8.8.1LvlLookuptable and Annex B
split_superframe. Verified againsttrace_headerson 15 streams
(alt-ref pyramid, superframes, show_existing_frame, intra-only,
scaled references, resizing, segmentation features, lf deltas,
frame-parallel, 10-bit, 4:4:4, lossless) and the in-force state
against the decode traces staged indocs/video/vp9/fixtures/. - av1:
av1::sequence::parse_sequence_header_obu— the complete
§5.5 sequence header (every operating point,decoder_model_info(),
operating parameters, initial display delays).av1::frame— the
§5.9 uncompressed header for key, inter, intra-only and switch
frames andshow_existing_frameagainstAv1RefState: frame ids
withmark_ref_frames(),ref_order_hint[], short reference
signaling via the §7.8 set_frame_refs process,frame_size_with_refs(),
superres, uniform / explicit tile info, quantization with matrices,
segmentation and loop filter deltas fromload_previous()or
setup_past_independence(), delta q / lf, CDEF, loop restoration,
TX mode, reference select, skip mode frames, warped motion, global
motion decoded againstPrevGmParams, film grain incl.
load_grain_params(), lossless derivation;Av1RefState::updateis
the §7.20 reference frame update (after the §7.21 load for a shown
existing key frame). Alsosetup_shear()(§7.11.3.6 with the
§7.11.3.7Div_Lut, checked against the spec text),
default_gm_params(),LOOP_FILTER_REF_DELTAS_DEFAULT,
parse_tile_group()andav1::iter_obus. Verified against
trace_headerson 39 committed streams (and all 140 staged in
docs/video/av1/fixtures/locally): short refs, switch frames,
error resilience, frame ids, show_existing frames, global motion,
film grain (AR, CSFL, lag 3, predicted), superres + tiles, tile
groups, segmentation, QM, delta q/lf, LR, CDEF, skip mode, temporal
/ spatial layers, 10/12-bit, monochrome, 4:4:4, SVT-AV1 random access
with overlays. - fuzz: new
streamstarget drives elementary streams through the
stateful front ends (H.264 parser + POC + DPB, HEVC parser + RPS +
lists, VP9 superframes + header state, AV1 OBUs + frame header state +
tile groups); theparserstarget also runs the complete H.264 slice
header and HEVC slice segment header. - h266: complete VPS walk (§7.3.2.3) —
parse_vpsnow retains every
syntax element ofvideo_parameter_set_rbsp()including the
multi-layer machinery (inter-layer dependency block, OLS modes
0/1/2 with the §7.4.3.3TotalNumOlss/NumMultiLayerOlss
derivations and the mode-2 reference-layer transitive closure, the
PTL list with per-slot max-tid, per-multi-layer-OLS DPB sizing and
the OLS timing/HRD list), andwrite_vps/write_vps_nalare its
byte-exact inverses. Single-layer VPSs — previously cut short after
vps_layer_id[0]— now walk their PTL slot, extension bits and
trailing bits too.VvcVpsis the lossless representation
(layers/ptls/dpb_params/ols_dpbs/timing_hrd
replace the old prefix-only fields). - fuzz: the parsers target now asserts parse→write fixed points for
the H.266 full-walk SPS/PPS, the HEVC typed SEI families (context
free viaencode_sei_message, and BP/PT against an SPS-VUI HRD
context recovered from an input prefix), the AV1 sequence header
and the VP9 keyframe uncompressed header.parse_sequence_header
additionally rejects zerotiming_infoclock fields (§6.4.3) so
the writer inverse holds over the full accepted envelope. - vp9:
write_uncompressed_header— inverse of
parse_uncompressed_headerover the keyframe envelope (§6.2 incl.
colour config, loop-filter/quant/segmentation blocks, tile info and
the byte-alignment padding), byte-exact on the crate's IVF fixture.
Fixed
- vp9: the keyframe walk skipped the §6.2
refresh_frame_context/
frame_parallel_decoding_modepair and the rawframe_context_idx
f(2), shifting every later field (loop filter, quant, segmentation,
tiles,header_size_in_bytes) by four bits. The fixture
expectations pinned that misparse and are re-pinned to the correct
walk (base_q 37 / loop-filter 2 / 186-byte compressed header, with
the encoder explicitly coding the spec-default ref deltas
[1, 0, -1, -1]). The raw coded index is retained on a new
coded_frame_context_idxfield; the derivedframe_context_idx
stays 0 per the intra reset. - av1:
write_sequence_header— byte-exact inverse of
parse_sequence_headerover the single-operating-point envelope
(§5.5 incl.trailing_bits()), pinned byte-exact on the crate's
keyframe fixture. The parser now retainstiming_info(), the
initial-display-delay pair, the colour-description triple and
separate_uv_delta_qlosslessly, and gains the §6.4.2 identity
(sRGB 4:4:4) branch — identity streams previously misread a
color_rangebit that the spec never codes there. - hevc: typed SEI write direction —
encode_sei_messageis the
inverse ofdecode_sei_messagefor every context-free family
(MDCV, CLL, recovery point, ITU-T T.35, user-data-unregistered,
raw pass-through), and the HRD-coupled pair gains typed decode +
encode:decode_buffering_period/encode_buffering_period
(§D.2.2 — IRAP CPB params, NAL/VCL initial-delay lists sized by
CpbCnt, alt delays, theuse_alt_cpb_params_flag
payload-extension slot) anddecode_pic_timing/
encode_pic_timing(§D.2.3 — frame-field info, AU/DPB delays,
sub-picture decoding-unit lists with common or per-DU removal
increments), both against aSeiHrdContextcarrying the SPS-VUI
hrd_parameters()+ sub-layer id +frame_field_info_present_flag.
Hostilenum_decoding_units_minus1counts are bounded by the
remaining payload. - h266: complete PPS walk (§7.3.2.5) —
parse_ppsnow retains every
syntax element ofpic_parameter_set_rbsp()through
rbsp_trailing_bits()andwrite_pps/write_pps_nalare its
byte-exact inverses. New coverage: subpicture id mapping, the tile
grid (explicit columns/rows + §6.5.1 uniform-fill derivation), the
rectangular-slice layout (per-slice width/height presence
conditions driven by a replayedSliceTopLeftTileIdxwalk,
tile-splitting via explicit CTU-row slice heights with the
NumSlicesInTileadvance, raster and out-of-order
pps_tile_idx_delta_valwalks), chroma tool offsets + CU chroma-QP
offset lists, deblocking control, the in-PH signalling flags and
verbatimpps_extension_dataretention. Loop-driving counts are
bounded by the Table A.2 level-6.3 limits (MaxTileCols ≤ 30,
MaxTilesPerAu ≤ 990,MaxSlicesPerAu ≤ 1000). - h266: complete SPS walk (§7.3.2.4) —
parse_spsnow retains every
syntax element ofseq_parameter_set_rbsp()through
rbsp_trailing_bits()andwrite_sps/write_sps_nalare its
byte-exact inverses. New coverage: subpicture layout (geometry
inference incl. the same-size grid, treated-as-pic / loop-filter
flags, explicit id mapping),dpb_parameters()(§7.3.4),
general_timing_hrd_parameters()/ols_timing_hrd_parameters()/
sublayer_hrd_parameters()(§7.3.5) with CPB schedule lists,
ref_pic_list_struct()templates (§7.3.10, ST/LT/inter-layer
entries), chroma-QP mapping tables, all partition / coding-tool
flags, LADF, virtual boundaries,sps_range_extension(), verbatim
sps_extension_dataretention and the opaque byte-aligned
vui_payload()block. §7.4 value ranges are enforced (MaxDpbSize,
MaxSlicesPerAu,hrd_cpb_cnt_minus1 ≤ 31, RPL bounds, …) so
hostile counts cannot drive unbounded loops. The DPB / HRD / RPLS
sub-structures live in a new publich266::paramsmodule for reuse
by the VPS walk.
Changed
- h266:
VvcPpsis now the lossless full-walk representation —
presence flags gating unparsed blocks are replaced byOption
fields (pps_conf_win_offsets,pps_scaling_win_offsets,
subpic_id_mapping,partition,chroma_tool_offsets,
deblocking,pps_pic_width_minus_wraparound_offset), and
parsing no longer stops atpps_subpic_id_mapping_present_flag. - h266:
VvcSpsis now the lossless full-walk representation —
presence flags that gated unparsed blocks
(sps_ptl_dpb_hrd_params_present_flag,
sps_subpic_info_present_flag) are replaced by the corresponding
Optionfields, and subpicture streams no longer return
Unsupported. - h266: OPI + DCI RBSPs —
parse_opi/write_opi/write_opi_nal
(operating point information, §7.3.2.2) andparse_dci/
write_dci/write_dci_nal(decoding capability information,
§7.3.2.1 with 1..=16profile_tier_level(1, 0)entries), both
byte-exact parse→write inverses.profile_tier_level()parsing is
now lossless: thegeneral_constraints_info()(§7.3.3.2) content
bits are retained verbatim onVvcProfileTierLevel(new
gci_present_flag/gci_bitsfields) and a public
write_profile_tier_levelemits the full §7.3.3.1 structure.
Unretainedopi/dci_extension_flag == 1payloads are refused as
Unsupported. - h266: SEI family — new
h266::seimodule with the §7.3.2.9 /
§7.3.6sei_rbsp()/sei_message()framing (0xFF run-length
accumulation, declared-size validation, byte-exact framing writers)
plus typed decode and byte-exact encode for every payload whose
syntax lives in H.266 Annex D: buffering_period (§D.3,
self-contained length fields), pic_timing (§D.4) and
decoding_unit_info (§D.5) against aVvcBufferingPeriod+
TemporalIdcontext (alt-CPB timing, decoding-unit blocks and the
§D.4.2/§D.5.2 inferences included), scalable_nesting (§D.6, nested
messages surfaced raw), subpic_level_info (§D.7), sei_manifest
(§D.8), sei_prefix_indication (§D.9) and the empty
constrained_rasl_encoding_indication (§D.10). Payload-alignment
bits are verified; H.274-delegated payload types surface raw via
VvcSei::Unknownper §D.2.2. - h266: adaptation parameter set family — new
h266::apsmodule with
the complete §7.3.2.6adaptation_parameter_set_rbsp()walk and
all three payload families: ALF (§7.3.2.18 — luma/chroma
coefficient sets with clipping indices plus both cross-component
filter banks), LMCS (§7.3.2.19 — piecewise-linear model incl. the
chroma residual scaling delta) and scaling lists (§7.3.2.20 — all
28 ids in §6.5.2 up-right-diagonal delta coding with the 64×64
quadrant skip and copy/pred-mode referencing). Byte-exact writers
(write_aps/write_aps_nal) round-trip every accepted parse;
spec ranges are enforced (alf_luma_num_filters_signalled_minus1 ≤ 24, coefficient magnitudes ≤ 128, LMCS bin-index ordering,
scaling_list_pred_id_delta ≤ maxIdDelta, delta coefficients in
−128..=127). Reservedaps_params_typevalues and
aps_extension_flag == 1are refused asUnsupported. - hevc: byte-exact VPS/SPS/PPS writers —
write_vps/write_vps_nal,
write_sps/write_sps_nalandwrite_pps/write_pps_nalare full
inverses of the parsers (§7.3.2.1/§7.3.2.2.1/§7.3.2.3.1 +
rbsp_trailing_bits(), canonical layer-0/TID-0 NAL headers,
emulation-prevention encoding), pinned byte-exact against the
reference fixture's parameter sets and against synthetic streams
covering scaling lists, PCM, explicit + inter-predicted ST-RPS,
long-term pics, VUI/HRD, tiles, the range extensions and
cprms-inherited VPS HRD entries. Hand-built structs are validated
structurally (gate-flag/Optionconsistency, list-length vs.
declared-count checks, §7.4.8 re-derivation of inter-predicted RPS
resolved vectors); unrepresentable inputs (vps_extension_flag,
non-zerosps/pps_extension_4bits, multilayer/3D/SCC extensions)
are refused asUnsupported. - hevc: lossless parse retention backing the writers —
HevcProfileTierLevelnow keeps the 48 constraint/reserved bits,
the inter-flag reserved run and every coded sub-layer profile/level
entry (HevcSubLayerPtl/HevcSubLayerProfile); VPS/SPS keep the
raw sub-layer ordering tables (HevcSubLayerOrderingInfo) and
present flags;HevcShortTermRpsrecords its raw §7.3.7 coding
(HevcStRpsCoding); VPS entries keepvps_reserved_0xffff_16bits
and per-entrycprms_present_flag(newHevcVpsHrdEntryreplaces
the(idx, hrd)tuple); SPS/PPS keep*_extension_present_flag+
*_extension_4bits.
Changed
- hevc: the per-sub-layer DPB cap (
max_dec_pic_buffering_minus1 ≤ 15,
§A.4.2) is now enforced on every coded VPS/SPS ordering-info
entry, not just the highest sub-layer's;vps_max_sub_layers_minus1
/sps_max_sub_layers_minus1now reject the reserved value 7
(§7.4.3.1 / §7.4.3.2.1 pin the range to 0..=6). - fuzz:
parserstarget now asserts the HEVC VPS/SPS/PPS
parse→write→parse fixed points (writer refusals restricted to the
documentedUnsupportedenvelopes), the H.266 APS fixed point, the
H.266 SEI framing fixed point, decode→encode byte fixed points
for every typed Annex-D payload, and the BP-context PT/DUI pair
from a split input.
Fixed
-
h266/sei: two fuzz-found truncation soundness holes in the typed SEI
decoders — (1) a payload shorter than its syntax decoded as zeros
via the shared reader's zero-fill-past-the-end contract (e.g. an
emptysei_manifest"decoded" as a zero-entry manifest); the
payload-alignment check now rejects any over-read; (2)ue(v)
invoked exactly at the end of a payload returned 0 without
consuming anything, letting truncatedpic_timing/
decoding_unit_info/ nesting payloads decode as if a real zero
had been coded; all Annex-Due(v)reads now fail hard at
end-of-payload. Both breaks were caught by the new decode→encode
byte fixed points and carry regression tests. -
h264: complete SPS parse — scaling lists (§7.3.2.1.1.1
scaling_list()
withUseDefaultScalingMatrixFlagand freeze-after-zero semantics) and
full VUI/HRD (Annex E §E.1.1/§E.1.2: aspect ratio incl. Extended_SAR,
overscan, video signal type + colour description, chroma loc, timing
info, NAL/VCL HRD with CPB schedule entries, low-delay flag,
pic_struct, bitstream restriction). New typesH264ScalingLists,
H264Vui,H264HrdParameters,H264CpbEntry; helpers
sample_aspect_ratio()(Table E-1),field_rate()/frame_rate()
(§E.2.1),bit_rate()/cpb_size()(§E.2.2). -
h264: PPS scaling lists via new
parse_pps_with_sps/
parse_pps_nal_with_sps(§7.3.2.2 list count depends on the active
SPSchroma_format_idc);parse_idr_onlyfeeds the SPS context
through automatically. -
h264: hostile-input guards —
delta_scalerange (−128..=127,
§7.4.2.1.1.1) andcpb_cnt_minus1 ≤ 31(§E.2.2) bound all loops. -
h264: SEI parsing —
h264::seimodule with §7.3.2.3/§7.3.2.3.1
sei_rbsp()/sei_message()framing (0xFF run-length payloadType /
payloadSize accumulation, declared-size-vs-actual-bytes validation)
plus byte-exact framing writers (write_sei_message/
write_sei_rbsp). Typed decoders: buffering_period (§D.1.2, HRD
field widths from the active SPS), pic_timing (§D.1.3 incl. the full
clock-timestamp ladder, NumClockTS per Table D-1, reserved
pic_struct rejected), user_data_registered_itu_t_t35 (§D.1.6),
user_data_unregistered (§D.1.7), recovery_point (§D.1.8); every
other type surfaced raw per §D.2.1. -
h264: byte-exact SPS/PPS writers —
write_sps/write_sps_naland
write_pps/write_pps_nalare full inverses of the parsers
(§7.3.2.1.1 / §7.3.2.2 +rbsp_trailing_bits(), NAL wrapping with
emulation-prevention insertion). parse→write reproduces both h264
fixtures' SPS and PPS RBSP bytes exactly. Parser now also retains
the POC-type-1 offset fields (offset_for_non_ref_pic,
offset_for_top_to_bottom_field,offsets_for_ref_frame) and the
coded scaling-list count, and bounds
num_ref_frames_in_pic_order_cnt_cycleto 0..=255 (§7.4.2.1.1).
PPS recordshigh_profile_tail_presentso the optional §7.3.2.2
tail round-trips bit-for-bit. -
hevc: SPS/PPS walk driven to the extension flags — every former
Unsupportedrefusal except SCC/multilayer/3D payloads now parses:
scaling_list_data (§7.3.4 with §7.4.5 range checks), PCM block,
short-term RPS with the full §7.4.8 inter-set-prediction derivation
(7-59..7-71) resolved toDeltaPocS0/S1form, long-term RPS,
VUI/HRD (§E.2.1/§E.2.2/§E.2.3 incl. sub-pic HRD fields and
per-sub-layer CPB schedules), SPS/PPS range extensions
(§7.3.2.2.2/§7.3.2.3.2), PPS tile grid + WPP. New types
HevcScalingListData,HevcShortTermRps,HevcVui,
HevcHrdParameters,HevcCpbEntry,HevcTiles,
Hevc{Sps,Pps}RangeExtension,HevcDefaultDisplayWindow; helpers
sample_aspect_ratio()(Table E.1),picture_rate()(§E.3.1),
num_negative_pics()/num_positive_pics()/num_delta_pocs()
(7-63/7-64/7-71). -
hevc: hostile-input bounds —
sps_max_dec_pic_buffering_minus1 ≤ 15
(§A.4.2 MaxDpbSize cap),num_short_term_ref_pic_sets ≤ 64,
num_long_term_ref_pics_sps ≤ 32(§7.4.3.2.1),cpb_cnt_minus1 ≤ 31
(§E.3.2),chroma_qp_offset_list_len_minus1 ≤ 5(§7.4.3.3.2),
tile column/row counts checked against remaining payload bits. -
av1: metadata OBU family (§5.8) —
parse_metadata_obu/
write_metadata_obucovering HDR CLL (§5.8.3), HDR MDCV (§5.8.4),
scalability incl. the fullscalability_structure()(§5.8.5/§5.8.6,
SCALABILITY_SS), ITU-T T.35 (§5.8.2 with the last-non-zero-byte
trailing rule enforced both ways) and timecode (§5.8.7 ladder);
reserved/user-private types surfaced raw per the §5.8.1 note. All
five families round-trip through the writer, including end-to-end
framing throughwrite_obu/read_obu. -
nal: framing converters —
split_length_prefixed,
annex_b_to_length_prefixed,length_prefixed_to_annex_bre-frame
elementary streams between Annex-B start-code form (ITU-T Annex B)
and 1..4-byte big-endian length-prefixed form (ISO base-media
sample framing) without touching NAL bodies. Declared lengths are
validated against actual bytes; oversize NALs that cannot fit the
prefix width are refused. -
hevc: SEI module (
hevc::sei) — §7.3.5sei_message()framing
(prefix type 39 + suffix type 40 NALs both accepted) with byte-exact
framing writers, plus typed decoders for ITU-T T.35 (§D.2.6),
user_data_unregistered (§D.2.7), recovery_point (§D.2.8, signed
recovery_poc_cnt), mastering_display_colour_volume (§D.2.28, type
137) and content_light_level_info (§D.2.35, type 144); everything
else surfaced raw per §D.3.1. -
fuzz: parsers target now drives H.264 SEI (context-free + SPS-coupled
decode), HEVC SEI, AV1 metadata, and the framing converters at every
prefix width, and asserts parse→write→parse fixed points (H.264
SPS/PPS/SEI, HEVC SEI, AV1 metadata, length-prefixed framing) on
every successful parse. -
hevc: VPS walk completed through
vps_extension_flag(§7.3.2.1) —
base-layer flags, sub-layer ordering info (DPB/reorder/latency,
§A.4.2 cap enforced),vps_max_layer_id+ layer-set inclusion
bitmasks (vps_num_layer_sets_minus1 ≤ 1023enforced), timing info,
and the HRD list with the §7.4.3.1cprms_present_flag == 0
common-info inheritance from the previous entry.
Fixed
- hevc: fuzz-found panic — a hostile SPS with out-of-range coding-block
log2 fields drove1u32 << CtbLog2SizeYpast 31 in the
slice-segment-address width computation (and silently truncated
through the u8 struct fields). The SPS parser now rejects
CtbLog2SizeYoutside 4..=6 (§A.3 profile conformance) and the
slice-header parser bounds the shift defensively for
caller-constructed SPS structs. - H.264 / HEVC SPS parsers now reject an out-of-range
log2_max_frame_num_minus4(H.264) and
log2_max_pic_order_cnt_lsb_minus4(H.264 / HEVC) with
InvalidData. The respective specs (H.264 §7.4.2.1.1,
H.265 §7.4.3.2.1) constrain both to0..=12, so the dependent
frame_num/pic_order_cnt_lsbfields are at most 16 bits. A
malformed SPS carrying a larger value previously slipped through SPS
parsing and then droveBitReader::u(n > 32)inside
parse_slice_header_minimal, panicking the host application on a
hostile fixture. Both fields are now validated at the SPS parse site,
mirroring the existing H.266 bound on
sps_log2_max_pic_order_cnt_lsb_minus4. Found by the newparsers
fuzz target.
Added
-
parsersfuzz target (fuzz/fuzz_targets/parsers.rs) — a second
panic-hardening harness covering the per-codec header parsers (the
layer above theBitReader/BitWriterprimitives thereader
target already hammers). It drives every context-freeparse_*entry
point of the H.264, HEVC, H.266, MPEG-2, VC-1, VP8 and VP9 modules at
several input-derived byte offsets, and feeds the context-dependent
slice / picture / entry-point parsers an SPS / PPS / sequence-header
context recovered from a prefix of the same input. The invariant under
test is purely "no panic, no overflow, no out-of-bounds, no unbounded
loop on any byte sequence." It immediately surfaced the SPS-width
panic fixed above. -
BitReader::uvlc()andBitWriter::write_uvlc(value)— AV1 §4.10.3
unsigned variable-length code, completing the §4.10 descriptor family
alongside thele(n)sibling below,leb128(§4.10.5),su(n)
(§4.10.6) andns(n)(§4.10.7). Belowu32::MAXthe bit layout
coincides with the H.26xue(v)Exp-Golomb code, but the descriptors
diverge at the top of the range:ue(v)rejects 32+ leading zeros as
a syntax error whileuvlc()saturates tou32::MAX, consuming
the zero run through its terminating1bit and reading no suffix.
Both directions are therefore total — everyu32encodes (the
saturation code is 32 zeros + the done bit, 33 bits) and every input
decodes, so neither side returns aResult. This promotes the
privateread_uvlchelper previously buried inav1.rs(used by
timing_info()'snum_ticks_per_picture_minus_1) to the shared
descriptor surface, and fixes a positional divergence from the spec
in that helper: it stopped after the 32nd leading zero, whereas
§4.10.3 keeps consuming the run through the terminating bit — on a
(hypothetical) stream with a 33+-zero run every subsequent field
would have been misread. The shared reader follows the spec loop
exactly; a dedicated test pins the post-saturation bit position with
a sentinel field packed directly behind a 40-zero run. -
BitReader::le(n)andBitWriter::write_le(value, n)— AV1 §4.10.4
unsigned little-endiann-byte number (the descriptor AV1 uses
for byte-aligned tile-size fields,tile_size_minus_1coded as
le(TileSizeBytes)).ncounts bytes, not bits, and is capped at 8
so the result fits au64;n == 0is the trivial zero-bit read.
The implementation is the spec's literal composition off(8)reads
assembled least-significant-byte first, so it is position-agnostic
(the spec only employs it byte-aligned; callers wanting strictness
can assertbyte_aligned()first). The writer rejectsn > 8and
any value that does not fit innbytes, with nothing appended on
rejection.Test delta for the pair: 9 reader + 6 writer unit tests (known-value
tables, the §4.10.3 saturation + long-run positional pins,
end-of-stream run termination, little-endian assembly, unaligned
f(8)-composition equivalence, past-the-end zero padding, rejection
paths), 6 newroundtrip_props.rsinvariants (uvlc round-trip over
boundary + random values, uvlc/ue bit-layout agreement below
saturation in both encode directions, the 33-bit saturation-code
position,leround-trips across every width × bit offset,levs
read_byteslittle-endian agreement, writer rejection hygiene), and
the reader fuzz harness now drivesuvlc()/le(n)on attacker
bytes every opcode-tape iteration plus a structureduvlc+le
writer→reader round-trip stage. -
BitReader::su(n)andBitWriter::write_su(value, n)— AV1 §4.10.6
signed integer descriptor. Readsnbits as an unsignedf(n)value,
then reinterprets the top bit as a sign per the spec arithmetic
(signMask = 1 << (n - 1); if (value & signMask) value -= 2 * signMask)
— two's-complement sign extension of ann-bit field. This is the same
numeric mapping as the H.26xi(n)descriptor but is surfaced
separately so AV1 parsers can cite §4.10.6 directly; AV1 uses it for
delta_q = su(1 + 6)(§5.9.13) and the global-motion parameter reads
(§5.9.24). Accepts widths1..=32;n == 32round-trips the full
i32range includingi32::MIN/i32::MAX. The reader rejects
n == 0(thesignMaskshift is undefined for a zero-bit signed
field) andn > 32; the writer rejects the same widths plus any value
outside the representable-(2^(n-1)) .. 2^(n-1) - 1range (no silent
truncation, so the round-trip is total for accepted inputs).Five new reader unit tests pin the spec's two's-complement decode for
every raw pattern at widths1..=8, the §4.10.6 arithmetic example
(su(4)of0b1011→-5), the full-width-32i32endpoints, the
n == 1{0, -1}alphabet, and then == 0/n > 32rejections.
Six new writer unit tests mirror the fulli8round-trip, the spec
example inverse (-5→0b1011), out-of-range and zero/oversize-width
rejections, the full-i32-at-width-32 round-trip, and an exhaustive
1..=16× full-range round-trip through the writer/reader pair. Three
newroundtrip_props.rsinvariants extend that to a 1500-value random
round-trip per width1..=32, a per-width out-of-range rejection
sweep, and a cross-check thatsu(n)andi(n)agree numerically at
every bit offset for widths up to 24 (so a future divergence in either
decoder is caught). The reader fuzz harness now also drivessu(n)on
attacker bytes every opcode-tape iteration and adds a structured
write_su→suround-trip on attacker-derived(value, n)pairs. -
BitReader::ns(n)andBitWriter::write_ns(value, n)— AV1 §4.10.7
non-symmetric unsigned integer descriptor. Outputs values in range
0..n, emittingFloorLog2(n)bits for the lower part of the range
andFloorLog2(n) + 1bits for the upper part. Used by the AV1
syntax for tile sizes (width_in_sbs_minus_1,height_in_sbs_minus_1)
and film-grainsubexp_final_bits(§5.9.15 / §5.9.30). The reader
rejectsn == 0(the spec only definesns(n)forn >= 1), caps
nat1 << 30so the internal arithmetic always fits inu32,
and short-circuitsn == 1to return 0 without consuming any bits
(the trivial single-value alphabet). The writer enforces
value < n, the samen == 0and envelope rejections, and the
same zero-bit emission forn == 1. Powers of two are handled per
the spec (w = FloorLog2(n) + 1keeps a redundant high bit;
decoders that computewfromn - 1would otherwise undershoot
by one — patched explicitly).Six new in-module reader unit tests pin the spec's
n = 5byte
layout (codes00, 01, 10, 110, 111), confirmn == 1consumes
zero bits, exercise the power-of-two branch onn = 4, walk the
n = 3two-bit-for-everyone-but-zero pattern, and rejectn == 0
/nabove the supported envelope. Five new writer unit tests
mirror the reader's spec-table pinning, the zero-bit emission for
n == 1, rejection ofvalue >= n, rejection ofn == 0and
oversizedn, and an exhaustive1..=33×0..nround-trip
through the writer/reader pair. Four newroundtrip_props.rs
invariants extend that tonup to 257 exhaustively (spanning the
power-of-two boundary at 256), a 600-pair mixed-npacking test
that catches alignment bugs the per-value tests miss, a check that
ns(1)is invisible when sandwiched between twou(8)fields,
and the writer's rejection-paths-leave-buffer-clean contract. The
reader fuzz harness now also drivesns(n)on attacker bytes
every opcode-tape iteration and adds a structuredwrite_ns→
nsround-trip on attacker-derived(value, n)pairs. -
BitReader::peek_bits_u64(n)— 64-bit counterpart of the existing
peek_bits, symmetric withBitReader::u64. Inspects up to 64 bits
ahead of the currentbit_poswithout advancing it, with the same
past-the-end "zero bits" contract asu64. Borrows the reader
&selfso callers can peek without losing other borrows. Useful for
parsers that need to inspect a wide marker (e.g. AV1's
reference_frame_idu(v) class fields up to 16 bits, leb128-aware
look-aheads on a 64-bit horizon) before deciding whether to commit
to a branch. Five new in-module unit tests cover the bit-zero case
matchingu64(64), every (offset, width) pair on a 16-byte buffer
for widths 0..=64, past-end zero-padding (both fully past-end and
partial straddle), agreement withpeek_bitsfor widths up to 32,
and the width-zero no-op. Three newroundtrip_props.rsinvariants
exercise the new primitive: a 120-iteration randomised
every-offset-every-width parity check againstu64(asserting
peek_bitsagreement for n ≤ 32 and the past-end-low-bits-zero
contract), an empty-reader panic-hardening assertion across all
widths 0..=64, and a 400-iteration writer ↔ peek round-trip across
random(value, width)field sequences. The reader fuzz harness's
opcode tape now also callspeek_bits_u64on every iteration so
attacker bytes exercise the new surface. -
Access unit delimiter (AUD) parse + write for H.264, HEVC and H.266.
Each codec module now exposes a public NAL-level entry point and its
inverse:h264::parse_aud_nal/h264::write_aud_nal(§7.3.2.4 /
§7.4.2.4): surfaces the 3-bitprimary_pic_typeand verifies the
rbsp_trailing_bits()marker. The writer accepts the full u(3)
envelope (0..=7) and rejects oversized values as
[BitstreamError::InvalidData]. Constant
H264_PRIMARY_PIC_TYPE_MAX = 7documents the envelope.hevc::parse_aud_nal/hevc::write_aud_nal(§7.3.2.5 /
§7.4.3.5): surfaces the 3-bitpic_typefield on a
two-byte-NAL-header AUD. Per the H.265 spec's
"Decoders … shall ignore reserved values" clause, the parser
accepts the full u(3) range (0..=7) — including the reserved
values 3..=7 — and returns them verbatim. The writer mirrors the
same envelope so reserved values round-trip. Three documented
pic_typeconstants (HEVC_PIC_TYPE_I_ONLY = 0,
HEVC_PIC_TYPE_P_OR_I = 1,HEVC_PIC_TYPE_B_P_OR_I = 2) plus
HEVC_PIC_TYPE_MAX = 7.h266::parse_aud/h266::write_aud(§7.3.2.10 / §7.4.3.10):
surfaces bothaud_irap_or_gdr_flagu(1) andaud_pic_typeu(3)
on aVvcAccessUnitDelimiterstruct. Same reserved-value contract
as HEVC: 3..=7 round-trip unchanged. Writer rejects fields
outside their u(1) / u(3) envelopes as
[BitstreamError::InvalidData]. ConstantsAUD_PIC_TYPE_I_ONLY,
AUD_PIC_TYPE_P_OR_I,AUD_PIC_TYPE_B_P_OR_Iand
AUD_PIC_TYPE_MAX = 7document the envelope.
Each writer emits the canonical NAL header (H.264:
nal_ref_idc = 0
/ type 9; HEVC:layer_id = 0/tid_plus1 = 1/ type 35; H.266:
layer_id = 0/tid_plus1 = 1/ type 20) followed by a 1-byte
RBSP packing the signalled field(s) plus therbsp_trailing_bits()
marker. The single-byte RBSP cannot trigger the
0x00 0x00 0x0{0..3}start-code-emulation triple, so the encoded
EBSP is byte-identical to the RBSP and no
emulation-prevention stuffing is required.Twenty-five new in-module AUD tests cover the round-trip across
every u(3) value, the canonical byte layout for representative
inputs, reserved-value pass-through (HEVC + H.266), out-of-range
field rejection on the writer side, wrong-NAL-type rejection,
truncated-input rejection, header-only-NAL rejection, and
missing-stop-bit rejection. Five newroundtrip_props.rs
invariants exercise the writer / parser pair across the full u(3)
range for each codec (with0..=255oversized-value rejection on
the writer side), and pin the exact emitted byte layout for three
representative inputs (one per codec). -
BitWriter::write_rbsp_trailing_bits()— the exact inverse of
[BitReader::read_rbsp_trailing_bits]. Writes a single
rbsp_stop_one_bit(= 1) followed by enoughalignment_zero_bit
values to push the bit cursor to the next byte boundary. Three new
bit_writerunit tests cover the byte-boundary canonical case
(writer at bit 0 -> emits0x80), the
start-at-every-bit-position-then-reader-accepts-marker invariant
(prefix_bits ∈ 0..8), and the seven-payload-bits-fill-one-byte
case (0xffis a valid AUD RBSP). The H.264, HEVC and H.266 AUD
writers above use this helper to terminate their 1-byte RBSPs. -
IVF muxer (
ivf::write_header,ivf::write_frame,ivf::write_all)
— the inverse of the existing demuxer (parse_header,parse_frame,
parse_all).write_headeremits a 32-byteDKIFglobal header
exactly matching the reader's strict fixed-byte checks (version = 0
LE u16,header_len= 32 LE u16, zeroed reserved tail).write_frame
appends a 12-byte per-frame header (LE u32 size + LE u64 timestamp)
followed by the payload bytes.write_allis a convenience that
emits the global header plus an iterator of(timestamp, payload)
frames in one allocation. Each writer returns the
(start, end)byte range covering the appended block so callers
composing a larger container can locate the new bytes.write_frame
validatespayload.len() <= IVF_FRAME_PAYLOAD_MAX(the u32 wire
envelope) andwrite_alldoes the same pre-flight sweep across every
frame, leaving the output buffer untouched on rejection — mirroring
the rejection contract onav1::write_obu/av1::write_leb128.
Three new public byte-length constants document the wire-format
envelope:IVF_HEADER_LEN = 32,IVF_FRAME_HEADER_LEN = 12,
IVF_FRAME_PAYLOAD_MAX = u32::MAX as usize. Ten newivfunit
tests cover the lone-header round-trip, prefix-preserving append,
reserved-tail zeroing, single-frame and empty-payload round-trips,
multi-framewrite_all↔parse_all, the empty-frame-list case,
documented byte-offset placement, in-order concatenation of two
frames, and the boundary constant pinning. Five new
roundtrip_props.rsinvariants exercise the writer: a 5000-iteration
randomised global-header round-trip across four FourCCs and every
u16/u32 field width, a 2000-iteration frame round-trip with payload
lengths in 0..=4096, a 200-stream multi-framewrite_all
round-trip with 0..=16 frames per stream and per-frame payload
lengths up to 255 bytes, a 200-iteration "returned-range locates
appended block" check on top of a hand-written prefix, and a
fixed-byte-layout pin that matches the reader's strict checks.
Thefuzz/reader.rstarget now also (a) callsparse_header,
parse_frameandparse_allon attacker bytes (panic-hardening),
and (b) driveswrite_all+ an incrementalwrite_header+
write_framesequence from attacker-derived fields and asserts the
two paths produce byte-identical output thatparse_allrecovers. -
New
nalmodule hosting the shared
emulation_prevention_three_byte(0x03) byte-level helpers used by
every NAL-framed codec in the crate.nal::ebsp_to_rbsp(the
stripper) is identical to the byte-identical copies previously
carried byh264,hevcandh266; those three modules now
re-export the shared definition so a future drift can no longer
affect just one codec.nal::rbsp_to_ebspis the inverse — the
encoder-side inserter that takes an RBSP built throughBitWriter
and emits a wire-framed EBSP. It escapes every0x00 0x00 Xtriple
withX ∈ {0x00, 0x01, 0x02, 0x03}per ITU-T H.264 §7.4.1.1 /
H.265 §7.4.1.1 / H.266 §7.4.2.1, and appends the trailing escape
guard the spec mandates when the RBSP ends on a0x00 0x00
suffix. Eleven newnalunit tests cover canonical triple
stripping, every escaped third-byte value (0x00..=0x03), the
unescaped third-byte boundary at 0x04, longer interior zero runs
whose escapes overlap, the trailing-zero-guard round-trip, the
unaffected-bytes pass-through, and the empty-input identity. Three
newroundtrip_props.rsinvariants: a 11-length × 200-iteration
random RBSP round-trip through the inverse pair plus 14
hand-constructed edge cases (empty, lone0x00, three-zero clusters,
the all-zeros sequence at lengths 8 and 9, interior triple-zero
windows); a "no forbidden window" scan asserting the framed EBSP
contains no0x00 0x00 0x00or0x00 0x00 0x01triple at any
offset; and a re-export identity check that the three codec
modules'ebsp_to_rbspproduce byte-identical output to the shared
nal::ebsp_to_rbspon a representative fixture.
Changed
-
h264::ebsp_to_rbsp,hevc::ebsp_to_rbspandh266::ebsp_to_rbsp
are nowpub usere-exports ofnal::ebsp_to_rbsp. Behaviour is
bit-identical to the previous private copies (which were already
byte-equivalent across the three modules); the function signature
is unchanged so every existing caller (tests/h264_idr.rs,
h264::parse_sps_nal,hevc::parse_sps_nal, the H.266 SPS / PPS /
picture-header routes, etc.) continues to type-check without
modification. The module-level rustdoc on each codec now points at
the shared helper. -
H.266 / VVC SPS parser extended past
sps_bitdepth_minus8(ITU-T
H.266 §7.3.2.4). Three new structural fields are surfaced on
VvcSps:sps_entropy_coding_sync_enabled_flagu(1) (the WPP
enable HW bridges need for the per-picture VA-API / Vulkan
parameter),sps_entry_point_offsets_present_flagu(1), and
sps_log2_max_pic_order_cnt_lsb_minus4u(4). The new field drives
the bit-width ofph_pic_order_cnt_lsb(7.3.2.8) via
MaxPicOrderCntLsb = 1 << (sps_log2_max_pic_order_cnt_lsb_minus4 + 4), surfaced as theVvcSps::poc_lsb_width()and
VvcSps::max_pic_order_cnt_lsb()convenience accessors plus a new
public constantSPS_LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4_MAX = 12
(the spec envelope dictated byMaxPicOrderCntLsb ≤ 2^16). Values
outside0..=12returnBitstreamError::InvalidData. -
H.266 / VVC SPS-context picture-header parser
parse_picture_header_with_sps(nal_body, &VvcSps)(ITU-T H.266
§7.3.2.8). Extends the context-freeparse_picture_header()by
threading the active SPS through, so the parser can resolve the
ph_pic_order_cnt_lsbu(v) width (from
sps_log2_max_pic_order_cnt_lsb_minus4 + 4) and decode that field
plus the conditionalph_recovery_poc_cntue(v) that follows when
ph_gdr_pic_flag = 1. Two new optional fields onVvcPictureHeader
surface those values (ph_pic_order_cnt_lsb: Option<u32>,
ph_recovery_poc_cnt: Option<u32>); both areSome(_)only on the
SPS-context path andNoneon the context-free
parse_picture_header()path. Everything past
ph_recovery_poc_cnt(theNumExtraPhBitsarray, the
sps_poc_msb_cycle_flagblock, every ALF / LMCS / scaling-list /
virtual-boundary / RPL / partition-constraint / deblocking /
QP-delta sub-block gated on latersps_*/pps_*flags) stays
out of scope. -
Nine new h266 unit tests cover (a) IRAP picture with 4-bit POC LSB
decoding through the SPS context, (b) a GDR picture exercising the
ph_recovery_poc_cntpath with an 8-bit POC LSB, (c) a non-IRAP
picture withinter_allowed = 0confirming the inferred-intra
branch survives the SPS-context route, (d) a 16-bit POC LSB at the
spec maximum (sps_log2_max_pic_order_cnt_lsb_minus4 = 12,
poc_lsb = 0xffff), (e) wrong-NAL-type rejection on
parse_picture_header_with_sps, (f) truncated input rejection on
the SPS-context entry, (g) oversized-ph_pic_parameter_set_id
rejection through the same entry, (h) the new SPS envelope check
(sps_log2_max_pic_order_cnt_lsb_minus4 = 13→ InvalidData) using
the existing 1080p fixture with one byte rewritten, and (i) an
independent SPS round-trip throughBitWriterthat asserts the
three new fields decode to their written values. Plus one new
tests/h266_nal_walker.rsintegration test driving a synthetic
Annex-B VPS + SPS + PPS + PH + IDR_W_RADL AU end-to-end through
split_annex_b→parse_nal_header→parse_sps→
parse_picture_header_with_spsand asserting the recovered
ph_pic_order_cnt_lsb. -
One new
tests/roundtrip_props.rsinvariant: a 1092-path
exhaustive sweep that drivesparse_picture_header_with_sps
through every legal POC LSB width
(sps_log2_max_pic_order_cnt_lsb_minus4 = 0..=12) with both an
IRAP and a GDR picture per width, exercising endpoint values
(0and2^width - 1) and 40 random mid-range values per width. -
H.266 / VVC picture-header structural-prefix parser (ITU-T H.266
§7.3.2.7 / §7.3.2.8). Newparse_picture_header()decodes a PH NAL
body (NAL_TYPE_PH) throughph_pic_parameter_set_id— the always-
present prefix a HW bridge needs to classify the picture for
random-access entry-point selection:
ph_gdr_or_irap_pic_flagu(1),ph_non_ref_pic_flagu(1),
optionalph_gdr_pic_flagu(1),ph_inter_slice_allowed_flagu(1),
optionalph_intra_slice_allowed_flagu(1) and
ph_pic_parameter_set_idue(v). Parsing stops there because the next
field (ph_pic_order_cnt_lsb) isu(v)with a width derived from
the active SPS (sps_log2_max_pic_order_cnt_lsb_minus4 + 4per
§7.4.3.4 / §7.4.3.8) which a context-free parser cannot resolve
yet — routing that SPS context through the parser is deferred to a
later round.ph_pic_parameter_set_id > 63(above the
pps_pic_parameter_set_idu(6) envelope from §7.4.3.5) returns
BitstreamError::InvalidData. The result struct (VvcPictureHeader)
exposesis_irap(),is_gdr()andintra_slice_allowed()
convenience accessors that resolve the §7.4.3.8 inference rules
(ph_intra_slice_allowed_flagis inferred to 1 when not signalled).
A new public constantPH_PIC_PARAMETER_SET_ID_MAX = 63documents
the validated envelope. -
Nine new h266 unit tests cover (a) an IRAP picture
(gdr_or_irap = 1,gdr_pic = 0), (b) a GDR non-reference picture
(gdr_or_irap = 1,gdr_pic = 1,non_ref = 1), (c) a non-IRAP
inter-only picture (noph_gdr_pic_flag,intra = 0), (d) a
picture withinter_allowed = 0exercising the inferred-intra path,
(e) wrong-NAL-type rejection, (f) truncated input, (g)
oversized-ph_pic_parameter_set_idrejection, (h) emulation-
prevention-byte stripping viaebsp_to_rbspand (i) the 2x2x{1,2}x2x
{1,2} Cartesian product of every legal signalled/inferred flag
combination. Plus one newtests/h266_nal_walker.rsintegration
test walking a synthetic VPS + SPS + PPS + PH + IDR_W_RADL Annex-B
access unit throughsplit_annex_b→parse_nal_header→
parse_picture_header. -
Two new
tests/roundtrip_props.rsinvariants: a 1152-path exhaustive
sweep that crosses every signalled/inferred flag combination with
every legalph_pic_parameter_set_id(0..=63), and a boundary-
rejection sweep across the 16 values immediately above the spec
maximum. -
BitReader::i(n)— readnMSB-first bits and interpret as a two's
complement signed integer (H.264 §7.2 / H.265 §7.2 / H.266 §7.2
i(n)descriptor). Accepts widths in1..=32; the full-width case
(n == 32) round-trips the entirei32range includingi32::MIN
andi32::MAX. Past-the-end bits remain zero per the reader's
documented over-read contract. -
BitWriter::write_i(value, n)— exact inverse of the new reader.
Refuses any value outside the representable
-(2^(n-1)) .. 2^(n-1) - 1range (no silent truncation), so the
round-trip contract is total for accepted inputs. -
BitReader::signed_magnitude(n)/BitWriter::write_signed_magnitude
— read/write a signed value asnmagnitude bits followed by a 1-bit
sign (1= negative), the layout used by VP9's
loop_filter_ref_deltasand a number of legacy headers. Widths in
1..=31; canonical encoding of zero is sign=0, so a hand-crafted
"negative zero" input decodes back to positive zero (the writer
picks the canonical form on re-emission). -
BitReader::te(x_max)/BitWriter::write_te(value, x_max)—
H.264 §9.1.2 truncated Exp-Golomb. Whenx_max == 1the code
collapses to a single bit equal to1 - value; for largerx_max
the helpers delegate toue/write_ue.x_max == 0is rejected
(no spec-defined code) and the writer additionally enforces
value <= x_max. -
BitReader::read_bytes(n)/BitWriter::write_bytes(bytes)—
byte-aligned slice helpers. Both reject unaligned positions with
InvalidDataand the reader returnsUnexpectedEndon a short
buffer without advancing the cursor, so failures are recoverable. -
Five new property-style invariants in
roundtrip_props.rsexercising
every new helper:i(n)round-trip for every width 1..=32 (1500
random values per width), the out-of-range rejection sweep for every
width 1..=31,signed_magnituderound-trip for every width 1..=31
(1500 random values per width) plus the negative-zero canonicalisation
invariant,te(v)round-trip across a handful of representative
x_maxvalues, and theread_bytes/write_bytesround-trip with
interleaved bit fields. Plus a dozen new unit tests in the
bit_reader/bit_writermodules covering the boundary cases
(full 8-bit enumeration ofi(n)decoding, rejection paths, etc.). -
av1::write_obu— the inverse ofav1::read_obu. Builds a
fully-framed OBU (obu_header [obu_extension_header] obu_size payload)
from anObuHeader+ payload byte slice and appends it to a
caller-providedVec<u8>, returning the(start, end)byte range
covering the framed OBU. Round-trip contract: feedingstartback
throughread_obureproduces the sameObuHeader, a payload range
whose length matchespayload.len(), andnext_offset == end. The
emitter validates every spec-required bit-field width up-front (obu_type
≤ 15,temporal_id≤ 7,spatial_id≤ 3, payload size ≤
LEB128_MAX) and refuses non-zerotemporal_id/spatial_idpaired
withextension_flag=0(which the reader would silently zero), so
the inverse pair is total. LOBF'sobu_has_size_field=1requirement
is enforced. Buffer is left untouched on rejection. Three new public
width-bound constants (OBU_TYPE_MAX,OBU_TEMPORAL_ID_MAX,
OBU_SPATIAL_ID_MAX) document the field widths. Ten new av1 unit
tests cover the empty-TD canonical form, payload-size round-trips at
the 1-byte / 2-byte size-field boundaries (0, 1, 16, 127, 128, 1024),
the full Cartesian product of legal(temporal_id, spatial_id)
pairs through the extension byte, append-without-clobber, every
validation rejection path (size-field-clear, oversizedobu_type,
oversizedtemporal_id/spatial_id, non-zero IDs without extension
flag), multi-byte leb128 size emission, the max-legal-IDs corner,
and a two-OBU concatenation walk. -
Three new
roundtrip_props.rsinvariants exercisingwrite_obu: a
400-iteration random-payload round-trip againstread_obuacross all
seven canonical OBU types and the LCG-shuffled extension-byte ID
space; a validator that every documented rejection path returns
InvalidDatawith the buffer untouched; and a 32-OBU concatenation
that walks the entire synthetic temporal unit back throughread_obu
in lock-step, asserting thenext_offsetchainparse_obu_stream
itself depends on. -
The
fuzz/reader.rstarget now hammerswrite_obualongside the
other writer surfaces — pulling shape bytes out of attacker input to
drive(obu_type, extension_flag, temporal_id, spatial_id, payload_len), asserting eitherwrite_obu → read_obu == identity
on accepted inputs or a buffer-preserving clean error on rejected
ones.