Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
output.*
/target/
38 changes: 15 additions & 23 deletions src/encoder/h264/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ impl H264Encoder {
_bitfield_align_1: [],
_bitfield_1: ash::vk::native::StdVideoEncodeH264SliceHeaderFlags::new_bitfield_1(
0, // direct_spatial_mv_pred_flag
0, // num_ref_idx_active_override_flag
// Always override the PPS default so decoders use the per-slice active count,
// preventing "Missing reference picture" errors when the DPB is not yet full.
1, // num_ref_idx_active_override_flag
0, // reserved
),
};
Comment on lines +94 to 107
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

num_ref_idx_active_override_flag is set to 1 unconditionally, but in H.264 this syntax element is only present for P/B/SP slices. For IDR/I slices (and any case where picture_info.pRefLists is NULL), forcing this flag risks generating a non-conformant slice header or a driver-side mismatch between the slice header and provided reference list info. Consider setting it conditionally based on slice_type (e.g., only when references are actually signaled) and keeping it 0 for IDR/I slices.

Copilot uses AI. Check for mistakes.
Expand Down Expand Up @@ -173,38 +175,28 @@ impl H264Encoder {
(0, 0)
}
} else if !is_idr && !self.l0_references.is_empty() {
// P-frame: L0 reference list.
// WE MUST FILL THE LIST UP TO THE PPS DEFAULT COUNT using duplicates if needed.

// Use negotiated active count.
let target_count = self.active_reference_count as usize;
let count = self.l0_references.len();

// 1. Fill actual references
for (i, ref_info) in self.l0_references.iter().enumerate() {
// P-frame: L0 reference list using actual available references.
// Clamp to the negotiated active count maximum.
let actual_count = self
.l0_references
.len()
.min(self.active_reference_count as usize);

for (i, ref_info) in self.l0_references.iter().take(actual_count).enumerate() {
if i < 32 {
ref_list0[i] = ref_info.dpb_slot;
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actual_count is already bounded by active_reference_count, and H.264 L0 reference lists are capped at 32; in this codebase active_reference_count is clamped to ≤32 during init. This makes the if i < 32 guard and the repeated .min(32) a bit misleading/redundant—consider clamping once (e.g., let actual_count = ...min(32)) and then writing without the extra conditional to keep the list length logic easier to reason about.

Copilot uses AI. Check for mistakes.
}

// 2. Pad with duplicates of the last reference if needed to reach target_count
if count < target_count && count > 0 {
let last_slot = ref_list0[count - 1];
let end = target_count.min(32);
ref_list0[count..end].fill(last_slot);
}

// We provide target_count entries if we have at least 1, otherwise 0.
(target_count.min(32), 0)
(actual_count.min(32), 0)
} else {
// IDR: no references.
(0, 0)
};

// Note: num_ref_idx_l0_active_minus1 in ReferenceListsInfo tells the driver/hardware
// how many entries in our RefPicList0 array are valid.
// Since we ensure 3 entries are valid (by duplicating), we set this to 2.

// num_ref_idx_l0_active_minus1 tells the driver how many entries in RefPicList0
// are valid and is encoded into the slice header (because we set
// num_ref_idx_active_override_flag=1 above).
let ref_lists_info = ash::vk::native::StdVideoEncodeH264ReferenceListsInfo {
flags: ref_lists_info_flags,
num_ref_idx_l0_active_minus1: if num_ref_l0 > 0 {
Expand Down
Loading