From 692eaa005334a66f01362210eca87cab4a55798d Mon Sep 17 00:00:00 2001 From: claude-noether Date: Sun, 10 May 2026 09:50:25 +0000 Subject: [PATCH] fresnel-fourier iter4 Phase 7 fix-forward: gate ANNEX-B start-code prepend on H.264/HEVC profiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- src/context.c | 25 ++++++++++++++++++++++++- src/vp9.c | 26 +++++++++++++++----------- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/context.c b/src/context.c index b7a34cf..b583917 100644 --- a/src/context.c +++ b/src/context.c @@ -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) { diff --git a/src/vp9.c b/src/vp9.c index b4444b2..436f684 100644 --- a/src/vp9.c +++ b/src/vp9.c @@ -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); } } }