Video Encoding

You have a video file and something downstream refuses it. Search for video encoding and you get bitrate ladders, CMAF packaging, and per-title encoding for a streaming service you're not building. You need one playable file out of a pipeline that already has fourteen other steps in it.
Quick answer: Video encoding is compressing video into a delivery file with a chosen codec, a chosen quality target, and a container. For a single output file, H.264 at CRF 23 inside an MP4 with faststart covers almost every web and social case: ffmpeg -i input.mov -c:v libx264 -crf 23 -preset medium -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart output.mp4. If you can't install FFmpeg where your pipeline runs, send that same encode to FFmpeg Micro as one API call and download the result, billed on the input's duration in seconds.The hard part of video encoding is not the codec
Conventional wisdom says encoding is a codec decision, so most of the writing about it is a codec comparison. That's partly fair: codecs are where the compression research lives, and AV1 really does beat H.264 on bits per pixel. But for a builder with one video step, the codec is the setting least likely to hurt you. NetInt's 2026 state of video encoding survey of 286 professionals found H.264 still at 84% production adoption against AV1's 17%, with budget and team capacity outranking technical barriers by roughly four to one. Nobody's pipeline is stuck because they picked H.264.
What breaks pipelines is where the encode runs. An encode needs a binary, minutes of CPU, disk for input and output, and a caller patient enough to wait. That combination is exactly what n8n Cloud, Zapier, Vercel functions, and most agent runtimes don't give you. Treat encoding as a job: hand over an input and some settings, get a file back, pay for it.
Encoding, transcoding, and remuxing cost very different amounts
The three words get used as synonyms and they are not. Encoding turns pixel data into a compressed bitstream. Transcoding decodes an existing compressed file and re-encodes it, usually into different settings. Remuxing changes only the container, copying the compressed streams across untouched.
One of them is nearly free. Uncompressed 1080p30 runs at roughly 1.5 Gbps, which is why delivery files are compressed and why a real re-encode burns CPU proportional to duration. A remux doesn't decode anything:
# Re-encode: minutes of CPU, quality loss, full control
ffmpeg -i input.mkv -c:v libx264 -crf 23 -c:a aac -b:a 128k out.mp4
# Remux: seconds, zero quality loss, no control over the video
ffmpeg -i input.mkv -c copy -movflags +faststart out.mp4
Run ffprobe on the source first. If it's already H.264 video with AAC audio and the only problem is an MKV wrapper or a moov atom at the end, you want the second command. Filters and stream copy can't coexist, so the moment you add -vf scale=... you're re-encoding whether you meant to or not.
Three settings decide your encode
Codec, quality target, and container are the three settings worth deliberating over. Everything else is a default to leave alone until a platform complains.
Codec: libx264 unless something forces your hand
H.264 via libx264 is the compatibility floor. It plays in every browser, every social upload pipeline, and every mobile decoder shipped in the last fifteen years. Choose HEVC when a client demands it and set -tag:v hvc1 so Apple's decoders recognize it, VP9 or AV1 when you control playback and bandwidth is the bill you're cutting. Pair it with -c:a aac -b:a 128k: AAC stereo is what upload APIs expect, and leaving Opus or FLAC in an MP4 is a common silent rejection.
Quality: CRF for one file, bitrate when a platform caps you
CRF lets the bitrate float with scene complexity, which is what you want for one file instead of rungs on a ladder. libx264 defaults to CRF 23, and sane values run from 18 to 28, lower being larger and better. Use -b:v only when something downstream has a hard ceiling. Forasoft's 2026 encoding guide puts reasonable H.264 starting points at 2.5 to 4.0 Mbps for 720p and 4.5 to 8.0 Mbps for 1080p. Instagram's publishing API rejects containers above 25 Mbps video bitrate, which CRF alone won't guarantee you stay under.
-preset trades encode time for file size at the same CRF. medium is the default, veryfast is roughly twice the speed and maybe 10% larger, slow the opposite trade. If you pay for compute by the second, preset is the lever.
Container: MP4, and always faststart
MP4 with -movflags +faststart should be your default output. Without that flag, FFmpeg writes the moov atom at the end of the file, so a browser can't start playback until the whole thing downloads, and some CDNs and preview generators give up. Add -pix_fmt yuv420p while you're there. Anything encoded as yuv444p or 10-bit looks fine in VLC and plays as a black rectangle in Safari. There's a longer version of this argument in Facebook video specs aren't the problem. Your encode is.
The same encode, as one API call
An encode you can't run locally becomes four HTTP requests: ask for a presigned upload URL, PUT the file to it, confirm the upload, then submit the job with the FFmpeg flags you already know:
curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $FM_API_KEY" \
-d '{
"inputs": [{ "url": "gs://<YOUR_BUCKET>/1234567890-input.mov" }],
"outputFormat": "mp4",
"options": [
{ "option": "-c:v", "argument": "libx264" },
{ "option": "-crf", "argument": "23" },
{ "option": "-preset", "argument": "medium" },
{ "option": "-pix_fmt", "argument": "yuv420p" },
{ "option": "-c:a", "argument": "aac" },
{ "option": "-movflags", "argument": "+faststart" }
]
}'
The response comes back immediately with a job id and status: "pending". Poll GET /v1/transcodes/:id until status is completed, then GET /v1/transcodes/:id/download for a signed URL. Status checks, job listing, and downloads are free. If you'd rather not hand-roll flags, a simple mode takes "preset": { "quality": "medium", "resolution": "1080p" } and picks them for you. The API docs have the full request shapes, and jobs over two minutes of input run in a separate lane, so a long encode never queues behind short ones.
Before you port a complex command: -filter_complex isn't supported, so multi-input graphs become the API's own overlay and text options, or sequential jobs.
Per output minute is the wrong meter for a pipeline
Almost every managed encoder bills on what it produces, not what you gave it:
| Service | What you're billed for | Published rate |
|---|---|---|
| AWS Elemental MediaConvert | Normalized output minutes multiplied by resolution, frame rate, codec, and multi-pass factors | From $0.0075/min (Basic), $0.015/min (Professional) |
| Google Cloud Transcoder API | Output minutes, per output | $0.015/min SD to $0.06/min UHD |
| Bitmovin | Output minutes by codec and pass count | $0.100/min, 2-pass HEVC HD VOD |
| Coconut | Output minutes by resolution | $0.0075 SD, $0.015 HD, $0.030 UHD |
Two things follow. Produce three renditions from one source and you pay three times, even though you uploaded once. And you can't price a "normalized minute" until after the job runs, because the multipliers depend on what came out.
FFmpeg Micro meters the input instead. One token buys 10 seconds of input video, metered per second with no rounding up to the minute. Trim 30 seconds out of a one-hour recording and you're billed for 30 seconds, not the hour. Failed jobs are never billed. On the Starter plan, $19.99 for 2,500 tokens, a one-minute input is 6 tokens, just under 5 cents, and you know that number before you submit rather than after.
The same math is the honest argument against running your own box. A RunPod GPU at $0.33/hr sounds cheap until you divide by videos actually encoded: RunPod FFmpeg at $0.33/hr isn't cheap. Price it per video.
Where to encode when FFmpeg isn't an option
n8n Cloud has no shell, Zapier has no filesystem, Make has no binaries, and an agent loop has no business waiting six minutes on a subprocess. All four can make an HTTP request, which is all a job-shaped encoder needs. More than 300 of the 700-plus developers and automation builders on the platform run FFmpeg Micro from Make or n8n, and the n8n community node has passed 1,800 downloads. For self-hosted n8n, how to use FFmpeg in n8n without touching your Docker image covers the HTTP Request node setup.
Maintenance matters as much as availability. FFmpeg 9.0 "Lei" landed in August 2026 and hard-removed `-vsync`, `-top`, `-qphist`, and `-filter_complex_script`, along with every libnpp filter, so scripts that had worked for years stopped parsing.
Pitfalls that show up in production
Encode failures in production rarely look like compile errors. They look like files that come out wrong or get rejected downstream.
- Odd dimensions. H.264 needs even width and height, so a computed scale throws "height not divisible by 2". Use
scale=1280:-2, not-1. - Variable frame rate sources. Screen recorders and phones write VFR, and Amazon's listing review rejects it. Force CFR with
-r 30 -fps_mode cfr, since-vsyncis gone in FFmpeg 9. - CRF silently ignored.
-crfmeans nothing to hardware encoders likeh264_nvenc, which want-cqor-b:v. You get a default-bitrate file with no warning. - Trimming after the input.
-ssbefore-iseeks fast; after-iit decodes everything it skips. On a one-hour source that's seconds versus minutes. - Re-encoding what you could copy. If
ffprobesays H.264 and AAC and you only need a different container,-c copyis the answer.
When one MP4 isn't the right answer
A single encode stops being enough when viewers on bad connections are the product. For a course platform or a membership site where people watch 40-minute videos end to end, you want adaptive bitrate: several renditions with aligned keyframes and an HLS or DASH manifest, delivered from a CDN. FFmpeg Micro produces single-file outputs today, so that packaging step belongs in your own infrastructure or with a managed streaming platform. Same answer if you need a drag-and-drop timeline editor; this is an API, not an editor.
FAQ
Is video encoding the same thing as transcoding?
Video encoding is compressing video into a bitstream; transcoding is decoding an existing compressed file and encoding it again with different settings. Every transcode contains an encode, but you can also encode from a raw or image-sequence source, which isn't transcoding. Changing only the container is a remux, and it costs almost nothing.
Am I charged when an encode fails?
Failed jobs are never billed on FFmpeg Micro. Billing is metered per second on the input video actually processed, so a job that errors on a corrupt input or an unsupported codec costs zero tokens.
What CRF value should I use for social video?
CRF 23 is the libx264 default and a good starting point for social and web delivery, with usable values between 18 and 28. Drop to CRF 20 for footage with a lot of motion or fine detail, where artifacts show up faster. Below 18 mostly buys file size.
Can an AI agent run a video encode?
An AI agent can run a video encode through the FFmpeg Micro MCP server at mcp.ffmpeg-micro.com, which exposes transcode jobs as a tool call. Give the agent its own API key, not your main one, and watch the token balance: an agent that retries a bad encode in a loop spends real input seconds each time.
Grab a free key, paste the curl above with your own file, and see what comes back: sign up free gets you 200 tokens, about 33 minutes of video, no card.
About Javid Jamae
Founder & CEO at FFmpeg Micro
Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.
You might also like

Video Transcoding Isn't a Bitrate Ladder. It's One File at Spec
Video transcoding is demux, decode, filter, re-encode, remux. The pipeline version: one file at platform spec as an FFmpeg command, a REST job, or n8n node.

n8n CVE October 2026: upgrade without breaking FFmpeg
n8n CVE October 2026: patch to 1.123.76, 2.37.7, or 2.38.2, what each flaw allows, NODES_EXCLUDE mitigations, and how to upgrade without breaking FFmpeg.

FFmpeg "Buffer Queue Overflow, Dropping" Is a Timestamp Bug
FFmpeg's "buffer queue overflow, dropping" warning means one input in your filter graph outruns another. Find the starving input and fix PTS and durations.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free