Skip to content

h264: fix "Missing reference picture" decode errors after IDR when max_reference_frames > 1#9

Merged
hgaiser merged 5 commits intomainfrom
copilot/fix-h264-reference-picture-decode-errors
Apr 11, 2026
Merged

h264: fix "Missing reference picture" decode errors after IDR when max_reference_frames > 1#9
hgaiser merged 5 commits intomainfrom
copilot/fix-h264-reference-picture-decode-errors

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 10, 2026

With max_reference_frames > 1, the PPS advertises num_ref_idx_l0_default_active_minus1 = max_refs - 1, but the slice header had num_ref_idx_active_override_flag = 0, so decoders used that PPS default for every slice — including P-frames immediately after an IDR where the DPB holds only one picture. Result: "Missing reference picture" warnings and decode failures until the DPB filled up.

Changes

  • num_ref_idx_active_override_flag = 1 — always set in the slice header so each slice encodes its own active reference count, overriding the PPS default. Decoders now see the true per-slice count rather than the max-configured value.
  • Remove reference-list padding — the previous workaround duplicated the last DPB slot to inflate RefPicList0 to active_reference_count entries. This didn't fix the decoder-side issue and is no longer needed; the list is now populated with only the actually-available references (clamped to active_reference_count).
  • Add target/ to .gitignore — prevent Rust build artifacts from being committed.

Copilot AI and others added 2 commits April 10, 2026 12:48
@hgaiser hgaiser requested a review from Copilot April 10, 2026 12:52
Copilot AI changed the title [WIP] Fix h264: PPS num_ref_idx_l0_default_active_minus1 decode issues h264: fix "Missing reference picture" decode errors after IDR when max_reference_frames > 1 Apr 10, 2026
Copilot AI requested a review from hgaiser April 10, 2026 12:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adjusts the H.264 encoder’s slice-header/reference-list signaling to avoid decoder errors when the PPS default reference count exceeds the currently-available DPB references (e.g., immediately after an IDR), and cleans up build output handling.

Changes:

  • Forces per-slice signaling of the active reference count and updates reference-list construction to use the actual available L0 references (no padding duplicates).
  • Updates internal comments around H.264 ref list signaling behavior.
  • Ignores Cargo build artifacts by adding /target/ to .gitignore.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/encoder/h264/encode.rs Sets num_ref_idx_active_override_flag and adjusts L0 reference list population to avoid relying on PPS defaults/padding.
.gitignore Adds /target/ to prevent committing Rust build artifacts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 94 to 104
// Build StdVideoEncodeH264SliceHeader.
let slice_header_flags = ash::vk::native::StdVideoEncodeH264SliceHeaderFlags {
_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
),
};
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.
Comment on lines 178 to 188
// 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.
@hgaiser
Copy link
Copy Markdown
Owner

hgaiser commented Apr 10, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 10, 2026

@copilot apply changes based on the comments in this thread

Applied both review changes in 3e90f05:

  1. num_ref_idx_active_override_flag is now only set for non-IDR slices (!is_idr as u32), keeping it 0 for IDR/I slices per the H.264 spec.
  2. The P-frame reference list now clamps actual_count once with .min(32) upfront, removing the redundant per-iteration if i < 32 guard and the trailing .min(32) on the returned count.

@skirsten
Copy link
Copy Markdown
Contributor

I tested it and did not get any error 👍. Thanks for the fix.

Btw, you might want to squash those commits as they contain 60MB of build artifacts.

@hgaiser
Copy link
Copy Markdown
Owner

hgaiser commented Apr 11, 2026

I tested it and did not get any error 👍. Thanks for the fix.

Btw, you might want to squash those commits as they contain 60MB of build artifacts.

Great 👍

Yeah, I noticed.. thanks for the warning though!

@hgaiser hgaiser merged commit 404cd8d into main Apr 11, 2026
6 checks passed
@hgaiser hgaiser deleted the copilot/fix-h264-reference-picture-decode-errors branch April 11, 2026 22:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

h264: PPS num_ref_idx_l0_default_active_minus1 exceeds actual DPB occupancy after IDR, causing "Missing reference picture" decode errors

4 participants