luvcraft/video-screen.lisp
The rgba words swscale writes into, reused for every picture.
The argument table remains live through submission, then the next world's frame replaces it after that submission has been committed.
Playback state. START is the internal real time the film began at, and SHOWN is the index of the picture currently on the texture.
The soundtrack, when the film has one; then it is also the clock.
The screen's middle in the world: where its sound comes from.
A video file playing on one world rectangle.
The width every picture is scaled to before upload.
A fixed size keeps one texture and one swscale context alive for the whole film, and costs nothing a video wall would notice: the screen is a few metres of world at most.
Return the texture width and height for video, preserving its aspect.
Return the one 36-byte instance record describing the screen rectangle.
Return the lower-left corner and edge vectors of a screen facing camera.
The screen hangs distance ahead of the camera and lift above its eye, sized
width by height in cells, square to the camera's own basis.
Open pathname and build a world screen playing it, facing camera.
height is the screen's height in cells; its width follows the film's aspect.
When rectangle is supplied, it is called with that aspect and returns the
lower-left origin, right edge, and up edge of an authored world rectangle.
hardware is NIL, :AUTO, or :REQUIRED. :REQUIRED rejects a file unless its
first decoded picture actually lives in a hardware surface.
The sound starts as soon as the screen exists; the first picture goes up against its clock.
The caller is already being told why the screen could not be built, so trouble unwinding it is a warning beside that.
Release screen's pipeline, GPU resources, and open film.
Each step is contained so that a failure early on cannot strand the film's
decoder or the resources after it; the failures travel out through whatever
release report is running. See with-release-report.
Picture handles can disappear as soon as their native teardown transfers into the HAL retirement ledger. This therefore requests importer closure after logical retirement; each adopted plane's owner callback keeps the backend-native importer state alive until physical retirement succeeds.
True when screen retains no logical owner which a caller could retry.
Process-root an incompletely released startup screen for later retry.
Release screen, retaining it globally across an exceptional unwind.
Retry every screen retained by an earlier failed startup unwind.
Bind screen's current picture for this frame and retain it through submit.
Encoding has already committed the preceding frame before the next
callback begins. Destroying the old semantic argument table now is
safe; destroying the new one before submit is not.
Retry screen's previously failed picture retirements, retaining failures.
Adopt and atomically publish screen's current decoded hardware frame.
The complete candidate is built before screen changes. If adoption signals,
the preceding picture remains published; after publication its replacement is
retired with warnings so teardown trouble cannot roll the screen backward.
Put PREVIOUS somewhere durable before attempting teardown. A failed destroy therefore remains owned and retryable rather than falling out of reach behind the newly published candidate.
Return the index of the picture that should be showing now.
The film starts on the first call rather than when the screen was built, so a slow world load does not begin the film in the middle.
How many pictures one world frame may decode to catch up.
Catching up has to be bounded, because the debt is not: a world frame that stalls for a second owes a second of film, and paying that back inside the next frame stalls the world again. Past the limit the film simply slips, which nobody watching a screen on a wall will mind.
The picture due by the soundtrack's clock, or NIL to hold the last one.
When the sound has started over, the picture starts over with it; while the previous pass's tail is still sounding, the last picture holds.
Decode up to the picture that is due now and upload it. Return true if so.
Pictures that came due while the last world frame was being drawn are decoded and discarded rather than shown, so the film keeps the world's time instead of the renderer's. A film with sound keeps the sound's time instead: the ear is the stricter judge, so the speaker is the clock and the picture follows.
At most one rewind per call. A film that decodes nothing at all would otherwise rewind and fail forever inside one world frame, which is a hang rather than a dropped picture. With sound, the sound says when to start over; a picture that runs out first just holds.
Whatever the loop managed, the film's clock now reads whatever SHOWN says, so the next call asks for the picture after this one instead of trying to make up the same difference all over again. (The sound's clock is not ours to move: it simply drops the pictures it must.)
Return the internal-time span count pictures of screen's film occupy.
Hear screen's film from where camera stands, facing as it faces.
Stop screen's sound now, leaving the picture to keep its own time.
(screen device)Decode up to the picture that is due now and upload it. Return true if so. Pictures that came due while the last world frame was being drawn are decoded and discarded rather than shown, so the film keeps the world's time instead of the renderer's. A film with sound keeps the sound's time instead: the ear is the…
One atomically publishable and explicitly owned decoded picture.
A video file playing on one world rectangle.
An open video file and its decoder.
How the children of a list are arranged.
The width every picture is scaled to before upload. A fixed size keeps one texture and one swscale context alive for the whole film, and costs nothing a video wall would notice: the screen is a few metres of world at most.
The maximum of compatible quantities.
Multiplication and scalar scaling.
Division of two represented quantities.
(origin right-edge up-edge)(camera distance lift width height)Return the lower-left corner and edge vectors of a screen facing CAMERA. The screen hangs DISTANCE ahead of the camera and LIFT above its eye, sized WIDTH by HEIGHT in cells, square to the camera's own basis.
(camera)(center right up x y scale)Subtraction or unary negation.
(x y z)(device camera pathname target-format
&key (distance 12.0) (lift 4.0) (height 4.5) rectangle (loop-p t)
(hardware :auto))Open PATHNAME and build a world screen playing it, facing CAMERA. HEIGHT is the screen's height in cells; its width follows the film's aspect. When RECTANGLE is supplied, it is called with that aspect and returns the lower-left origin, right edge, and up edge of an authored world rectangle. HARDWARE is NIL, :AUTO, or…
(device hardware-policy)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.
(pathname &key (hardware :auto) hardware-configuration)Open PATHNAME, find its best video stream, and start a decoder for it. Returns a VIDEO. The caller owns it and must CLOSE-VIDEO it.
(video)Decode until VIDEO's frame holds the next picture. Return the frame or NIL. NIL means the file is exhausted; VIDEO's frame is left holding the last picture that was decoded.
Logical negation of one test or raw truth value.
Logical conjunction of tests and raw truth values.
(frame)(device)Return an importer for hardware frames decoded for DEVICE, or NIL.
(device descriptor)Asks the DEVICE for a handle to newly created instance of some object fulfilling the DESCRIPTOR.
(importer frame width height)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.
(device plane-count make-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.
(&key role (stage :fragment) vertex-role label device layout vertex-module
vertex-buffers target-format target-blend primitive depth-stencil)Create and install a live mathematical render pipeline. VERTEX-MODULE is borrowed when VERTEX-ROLE is NIL and STAGE is not :VERTEX. Every module compiled from ROLE or VERTEX-ROLE is owned by the returned artifact and retired on replacement or explicit release.
Addition over compatible quantities.
(pathname &key (loop-p t))Open PATHNAME's soundtrack into a sink and start pumping it, or return NIL for a silent film.
(screen device)(&body body)(screen)Release SCREEN's pipeline, GPU resources, and open film. Each step is contained so that a failure early on cannot strand the film's decoder or the resources after it; the failures travel out through whatever release report is running. See WITH-RELEASE-REPORT.
(&body body)(name &body body)(handle)Logically invalidate HANDLE immediately. Native teardown may be deferred until submitted work which captured HANDLE has completed.
(artifact)(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.
(importer)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.
(sound)(video)(screen)Exceptional startup-owned screens whose logical release needs a retry.
(screen device uniform-buffer)(queue work)Schedule some command buffers on the QUEUE. Submission is asynchronous: returning does not mean the GPU has finished the work, only that the implementation retains everything the work depends on until it completes. Use SUBMITTED-WORK-DONE to wait.
(picture plane)(screen &optional frame)Adopt and atomically publish SCREEN's current decoded hardware frame. The complete candidate is built before SCREEN changes. If adoption signals, the preceding picture remains published; after publication its replacement is retired with warnings so teardown trouble cannot roll the screen backward.
An explicitly owned AVFrame.
Logical disjunction of tests and raw truth values.
(screen)Return the index of the picture that should be showing now. The film starts on the first call rather than when the screen was built, so a slow world load does not begin the film in the middle.
(video width height &key array (alpha 255))Return VIDEO's current picture as a HEIGHT by WIDTH array of RGBA words. Each word is red in its low byte through ALPHA in its high byte, which is the packing luvcraft's block atlas uses. ARRAY is filled and returned when given, so a player can convert into the same array every frame. ALPHA is written rather than…
(queue destination data data-layout size)How many pictures one world frame may decode to catch up. Catching up has to be bounded, because the debt is not: a world frame that stalls for a second owes a second of film, and paying that back inside the next frame stalls the world again. Past the limit the film simply slips, which nobody watching a screen on a…
(screen sound)The picture due by the soundtrack's clock, or NIL to hold the last one. When the sound has started over, the picture starts over with it; while the previous pass's tail is still sounding, the last picture holds.
(sound)Seconds into the current pass of the film, as heard. Negative for the moment after a rewind while the previous pass's tail is still coming out of the speaker: the picture should hold its last frame until this comes round to zero.
Test whether one compatible scalar is at least another.
(video)Test whether one compatible scalar is less than another.
Test whether one compatible scalar is greater than another.
(screen count)(screen camera)(sound source listener right)Hear SOUND, which comes from world point SOURCE, at LISTENER facing with RIGHT as the ear-to-ear axis: set the gain by distance and the pan by bearing. Distance follows an inverse square past the reference distance -- a screen in the next field is a murmur, at the wall it is the film. Pan is constant power over the…
(screen)
A decoded video playing on a rectangle in the block world.
The screen is the plainest drawable luvcraft has: one instanced quad, one sampled texture, no shading model. Everything interesting happens between frames rather than inside them -- a decoder is a clock, and the question is what to do when the wall clock and the film's clock disagree.
The answer here is the simple one: catch up by decoding, never by waiting.
advance-video-screendecodes as many pictures as have come due since the last frame and uploads only the last of them, so a slow render drops pictures instead of falling behind, and a fast render uploads nothing. That is what makes playback keep time with the world rather than with the frame rate the world happens to be running at.Software pictures pass through swscale and one reusable
rgbatexture. Hardware pictures cross the backend video-import protocol as one retained two-plane cohort. Both arrive here as the same atomically publisheddecoded-video-picture; platform surfaces and synchronization stay in the bridge files beside their GPU backends.