Playback handler
Implementation: src/app/ui/handlers/playback_handler.py
Pressing Play looks simple, but smooth playback needs three things to line
up: a timer that decides when to show the next frame, a background decoder
that has already prepared that frame, and a render step that paints it.
PlaybackHandler is the GUI-thread piece that owns the timer and the transport
buttons; it does not decode anything itself.
Where it sits
Arrows are calls. The decode worker runs on its own thread and fills the buffer; see video infrastructure for how. For the whole stack, see the big picture.
Structure
The transport panel emits button signals that the handler connects directly.
The seek slider is the exception: its seek_pos_changed signal is connected by
UIController, which forwards to on_seek.
Playing or stopped
Arrows are state transitions. Stepping to the next or previous frame, or seeking, stops playback first and then moves a single frame.
What one timer tick does
Each tick first checks that a session is selected and that it is not at the last frame. It then asks the Application whether a buffered frame is ready; that call also advances the frame index when it succeeds. A ready frame is rendered, and a missing one is skipped so the next tick can try again.
Current behaviour
- The buffered-frame check can block the GUI thread for up to about 2 seconds while it waits for the decode worker, so a slow decoder can stall the window rather than only dropping a frame.
- Seeking fires only when the slider is released, stops playback, and does
not resume it; a
FIXMEin the code records this. PlaybackHandler.render_frame_requestedis declared but never emitted.
Worked example: pressing Play
- The click reaches
on_play, which asks the Application to mark the session as playing and reads the frame interval derived from the video's frame rate. - The handler starts its
QTimerwith that interval and updates the status bar. - Meanwhile the decode worker keeps the ring buffer ahead of the playhead.
- Every tick consumes one buffered frame and calls
UIController.render_frame_for_session_id, which repaints the preview, frame label, slider, and status bar (see rendering). - At the last frame, on an error, or when another session is selected, the handler stops the timer and playback state.
Ownership
The handler owns the timer and button wiring. The session owns the playhead and playing flag, and the decode worker owns the buffer. Session switching is described in session handlers.