luv

Workshop wiki

video-interop.lisp

luvcraft/video-interop.lisp

system luvcraft/core · 27 definitions · on GitHub

Portable ownership boundary between decoded hardware frames and the HAL.

A decoder configuration and a frame importer belong to the GPU backend. The resulting picture does not: it is one complete, explicitly owned cohort of plane textures and their views. Video screens publish only complete pictures, so a failed chroma import cannot disturb the luma and chroma pair which the preceding frame is still displaying.

in-package#:luvcraft
defgenericvideo-decode-configuration
devicehardware-policy
:documentation

Return FFmpeg's hardware selector and configuration for device.

hardware-policy is :AUTO or :REQUIRED. Two values are returned: the selector accepted by LIBAV:open-video and its backend-private configuration. A device without a decode bridge returns two NIL values and therefore uses software.

defmethodvideo-decode-configuration
devicehardware-policy
declare
ignoredevicehardware-policy
valuesnilnil
defclassvideo-frame-importer
device:initarg:device:readervideo-frame-importer-device
native-owner-retainers:initform0:accessorvideo-frame-importer-native-owner-retainers:documentation"Number of adopted native owners whose HAL retirement has not finished."
release-state:initform:open:accessorvideo-frame-importer-release-state:documentation"One of :OPEN, :REQUESTED, :RETIRING, :QUEUED, or :RELEASED."
native-retirement-teardown:initformnil:accessorvideo-frame-importer-native-retirement-teardown:documentation"Cached retryable closure transferred when persistent state retires."
lifetime-lock:initform
sb-thread:make-mutex:name"video frame importer lifetime"
:readervideo-frame-importer-lifetime-lock
:documentation

Backend-owned state for adopting decoded hardware frames into DEVICE.

Every native plane owner retains this object until the HAL has completed its physical retirement. Asking to release the importer closes admission at once, but its backend state remains live until the last such owner callback runs.

defgenericmake-video-frame-importer
device
:documentation

Return an importer for hardware frames decoded for device, or NIL.

defmethodmake-video-frame-importer
device
declare
ignoredevice
nil
defgenericadopt-decoded-video-frame
:documentation

Build and return one complete decoded-video-picture.

frame remains borrowed from the decoder. An implementation must retain every native plane for the lifetime of the returned picture and must release every part of an incomplete candidate before propagating an error.

defgenericrelease-video-frame-importer
importer
:documentation

Request release of importer's backend-owned persistent state.

The request is idempotent. Native state is released only after every adopted plane owner has completed physical retirement in the HAL.

defgenericrelease-video-frame-importer-native-state
importer
:documentation

Release importer's backend-native state after its last owner retires.

defmethodrelease-video-frame-importer-native-state
declare
ignoreimporter
values
defunmake-video-frame-importer-native-retirement-teardown
importer

Return one persistent, idempotent native-state teardown for importer.

let
native-state-released-pnil
lambda
unlessnative-state-released-p
setfnative-state-released-pt
sb-thread:with-mutex
video-frame-importer-lifetime-lockimporter
setf
video-frame-importer-release-stateimporter
:released
video-frame-importer-native-retirement-teardownimporter
nil
values
defunmaybe-retire-video-frame-importer-native-state
importer

Transfer a ready importer's persistent native state into HAL retirement.

let
retire-pnil
teardownnil
sb-thread:with-mutex
video-frame-importer-lifetime-lockimporter
when
and
eq:requested
video-frame-importer-release-stateimporter
zerop
video-frame-importer-native-owner-retainersimporter
setf
video-frame-importer-release-stateimporter
:retiring
teardown
or
video-frame-importer-native-retirement-teardownimporter
setf
video-frame-importer-native-retirement-teardownimporter
retire-pt
whenretire-p
let
transferred-pnil
unwind-protect
luv::retire-gpu-native-owner
video-frame-importer-deviceimporter
importerteardown
lambda

Queue implementations call this only after their ledger durably owns importer and both closures.

setftransferred-pt
sb-thread:with-mutex
video-frame-importer-lifetime-lockimporter
unless
eq:released
video-frame-importer-release-stateimporter
setf
video-frame-importer-release-stateimporter
:queued
values

The default/non-live method can fail before transfer. Preserve a caller-owned retry in that case; once invalidated, the HAL ledger is the durable owner and :QUEUED must survive every later failure.

unlesstransferred-p
sb-thread:with-mutex
video-frame-importer-lifetime-lockimporter
when
eq:retiring
video-frame-importer-release-stateimporter
setf
video-frame-importer-release-stateimporter
:requested
importer
defunretain-video-frame-importer-native-owner
importer

Record one native plane owner admitted while importer is still open.

