VideoPlayback
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
Properties
Frames the SCHEDULE dropped because their time had passed.
Frames the schedule presented with no renderer attached.
Frames a renderer was handed and refused, for example because its surface is gone.
Every frame that left the schedule, whatever became of it: submitted, headless or refused.
Frames the schedule held on screen for a second period, because video was ahead of the master clock.
Frames a renderer accepted.