ext-ffmpeg
FFmpeg language bindings for PHP
By
A PHP extension that binds the FFmpeg libraries directly — in pure C against the
Zend API. Open, probe, filter, and transcode media with a real object model and
real typed exceptions. No shell_exec. No string-building. No FFI.
Open → probe → filter → compose → transcode → save
The whole pipeline, in PHP.
- 01
open
Eagerly probe a file — container, duration, and typed stream views in one call.
- 02
generate
Synthesize a stream from nothing — solid colors, test patterns, tones, silence — then filter and encode it like any other.
- 03
probe
Read dimensions, codecs, frame rate, sample rate — as real typed, readonly properties.
- 04
filter
Build a filter graph in PHP — scale, crop, overlay, normalize, even per-frame logic.
- 05
compose
Assemble an output from stream views — map a video and audio stream into one container.
- 06
transcode
Re-encode per stream, with codecs chosen as a typed enum.
- 07
remux
Stream-copy without re-encoding — change container at packet speed, no quality loss.
- 08
save
Write straight to the target via avio. Stateless, re-runnable, leak-free.
A few lines, not a shell script.
Compose an output from stream views, choose codecs as a typed enum, and write it.
save() builds the output context, transcodes, and tears it down — within
the call.
use FFmpeg\Media;
use FFmpeg\MediaEncoder;
use FFmpeg\Codec\VideoCodec;
use FFmpeg\Codec\AudioCodec;
$media = Media::open('input.mov');
// Re-encode the video to H.264, stream-copy the audio, write straight to disk.
(new MediaEncoder())
->addVideo($media->videoStream(), VideoCodec::H264)
->addAudio($media->audioStream(), AudioCodec::Copy)
->save('output.mp4'); Why a native extension?
No shell_exec
No CLI string-building, no escaping, no parsing stderr. You call methods; FFmpeg runs in-process.
Typed exceptions
Every failure is a FFmpeg\Exception\* carrying ->operation and ->avError. No bare false.
GC-tied lifecycle
Native resources hang off PHP objects and free on garbage collection. No manual cleanup.
OO-first
Media, streams, MediaEncoder — a real object model. No av_* soup in the global namespace.
Pure C / Zend API
Not FFI, not a wrapper around the binary. A native extension compiled against the libraries.
Typed filter catalog
Every FFmpeg filter as a typed, final PHP class — axis-checked apply()/generate(), with runnable examples beside the equivalent CLI.
Roadmap
Where this is going.
The destination is frame-level media work at the language level: PHP — and the native CV/ML ecosystem — operating on real frames, with real access to what FFmpeg knows.
Subtitles & multi-track muxing
Map more than one video or audio track — plus subtitle streams — into a single output container.
Frame-level access
Reach individual decoded frames from PHP — work on them in raw PHP, or hand them to ImageMagick, OpenCV, and MediaPipe (sibling extensions) with no serialization.
PHP inside the filter
The constants FFmpeg gives filter expressions (t, n, w, h, text_w…) handed to your PHP callables as live runtime values — not pre-baked expression strings.
Support the work
Native extensions take real time.
Binding FFmpeg in C — getting the object model, the lifecycle, and the docs right — is slow, careful work, and sponsorship is what keeps it moving toward filters and beyond. If ext-ffmpeg saves you from shelling out to a binary, consider chipping in.
And none of this exists without FFmpeg — please support FFmpeg too.
Ready to read the docs?
An Artisan Build project.
Built on FFmpeg — an independent binding, not affiliated with or endorsed by the FFmpeg project. Support FFmpeg.