# FFmpeg
`deft/ffmpeg` brings video and audio playback to TUI panels: a worker
thread decodes through a runtime FFI binding to the system libav*
libraries, frames land in a stable pixel buffer, and the panel draws them
with `draw/image`. It is a nested package inside stdext and mounts as its
own top-level package.
import "deft/ffmpeg" as ffmpeg
This is the Deft half of the Video app — see
FFI for the binding layer and
Graphics for the draw pipeline.
## Requirements
The host must be built with `-Dffi=true` and have a supported system
FFmpeg installed (libavutil 58/59/60 — FFmpeg 6.1 / 7.1 / 8.1). Audio
additionally needs swresample (7/8; FFmpeg 6 is video-only). The
package manifest marks `ffmpeg` as an `:optional` capability, and
`available?` reports whether the host can play.
## API
| Def | Signature | Description |
|---|---|---|
| `available?` | `{||}` | FFI compiled in and libav* loads |
| `probe` | `{| path |}` | `%{ w h fps duration }` or `%Err` |
| `play` | `{| path opts |}` | Start a player (player ref or `%Err`); opts `:max-width :max-height` |
| `pause` / `resume` / `stop` | `{| p |}` | Transport control |
| `seek` | `{| p sec |}` | Seek to a position |
| `position` | `{| p |}` | Seconds of the last shown frame |
| `playing?` / `error` | `{| p |}` | State accessors |
| `dims` | `{| p |}` | Native `%{ w h }` |
| `draw` | `{| ctx p col row w h |}` | Draw the current frame; returns a bool |
set p [ffmpeg/play "/path/clip.mp4" %{ :max-width 800 :max-height 450 }] defimpl VideoApp Panel { draw {| ctx | [ffmpeg/draw $ctx $p 0 0 $w $h] } }
## How It Plays
- Worker — decode runs in a `defworker` child runtime
(`deft/ffmpeg/worker`); bursts of ~0.5 s of content are yielded to the
player, paced by ring backpressure. Sequential bursts continue the
parked decoder; seeks restart from the nearest keyframe.
- Pacing — a 16 ms poller shows frames when their presentation
timestamp is due against a wall-clock origin; audio (S16, 44.1 kHz,
stereo) is pushed to `audio/stream-*` on SDL hosts. Pause freezes the
clock; EOF loops to 0 after the queued tail plays; a 5 s stall
watchdog surfaces an error.
- Binding — `deft/ffmpeg/lib` dlopens the libraries, probes the
FFmpeg major, and reads structs through per-version offset tables, so
no build-time linking is required.
## See Also
- Video app help — the panel UI
- FFI — foreign-function bindings
- Graphics — pixel buffers and `draw/image`
- defworker — the worker runtime model