Fetched gsth265parser.c (5409 lines) + .h (2440 lines) from GStreamer main mirror. Plus GstBitReader (~600 LOC vendored separately) as the parser's only non-self-contained dependency. License LGPL v2.1+ (Intel + Sreerenj Balachandran), preserves verbatim in vendored copies; compatible with backend COPYING.LGPL. Add README note listing the two vendored files. GLib adaptation mapped to 6 mechanical replacements: GArray/g_array_* -> plain C dynamic arrays (count+ptr) g_malloc/g_free -> libc malloc/free g_clear_pointer -> inline free+NULL g_assert -> propagate parser-failure-code (NOT abort!) gboolean/gint/etc -> stdbool/stdint GST_DEBUG_* -> backend's request_log/error_log Vendor the FULL parser unchanged per upstream-alignment rule; dead code (PPS/slice/SEI parsing we don't strictly need) is acceptable to preserve upstream-bug-fix-sync simplicity. Header strategy concretized: new src/hevc-ctrls/v4l2-hevc-ext-controls.h ~50 lines with verbatim kernel UAPI defs; runtime probe via VIDIOC_QUERYCTRL at backend init, stored per-driver_data, gated by both kernel-supports + active driver-kind is vdpu381/383. Build system impact: 2-line Makefile.am addition, no autoconf, no pkg-config changes. Compile time uptick acceptable. New constraints (6 total): 1. Vendored LGPL header verbatim preservation + README note 2. Hand-build install path (carries from iter1) 3. Reboot needed after HEVC OOPS recovery (iter2 test cycle) 5. Replace g_assert with error propagation, not abort 6. Parser interpretation may differ from kernel even with same spec Ready for Phase 3 (mostly inherited from iter1 + iter2 phase 0). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8.0 KiB
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 linesgsth265parser.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 <sreerenj.balachandran@intel.com>). 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.h> assert(); __builtin_unreachable() for not_reached |
gboolean, gchar, gint, guint, gint8/16/32/64, guint8/16/32/64 |
C99 <stdbool.h> + <stdint.h> (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:
#include <gst/base/gstbitreader.h>
...
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.amlists each source file explicitly. Addingsrc/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-configline 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 buildtypically 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_RPSand_LT_RPSconstants (the exact integer literals from kernelv4l2-controls.h7.0). - Defines
struct v4l2_ctrl_hevc_ext_sps_st_rpsand_lt_rps(exact verbatim from kernel UAPI 7.0). - Defines the
V4L2_HEVC_EXT_SPS_*_RPS_FLAG_*flag constants. - Includes
<linux/types.h>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):
/* 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.somd5 still0c9a7efaab…(hand-built7ac934e, the iter1 substrate). - Source clip
~/measurements/encoded/bbb_60s_720p.hevc.mp4intact (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)
- Vendored LGPL code must keep its license header verbatim. Adding a top-level
README.mdnote listinggsth265parser.c+gstbitreader.cas LGPL-licensed third-party components. - Backend rebuild after any vendoring change requires re-
installto/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. - 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)
- Vendored parser's
g_asserttriggering at runtime — once GLib's assert is replaced with libcassert, a parser-detected malformed bitstream may abort the whole process instead of returning a parse error. Mitigation: replaceg_assertwith parser-returning-failure-code in the vendored adaptation, not withassert. Spec-violating inputs should propagate up, not crash the backend. - 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_rpsexpects, 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).