sb-thread:with-mutex
video-frame-importer-lifetime-lockimporter
unless
eq:open
video-frame-importer-release-stateimporter
error"Cannot adopt a native video plane after importer release was requested."
incf
video-frame-importer-native-owner-retainersimporter
importer
defunrelease-video-frame-importer-native-owner
importer

Drop one native owner retainer, without losing a pending release request.

sb-thread:with-mutex
video-frame-importer-lifetime-lockimporter
unless
plusp
video-frame-importer-native-owner-retainersimporter
error"Video frame importer native-owner retainer underflow."
decf
video-frame-importer-native-owner-retainersimporter
importer
defunmake-video-frame-importer-owner-release
importerrelease-native-owner

Retain importer and return an idempotent native-owner release callback.

The callback first runs release-native-owner. Only its successful completion drops the importer retainer. If importer closure was already requested, the same callback then performs (or retries) that closure. This ordering lets a HAL retirement ledger retry any failed native teardown without prematurely freeing the importer state which minted it.

check-typerelease-native-ownerfunction
let
native-owner-released-pnil
importer-retainer-released-pnil
lambda
unlessnative-owner-released-p
funcallrelease-native-owner
setfnative-owner-released-pt
unlessimporter-retainer-released-p
setfimporter-retainer-released-pt

Importer retirement is a separate ledger entry. A persistent-state failure therefore cannot make this plane callback run twice.

values
defmethodrelease-video-frame-importer
importernull
values
defmethodrelease-video-frame-importer
sb-thread:with-mutex
video-frame-importer-lifetime-lockimporter
when
eq:open
video-frame-importer-release-stateimporter
setf
video-frame-importer-release-stateimporter
:requested
values
defclassdecoded-video-picture
textures:initarg:textures:accessordecoded-video-picture-textures:documentation"Plane textures in shader binding order."
views:initarg:views:accessordecoded-video-picture-views:documentation"Views corresponding one-for-one with TEXTURES."
:documentation

One atomically publishable and explicitly owned decoded picture.

defundecoded-video-picture-view
pictureplane

Return picture's view for plane, or NIL when it has no such plane.

nthplane
decoded-video-picture-viewspicture
defundecoded-video-picture-released-p
picture

True when picture no longer owns a view or texture.

or
nullpicture
and
null
decoded-video-picture-viewspicture
null
decoded-video-picture-texturespicture
defuntry-release-decoded-video-resource
nameresource

Destroy resource as release step name and report whether it succeeded.

let
released-pnil
releasingname
destroyresource
setfreleased-pt
released-p
defunrelease-decoded-video-picture
picture

Release picture's views before any of its textures. Idempotent.

Failed handles remain attached for a later release attempt. Textures are not retired at all until every view is gone, preserving the dependency order even when one view's destruction reports a failure.

whenpicture
setf
decoded-video-picture-viewspicture
delete-if
lambda
view
try-release-decoded-video-resource:decoded-video-picture-viewview
decoded-video-picture-viewspicture
unless
decoded-video-picture-viewspicture
setf
decoded-video-picture-texturespicture
delete-if
lambda
texture
try-release-decoded-video-resource:decoded-video-picture-texturetexture
decoded-video-picture-texturespicture
picture
defvar*decoded-video-picture-release-backlog*nil"Incomplete construction candidates whose logical release needs a retry."
defvar*decoded-video-picture-release-backlog-lock*
sb-thread:make-mutex:name"decoded video picture release backlog"
defunretain-decoded-video-picture-release-backlog
picture

Process-root picture after construction rollback could not release it.

picture
defunrelease-decoded-video-picture-or-retain
picture

Release picture, retaining it across an exceptional construction unwind.

picture
defunmake-decoded-video-picture-from-planes
deviceplane-countmake-plane-texture

Build a picture transactionally from plane-count native plane textures.

make-plane-texture is called with each zero-based plane index and returns an owned HAL texture. This function creates the corresponding views. If either step fails, all views built so far are destroyed before every owned texture.

check-typeplane-count
integer1*
let
texturesnil
viewsnil
completed-pnil
unwind-protect
let
picture
progn
dotimes
planeplane-count
let
texture
funcallmake-plane-textureplane
unlesstexture
error"Decoded video plane ~D produced no texture."plane

Record the texture before creating its view: a view failure must still retire this newly adopted plane.

pushtexturetextures
let
view
createdevice
make-texture-view-descriptor:texturetexture
unlessview
error"Decoded video plane ~D produced no view."plane
pushviewviews
make-instance'decoded-video-picture:textures
reversetextures
:views
reverseviews
setfcompleted-pt
picture
unlesscompleted-p
with-release-warnings
let
candidate
make-instance'decoded-video-picture:texturestextures:viewsviews