picture, request_pool: transparent OUTPUT-pool resize on bitstream overrun (#15) #16

Merged
marfrit merged 1 commits from claude-noether/libva-v4l2-request-fourier:noether/output-pool-resize-issue-15 into master 2026-05-21 11:23:09 +00:00

1 Commits

Author SHA1 Message Date
claude-noether 5939ac6ae0 picture, request_pool: transparent OUTPUT-pool resize on bitstream overrun
Follow-up to #13 (PR #14, bounds-check floor).  When a stream-level
resolution upshift mid-session pushes an Annex-B start code / VP8
header pad / slice payload past the OUTPUT pool slot's mmap, the
bounds check used to return VA_STATUS_ERROR_ALLOCATION_FAILED and
force the libva consumer to recreate the surface (losing the frame).
This patch absorbs the resize transparently:

  1. codec_store_buffer's three append sites call a new
     codec_store_buffer_ensure_capacity() before each memcpy/memset.
  2. On overflow, ensure_capacity snapshots the in-flight surface's
     accumulated bytes, temporarily releases its OUTPUT pool slot,
     and calls request_pool_resize.
  3. request_pool_resize STREAMOFFs the OUTPUT queue, munmaps every
     slot, closes every per-slot media-request fd, REQBUFS(0)s the
     V4L2 buffers, re-issues S_FMT with a sizeimage hint = 2× the
     required total (capped at 1 GiB, rounded up to a 4 KiB page),
     CREATE_BUFSes the original slot count, per-slot queries +
     mmaps + media_request_allocs, and STREAMONs.
  4. ensure_capacity re-acquires a pool slot, re-mirrors
     source_{index,data,size,request_fd} onto the surface, and
     restores the saved bytes via memcpy.

The cached S_FMT params (pixelformat, picture_width, picture_height)
are stashed on the request_pool at init time so the resize is fully
self-contained — caller passes only the new sizeimage hint.

A new v4l2_set_format_sizeimage() helper accepts an explicit
sizeimage override; v4l2_set_format keeps the SOURCE_SIZE_MAX (1 MiB)
default for CreateContext-time S_FMT.

The pre-condition for the resize is "no pool slot may be borrowed."
The inline-Sync-in-EndPicture pattern (RequestEndPicture calls
RequestSyncSurface before returning) guarantees that during
codec_store_buffer, the only borrowed slot is the current
render_surface_id's — which the resize trigger explicitly releases
before invoking the pool function. request_pool_resize asserts the
invariant via a busy-scan and bails loudly if anyone breaks it
rather than corrupting in-flight V4L2 state.

On resize failure: re-acquire the just-released slot (it was a
clean busy=false flip; the resize aborted before tearing it down
in the common case, or zeroed its mmap fields in the late-abort
case — either way the re-acquire keeps surface_object's mirror
internally consistent) and surface the original
VA_STATUS_ERROR_ALLOCATION_FAILED so libva clients fall back to
surface recreation as before this patch.

CAPTURE side is untouched — the V4L2 stateless API treats per-queue
streaming independently, so STREAMOFF/STREAMON on OUTPUT does not
disrupt the CAPTURE queue, and a resolution-upshift CAPTURE budget
mismatch becomes a clean V4L2_BUF_FLAG_ERROR on the next DQBUF
(handled by the existing surface error path).

Closes marfrit/libva-v4l2-request-fourier#15.
2026-05-21 13:11:55 +02:00