Short answer: on Ubuntu and Debian, sudo apt install ffmpeg installs ffmpeg and ffprobe from the distribution, which is the right choice for most servers. On Windows 10 and 11, run winget install --id Gyan.FFmpeg -e, or unzip a build linked from ffmpeg.org and add its bin folder to PATH. Then ffmpeg -version in a new terminal confirms it.
sudo apt update
sudo apt install -y ffmpeg
ffmpeg -version | head -n 1winget install --id Gyan.FFmpeg -e
# close the window, open a new terminal, then:
ffmpeg -versionThe package versions below were read with apt-cache policy on Debian 12 on 21 October 2026 and, for Ubuntu, from Ubuntu’s package archive. No video was encoded for this article: the command lines follow FFmpeg’s own documentation on ffmpeg.org, so check each output as you go.
Which install method should you use?
| Method | Version you get | Use it for |
|---|---|---|
apt install ffmpeg | The one your release ships (table below), with security updates | Servers, scripts, anything that should keep working after updates |
| Static build (Linux) | A current release or a daily build | A newer FFmpeg than your distribution has, next to the packaged one |
winget install Gyan.FFmpeg | The current release build | Windows 10 and 11 |
| Zip build + PATH (Windows) | Whatever build you download | Windows Server, or machines without winget |
brew install ffmpeg | Homebrew's current version | macOS |
The FFmpeg project itself publishes only source code. Every ready-made binary, the distribution packages included, is built by someone else, and the download page on ffmpeg.org lists the builders it links to for Linux, Windows and macOS.
Install FFmpeg on Ubuntu and Debian
sudo apt update
sudo apt install -y ffmpegThat one package brings ffmpeg, ffprobe and the ffplay player, plus the codec libraries. Expect apt to pull in around a hundred packages: on a Debian 12 server, a simulated install (apt-get -s install ffmpeg) listed 104 new ones. Which FFmpeg you get depends on the release:
| Release | FFmpeg in the archive | Where the number comes from |
|---|---|---|
| Debian 12 (bookworm) | 5.1.x (5.1.9-0+deb12u1 when checked) | apt-cache policy ffmpeg, 21 October 2026 |
| Debian 13 (trixie) | 7.1.x | Debian's package archive |
| Ubuntu 22.04 LTS | 4.4.x | Ubuntu's package archive |
| Ubuntu 24.04 LTS | 6.1.x | Ubuntu's package archive |
| Any other release | apt policy ffmpeg | Run it on the machine |
apt-cache policy ffmpeg | head -n 3ffmpeg:
Installed: (none)
Candidate: 7:5.1.9-0+deb12u1The 7: in front is Debian’s package epoch, not part of the FFmpeg version, and ffmpeg -version later prints it as 5.1.9-0+deb12u1. The Debian build is not a stripped-down one: on Debian 12, apt-cache depends libavcodec59 lists libx264, libx265, libvpx, libaom, SVT-AV1, dav1d, Opus and LAME, so H.264, HEVC, VP9 and AV1 encoding all work out of the box. What it leaves out is the non-free Fraunhofer AAC encoder; FFmpeg’s built-in aac encoder is what you use instead.
E: Unable to locate package ffmpeg
On Ubuntu, FFmpeg lives in the universe component. Standard installs have it switched on; some minimal images do not. Enable it and try again:
sudo add-apt-repository universe
sudo apt update
sudo apt install -y ffmpegOn Debian it is in main, so this error there almost always means the package lists were never downloaded; sudo apt update fixes it. Other causes are in Unable to locate package. On other systems: apk add ffmpeg on Alpine, brew install ffmpeg on a Mac, and on Rocky Linux and AlmaLinux the package comes from the RPM Fusion repository, which needs EPEL enabled first.
A newer FFmpeg on Linux: the static build
When a filter or encoder you need is newer than your distribution’s FFmpeg, take a static build instead of replacing half the media stack with a third-party repository. A static build is a single self-contained binary: nothing to install, nothing that conflicts with the apt package. ffmpeg.org’s download page links Linux static builds for amd64 and arm64; the link below is the release build it points to:
- 1Download and unpack
Linux · amd64 cd /tmp curl -LO https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz tar -xf ffmpeg-release-amd64-static.tar.xz ls -d ffmpeg-*-amd64-staticIf that file has moved, take the current link from the “Linux Static Builds” entry on ffmpeg.org’s download page. The folder name carries the version number.
- 2Put the two binaries on your PATH
Linux sudo install -m 755 ffmpeg-*-amd64-static/ffmpeg ffmpeg-*-amd64-static/ffprobe /usr/local/bin/ hash -r which -a ffmpeg/usr/local/bincomes before/usr/binin the default PATH on Debian and Ubuntu, so the static build now wins over a packaged one, andwhich -alists both in that order. To go back, delete the two files from/usr/local/bin.
Install FFmpeg on Windows
With winget (Windows 10 and 11)
winget search ffmpeg
winget install --id Gyan.FFmpeg -eGyan.FFmpeg is the full release build from gyan.dev, one of the two Windows builders ffmpeg.org links to; winget search ffmpeg shows the other packages on offer. winget unpacks it, puts command aliases for ffmpeg, ffprobe and ffplay into a folder on your user PATH, and asks you to restart your shell when it had to add that folder. Do that: a terminal that was already open keeps its old PATH, and ffmpeg in it still is not found.
From the zip, on Windows Server or without winget
winget is built into Windows 10 and 11, but it is usually not there on Windows Server 2022 or 2019. The zip route works everywhere and needs no installer:
- 1Download and unpack the build
On ffmpeg.org’s download page, choose Windows, then one of the linked builds. The “release essentials” zip from gyan.dev is enough for H.264, HEVC, AAC and HLS work. From PowerShell:
PowerShell $zip = "$env:TEMP\ffmpeg.zip" Invoke-WebRequest "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip" -OutFile $zip -UseBasicParsing Expand-Archive $zip -DestinationPath C:\ Get-ChildItem C:\ -Directory -Filter "ffmpeg-*" | Select-Object -First 1 | Rename-Item -NewName ffmpeg Test-Path C:\ffmpeg\bin\ffmpeg.exeTrueon the last line meansC:\ffmpeg\binnow holdsffmpeg.exe,ffprobe.exeandffplay.exe. - 2Add C:\ffmpeg\bin to PATH
PowerShell · for your user $bin = "C:\ffmpeg\bin" $user = [Environment]::GetEnvironmentVariable("Path", "User") [Environment]::SetEnvironmentVariable("Path", "$user;$bin", "User")For every user on the machine, run PowerShell as Administrator and use
"Machine"in both places instead of"User". The same thing by mouse: press Win+R, runsysdm.cpl, Advanced, Environment Variables, selectPath, Edit, New, and enterC:\ffmpeg\bin. - 3Open a new terminal and check
PowerShell ffmpeg -version where.exe ffmpeg
If Windows answers 'ffmpeg' is not recognized as an internal or external command (Command Prompt) or The term 'ffmpeg' is not recognized (PowerShell), the folder is not on PATH yet, or the terminal is older than the change. On a Windows VPS over Remote Desktop, signing out and back in refreshes PATH for every new window.
Check the install: -version, -encoders, ffprobe
ffmpeg -version # version, compiler, build flags
ffmpeg -hide_banner -encoders | grep -E 'libx264|aac'
ffmpeg -hide_banner -buildconf | grep -i x264 # was it built with libx264?The first line of -version names the build, for example ffmpeg version 5.1.9-0+deb12u1 on Debian 12, and the configuration: line lists every --enable- flag it was built with. -hide_banner drops that header from the other commands. In the encoder list, each line starts with flags (the V or A says video or audio) followed by the name you pass to -c:v or -c:a:
V....D libx264 libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)
A....D aac AAC (Advanced Audio Coding)On Windows, use findstr in place of grep: ffmpeg -hide_banner -encoders | findstr libx264. ffprobe comes with every build and reads a file without changing it, which is how you check what a source really contains before you transcode it:
ffprobe -hide_banner input.mp4
ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name,width,height,r_frame_rate -of compact input.mp4
ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 input.mp4stream|codec_name=h264|width=1920|height=1080|r_frame_rate=30/1Three commands to try first
# convert anything to an MP4 that plays everywhere (H.264 + AAC)
ffmpeg -i input.mov -c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 128k -movflags +faststart output.mp4
# cut 30 seconds from 1:00 without re-encoding (cuts land on keyframes)
ffmpeg -ss 00:01:00 -i input.mp4 -t 30 -c copy clip.mp4
# extract the audio as MP3
ffmpeg -i input.mp4 -vn -c:a libmp3lame -q:a 2 audio.mp3-crf sets quality for libx264: 23 is the default, lower is better and larger. -movflags +faststart moves the MP4 index to the front so a browser can start playing before the whole file has downloaded. -c copy copies the streams as they are, which takes seconds instead of minutes but cannot change codec, size or bitrate.
Transcode a video to HLS
HLS cuts a video into short segments and lists them in an .m3u8 playlist, which any web server can serve and every current player understands. One rendition first:
mkdir -p hls
ffmpeg -i input.mp4 \
-c:v libx264 -preset veryfast -crf 21 -pix_fmt yuv420p \
-force_key_frames "expr:gte(t,n_forced*2)" \
-c:a aac -b:a 128k -ac 2 \
-f hls -hls_time 6 -hls_playlist_type vod \
-hls_segment_filename "hls/seg_%03d.ts" hls/index.m3u8-force_key_frames puts a keyframe every 2 seconds whatever the frame rate, so the 6-second segments can be cut cleanly. -hls_playlist_type vod writes a complete playlist that players can seek in. For viewers on different connections, encode a ladder of renditions and let a master playlist offer them:
mkdir -p hls
ffmpeg -i input.mp4 \
-filter_complex "[0:v]split=2[a][b];[a]scale=-2:1080[v1];[b]scale=-2:720[v2]" \
-map "[v1]" -map "[v2]" -map 0:a:0 -map 0:a:0 \
-c:v libx264 -preset veryfast -pix_fmt yuv420p \
-b:v:0 5000k -maxrate:v:0 5350k -bufsize:v:0 10000k \
-b:v:1 2800k -maxrate:v:1 3000k -bufsize:v:1 5600k \
-force_key_frames "expr:gte(t,n_forced*2)" \
-c:a aac -b:a 128k -ac 2 \
-f hls -hls_time 6 -hls_playlist_type vod \
-var_stream_map "v:0,a:0 v:1,a:1" -master_pl_name master.m3u8 \
-hls_segment_filename "hls/stream_%v_%03d.ts" hls/stream_%v.m3u8The player loads hls/master.m3u8 and switches between the two renditions as the connection allows. scale=-2:720 keeps the aspect ratio and rounds the width to an even number, which H.264 in 4:2:0 needs. Serve the folder from nginx like any static files; the .m3u8 and .ts types are already in nginx’s stock mime.types.
Push a stream to an RTMP server
FFmpeg can act as the encoder for a live stream, in place of OBS. This sends a video file to an nginx RTMP server as if it were live (-re reads the input at its normal speed instead of as fast as possible):
ffmpeg -re -i input.mp4 \
-c:v libx264 -preset veryfast -b:v 3000k -maxrate 3000k -bufsize 6000k \
-pix_fmt yuv420p -g 60 \
-c:a aac -b:a 128k -ar 48000 \
-f flv rtmp://203.0.113.10/live/mystream-g 60 is a keyframe every 60 frames, 2 seconds at 30 fps; use 50 for a 25 fps source. Add -stream_loop -1 before -i to loop the file forever, and if the file is already H.264 and AAC, -c copy in place of the encoder options sends it without re-encoding. The server side, from the rtmp block to the HLS output and the firewall rule for port 1935, is in setting up an RTMP server with nginx.
CPU encoding with libx264: what it costs
Everything above encodes on the CPU with libx264, which uses all available cores by default. The preset trades CPU time for file size: ultrafast, superfast, veryfast, faster, fast, medium (the default), slow, slower, veryslow. A slower preset gives the same quality at a lower bitrate, at the cost of more CPU per frame.
- Watch
speed=in the progress line. It shows how fast FFmpeg encodes relative to real time. For a file job, any value works; for a live stream it has to stay above1x, or the stream falls behind and viewers buffer. - Every rendition is its own encode. A 1080p, 720p and 480p ladder costs roughly the CPU of three encodes, so tune the preset and the ladder before adding hardware.
- For low latency add
-tune zerolatency, which drops the lookahead that adds delay, at some cost in quality per bit.
Running FFmpeg on a VPS or dedicated server
Because libx264 spreads across cores, the vCore count of a server matters more for transcoding than for most web work; the Standard KVM plans run from 2 to 32 vCores. Delivery is the other half: a live stream costs viewers times bitrate in upstream bandwidth, which the bandwidth calculator works out for you. For an always-on ladder or a large audience, a dedicated machine with an unmetered 10 Gbit/s port, the Streaming Dedicated line in Amsterdam, is the usual next step. Running a channel line-up rather than one stream? How ingest, transcoding and delivery fit together is in what IPTV is and how it works.
Common FFmpeg errors and fixes
| Message | Cause | Fix |
|---|---|---|
bash: ffmpeg: command not found | Not installed, or a static build not on PATH | apt install ffmpeg, or copy the binaries to /usr/local/bin |
'ffmpeg' is not recognized as an internal or external command | Windows: bin folder not on PATH, or an old terminal | Add C:\ffmpeg\bin to PATH, open a new terminal |
E: Unable to locate package ffmpeg | Ubuntu universe off, or no apt update yet | add-apt-repository universe, then apt update |
Unknown encoder 'libx264' | A build without libx264 (LGPL builds leave it out, because x264 is GPL) | Use the distribution package or a GPL build |
height not divisible by 2 (1280x721) | H.264 with 4:2:0 colour needs even dimensions | Scale with -2, as in scale=-2:720 |
Connection refused | Pushing RTMP: nothing listens on 1935, or a firewall drops it | Check the RTMP server and open TCP 1935 |
Too many packets buffered for output stream | One input stream delivers its first packets much later than the other | Add -max_muxing_queue_size 1024 |
error while loading shared libraries: libavcodec.so | A binary built against libraries that are not installed | Use the distribution package or a static build |
The last one has a general fix for any program that prints it, in error while loading shared libraries.
Frequently asked
How do I install FFmpeg on Ubuntu?
Run sudo apt update, then sudo apt install ffmpeg. The package is in Ubuntu's universe component; if apt says Unable to locate package ffmpeg, enable it with sudo add-apt-repository universe and run apt update again. ffmpeg -version confirms the install. Ubuntu 24.04 ships FFmpeg 6.1 and Ubuntu 22.04 ships 4.4.
How do I install FFmpeg on Windows?
On Windows 10 or 11, run winget install --id Gyan.FFmpeg -e and open a new terminal. Without winget, for example on Windows Server, download one of the Windows builds linked from ffmpeg.org's download page, unzip it to C:\ffmpeg and add C:\ffmpeg\bin to the Path environment variable. ffmpeg -version in a new window confirms it.
How do I check if FFmpeg is installed?
Run ffmpeg -version. If it prints a version and the build configuration, FFmpeg is installed and on your PATH; command not found, or 'is not recognized' on Windows, means it is missing or its folder is not on PATH. ffmpeg -hide_banner -encoders lists the encoders the build has, for example libx264 for H.264.
Why does FFmpeg say Unknown encoder 'libx264'?
The build was compiled without libx264. LGPL builds leave it out because x264 is GPL-licensed, and some minimal builds skip it. Use your distribution's package (Debian and Ubuntu include libx264) or a GPL build from the links on ffmpeg.org, then check with ffmpeg -hide_banner -encoders.