From 772d3edee147e6beb49da6740a7b8c837b79d242 Mon Sep 17 00:00:00 2001 From: antono2 Date: Wed, 7 Oct 2026 14:21:24 +0200 Subject: [PATCH] Read every HRD buffering entry and validate its count --- README.md | 4 +++- h264.v | 4 +++- hrd_test.v | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 hrd_test.v diff --git a/README.md b/README.md index 50fe06f..3737e04 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,9 @@ v -cc msvc test . They cover fixed-width and Exp-Golomb bit reading, truncated input behavior, NAL headers, RBSP look-ahead, integer bit widths, and representative -High-profile SPS/PPS parsing used by the player. +High-profile SPS/PPS parsing used by the player. HRD buffering syntax tests cover +one, two, and the maximum 32 CPB entries, including alignment of the following +delay fields. Counts beyond 32 entries are rejected by an assertion. CI also runs strict V3 with TinyCC on Linux, using a pinned compiler snapshot. The regression samples cover custom SPS/PPS scaling lists and the default-list diff --git a/h264.v b/h264.v index 0f16ff0..ff44f33 100644 --- a/h264.v +++ b/h264.v @@ -412,11 +412,13 @@ pub fn (mut b Bitstream) read_scaling_list(mut scaling_list []i32, size_of_scali // read_hrd_parameters consumes HRD syntax at the current cursor into sps.hrd. // Normally called by read_vui_parameters; it does not schedule decoder buffering. +// The coded count is one less than the number of entries and must be at most 31. pub fn (mut sps SequenceParameterSet) read_hrd_parameters(mut b Bitstream) { sps.hrd.cpb_cnt_minus1 = b.ue() + assert sps.hrd.cpb_cnt_minus1 < 32 sps.hrd.bit_rate_scale = b.u(4) sps.hrd.cpb_size_scale = b.u(4) - for sched_sel_idx in 0 .. sps.hrd.cpb_cnt_minus1 { + for sched_sel_idx in 0 .. sps.hrd.cpb_cnt_minus1 + 1 { sps.hrd.bit_rate_value_minus1[sched_sel_idx] = b.ue() sps.hrd.cpb_size_value_minus1[sched_sel_idx] = b.ue() sps.hrd.cbr_flag[sched_sel_idx] = b.u1() diff --git a/hrd_test.v b/hrd_test.v new file mode 100644 index 0000000..15feb7f --- /dev/null +++ b/hrd_test.v @@ -0,0 +1,32 @@ +// Verifies HRD entry counts and the cursor position of following syntax fields. +module h264 + +import encoding.hex + +fn test_hrd_reads_all_cpb_entries() { + // H.264 E.1.2 encodes count minus one. Fixtures contain 1, 2 and 32 CPBs, + // distinct entry values, four delay widths, and an 0xa5 cursor sentinel. + for count, encoded in { + 1: '9a30208a63a294' + 2: '468c08220102531d14a0' + 32: '04068c08220102507e303e9c1e8403c89076140ea2c1c860388d06e1c0da3c1a8200d2110660903284c188280c21505e0b02e85c168300b2190560d02a86c148380a21d04e0f02687c1281002482104604408a531d14a0' + } { + mut stream := Bitstream{} + stream.init(hex.decode(encoded)!) + mut sps := SequenceParameterSet{} + sps.read_hrd_parameters(mut stream) + assert sps.hrd.cpb_cnt_minus1 == u32(count - 1) + assert sps.hrd.bit_rate_scale == 3 + assert sps.hrd.cpb_size_scale == 4 + for i in 0 .. count { + assert sps.hrd.bit_rate_value_minus1[i] == u32(i + 2) + assert sps.hrd.cpb_size_value_minus1[i] == u32(64 - i) + assert sps.hrd.cbr_flag[i] == u32(i % 2) + } + assert sps.hrd.initial_cpb_removal_delay_length_minus1 == 5 + assert sps.hrd.cpb_removal_delay_length_minus1 == 6 + assert sps.hrd.dpb_output_delay_length_minus1 == 7 + assert sps.hrd.time_offset_length == 8 + assert stream.u(8) == 0xa5 + } +}