ProjectsEncoding
FFmpeg encoding on Cloudflare Containers
Your own ladder and packaging, started by an upload, served from R2
Example design
- 01Object createdA mezzanine file lands in the uploads bucket. An R2 event notification, filtered by prefix and suffix, puts a message on a queue.
- 02Job picked upA Worker consumes the message and works out the ladder for this title.
- 03Start encodeThe Worker starts a container through a Durable Object, one per job, and passes it the source location and the ladder.
- 04Read sourceFFmpeg reads the source from R2 and encodes each rung.
- 05Write renditionsCMAF segments are written back to R2 with HLS and DASH manifests that share them.
- 06ReportThe container reports the result, including a VMAF score for each rung, and stops.
- 07PublishThe Worker marks the title ready. Players fetch segments from R2 through a custom domain, cached at the edge.
- ifAn encode failsThe Worker does not acknowledge the message, so the queue retries the job. After the last retry it goes to a dead letter queue and someone is alerted with the FFmpeg log.
The problem
Managed encoding gives you its own ladder, codecs and packaging. Some catalogues need more control: a ladder per title, AV1 next to H.264, a CMAF layout an existing player expects, or slates burned in at the start. Running FFmpeg yourself used to mean a fleet of encode servers sized for the busiest day. Here the encode runs in a container that starts when a file arrives and stops when the job is done.
What it uses
- R2
- Source files, renditions and manifests
- Queues
- Upload events, retries and a dead letter queue
- Workers and Durable Objects
- Job control, one object per encode
- Containers
- FFmpeg, in an image you build and version
The decisions, and why
- Instance typestandard-4: 4 vCPU, 12 GiB
- Encoding is CPU bound and this is the largest type available. Long titles are split into chunks and encoded in parallel containers.
- TriggerR2 event notification to a queue
- The queue retries failed jobs, and its consumer concurrency stops a burst of uploads from starting more encodes than you want to pay for at once.
- OutputCMAF, with HLS and DASH manifests
- One set of segments serves both manifest types, so storage is not doubled.
- LadderPer title, from measured quality
- Each title gets the rungs its content needs. Stream Ladder covers how the ladder is built.
- DeliveryFrom R2
- R2 does not charge for egress, which matters more for video than for most content.
Limits to plan around
- The largest container has 4 vCPU and 12 GiB of memory, so long or high-resolution sources have to be split into chunks.
- Local disk is 20 GB on the largest instance, so sources are read from R2 in pieces and not copied whole.
- Containers run on the Workers Paid plan.
What you get
- FFmpeg container image with a pinned build
- Worker, queue and Durable Object job control
- Ladder definitions and the chunking logic
- VMAF reporting for every rung
- Dead letter handling and alerts
- Runbook for codec and preset changes
Related product
Stream Ladder: per-title encoding ladder design and validation.
Read about Stream LadderOther projects
More video work on Cloudflare.
- Serverless video platformUploads, encoding, captions and signed playback with no servers to run
- Sub-second live with WHIP and WHEPLive auctions, Q&A and watch-alongs where a few seconds of delay is too much
- Searchable video archiveFind the moment in hours of recordings by what was said
- Thumbnails and previews by URLHover previews, thumbnails and storyboards for a clip library, with no batch jobs
- Instant clips from a live streamViewers clip the moment they just saw and share it while the event is still on
- One live feed to many platformsSend one encoder feed to your own site and to YouTube, Twitch and others at once
DRM solutions
Three corporate use cases, each with a Widevine demo that runs in your browser and checks what your device supports.
Talk about your video project
Tell us what you are building, or what is not working in the platform you have.
128 City Road, London, EC1V 2NX, United Kingdom
17420568
Registered in England and Wales