Skip to content

Video clips

The player reads Motion-JPEG QuickTime files from /data and draws them centred on the round panel, timed by the clip's own time-to-sample table — so a clip plays at the speed it was authored at, not at whatever rate the decoder happens to manage.

For a single picture, or an animated GIF, see Images. An animated GIF plays on the same task as a clip, so video stop and video status work on it too.

Making a clip

Export at 120×120; anything up to 240×240 fits the panel. Then convert:

ffmpeg -i <input> -c:v mjpeg -q:v 9 -an <output>.mjpeg.mov

-q:v 9 trades quality for size, and -an drops the audio track, which the board has no use for.

Width and height must both be multiples of 8

JPEG is coded in 8×8 blocks, and the fast path decodes 16 lines at a time. A clip whose dimensions are not multiples of 8 still plays, but silently falls back to decoding whole frames, which is about twice as slow at 240×240. 120×120 and 240×240 are both fine; 150×150 is not.

Put it on the board with fs_xfer.py put, then play it.

Playing

video play leia.mjpeg.mov
video play leia.mjpeg.mov loop
video stop

loop repeats the clip until video stop. Without it, the clip plays once and the screen turns off — the panel sleeps with its backlight off whenever nothing is showing.

Starting another clip, an image show or a screen colour over a playing clip keeps the panel on and swaps what is on it.

Looking at a clip

video info leia.mjpeg.mov

reports what the file contains — dimensions, frame count, durations — without playing it. It is also the quickest way to find out whether a file survived its upload intact.

video status

reports, per frame: the time to read it from flash, to decode it, and to decode and draw it. It also reports the paint time, from the first pixels sent to the panel to the last. Paint time is what tearing depends on: it is how long the panel spends halfway through an update.

Decoding modes

By default frames are streamed: decoded 16 lines at a time into one of two small DMA buffers, with each block sent to the panel while the next one decodes.

video play leia.mjpeg.mov frame

forces whole-frame mode, which decodes the entire frame before sending any of it. This is also the automatic fallback for clips whose dimensions are not multiples of 8.

To check the fast path against the slow one:

video verify leia.mjpeg.mov

decodes sample frames both ways and compares them byte for byte.

Measured on the test clips at 30 fps — a 33.3 ms frame budget:

Clip Streamed: decode+draw Streamed: paint Whole frame: decode+draw Whole frame: paint
120×120 4.6 ms 4.1 ms 4.9–5.2 ms 3.2 ms
240×240 14.2–14.6 ms, none late 13.6 ms 28.3–30.2 ms, some late 17.8 ms

Why streaming exists at all, and what the numbers mean, is in Video internals.

If a frame is late

Anything that writes to flash while a clip plays — saving a Wi-Fi network, an NVS write — pauses both CPU cores for the duration of the write, and can make a frame late.

The firmware already handles the one case it controls: the console's command history is written only when no clip is playing. Everything else is up to you. If playback stutters in a way that video status says it should not, look for something writing to flash.