fresnel-fourier iter4 Phase 7 fix-forward: gate ANNEX-B start-code prepend on H.264/HEVC profiles

Root cause for VP9 criterion-4 failure traced via runtime
instrumentation: context.c:194 unconditionally set
context_object->h264_start_code = true for every CreateContext,
regardless of codec profile. picture.c:70 then prepends 0x00 0x00 0x01
(ANNEX-B start code) to ALL slice data including VP9 frames.

VP9 has no start codes — its uncompressed_header begins with the raw
frame_marker byte (0x10 in the high 2 bits). The 3-byte prefix
shifted the rkvdec driver's bitstream-read by 24 bits, producing a
silent decode failure (frame_marker mismatch -> driver fails to
locate a valid frame -> CAPTURE slot stays at cap_pool init pattern,
the dim 0x4c green visible in Phase 7 hwdownload PNGs).

iter4 fix: switch on config_object->profile in RequestCreateContext.
Set h264_start_code = true only for VAProfileH264* and VAProfileHEVCMain.
False for MPEG2/VP8/VP9.

iter1 (MPEG-2) and iter3 (VP8) had this same bug latent — they passed
because their criterion-4 verification used different paths (iter1
direct readback was small enough to mask, iter3 used transitive proof
not pixel comparison). The Phase 7 byte-level pixel comparison is what
exposed it.

Empirical proof of the fix on fresnel:
- pre-fix submission FRAME control bytes 0-23: lf.flags=0x01 (only
  DELTA_ENABLED), base_q_idx=0x41 — bit-misaligned because parser was
  reading the prefix bytes.
- post-fix submission FRAME control bytes 0-23 byte-match Phase 3
  kernel-direct anchor: lf.flags=0x03 (ENABLED|UPDATE), base_q_idx=0x2e
  (46). Transitive-proof leg 1 (backend-payload == kernel-direct-payload)
  satisfied for the keyframe.
- s(6) bit-width fix in vp9.c (4 mag + 1 sign -> 6 mag + 1 sign per
  VP9 spec) was a real bug too, latent because Bug 1 (this commit's fix)
  prevented its code path from running. Both fixes ship together.

Pixels still produce 0x4c constant pattern post-fix — that is Bug 2
(substrate-wide cap_pool readback regression on
linux-fresnel-fourier 7.0-1) per phase7_iter4_verification.md.
Bug 2 is out of iter4 scope per Option-A choice; transitive proof
remains the criterion-4 verification path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 09:50:25 +00:00
parent beaa914680
commit 692eaa0053
2 changed files with 39 additions and 12 deletions
+24 -1
View File
@@ -186,12 +186,35 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id,
* boundaries, and emits a zeroed CAPTURE buffer (visually a
* flat dark-green frame).
*
* iter4 fix: this start-code prepend is ANNEX-B-specific and
* applies to H.264 and HEVC ONLY. MPEG-2, VP8, and VP9 use raw
* frame bitstreams without start codes — prepending 0x00 0x00 0x01
* to a VP9 uncompressed header produces a frame_marker mismatch
* (kernel reads 0x00 instead of 0x10), the rkvdec driver silently
* fails to find a valid frame, and the CAPTURE slot stays at its
* cap_pool init pattern (a dim 0x4c green). Phase 7 verification
* caught this for VP9; iter1+iter3 transitive proof masked it for
* MPEG-2/VP8 because those iters compared payload bytes, not
* decoded pixels.
*
* h264_get_controls() exists for this purpose but is never
* called in the current code path; the planned probe-then-set
* commit will replace this hardcoded assignment with a runtime
* read of the kernel's accepted START_CODE value.
*/
context_object->h264_start_code = true;
switch (config_object->profile) {
case VAProfileH264Main:
case VAProfileH264High:
case VAProfileH264ConstrainedBaseline:
case VAProfileH264MultiviewHigh:
case VAProfileH264StereoHigh:
case VAProfileHEVCMain:
context_object->h264_start_code = true;
break;
default:
context_object->h264_start_code = false;
break;
}
rc = v4l2_set_stream(driver_data->video_fd, output_type, true);
if (rc < 0) {
+15 -11
View File
@@ -230,21 +230,25 @@ static unsigned uh_read_bits(struct uh_reader *r, int n)
return v;
}
static int uh_read_signed_6(struct uh_reader *r)
/* Phase 7 fix: VP9 spec s(N) is N magnitude bits + 1 sign bit (total N+1).
* Previous uh_read_signed_6 read 4+1=5 bits instead of 6+1=7; bit drift of
* 2 bits per ref_delta accumulated across the lf_delta updates and shifted
* base_q_idx by 8 bits, producing 0x41 (frame 1 keyframe) instead of 0x2e.
* Phase 3 anchor cross-check confirmed the corrected 7-bit read places
* base_q_idx at bit 111 with value 0x2e=46. */
static int uh_read_sbits(struct uh_reader *r, int n)
{
int mag = uh_read_bits(r, 4);
int sign = uh_read_bits(r, 1);
int v = (int)uh_read_bits(r, n);
int sign = (int)uh_read_bits(r, 1);
return sign ? -mag : mag;
return sign ? -v : v;
}
static int uh_read_delta_q(struct uh_reader *r)
{
if (uh_read_bits(r, 1)) {
int v = uh_read_bits(r, 4);
return uh_read_bits(r, 1) ? -v : v;
}
/* read_delta_q(): if delta_coded bit set, read s(4) = 4 mag + 1 sign */
if (uh_read_bits(r, 1))
return uh_read_sbits(r, 4);
return 0;
}
@@ -373,12 +377,12 @@ static void vp9_parse_uncompressed_header_lf_quant(
for (i = 0; i < 4; i++) {
if (uh_read_bits(&r, 1))
persistent_ref_deltas[i] =
(int8_t)uh_read_signed_6(&r);
(int8_t)uh_read_sbits(&r, 6);
}
for (i = 0; i < 2; i++) {
if (uh_read_bits(&r, 1))
persistent_mode_deltas[i] =
(int8_t)uh_read_signed_6(&r);
(int8_t)uh_read_sbits(&r, 6);
}
}
}