Guides

How to install FFmpeg on Ubuntu, Debian and Windows, and check that it works

Install FFmpeg with apt on Ubuntu and Debian, winget or a zip build on Windows, add it to PATH, check -version and encoders, then make HLS and push RTMP.

Published ~11 min read
On this page

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.

Debian · Ubuntu
sudo apt update
sudo apt install -y ffmpeg
ffmpeg -version | head -n 1
Windows 10 · 11 (PowerShell)
winget install --id Gyan.FFmpeg -e
# close the window, open a new terminal, then:
ffmpeg -version

The 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?

MethodVersion you getUse it for
apt install ffmpegThe one your release ships (table below), with security updatesServers, scripts, anything that should keep working after updates
Static build (Linux)A current release or a daily buildA newer FFmpeg than your distribution has, next to the packaged one
winget install Gyan.FFmpegThe current release buildWindows 10 and 11
Zip build + PATH (Windows)Whatever build you downloadWindows Server, or machines without winget
brew install ffmpegHomebrew's current versionmacOS

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

Debian · Ubuntu
sudo apt update
sudo apt install -y ffmpeg

That 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:

ReleaseFFmpeg in the archiveWhere 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.xDebian's package archive
Ubuntu 22.04 LTS4.4.xUbuntu's package archive
Ubuntu 24.04 LTS6.1.xUbuntu's package archive
Any other releaseapt policy ffmpegRun it on the machine
Debian 12 · check the candidate before installing
apt-cache policy ffmpeg | head -n 3
Output on Debian 12, 21 October 2026
ffmpeg:
  Installed: (none)
  Candidate: 7:5.1.9-0+deb12u1

The 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:

Ubuntu
sudo add-apt-repository universe
sudo apt update
sudo apt install -y ffmpeg

On 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:

  1. 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-static

    If 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.

  2. 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/bin comes before /usr/bin in the default PATH on Debian and Ubuntu, so the static build now wins over a packaged one, and which -a lists 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)

PowerShell or Command Prompt
winget search ffmpeg
winget install --id Gyan.FFmpeg -e

Gyan.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:

  1. 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.exe

    True on the last line means C:\ffmpeg\bin now holds ffmpeg.exe, ffprobe.exe and ffplay.exe.

  2. 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, run sysdm.cpl, Advanced, Environment Variables, select Path, Edit, New, and enter C:\ffmpeg\bin.

  3. 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

any system
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:

Example output (excerpt)
 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:

any system
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.mp4
Example output of the second command
stream|codec_name=h264|width=1920|height=1080|r_frame_rate=30/1

Three commands to try first

any system
# 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:

any system · one rendition
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:

any system · 1080p and 720p with a master playlist
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.m3u8

The 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):

any system
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 above 1x, 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

MessageCauseFix
bash: ffmpeg: command not foundNot installed, or a static build not on PATHapt install ffmpeg, or copy the binaries to /usr/local/bin
'ffmpeg' is not recognized as an internal or external commandWindows: bin folder not on PATH, or an old terminalAdd C:\ffmpeg\bin to PATH, open a new terminal
E: Unable to locate package ffmpegUbuntu universe off, or no apt update yetadd-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 dimensionsScale with -2, as in scale=-2:720
Connection refusedPushing RTMP: nothing listens on 1935, or a firewall drops itCheck the RTMP server and open TCP 1935
Too many packets buffered for output streamOne input stream delivers its first packets much later than the otherAdd -max_muxing_queue_size 1024
error while loading shared libraries: libavcodec.soA binary built against libraries that are not installedUse 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.

Related articles

All guides