Files
fresnel-fourier/phase3_iter1_baseline.md
T
claude-noether b9625af278 iter1 Phase 3: baseline measurements — Phase 2 confirmed empirically
Four Phase 3 baselines captured on fresnel post-reboot 2026-05-08
00:39 CEST. SDDM watchpoint condition stayed green (greeter passed
cleanly on the new boot). All four baselines confirm Phase 2's
situation analysis empirically; one Phase 1 criterion needs minor
adjustment (Phase 3 → Phase 1 loopback per feedback_dev_process.md).

Baseline A — pre-patch failure mode (master tip 65969da):

  ffmpeg -hwaccel vaapi -i bbb_720p10s_mpeg2.ts ... under strace +
  LIBVA_TRACE captures the chain:

  vaInitialize ret = SUCCESS
  vaQueryConfigProfiles ret = SUCCESS
  vaCreateConfig(profile=VAProfileMPEG2Main, entrypoint=VLD)
    ret = VA_STATUS_ERROR_UNSUPPORTED_PROFILE

  No V4L2 ioctls beyond ENUM_FMT probes from RequestQueryConfigProfiles.
  Confirms Phase 2 Bug 1 (config.c:55-69 fall-through to default).

Baseline B — post Bug 1 scratch patch (the missing break added):

  vaCreateConfig now returns SUCCESS. V4L2 setup proceeds:
  CREATE_BUFS, QUERYBUF (40), REQBUFS, STREAMON, S_FMT, etc.
  Then VIDIOC_S_EXT_CTRLS fails:

    ioctl(/dev/video5, VIDIOC_S_EXT_CTRLS,
          {ctrl_class=0xf010000,
           count=1,
           controls=[
             {id=V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
              size=56, ...}
           ]})
        = -1 EINVAL

  CID 0x9909fa (V4L2_CID_MPEG_BASE+250) doesn't exist on this kernel —
  mainline removed it in favor of the split V4L2_CID_STATELESS_MPEG2_*
  CIDs. Size 56 = sizeof(combined v4l2_ctrl_mpeg2_slice_params) from
  the fork's local include/mpeg2-ctrls.h. Confirms Phase 2 Bug 2.

  Auxiliary EINVAL: src/context.c:142-155 unconditionally sets H.264
  device-wide controls (H264_DECODE_MODE, H264_START_CODE) on every
  CreateContext, regardless of profile. EINVALs on hantro-vpu-dec
  (no H.264 controls there). Intentional best-effort behavior —
  return value is cast to (void) and discarded. Auxiliary, not iter1
  scope.

Baseline C — cross-validator verbatim contract anchor:

  ffmpeg -hwaccel v4l2request strace shows ONE batched call per frame:

    ioctl(/dev/video5, VIDIOC_S_EXT_CTRLS,
          {ctrl_class=0xf010000,    // V4L2_CTRL_CLASS_CODEC_STATELESS
           count=3,
           controls=[
             {id=0xa409dc, size=12,  ...},   // SEQUENCE
             {id=0xa409dd, size=32,  ...},   // PICTURE
             {id=0xa409de, size=256, ...}    // QUANTISATION
           ]}) = 0

  Field-by-field decode of frame 1 (I-picture):
    SEQUENCE: 1280×720, vbv=0x151800, profile_level=0,
              chroma_format=1, flags=PROGRESSIVE
    PICTURE: back/fwd_ref_ts=0/0, flags=0x82
             (FRAME_PRED_DCT|PROGRESSIVE), f_code=0xF×4 (I-frame
             default), P_C_T=1 (I), structure=3 (FRAME),
             intra_dc_precision=0
    QUANTISATION: starts [8, 16, 16, 19, 16, 19, 22, 22, ...] —
                  canonical MPEG-2 default intra matrix in zigzag
                  scanning order.

  Frame 2 (P-picture) shows real f_code values {{1,1},{15,15}}
  and forward_ref_ts pointing to frame 1's timestamp. Confirms
  Phase 2's claim that matrices arrive in zigzag order;
  no permutation needed in the libva backend (kernel's
  hantro_mpeg2_dec_copy_qtable handles zigzag-to-raster).

  This is the iter1 contract anchor: every Phase 4 implementation
  diff must produce a structurally indistinguishable
  VIDIOC_S_EXT_CTRLS call.

