Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 37 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,59 @@ jobs:
linux:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: prantlf/setup-v-action@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: prantlf/setup-v-action@92f20bea50d2c9931a28c96bb4997a3c7357baf0 # v4
with:
version: 0.5.2
- run: v test .

windows:
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
- uses: prantlf/setup-v-action@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: prantlf/setup-v-action@92f20bea50d2c9931a28c96bb4997a3c7357baf0 # v4
with:
version: 0.5.2
- name: Test with the Microsoft C compiler
run: v -cc msvc test .

v3:
name: Pinned V3 / Linux / TinyCC
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
path: source
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: vlang/v
ref: 0dc6a692ed5333cbe3f05ff63ae0766f0333038a
path: toolchain/v
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: vlang/vc
ref: 8af812feb76c678abd86a8e682fd9ab2790e519c
path: toolchain/v/vc
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: vlang/tccbin
ref: d6e7ac1b1bcc98aed734a6ecbfa8509f24606c74
path: toolchain/v/thirdparty/tcc
- run: make -C toolchain/v local=1
- run: toolchain/v/v -new-compiler -cc tcc test source

test:
if: always()
needs: [linux, windows]
needs: [linux, windows, v3]
runs-on: ubuntu-24.04
steps:
- name: Verify required platforms
env:
LINUX_RESULT: ${{ needs.linux.result }}
WINDOWS_RESULT: ${{ needs.windows.result }}
V3_RESULT: ${{ needs.v3.result }}
run: |
test "$LINUX_RESULT" = success
test "$WINDOWS_RESULT" = success
test "$V3_RESULT" = success
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,11 @@ 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.

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
flag. Scaling lists are copied explicitly into their fixed storage arrays.

Callers of `Bitstream.read_scaling_list` should pass the flag as `&flag`, not
`mut &flag`. The pointer itself is not reassigned; only its pointed-to value is
written. This avoids a pointer-to-pointer mismatch in V3-generated C.
27 changes: 21 additions & 6 deletions h264.v
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ pub fn (mut nal NetworkAbstractionLayerHeader) read_nal_header(mut b Bitstream)
nal.type = unsafe { NAL_UNIT_TYPE(b.u(5)) }
}

pub fn (mut b Bitstream) read_scaling_list(mut scaling_list []i32, size_of_scaling_list i32, mut use_default_scaling_matrix_flag &u32) {
pub fn (mut b Bitstream) read_scaling_list(mut scaling_list []i32, size_of_scaling_list i32, use_default_scaling_matrix_flag &u32) {
mut last_scale := i32(8)
mut next_scale := i32(8)
mut delta_scale := i32(0)
Expand Down Expand Up @@ -577,11 +577,19 @@ pub fn (mut sps SequenceParameterSet) read_sps(mut b Bitstream) {
sps.seq_scaling_list_present_flag[i] = b.u1()
if sps.seq_scaling_list_present_flag[i] != 0 {
if i < 6 {
b.read_scaling_list(mut sps.scaling_list_4x4[i][0..], 16, mut
mut list := []i32{len: 16}
b.read_scaling_list(mut list, 16,
&sps.use_default_scaling_matrix_4x4_flag[i])
for j in 0 .. 16 {
sps.scaling_list_4x4[i][j] = list[j]
}
} else {
b.read_scaling_list(mut sps.scaling_list_8x8[i - 6][0..], 64, mut
mut list := []i32{len: 64}
b.read_scaling_list(mut list, 64,
&sps.use_default_scaling_matrix_8x8_flag[i - 6])
for j in 0 .. 64 {
sps.scaling_list_8x8[i - 6][j] = list[j]
}
}
}
}
Expand Down Expand Up @@ -676,12 +684,19 @@ pub fn (mut pps PictureParameterSet) read_pps(mut b Bitstream) {
pps.pic_scaling_list_present_flag[i] = b.u1()
if pps.pic_scaling_list_present_flag[i] != 0 {
if i < 6 {
// Make it a slice to get a dynamic array
b.read_scaling_list(mut pps.scaling_list_4x4[i][0..], 16, mut
mut list := []i32{len: 16}
b.read_scaling_list(mut list, 16,
&pps.use_default_scaling_matrix_4x4_flag[i])
for j in 0 .. 16 {
pps.scaling_list_4x4[i][j] = list[j]
}
} else {
b.read_scaling_list(mut pps.scaling_list_8x8[i - 6][0..], 64, mut
mut list := []i32{len: 64}
b.read_scaling_list(mut list, 64,
&pps.use_default_scaling_matrix_8x8_flag[i - 6])
for j in 0 .. 64 {
pps.scaling_list_8x8[i - 6][j] = list[j]
}
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions h264_test.v
Original file line number Diff line number Diff line change
@@ -1,5 +1,50 @@
module h264

import encoding.hex

fn test_custom_sps_scaling_lists_are_stored() {
// FRExt_MMCO4_Sony_B conformance SPS, excluding its NAL header.
data :=
hex.decode('64001fad9464763b8ac4444a323b1dc5622225191d8ee2b11114222b373669a844566e6cd35088acdcd9a69444cd1b9bc57c9f93f9bf27c9e4e4cd251a4689c9ebe4fd7f27ebe4f5c9a906c694160964')!
mut stream := Bitstream{}
stream.init(data)
mut sps := SequenceParameterSet{}
sps.read_sps(mut stream)
assert sps.seq_parameter_set_id == 0
assert sps.scaling_list_4x4[0][..4] == [i32(6), 12, 12, 19]
assert sps.scaling_list_8x8[0][..4] == [i32(6), 10, 10, 13]
for i in 0 .. 6 {
assert sps.scaling_list_4x4[i][15] != 0
}
for i in 0 .. 2 {
assert sps.scaling_list_8x8[i][63] != 0
}
}

fn test_custom_pps_scaling_list_is_stored() {
mut stream := Bitstream{}
stream.init(hex.decode('ce3c7fffe0c0')!)
mut pps := PictureParameterSet{}
pps.read_pps(mut stream)
assert pps.pic_scaling_matrix_present_flag == 1
for value in pps.scaling_list_4x4[0] {
assert value == 8
}
}

fn test_scaling_list_default_flag_points_to_value_not_pointer() {
mut stream := Bitstream{}
// signed Exp-Golomb -8 makes the first nextScale zero.
stream.init([u8(0x08), 0x80])
mut list := []i32{len: 16}
mut use_default := u32(0)
stream.read_scaling_list(mut list, 16, &use_default)
assert use_default == 1
for value in list {
assert value == 8
}
}

fn test_fixed_width_reads_cross_byte_boundaries() {
mut stream := Bitstream{}
stream.init([u8(0xa5), 0xc0])
Expand Down