diff --git a/phase2_situation_iter2.md b/phase2_situation_iter2.md new file mode 100644 index 0000000..def9ff1 --- /dev/null +++ b/phase2_situation_iter2.md @@ -0,0 +1,97 @@ +# Phase 2 — iter2 situation analysis (HEVC backend EXT_SPS_*_RPS extension) + +Context reset 2026-05-16 evening. iter2 substrate from Phase 0 still holds (no time has elapsed since Phase 0 close). Re-verifies the dependency chain end-to-end now that Phase 1 picked the architecture (vendor GStreamer parser) + a header strategy (runtime-optional probe, no `#ifndef` shim). + +## Vendored-parser characterization + +Fetched 2026-05-16 from GStreamer main mirror (`github.com/GStreamer/gstreamer @ subprojects/gst-plugins-bad/gst-libs/gst/codecparsers/`): + +- `gsth265parser.c` — **5409 lines** +- `gsth265parser.h` — **2440 lines** +- Total: **7849 lines** + +Coverage: whole H.265 parser — NAL header, SPS, PPS, slice header, SEI messages, scaling lists, VUI. Our iter2 only needs NAL-header (to locate SPS NAL) + SPS parsing (specifically `short_term_ref_pic_set` + long-term RPS), but per the upstream-alignment-over-speed rule we **vendor the full parser unchanged** to preserve future bug-fix sync simplicity. Dead code in the vendored portion is acceptable. + +**License**: LGPL v2.1-or-later (`Copyright (C) 2012 Intel Corporation`, `Copyright (C) 2013 Sreerenj Balachandran `). Compatible with backend's existing `COPYING.LGPL`. The vendored file keeps its LGPL header verbatim; backend's MIT-licensed files remain MIT. + +**GLib dependencies to adapt** (mechanical replacement; no logic changes): + +| GLib API | Backend replacement | +|----------|---------------------| +| `GArray` + `g_array_*` (heavily used for variable-length SPS structures) | plain C dynamic arrays — pair of `size_t count` + heap-allocated pointer; helper macros if it cleans up the call sites | +| `g_malloc`, `g_free`, `g_slice_*` | libc `malloc` / `free` | +| `g_clear_pointer` | inline equivalent (`free(p); p=NULL`) | +| `g_assert`, `g_assert_not_reached` | `` `assert()`; `__builtin_unreachable()` for not_reached | +| `gboolean`, `gchar`, `gint`, `guint`, `gint8/16/32/64`, `guint8/16/32/64` | C99 `` + `` (`bool`, `int8_t`, etc.) | +| `GST_DEBUG_CATEGORY` / `GST_DEBUG`/`_WARNING`/`_ERROR` | backend's existing `request_log` / `error_log` macros (or strip to bare `fprintf(stderr, …)` if cleaner) | + +**Additional dependency** uncovered during fetch: `GstBitReader` from `gst-base/gstbitreader.h`. The H.265 parser pulls it via: + +```c +#include +... +GstBitReader br; +gst_bit_reader_init (&br, data, nalu->size - nalu->offset); +gst_bit_reader_skip_unchecked (&br, 1); +nalu->type = gst_bit_reader_get_bits_uint8_unchecked (&br, 6); +``` + +This is a separate vendor target — GStreamer's `subprojects/gstreamer/gst/parse/gstbitreader.c` + `.h` (roughly ~400 lines, plain bit-reading utility). Same LGPL header. Vendoring shape is identical: drop GLib types, replace `g_assert` etc. + +Alternative: the backend already has `src/h264_slice_header.c` which does H.264 slice-header bit-reading — check whether it has a reusable bit-reader the H.265 vendor could use instead of pulling in GStreamer's `gstbitreader`. Reduces vendored-code surface IF the existing reader's API is compatible enough. Phase 4 detail. + +## Build-system impact + +- Backend's `Makefile.am` lists each source file explicitly. Adding `src/gsth265parser/{gsth265parser.c, gstbitreader.c}` is a 2-line addition. No autoconf changes (no new external deps; LGPL vendored code is self-contained C). +- The `pkg-config` line stays as-is (no new packages required). +- The build now includes ~7-8k lines of vendored parser code, ~600 lines of vendored bit-reader. Compile time impact: minor (these are mostly straight-line bitstream parsing, not heavy template / metaprogramming). The build-time uptick on ampere is acceptable — N=1 test shows `ninja -C build` typically completes in <30s currently. + +## Header strategy concrete shape + +`src/hevc-ctrls/v4l2-hevc-ext-controls.h` (new file, ~50 lines): +- Defines `V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS` and `_LT_RPS` constants (the exact integer literals from kernel `v4l2-controls.h` 7.0). +- Defines `struct v4l2_ctrl_hevc_ext_sps_st_rps` and `_lt_rps` (exact verbatim from kernel UAPI 7.0). +- Defines the `V4L2_HEVC_EXT_SPS_*_RPS_FLAG_*` flag constants. +- Includes `` for `__u8/16/32` (which the host already has from 6.19 headers). +- Has a comment block citing the upstream UAPI source (kernel commit / version where these landed). + +Backend includes this header from `src/h265.c` (and from the vendored parser's call sites). When the host eventually bumps `linux-api-headers` to 7.0+, this internal header is dead but harmless — the kernel's `v4l2-controls.h` will have the same constants and the C preprocessor / linker won't notice. + +Runtime probe at backend init (in `src/context.c` or a new helper): + +```c +/* gracefully detect whether the running kernel knows these controls */ +static bool probe_hevc_ext_sps_controls(int video_fd) { + struct v4l2_queryctrl q = {.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS}; + if (ioctl(video_fd, VIDIOC_QUERYCTRL, &q) < 0) return false; + q = (struct v4l2_queryctrl){.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS}; + if (ioctl(video_fd, VIDIOC_QUERYCTRL, &q) < 0) return false; + return true; +} +``` + +Stored on `driver_data` per-device-fd. h265_set_controls populates+submits the new controls only when `driver_data->has_hevc_ext_sps_rps` is true AND the active driver-kind is one of `rkvdec-vdpu381` / `rkvdec-vdpu383` (gated per `feedback_per_driver_kludge_gating`). For RK3399 rkvdec, the controls are skipped entirely (kernel doesn't have them, control submission would NAK). + +## Re-verified Phase 0 substrate (post-Phase-1) + +- ampere reachable, uptime since SDDM auto-login setup at ~10:36; `XDG_RUNTIME_DIR=/run/user/1001`. +- Backend `/usr/lib/dri/v4l2_request_drv_video.so` md5 still `0c9a7efaab…` (hand-built `7ac934e`, the iter1 substrate). +- Source clip `~/measurements/encoded/bbb_60s_720p.hevc.mp4` intact (5.3 MB, iter1 encoded May 16 08:20). +- Kernel `7.0.0-rc3-devices+` running; no new dmesg lines since iter1 close (no HEVC attempts in iter2 Phase 0/1, so no new wedge). + +## Constraints (new in iter2 vs ampere-fourier iter1) + +1. **Vendored LGPL code must keep its license header verbatim.** Adding a top-level `README.md` note listing `gsth265parser.c` + `gstbitreader.c` as LGPL-licensed third-party components. +2. **Backend rebuild after any vendoring change requires re-`install` to `/usr/lib/dri/`.** The hand-build location is unowned-but-pacman-claims-ownership per Phase 0 carryover. Test cycle is: edit → `ninja -C build` → `sudo install -m644 build/src/v4l2_request_drv_video.so /usr/lib/dri/` → re-run ffmpeg. +4. **HEVC failure recovery requires reboot** (per ampere-fourier iter1 Phase 0 — the m2m wedge cascades). Iter2 Phase 6 test cycles must budget ~30 s per reboot if any iteration triggers the OOPS again. + +## Known failure modes (iter2-specific additions) + +5. **Vendored parser's `g_assert` triggering at runtime** — once GLib's assert is replaced with libc `assert`, a parser-detected malformed bitstream may abort the whole process instead of returning a parse error. Mitigation: replace `g_assert` with parser-returning-failure-code in the vendored adaptation, not with `assert`. Spec-violating inputs should propagate up, not crash the backend. +6. **GStreamer parser may produce different RPS data than kernel expects** — even with the same H.265 spec, there's room for subtle interpretation. Phase 7 C3 (frame 0 byte-identical) is the contract; if it fails, the vendored parser's output differs from what `rkvdec_hevc_assemble_hw_rps` expects, and bisection against GStreamer's gst-launch test output (or FFmpeg WIP) is needed. + +## Phase 2 close + +Vendoring spec concrete: 5409 + 2440 + ~600 lines (gsth265parser + gstbitreader), GLib-to-libc adaptation mapped to 6 mechanical replacements, build system impact minor, header shim file shape decided, runtime probe sketched. Six new constraints/failure-modes catalogued. + +Ready for Phase 3 baseline (which for iter2 is mostly inherited from ampere-fourier iter1 + iter2 Phase 0's existing HEVC OOPS reproducer).