VideoPlayback

class VideoPlayback(renderer: VideoRenderer?, clock: MonotonicClock = MonotonicClock.System, containerFrameRate: Double? = null, timestampsMayJump: Boolean = false, queueCapacity: Int = 4, dropPolicy: FrameDropPolicy = FrameDropPolicy.LateOnly) : AutoCloseable

The engine's video half: a frame queue, the presentation schedule, and the drop and repeat decision.

The full player composes this with AudioPlayback. Together they are the synchronisation the whole library exists to get right, and the division of labour between them is the one every serious player settles on: audio runs undisturbed and drives the clock, and video is adjusted to match it. The ear notices a discontinuity in sound immediately; the eye rarely notices a duplicated frame.

What one tick does

Reads the queue, works out how long the frame on screen should stay there, and either presents the next frame, waits, or drops it. The rule it applies is SyncLaw, which is a pure function with its own table-driven tests, so the hard part is decided somewhere it can be checked rather than inside a loop that has to be watched.

Threading

submit is called from the video decoder coroutine. tick is called from the scheduler coroutine. The queue between them is single producer, single consumer. Nothing else is shared.

Ownership

A frame has exactly one owner at every instant: the queue until it is advanced, then the renderer from the moment VideoRenderer.present is called, including when it fails. With no renderer attached this class closes the frame itself. Nothing here holds a frame it has handed over, so nothing here can close one twice or read one a pool has already taken back.

Constructors

Link copied to clipboard
constructor(renderer: VideoRenderer?, clock: MonotonicClock = MonotonicClock.System, containerFrameRate: Double? = null, timestampsMayJump: Boolean = false, queueCapacity: Int = 4, dropPolicy: FrameDropPolicy = FrameDropPolicy.LateOnly)

Properties

Link copied to clipboard

How much decoded video is held ahead of the frame on screen.

Link copied to clipboard

Video clock minus master clock at the last presented frame. Positive means video is ahead.

Link copied to clipboard

Frames the SCHEDULE dropped because their time had passed.

Link copied to clipboard

Frames the schedule presented with no renderer attached.

Link copied to clipboard
Link copied to clipboard

Frames a renderer was handed and refused, for example because its surface is gone.

Link copied to clipboard

Every frame that left the schedule, whatever became of it: submitted, headless or refused.

Link copied to clipboard

Frames the schedule held on screen for a second period, because video was ahead of the master clock.

Link copied to clipboard

The playback rate as a multiplier of real time. Frame durations and sync corrections are computed in media time and divided by the rate into wall time, and the video clock extrapolates at the same rate, so a video-only file paces correctly with no audio to follow.

Link copied to clipboard

Frames a renderer accepted.

Functions

Link copied to clipboard
open override fun close()
Link copied to clipboard
fun flush(newGeneration: Generation)

Marks the end of a generation. Everything queued is dropped and the schedule restarts.

Link copied to clipboard
fun position(): Pts?

The video clock: the timestamp of the last presented frame, plus the media time since it was presented while the schedule runs. Null before the first frame.

Link copied to clipboard
suspend fun submit(frame: VideoFrame): Boolean

Hands a decoded frame over, suspending while the queue is full.

Link copied to clipboard
suspend fun tick(masterClock: Pts?): Duration

One step of the presentation schedule.

Link copied to clipboard

Hands a decoded frame over without suspending.