Baseline D — H.264 regression check (Phase 1 criterion #5):

  T4 reference hashes match exactly with scratch Bug 1 fix installed:
    HW frame 1: f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9
    SW frame 1: f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9
    HW frame 2: 7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8
    SW frame 2: 7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8

  Bug 1 fix in isolation does not regress H.264.

Phase 1 criterion #3 needs adjustment (Phase 3 → Phase 1 loopback):

  Original wording: "mpv --hwdec=vaapi-copy ... engages the backend"
  Reality: mpv-vaapi-copy never loads libva for MPEG-2. mpv's hwdec
  policy filters MPEG-2 out before libva is touched. Zero V4L2
  ioctls, zero libva trace, silent SW fallback. Independent of
  Bug 1 fix state.

  Adjusted criterion #3 (proposed; locks alongside Phase 4 plan):
    "ffmpeg -hwaccel vaapi -i bbb_720p10s_mpeg2.ts -frames:v 2
     -f null - shows vaCreateConfig SUCCESS, no Failed to create
     decode configuration lines, no EINVAL from VIDIOC_S_EXT_CTRLS,
     exits 0 cleanly."

  mpv-driven testing moves to a follow-up task (mpv hwdec-codecs
  filter override), separate from iter1.

Other 4 Phase 1 criteria (vainfo regression, vaCreateConfig SUCCESS,
DMA-BUF GL pixel verify HW=SW, T4 H.264 regression) hold as locked.

Scratch state cleanup: scratch patch reverted, master backend
reinstalled, MPEG-2 fails again with vaCreateConfig=12 — back to
Baseline A state, no leak.

Phase 4 plan inputs:

  - Diff scope: src/config.c (1 break), src/mpeg2.c (rewrite to
    new API), include/mpeg2-ctrls.h (delete or empty). picture.c
    + context.c unchanged.
  - Contract anchor: cite verbatim from
    linux/v4l2-controls.h:1985-2105, FFmpeg
    libavcodec/v4l2_request_mpeg2.c:130-155, kernel
    drivers/media/platform/verisilicon/hantro_mpeg2.c, AND this
    document's Baseline C verbatim payload.
  - Phase 7 verification: re-run all 5 Phase 1 criteria
    (with #3 adjusted), byte-by-byte compare post-fix
    VIDIOC_S_EXT_CTRLS payload against Baseline C.

Evidence files:

  Tracked (text):
    phase3_iter1_baseline.md (writeup with verbatim raw output)
    phase0_evidence/2026-05-07/iter1_phase3/baseline_A_ffmpeg/ffmpeg.stdout
    phase0_evidence/2026-05-07/iter1_phase3/baseline_B_postbug1/ffmpeg.stdout
    phase0_evidence/2026-05-07/iter1_phase3/baseline_C_xvalidator/ffmpeg.stdout

  Gitignored (regenerable from re-run incantations in the writeup):
    *.strace.*  *.txt (ftrace) libva.trace.* (added the latter pattern)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 04:04:25 +00:00

22 KiB
Raw Blame History

Iteration 1 — Phase 3 (baseline measurements)

Phase 3 baselines for the iter1 MPEG-2 boolean-correctness work, captured 2026-05-08 00:39 CEST after fresnel reboot. All four baseline runs and the verbatim output anchors are in phase0_evidence/2026-05-07/iter1_phase3/.

Phase 3 discipline (per feedback_dev_process.md): raw data leads, derived numbers are anchored to the visible tool invocation that produced them. Every "this matches Phase 2 prediction" claim cites a verbatim line from the captured trace, not a paraphrase.

Reset context

$ ssh fresnel 'hostname; uname -r; uptime'
fresnel
6.19.9-99-eos-arm
 00:31:35 up 4 min,  2 users,  load average: 1.01, 0.70, 0.34

$ loginctl list-sessions --no-pager | head
SESSION  UID USER      SEAT  LEADER CLASS   TTY  IDLE SINCE
      2 1000 mfritsche seat0 2244   user    tty1 no   -

fresnel rebooted between Phase 2 and Phase 3 (uptime 4 min explains the No route to host Phase 2 noted). SDDM watchpoint condition not triggered: journalctl -u sddm -b | grep -E "(qFatal|crash|Error|fatal|SIGABRT)" returns empty for this boot. Plasma Wayland session active on tty1, mfritsche logged in.

Baseline A — pre-patch failure mode

Goal: capture the exact path that produces vaCreateConfig: 12 (UNSUPPORTED_PROFILE) on master tip 65969da, before any iter1 work touches the code.

Invocation:

strace -ff -tt -y -e trace=ioctl,openat,close \
  -o /tmp/iter1_phase3/baseline_A_ffmpeg/ffmpeg.strace \
  env LIBVA_DRIVER_NAME=v4l2_request \
      LIBVA_V4L2_REQUEST_VIDEO_PATH=/dev/video5 \
      LIBVA_V4L2_REQUEST_MEDIA_PATH=/dev/media2 \
      LIBVA_TRACE=/tmp/iter1_phase3/baseline_A_ffmpeg/libva.trace \
  ffmpeg -hide_banner -loglevel debug -hwaccel vaapi \
    -i ~/fourier-test/bbb_720p10s_mpeg2.ts -frames:v 2 -f null -

Verbatim libva trace (baseline_A_ffmpeg/libva.trace.*):

[5276.234210][ctx none] VA-API vendor string: v4l2-request
[5276.234352][ctx none] vaInitialize ret = VA_STATUS_SUCCESS, success (no error)
[5276.264142][ctx none] vaQueryConfigProfiles ret = VA_STATUS_SUCCESS, success (no error)
[5276.264347][ctx none] va_TraceCreateConfig
[5276.264351][ctx none]   profile = 1, VAProfileMPEG2Main
[5276.264354][ctx none]   entrypoint = 1, VAEntrypointVLD
[5276.264357][ctx none]   num_attribs = 0
[5276.264606][ctx none] vaCreateConfig ret = VA_STATUS_ERROR_UNSUPPORTED_PROFILE, the requested VAProfile is not supported
[5276.425879][ctx none] va_TraceTerminate
[5276.426283][ctx none] vaTerminate ret = VA_STATUS_SUCCESS, success (no error)

Verbatim ffmpeg log (baseline_A_ffmpeg/ffmpeg.stdout):

[VAAPI @ 0xaaaaef94e010] libva: User environment variable requested driver 'v4l2_request'
[VAAPI @ 0xaaaaef94e010] libva: Trying to open /usr/lib/dri/v4l2_request_drv_video.so
[VAAPI @ 0xaaaaef94e010] libva: Found init function __vaDriverInit_1_23
[VAAPI @ 0xaaaaef94e010] Initialised VAAPI connection: version 1.23
[VAAPI @ 0xaaaaef94e010] VAAPI driver: v4l2-request.
[mpeg2video @ 0xaaaaef99ee10] Format vaapi chosen by get_format().
[mpeg2video @ 0xaaaaef99ee10] Format vaapi requires hwaccel mpeg2_vaapi initialisation.
[mpeg2video @ 0xaaaaef99ee10] Failed to create decode configuration: 12 (the requested VAProfile is not supported).
[mpeg2video @ 0xaaaaef99ee10] Failed setup for format vaapi: hwaccel initialisation returned error.
[mpeg2video @ 0xaaaaef99ee10] Format vaapi not usable, retrying get_format() without it.

Verbatim ioctl summary:

     10 ioctl(6</dev/video5>, VIDIOC_ENUM_FMT
      4 ioctl(4</dev/dri/renderD128>, DRM_IOCTL_VERSION
      1 ioctl(6</dev/video5>, VIDIOC_QUERYCAP

12 ftrace v4l2 lines (the ENUM_FMT probe events). Zero VIDIOC_S_FMT, zero REQBUFS, zero S_EXT_CTRLS, zero MEDIA_IOC_REQUEST_ALLOC. Decode never starts.

Confirms Phase 2 Bug 1 directly: vaCreateConfig returns VA_STATUS_ERROR_UNSUPPORTED_PROFILE for VAProfileMPEG2Main — the missing break; at src/config.c:65-66 makes execution fall through to default: (line 67-68) which returns the error code we observe (12).

mpv-as-driver does not reach this path: a separate baseline run with mpv --hwdec=vaapi-copy instead of ffmpeg -hwaccel vaapi showed mpv silently fall back to SW decode without ever loading libva for MPEG-2 (no [vaapi] log lines, zero V4L2 ioctls, zero libva trace files). mpv's hwdec policy filters MPEG-2 out of vaapi-copy candidates before libva is touched. Phase 1 success criterion #3 (mpv MPEG-2 engages backend) requires either an mpv config override or a different invocation path — to be addressed in Phase 4 plan. ffmpeg-direct invocations exercise the full path.

Baseline B — post Bug 1 patch failure mode

Goal: with the missing break; added as a Phase 3 scratch test, see what fails downstream. Predicted by Phase 2: VIDIOC_S_EXT_CTRLS returns EINVAL because the staging-era CID V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (= 0x9909fa) doesn't exist on this kernel.

Patch applied (scratch only, on throwaway branch iter1-phase3-scratch, reverted at end of Phase 3):

@@ -63,6 +63,8 @@ VAStatus RequestCreateConfig(VADriverContextP context, VAProfile profile,
 		break;
 	case VAProfileMPEG2Simple:
 	case VAProfileMPEG2Main:
+		// Phase 3 scratch — would break here in real fix
+		break;
 	case VAProfileHEVCMain:
 	default:
 		return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;

Rebuilt + installed (ninja -C build && sudo ninja -C build install).

Verbatim libva trace showing config-create now succeeds:

[5329.689037][ctx none] vaQueryConfigProfiles ret = VA_STATUS_SUCCESS
[5329.689228][ctx none] va_TraceCreateConfig
[5329.689233][ctx none]   profile = 1, VAProfileMPEG2Main
[5329.689237][ctx none]   entrypoint = 1, VAEntrypointVLD
[5329.689239][ctx none]   num_attribs = 0
[5329.689471][ctx none] vaCreateConfig ret = VA_STATUS_SUCCESS, success (no error)
[5329.689703][ctx none] vaQuerySurfaceAttributes ret = VA_STATUS_SUCCESS
... (9 more vaQuerySurfaceAttributes calls; surface format negotiation works)

Verbatim failing ioctl (extracted from baseline_B_postbug1/ffmpeg.strace.*, 6 occurrences across 5 frames):

ioctl(6</dev/video5>, VIDIOC_S_EXT_CTRLS,
    {ctrl_class=0xf010000 /* V4L2_CTRL_CLASS_??? */,
     count=1,
     controls=[
       {id=V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS,
        size=56,
        string="h\1\17\0\0\0\0\0H\307Z\226\254i\255\30..."}
     ]}
    => {controls=[...], error_idx=1}
    ) = -1 EINVAL (Invalid argument)
  • CID V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS = V4L2_CID_MPEG_BASE+250 = 0x9909fa — the fork's include/mpeg2-ctrls.h:13 symbol. The kernel doesn't recognize this CID (mainline removed it; replaced by the split V4L2_CID_STATELESS_MPEG2_{SEQUENCE,PICTURE,QUANTISATION} at 0xa409dc/dd/de).
  • size=56 matches sizeof(struct v4l2_ctrl_mpeg2_slice_params) from the fork's local header (combined sequence + picture + slice fields).
  • error_idx=1 = first (and only) control in the array failed validation.
  • 6 calls visible across the 5-frame attempt — one per frame, plus one buffer-pool bring-up artefact.

Confirms Phase 2 Bug 2 directly: the kernel rejects the staging-era CID. The fork's UAPI is stale; rewriting mpeg2.c against the new split API is non-optional.

Auxiliary EINVAL — H.264 device-init runs unconditionally on hantro:

ioctl(6</dev/video5>, VIDIOC_S_EXT_CTRLS,
    {ctrl_class=0,
     count=2,
     controls=[
       {id=0xa40900 /* V4L2_CID_STATELESS_H264_DECODE_MODE */, size=0, value=1, value64=1},
       {id=0xa40901 /* V4L2_CID_STATELESS_H264_START_CODE */,  size=0, value=1, value64=1}
     ]}
    => {error_idx=2}
    ) = -1 EINVAL (Invalid argument)

Source: src/context.c:142-155 unconditionally sets the H.264 device-wide controls (V4L2_CID_STATELESS_H264_DECODE_MODE = FRAME_BASED, V4L2_CID_STATELESS_H264_START_CODE = ANNEX_B) on every CreateContext, regardless of profile. This is intentional per the existing comment at src/context.c:138-141:

Errors here are not fatal: not every backing driver supports both controls (e.g. cedrus may default to SLICE_BASED without exposing DECODE_MODE).

The error is silently swallowed via (void)v4l2_set_controls(...) (line 153 — explicit cast discards the return). For MPEG-2 on hantro-vpu-dec the call's a no-op; the EINVAL is noise in the trace, not a bug. Out of scope for iter1; documented as auxiliary finding.

Verbatim ioctl summary (post-Bug-1 path engages full V4L2 lifecycle):

     40 ioctl(6</dev/video5>, VIDIOC_QUERYBUF
     22 ioctl(6</dev/video5>, VIDIOC_ENUM_FMT
     16 ioctl(7</dev/media2>, MEDIA_IOC_REQUEST_ALLOC
     10 ioctl(6</dev/video5>, VIDIOC_QBUF
     10 ioctl(6</dev/video5>, VIDIOC_G_FMT
     10 ioctl(6</dev/video5>, VIDIOC_DQBUF
      6 ioctl(6</dev/video5>, VIDIOC_S_EXT_CTRLS    <-- 6 fail with EINVAL
      4 ioctl(4</dev/dri/renderD128>, DRM_IOCTL_VERSION
      2 ioctl(6</dev/video5>, VIDIOC_STREAMON
      2 ioctl(6</dev/video5>, VIDIOC_STREAMOFF
      2 ioctl(6</dev/video5>, VIDIOC_REQBUFS
      2 ioctl(6</dev/video5>, VIDIOC_CREATE_BUFS
      1 ioctl(9<anon_inode:request>, MEDIA_REQUEST_IOC_REINIT
      1 ioctl(9<anon_inode:request>, MEDIA_REQUEST_IOC_QUEUE
      1 ioctl(6</dev/video5>, VIDIOC_S_FMT
      1 ioctl(6</dev/video5>, VIDIOC_QUERYCAP

The buffer-pool bring-up + per-frame plumbing (CREATE_BUFS, QUERYBUF, REQBUFS, STREAMON, REQUEST_ALLOC, QBUF, DQBUF, REQUEST_IOC_QUEUE) all succeeds. Only the codec-specific control submission is broken. This bounds the iter1 fix scope sharply.

Baseline C — cross-validator verbatim contract anchor

Goal: extract the exact byte-level VIDIOC_S_EXT_CTRLS payload that the working independent V4L2 client (ffmpeg's -hwaccel v4l2request) submits per MPEG-2 frame. This is the contract Phase 4 implementation must match.

Invocation (verbose strace decoding compound v4l2_ext_control payloads):

strace -ff -tt -y -v -e trace=ioctl \
  -o /tmp/iter1_phase3/baseline_C_xvalidator/ffmpeg.strace \
  ffmpeg -hide_banner -loglevel error -hwaccel v4l2request \
    -i ~/fourier-test/bbb_720p10s_mpeg2.ts -frames:v 2 -f null -

Verbatim per-frame submission (5 frames captured, frame 1 shown verbatim):

ioctl(5</dev/video5>, VIDIOC_S_EXT_CTRLS,
  {ctrl_class=0xf010000 /* V4L2_CTRL_CLASS_CODEC_STATELESS */,
   count=3,
   controls=[
     {id=0xa409dc /* V4L2_CID_STATELESS_MPEG2_SEQUENCE */,
      size=12,
      string="\0\5\320\2\0\30\25\0\0\0\1\1"},
     {id=0xa409dd /* V4L2_CID_STATELESS_MPEG2_PICTURE */,
      size=32,
      string="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\202\0\0\0\17\17\17\17\1\3\0\0\0\0\0\0"},
     {id=0xa409de /* V4L2_CID_STATELESS_MPEG2_QUANTISATION */,
      size=256,
      string="\10\20\20\23\20\23\26\26\26\26\26\26\32\30\32\33\33\33\32\32\32\32\33\33\33\35\35\35\"\"\"\35..."}
  ]}) = 0

Field-by-field decode (frame 1, BBB +30s seek into MPEG-2 fixture):

SEQUENCE (12 bytes, struct v4l2_ctrl_mpeg2_sequence per linux/v4l2-controls.h:2009):

Bytes (LE) Value Field
\0\5 0x0500 = 1280 horizontal_size
\320\2 0x02d0 = 720 vertical_size
\0\30\25\0 0x00151800 vbv_buffer_size
\0\0 0x0000 profile_and_level_indication
\1 1 chroma_format (4:2:0)
\1 V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE (0x01) flags

PICTURE (32 bytes, struct v4l2_ctrl_mpeg2_picture per linux/v4l2-controls.h:2056):

Bytes (LE) Value Field
\0\0\0\0\0\0\0\0 0 backward_ref_ts (I-frame, no ref)
\0\0\0\0\0\0\0\0 0 forward_ref_ts (I-frame, no ref)
\202\0\0\0 0x82 = FRAME_PRED_DCT(0x02) | PROGRESSIVE(0x80) flags
\17\17\17\17 f_code = {{15,15},{15,15}} (default for I) f_code[2][2]
\1 1 picture_coding_type (I)
\3 3 picture_structure (FRAME)
\0 0 intra_dc_precision (8-bit)
\0\0\0\0\0 0 reserved[5]

Frame 2 (P-picture per the MPEG-2 GOP) shows different values, verbatim from the next strace line:

PICTURE: "\0\0\0\0\0\0\0\0p\27\0\0\0\0\0\0\202\0\0\0\1\1\17\17\2\3\0\0\0\0\0\0"
Bytes (LE) Value Field
\0\0\0\0\0\0\0\0 0 backward_ref_ts (P, no backward)
p\27\0\0\0\0\0\0 0x1770 ns = 6000 (matches the I-frame's timestamp) forward_ref_ts (refers to frame 1)
\202\0\0\0 0x82 flags (same FRAME_PRED_DCT | PROGRESSIVE)
\1\1\17\17 f_code = {{1,1},{15,15}} (real motion vectors for P) f_code
\2 2 picture_coding_type (P)
\3 3 picture_structure (FRAME)
\0 0 intra_dc_precision
\0\0\0\0\0 0 reserved[5]

QUANTISATION (256 bytes = 4 × 64 bytes):

intra_quantiser_matrix[64] = [8, 16, 16, 19, 16, 19, 22, 22, 22, 22, 22, 22, 26, 24, 26, 27, 27, 27, 26, 26, 26, 26, 27, 27, 27, 29, 29, 29, 34, 34, 34, 29, ...]

This is the canonical MPEG-2 default intra matrix in zigzag scanning order — 8 is at zigzag-position 0 (DC coefficient), 16,16 at positions 1-2 (first AC pair). Confirms the kernel-doc claim that matrices arrive in zigzag scanning order (linux/v4l2-controls.h:2076-2084).

The remaining 192 bytes (non-intra, chroma_intra, chroma_non_intra) all start with \20\20... = 16,16,... — MPEG-2 default non-intra is a flat 16 matrix; chroma matrices duplicate luma when chroma_format=4:2:0.

This is the iter1 contract anchor: every Phase 4 implementation diff and Phase 7 verification must produce a VIDIOC_S_EXT_CTRLS call that's structurally indistinguishable from this — count=3, ctrl_class=V4L2_CTRL_CLASS_CODEC_STATELESS=0xf010000, the three CIDs in this order, with sizes 12 / 32 / 256 and the per-frame field values matching what VAAPI's VAPictureParameterBufferMPEG2 and VAIQMatrixBufferMPEG2 carry for the same fixture.

Baseline D — H.264 regression check (Phase 1 success criterion #5)

Goal: prove Bug 1 fix in isolation doesn't break H.264. Re-runs T4's reference incantation against bbb_1080p30_h264.mp4 with the scratch backend installed; expects byte-identical SHA-256 hashes against T4's reference values (f623d5f7… for frame 1, 7d7bc6f2… for frame 2 at +30s seek).

Verbatim hash output:

f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9  /tmp/iter1_phase3/baseline_D_h264_regr/png_seek_hw/00000001.jpg
7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8  /tmp/iter1_phase3/baseline_D_h264_regr/png_seek_hw/00000002.jpg
f623d5f7a41697f67dd227275c6f1b21ffc257f65626d32fde8229357f8764c9  /tmp/iter1_phase3/baseline_D_h264_regr/png_seek_sw/00000001.jpg
7d7bc6f2146dda8b2d223bba622c4b9fbe9674181ff1e02afe286b620342e0a8  /tmp/iter1_phase3/baseline_D_h264_regr/png_seek_sw/00000002.jpg

Pass: HW frame 1 == SW frame 1 == T4 reference; HW frame 2 == SW frame 2 == T4 reference. Bug 1 fix in isolation does not regress H.264.

Scratch state cleanup

After Baseline D, the scratch patch was reverted to keep master clean for Phase 4 work:

$ git checkout -- src/config.c
$ ninja -C build && sudo ninja -C build install
$ git branch -D iter1-phase3-scratch       # branch was empty — patch was uncommitted

Sanity check (master backend reinstalled, MPEG-2 should fail again):

$ ffmpeg -hwaccel vaapi -i bbb_720p10s_mpeg2.ts -frames:v 2 -f null -
[mpeg2video] Failed to create decode configuration: 12 (the requested VAProfile is not supported).
[mpeg2video] Failed setup for format vaapi: hwaccel initialisation returned error.

Back to Baseline A state — scratch state successfully cleaned.

What Phase 3 confirms / refutes from Phase 2

Phase 2 claim Phase 3 evidence Status
Bug 1: RequestCreateConfig rejects MPEG-2 via fall-through to default: returning VA_STATUS_ERROR_UNSUPPORTED_PROFILE Baseline A libva trace shows vaCreateConfig ret = VA_STATUS_ERROR_UNSUPPORTED_PROFILE for profile=VAProfileMPEG2Main confirmed
Bug 1 fix is sufficient to advance past vaCreateConfig Baseline B libva trace shows vaCreateConfig ret = VA_STATUS_SUCCESS post-patch confirmed
Bug 2: mpeg2.c uses staging-era CID V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS (0x9909fa) which mainline kernel removed Baseline B strace shows VIDIOC_S_EXT_CTRLS id=V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS size=56 = -1 EINVAL confirmed
Bug 2: kernel exposes the new split API (0xa409dc/dd/de) Baseline C strace shows ffmpeg-v4l2request submits these three CIDs successfully confirmed
Cross-validator submits 1 batched VIDIOC_S_EXT_CTRLS, count=3 per frame Baseline C verbatim payload shows exactly that confirmed
Quantisation matrices arrive in zigzag order Baseline C QUANTISATION first 4 bytes [8, 16, 16, 19] matches MPEG-2 default intra matrix in zigzag confirmed
H.264 device-init in context.c is best-effort and silently swallows EINVAL on hantro Baseline B strace shows the 0xa40900/0xa40901 EINVAL (silently); src/context.c:153 has (void)v4l2_set_controls(...) cast confirmed (auxiliary, not iter1 scope)
Phase 1 criterion #5 (H.264 regression check) holds with scratch Bug 1 fix in isolation Baseline D hashes match T4 reference exactly confirmed
mpv-as-driver engages the libva backend for MPEG-2 Baseline A's mpv variant: zero V4L2 ioctls, zero libva trace, silent SW fallback refuted — mpv silently bypasses vaapi for MPEG-2; Phase 1 criterion #3 needs adjustment

Phase 1 criterion #3 needs adjustment (Phase 3 → Phase 1 loopback)

Per feedback_dev_process.md's Phase 3 → Phase 1 loopback edge:

If baseline reveals the Phase 1 metric was tracking the wrong thing → loop back to Phase 1 with the corrected target.

The Phase 1 lock specified:

  1. End-to-end decode engages the backend. mpv --hwdec=vaapi-copy --frames=2 --vo=null --no-audio … logs the [vaapi] libva: Trying to open … chain, the Using hardware decoding (vaapi-copy) confirmation, and exits 0 with no Failed to create decode configuration lines.

Phase 3 baseline shows mpv-vaapi-copy never engages libva for MPEG-2 in the current configuration — neither pre-patch nor post-Bug-1-patch produces [vaapi] log lines or VA-API ioctls when invoked via mpv on the MPEG-2 fixture. The mpv hwdec policy (or ffmpeg-mpv glue layer) filters MPEG-2 out before libva is touched. So the Phase 1 criterion #3 wording can never be satisfied via the original incantation, regardless of whether iter1 fixes the libva backend.

Adjusted Phase 1 criterion #3 (proposed; locks alongside Phase 4 plan):

  1. End-to-end decode engages the backend. ffmpeg -hwaccel vaapi -i bbb_720p10s_mpeg2.ts -frames:v 2 -f null - 2>&1 (with the v4l2_request env vars set) shows the [VAAPI] libva: Trying to open /usr/lib/dri/v4l2_request_drv_video.so chain, vaCreateConfig ret = VA_STATUS_SUCCESS, no Failed to create decode configuration lines, no EINVAL from VIDIOC_S_EXT_CTRLS, and exits 0 cleanly.

The mpv invocation moves from criterion to optional follow-up (potentially needs an --vd override or a fix to mpv's hwdec-codecs filter; a separate, smaller iteration after iter1 lands).

The other four Phase 1 criteria (vainfo enumeration regression, vaCreateConfig success, DMA-BUF GL pixel verify HW=SW, T4 H.264 regression) hold as locked — no adjustment needed.

Phase 4 plan inputs

Phase 4 plan should specify:

  1. Diff scope (per Phase 2 phase2_iter1_situation.md):

    • src/config.c:55-69 — add break; for VAProfileMPEG2Simple/Main cases (3 lines).
    • src/mpeg2.c — full rewrite against the new split API.
    • include/mpeg2-ctrls.h — delete or empty (drop the staging-era header that masks the kernel's modern definitions).
    • src/picture.c — no changes (verified wired correctly in Phase 2).
    • src/context.c — no changes (the H.264 device-init EINVAL is auxiliary, by-design swallowed).
  2. Contract anchor (per Phase 6 contract-before-code per feedback_dev_process.md):

    • Cite verbatim from linux/v4l2-controls.h:1985-2105 — the three control struct definitions and flag constants.
    • Cite verbatim from FFmpeg libavcodec/v4l2_request_mpeg2.c:130-155 — the batched submission shape (3 controls, ctrl_class=V4L2_CTRL_CLASS_CODEC_STATELESS).
    • Cite verbatim from kernel drivers/media/platform/verisilicon/hantro_mpeg2.c::hantro_mpeg2_dec_copy_qtable — the kernel-side zigzag-to-raster permutation (so the libva backend doesn't double-permute).
    • Cite Baseline C verbatim payload from this document (SEQUENCE 12 bytes, PICTURE 32 bytes, QUANTISATION 256 bytes per frame).
  3. Field mapping table (per Phase 2 phase2_iter1_situation.md Bug 2 detail):

    • 6 structural changes from old to new API documented.
    • Source-data extraction in current src/mpeg2.c is sound; only destination-control-struct shape and CIDs change.
  4. Phase 7 verification harness:

    • Re-run all 5 Phase 1 boolean checks (with criterion #3 adjusted as above).
    • Compare the post-fix VIDIOC_S_EXT_CTRLS payload byte-by-byte against Baseline C's verbatim payload — exact match expected for SEQUENCE field values; PICTURE will differ on forward_ref_ts/backward_ref_ts (different timestamp source) and f_code (real values not defaults); QUANTISATION should match exactly for the same fixture.
  5. Mpv-criterion-3 follow-up (deferred):

    • File a follow-up task to investigate why mpv-vaapi-copy filters MPEG-2 out and how to override. Out of iter1 scope.

Phase 3 → Phase 4 close

Phase 3 baselines all four green. Phase 2 Bug 1 + Bug 2 + Bug 3 confirmed empirically. Phase 1 criterion #3 needs a minor wording adjustment (mpv → ffmpeg-direct anchor) — proposed text above; locks with Phase 4 plan if approved. Phase 4 can proceed with the contract-anchored diff scope.