cheat sheet

FFmpeg

Comprehensive FFmpeg reference covering transcoding, container conversion, scaling, filters, audio, subtitles, streaming, batch processing, and ffplay — with NVIDIA NVENC/NVDEC/CUDA alternatives, Vulkan compute codecs, VVC/H.266 decoding, and the FFmpeg 8.0 Whisper filter.

FFmpeg — Multimedia Processing

What it is

FFmpeg is a free, open-source multimedia framework maintained by the FFmpeg project that handles transcoding, muxing, demuxing, streaming, filtering, and format conversion for virtually every audio and video format in existence. It underpins hundreds of media applications and is extensible with hardware-accelerated encoders and decoders from NVIDIA (NVENC/NVDEC/CUDA), Intel (QSV), and AMD (AMF/VCE). Reach for FFmpeg whenever you need to convert, compress, clip, filter, or stream media files from the command line — it is the universal Swiss Army knife for multimedia processing.

Three core binaries: ffmpeg (process/convert), ffprobe (inspect — see ffprobe page), ffplay (playback — see ffplay section).

Version landscape (7.x → 8.x)

Major releases land roughly once a year. The two current-decade landmarks are 7.1 "Péter" (Sept 2024, LTS) and 8.0 "Huffman" (Aug 23, 2025). Use 7.1.x on stable distros that need long-term security fixes; use 8.0+ when you want Vulkan compute codecs, the Whisper transcription filter, or the latest VVC/AV1 hardware paths.

bash
# Check which major series ships
ffmpeg -version | head -1

# Quick capability probes for the headline new features
ffmpeg -h decoder=vvc 2>&1 | head -3    # 7.1+: stable VVC/H.266 decoder
ffmpeg -h encoder=av1_vulkan 2>&1 | head -3   # 8.0+: AV1 Vulkan encoder
ffmpeg -h filter=whisper 2>&1 | head -3 # 8.0+: OpenAI Whisper ASR filter
ffmpeg -h filter=pad_cuda 2>&1 | head -3      # 8.0+: GPU-side pad

Output: (none — exits 0 on success)

Highlights since 7.0:

  • 7.1 (LTS, Sept 2024) — VVC/H.266 software decoder promoted to stable; Vulkan H.264/H.265 hardware encoding; native AAC USAC + xHE-AAC + MV-HEVC + LC-EVC decoders; IAMF muxer/demuxer; CLI filtergraph chaining (-filter_complex chains feed each other directly); D3D12VA HEVC encoder; Intel QSV-accelerated VVC decoding; AVX2 VVC fast paths; YUVJ pixel format deprecated in favor of explicit colorspace negotiation.
  • 8.0 "Huffman" (Aug 2025) — Vulkan compute-shader codecs (FFv1 encode/decode, ProRes RAW decode — work on any Vulkan 1.3 GPU, no fixed-function video block needed); av1_vulkan hardware encoder; VP9 Vulkan decode hwaccel; VVC VA-API hardware decoding plus VVC support in Matroska/MKV; APV (Advanced Professional Video) decoder; ProRes RAW decoder; whisper audio filter (OpenAI Whisper ASR built-in — emits SRT/JSON without leaving the pipeline); new pad_cuda, colordetect, and scale_d3d11 filters; expanded VVC SCC support (IBC, Palette Mode, ACT).

Installation

bash
# macOS (includes all codecs)
brew install ffmpeg

# Ubuntu / Debian (full build)
sudo apt install ffmpeg

# Arch / Manjaro
sudo pacman -S ffmpeg

# Fedora (from RPM Fusion)
sudo dnf install ffmpeg ffmpeg-devel

# Build from source with NVENC support (requires CUDA SDK)
# https://trac.ffmpeg.org/wiki/HWAccelIntro
# Typical configure flags for NVIDIA:
./configure --enable-cuda-nvcc --enable-cuvid --enable-nvenc \
            --enable-nonfree --enable-libnpp \
            --extra-cflags=-I/usr/local/cuda/include \
            --extra-ldflags=-L/usr/local/cuda/lib64

# Verify version and configuration
ffmpeg -version

Output (ffmpeg -version):

text
ffmpeg version 8.0 Copyright (c) 2000-2025 the FFmpeg developers
built with gcc 14.2.1
configuration: --enable-gpl --enable-libx264 --enable-libx265 --enable-libsvtav1
               --enable-libvvenc --enable-vulkan --enable-libwhisper
               --enable-nvenc --enable-cuda-nvcc --enable-cuvid --enable-libnpp ...
libavutil      60.  3.100 / 60.  3.100
libavcodec     62.  3.100 / 62.  3.100
libavformat    62.  0.102 / 62.  0.102
...

Verifying NVIDIA NVENC / NVDEC support

NVENC is NVIDIA's hardware H.264/HEVC/AV1 encoder built into the GPU; NVDEC (via CUVID) is its hardware decoder counterpart. Run these checks before assuming GPU acceleration is available — driver version and GPU generation determine which codecs are supported.

bash
# Check GPU and driver
nvidia-smi

# List available hardware acceleration methods
ffmpeg -hwaccels

# List NVENC encoders
ffmpeg -encoders 2>/dev/null | grep -E "nvenc|cuvid"

# List NVDEC (hardware) decoders
ffmpeg -decoders 2>/dev/null | grep cuvid

# Quick encode test — will error if NVENC is unavailable
ffmpeg -f lavfi -i testsrc=duration=1:size=1280x720:rate=30 \
       -c:v h264_nvenc -t 1 -f null -

Output (ffmpeg -hwaccels):

text
Hardware acceleration methods:
cuda
vaapi
dxva2
qsv
videotoolbox
d3d11va
opencl
vulkan

Output (ffmpeg -encoders 2>/dev/null | grep nvenc):

text
 V..... h264_nvenc           NVIDIA NVENC H.264 encoder (codec h264)
 V..... hevc_nvenc           NVIDIA NVENC hevc encoder (codec hevc)
 V..... av1_nvenc            NVIDIA NVENC av1 encoder (codec av1)

Output (ffmpeg -decoders 2>/dev/null | grep cuvid):

text
 V..... av1_cuvid            Nvidia CUVID AV1 decoder (codec av1)
 V..... h264_cuvid           Nvidia CUVID H264 decoder (codec h264)
 V..... hevc_cuvid           Nvidia CUVID HEVC decoder (codec hevc)
 V..... vp9_cuvid            Nvidia CUVID VP9 decoder (codec vp9)

Output (nvidia-smi — abbreviated):

text
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 545.23.08    Driver Version: 545.23.08    CUDA Version: 12.3    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC|
|   0  NVIDIA GeForce RTX 4090  Off  | 00000000:01:00.0 Off |                  N/A |
+-----------------------------------------------------------------------------+

General syntax

Every FFmpeg invocation follows the pattern: global options, then one or more -i input pairs each preceded by input-specific options, then output options and the output file. Options that appear before -i apply to the input; options after apply to the output.

bash
ffmpeg [global_options] \
       [input_options] -i input_file \
       [output_options] output_file

# Multiple inputs
ffmpeg -i video.mp4 -i audio.aac -c copy output.mkv

# Stream specifiers  (0:v = video from first input, 0:a = audio, 0:s:0 = first subtitle)
ffmpeg -i in.mkv -map 0:v:0 -map 0:a:0 -c copy out.mp4

# Overwrite output without asking
ffmpeg -y -i in.mp4 out.mp4

# Suppress banner / progress
ffmpeg -hide_banner -loglevel error -i in.mp4 out.mp4

# Dry-run / probe only (reads input, produces no output)
ffmpeg -i in.mp4 -f null -

Output: (none — exits 0 on success)

Quick file information

A fast sanity check to confirm codec, resolution, duration, and bitrate before committing to a long transcode. For structured, scriptable output use ffprobe instead.

bash
# Show file info (prints to stderr; redirect to see cleanly)
ffmpeg -i input.mp4 2>&1 | grep -E "Duration|Stream"

Output (ffmpeg -i input.mp4 2>&1 | grep -E "Duration|Stream"):

text
  Duration: 00:01:30.24, start: 0.000000, bitrate: 5842 kb/s
    Stream #0:0(und): Video: h264 (High), yuv420p, 1920x1080, 5711 kb/s, 29.97 fps
    Stream #0:1(eng): Audio: aac, 48000 Hz, stereo, fltp, 128 kb/s

For structured inspection use ffprobe — see the ffprobe page.

Container conversion (remux without re-encoding)

Changing container format without touching the codec data — near-instant and lossless.

bash
# mp4 → mkv (copy all streams)
ffmpeg -i input.mp4 -c copy output.mkv

# mkv → mp4
ffmpeg -i input.mkv -c copy output.mp4

# Extract audio stream to file
ffmpeg -i input.mp4 -vn -c:a copy output.aac

# Extract video only (drop audio)
ffmpeg -i input.mp4 -an -c:v copy output.mp4

# Change subtitle mux format
ffmpeg -i input.mkv -c:v copy -c:a copy -c:s mov_text output.mp4

Output: (none — exits 0 on success)

H.264 transcoding

H.264 (AVC) is the most widely supported codec — every browser, phone, and smart TV can decode it. Use it when compatibility matters more than file size; libx264 is the go-to CPU encoder, and h264_nvenc offloads the work to an NVIDIA GPU.

CPU — libx264

bash
# CRF encode (18=visually lossless, 23=default, 28=lower quality)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a copy output.mp4

# Slower preset → better compression at same quality
ffmpeg -i input.mp4 -c:v libx264 -crf 20 -preset slow -c:a aac -b:a 192k output.mp4

# Target bitrate (CBR-like)
ffmpeg -i input.mp4 -c:v libx264 -b:v 4M -maxrate 4M -bufsize 8M output.mp4

# Fast web-streaming encode (baseline profile, two-pass)
ffmpeg -i input.mp4 -c:v libx264 -profile:v baseline -level 3.0 -crf 23 \
       -movflags +faststart output.mp4

Output: (none — exits 0 on success)

NVENC alternative (requires NVIDIA GPU — Kepler or newer):

bash
# Quality-based (CQ 0-51; lower = better, ~23 CRF ≈ CQ 23)
ffmpeg -i input.mp4 -c:v h264_nvenc -cq 23 -preset p4 -tune hq \
       -c:a copy output.mp4

# CBR at 4 Mbps
ffmpeg -i input.mp4 -c:v h264_nvenc -rc cbr -b:v 4M -bufsize 8M \
       -preset p4 output.mp4

# VBR with quality hint
ffmpeg -i input.mp4 -c:v h264_nvenc -rc vbr -cq 23 -b:v 0 \
       -preset p5 -tune hq output.mp4

# With hardware decode (-hwaccel cuda decodes on GPU too)
ffmpeg -hwaccel cuda -i input.mp4 -c:v h264_nvenc -cq 23 -preset p4 output.mp4

Output: (none — exits 0 on success)

HEVC / H.265 transcoding

HEVC delivers roughly half the bitrate of H.264 at equivalent quality, making it ideal for archiving or streaming 4K content. The tradeoff is higher encode time on CPU and slightly less universal playback support than H.264 — add -tag:v hvc1 for Apple device compatibility.

CPU — libx265

bash
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium \
       -c:a copy output.mp4

# 10-bit HEVC (better HDR, smaller files)
ffmpeg -i input.mp4 -c:v libx265 -crf 24 -preset slow \
       -x265-params "profile=main10" -pix_fmt yuv420p10le output.mp4

Output: (none — exits 0 on success)

NVENC alternative:

bash
# hevc_nvenc — note: add -tag:v hvc1 for Apple device compatibility
ffmpeg -i input.mp4 -c:v hevc_nvenc -cq 28 -preset p5 -tune hq \
       -tag:v hvc1 -c:a copy output.mp4

# 10-bit HEVC NVENC
ffmpeg -i input.mp4 -c:v hevc_nvenc -profile:v main10 -cq 24 \
       -preset p5 -pix_fmt p010le -tag:v hvc1 output.mp4

# Full hardware pipeline: decode on GPU, encode on GPU
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i input.mp4 -c:v hevc_nvenc -cq 28 -preset p5 -tag:v hvc1 output.mp4

Output: (none — exits 0 on success)

AV1 transcoding

AV1 is a royalty-free codec that outcompresses HEVC by another 20–30%, best suited for web delivery and long-term archival. CPU encoding is very slow — prefer SVT-AV1 for speed; NVENC AV1 hardware encoding requires an RTX 40-series (Ada Lovelace) or newer GPU.

CPU — libsvtav1 (fast) / libaom-av1 (slow, best quality)

bash
# SVT-AV1 (recommended for speed)
ffmpeg -i input.mp4 -c:v libsvtav1 -crf 32 -preset 6 \
       -c:a libopus -b:a 128k output.webm

# libaom — slow but highest quality
ffmpeg -i input.mp4 -c:v libaom-av1 -crf 30 -b:v 0 -cpu-used 4 \
       -c:a libopus -b:a 128k output.webm

Output: (none — exits 0 on success)

NVENC alternative (RTX 40-series / Ada Lovelace and newer — AV1 encoder not available on older NVIDIA GPUs; RTX 50-series Blackwell adds a third NVENC engine for even higher throughput):

bash
ffmpeg -i input.mp4 -c:v av1_nvenc -cq 32 -preset p4 -tune hq \
       -c:a libopus -b:a 128k output.mp4

# Hardware pipeline with AV1 decode + AV1 encode
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -c:v av1_cuvid -i input.mp4 \
       -c:v av1_nvenc -cq 32 -preset p4 output.mp4

Output: (none — exits 0 on success)

Vulkan AV1 encoder (FFmpeg 8.0+, requires a Vulkan 1.3 driver with VK_KHR_video_encode_av1 — currently RADV/AMD and recent NVIDIA Vulkan drivers; runs on any compatible GPU without vendor-specific SDKs):

bash
ffmpeg -init_hw_device vulkan -i input.mp4 \
       -c:v av1_vulkan -b:v 4M \
       -c:a libopus -b:a 128k output.mp4

Output: (none — exits 0 on success)

VVC / H.266 (Versatile Video Coding)

VVC is the H.265 successor — roughly 30–50% bitrate savings over HEVC at equivalent quality, at the cost of much higher decode complexity. FFmpeg 7.1 promoted the native software decoder to stable, and 8.0 added VA-API hardware decoding plus VVC-in-Matroska support. Encoding is via the external libvvenc (Fraunhofer) — slow but the only open VVC encoder shipping today.

bash
# Decode VVC (native software, 7.1+)
ffmpeg -i input.vvc -c:v libx264 -crf 23 output.mp4

# Decode VVC with Intel QSV hardware acceleration (7.1+)
ffmpeg -hwaccel qsv -c:v vvc_qsv -i input.vvc -c:v libx264 -crf 23 output.mp4

# Decode VVC with VA-API (8.0+; Intel Arc / AMD RDNA4+)
ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi \
       -c:v vvc -i input.vvc -c:v libx264 -crf 23 output.mp4

# Encode VVC with libvvenc (CPU, slow — preset 0=slowest..4=fastest)
ffmpeg -i input.mp4 -c:v libvvenc -qp 32 -preset 2 \
       -c:a libopus -b:a 128k output.vvc

# Mux VVC into Matroska (8.0+ adds native VVC-in-MKV)
ffmpeg -i input.vvc -i input.aac -c copy output.mkv

Output: (none — exits 0 on success)

Bitrate and quality control

CRF (Constant Rate Factor) is quality-targeted — the encoder varies bitrate per frame to maintain a consistent perceptual quality level; lower numbers mean better quality. Use CRF for archiving or local playback. Use target bitrate or two-pass encoding when you need a predictable file size or must hit a specific streaming budget.

bash
# CRF — constant rate factor (CPU encoders: libx264, libx265, libsvtav1)
# Lower = higher quality; libx264 default = 23; libx265 default = 28
ffmpeg -i in.mp4 -c:v libx264 -crf 20 out.mp4

# Target average bitrate
ffmpeg -i in.mp4 -c:v libx264 -b:v 2M out.mp4

# Two-pass encoding (most accurate average bitrate)
ffmpeg -i in.mp4 -c:v libx264 -b:v 2M -pass 1 -f null /dev/null
ffmpeg -i in.mp4 -c:v libx264 -b:v 2M -pass 2 out.mp4

# Constrained bitrate (CBR with tolerance)
ffmpeg -i in.mp4 -c:v libx264 -b:v 4M -maxrate 4M -bufsize 8M out.mp4

Output: (none — exits 0 on success)

NVENC quality / bitrate flags:

bash
# Constant quality (CQ) — analogous to CRF; range 0-51
ffmpeg -i in.mp4 -c:v h264_nvenc -rc constqp -qp 23 out.mp4

# Variable bitrate (VBR) — quality-target + optional max
ffmpeg -i in.mp4 -c:v h264_nvenc -rc vbr -cq 23 -b:v 0 -maxrate 8M out.mp4

# CBR
ffmpeg -i in.mp4 -c:v h264_nvenc -rc cbr -b:v 4M -bufsize 8M out.mp4

# Two-pass NVENC VBR
ffmpeg -i in.mp4 -c:v h264_nvenc -rc vbr -b:v 4M -2pass true out.mp4

Output: (none — exits 0 on success)

NVENC tuning reference

NVENC presets map from slowest/best (p7) to fastest/worst (p1). The deprecated slow/medium/fast names map to roughly p7/p4/p1.

bash
# Preset: p1 (fastest, lowest quality) to p7 (slowest, best quality)
ffmpeg -i in.mp4 -c:v h264_nvenc -preset p6 -tune hq out.mp4

# Tune modes
#   hq  — high quality (default for offline transcoding)
#   ll  — low latency (streaming)
#   ull — ultra low latency (< 1 frame delay)
#   lossless — lossless encode

# Rate control + lookahead
ffmpeg -i in.mp4 -c:v h264_nvenc \
       -preset p6 -tune hq \
       -rc vbr -cq 23 -b:v 0 \
       -rc-lookahead 32 \
       -spatial_aq 1 -temporal_aq 1 \
       -aq-strength 8 \
       out.mp4

# B-frame reference mode (improves quality, requires Turing+)
ffmpeg -i in.mp4 -c:v h264_nvenc -b_ref_mode each out.mp4

# Multipass (improves quality at cost of speed)
ffmpeg -i in.mp4 -c:v h264_nvenc -multipass fullres out.mp4

# Zero-latency (for real-time capture/streaming)
ffmpeg -i in.mp4 -c:v h264_nvenc -preset p1 -tune ull -zerolatency 1 out.mp4

Output: (none — exits 0 on success)

Audio operations

Use -c:a copy whenever the audio codec is already compatible with the output container — it avoids re-encoding and preserves quality. Re-encode to AAC or Opus when changing containers, normalizing, or mixing tracks.

bash
# Copy audio unchanged
ffmpeg -i in.mp4 -c:v libx264 -crf 23 -c:a copy out.mp4

# Transcode audio to AAC at 192k
ffmpeg -i in.mkv -c:v copy -c:a aac -b:a 192k out.mp4

# Transcode to Opus (best quality per bit below 256k)
ffmpeg -i in.mp4 -c:v copy -c:a libopus -b:a 128k out.webm

# Transcode to MP3
ffmpeg -i in.mp4 -vn -c:a libmp3lame -q:a 2 out.mp3

# Extract audio only
ffmpeg -i in.mp4 -vn -c:a copy out.aac

# Downmix stereo to mono
ffmpeg -i in.mp4 -ac 1 out.mp4

# Set audio sample rate
ffmpeg -i in.mp4 -ar 44100 out.mp4

# Delay audio by 0.5 seconds (sync fix)
ffmpeg -i in.mp4 -itsoffset 0.5 -i in.mp4 -map 0:v -map 1:a -c copy out.mp4

# Mix two audio tracks into one
ffmpeg -i in.mp4 -i music.mp3 \
       -filter_complex "[0:a][1:a]amix=inputs=2:duration=first:dropout_transition=3[a]" \
       -map 0:v -map "[a]" -c:v copy out.mp4

Output: (none — exits 0 on success)

Trimming and cutting

Placing -ss before -i is a fast seek that jumps to the nearest keyframe — nearly instant but may include a brief extra segment at the start. Placing -ss after -i decodes from the beginning for frame-accurate positioning, which is slower but exact. Use -c copy to avoid re-encoding when a keyframe boundary is acceptable.

bash
# Fast seek (keyframe-accurate; may include a few extra frames before -ss)
ffmpeg -ss 00:01:00 -i in.mp4 -t 30 -c copy out.mp4

# Accurate seek (slow — decodes from start; position exact)
ffmpeg -i in.mp4 -ss 00:01:00 -t 30 -c copy out.mp4

# Cut from 1:00 to 2:30 using -to (end position)
ffmpeg -ss 00:01:00 -to 00:02:30 -i in.mp4 -c copy out.mp4

# Remove first 10 seconds
ffmpeg -ss 10 -i in.mp4 -c copy out.mp4

# Keep last 60 seconds
duration=$(ffprobe -v error -show_entries format=duration \
           -of csv=p=0 in.mp4 | awk '{printf "%d", $1 - 60}')
ffmpeg -ss "$duration" -i in.mp4 -c copy out.mp4

Output: (none — exits 0 on success)

Concatenation

The concat demuxer joins clips losslessly without re-encoding, but all clips must share the same codec, resolution, and frame rate. The concat filter handles mismatched clips at the cost of a full re-encode — use it when clips differ in format or when you need frame-accurate joins.

bash
# Concat demuxer — lossless, no re-encode (all clips must share codec, resolution, fps)
# 1. Create a file list
printf "file '%s'\n" clip1.mp4 clip2.mp4 clip3.mp4 > filelist.txt
# 2. Concatenate
ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp4

# Concat filter — re-encodes; clips can differ in format
ffmpeg -i clip1.mp4 -i clip2.mp4 -i clip3.mp4 \
       -filter_complex "[0:v][0:a][1:v][1:a][2:v][2:a]concat=n=3:v=1:a=1[v][a]" \
       -map "[v]" -map "[a]" output.mp4

Output: (none — exits 0 on success)

NVENC alternative (for concat filter re-encode):

bash
ffmpeg -i clip1.mp4 -i clip2.mp4 \
       -filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" \
       -map "[v]" -map "[a]" \
       -c:v h264_nvenc -cq 23 -preset p4 output.mp4

Output: (none — exits 0 on success)

Resizing and scaling

The scale filter resizes video on CPU; use -2 in place of a dimension to auto-calculate the value that maintains aspect ratio (rounded to the nearest even number, required by most codecs). For GPU pipelines, scale_cuda and scale_npp keep frames in GPU memory and avoid slow PCIe round-trips.

bash
# Scale to 1280×720
ffmpeg -i in.mp4 -vf "scale=1280:720" -c:a copy out.mp4

# Scale width to 1280, preserve aspect ratio (height auto)
ffmpeg -i in.mp4 -vf "scale=1280:-2" -c:a copy out.mp4

# Scale height to 720, preserve aspect ratio
ffmpeg -i in.mp4 -vf "scale=-2:720" -c:a copy out.mp4

# Lanczos (higher quality downscale)
ffmpeg -i in.mp4 -vf "scale=1920:1080:flags=lanczos" -c:a copy out.mp4

# Downscale only if video is larger than 1920×1080
ffmpeg -i in.mp4 -vf "scale='min(1920,iw)':'min(1080,ih)':force_original_aspect_ratio=decrease" out.mp4

Output: (none — exits 0 on success)

NVENC alternative (GPU scaling — requires -hwaccel cuda):

bash
# scale_cuda — fast nearest/bilinear/bicubic on GPU
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i in.mp4 \
       -vf "scale_cuda=1280:720" \
       -c:v h264_nvenc -cq 23 -preset p4 out.mp4

# scale_npp — Lanczos on GPU via NVIDIA Performance Primitives
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i in.mp4 \
       -vf "scale_npp=1280:720:interp_algo=lanczos" \
       -c:v h264_nvenc -cq 23 -preset p4 out.mp4

# Keep aspect ratio with scale_cuda
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i in.mp4 \
       -vf "scale_cuda=1280:-2" \
       -c:v hevc_nvenc -cq 28 -preset p5 out.mp4

Output: (none — exits 0 on success)

Cropping and padding

Crop and pad filters are CPU-only. When used in a NVENC pipeline, add hwdownload,format=yuv420p before the filter and hwupload after.

bash
# Crop to 1280×720 starting at x=320, y=180
ffmpeg -i in.mp4 -vf "crop=1280:720:320:180" -c:a copy out.mp4

# Crop center 1920×816 (cinema 2.35:1 from 1920×1080)
ffmpeg -i in.mp4 -vf "crop=1920:816" -c:a copy out.mp4

# Pad to 1920×1080 with black bars (letterbox a 4:3 source)
ffmpeg -i in.mp4 -vf "pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black" -c:a copy out.mp4

Output: (none — exits 0 on success)

NVENC pipeline with CPU crop:

bash
# Decode on GPU, crop on CPU, re-upload, encode on GPU
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i in.mp4 \
       -vf "hwdownload,format=yuv420p,crop=1280:720:320:180,hwupload" \
       -c:v h264_nvenc -cq 23 -preset p4 out.mp4

Output: (none — exits 0 on success)

pad_cuda (FFmpeg 8.0+) — GPU-side padding eliminates the hwdownload/hwupload round-trip when letterboxing inside an NVENC pipeline:

bash
# Letterbox a 4:3 source to 1920x1080 entirely on GPU
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i in.mp4 \
       -vf "scale_cuda=1440:1080,pad_cuda=1920:1080:240:0:black" \
       -c:v h264_nvenc -cq 23 -preset p4 out.mp4

Output: (none — exits 0 on success)

Frame rate control

Use the fps filter rather than the global -r flag when possible — it applies the rate change only to the video stream without affecting audio timing. Motion interpolation (minterpolate) synthesizes in-between frames for smoother output but is computationally expensive.

bash
# Set output frame rate to 30 fps
ffmpeg -i in.mp4 -r 30 -c:a copy out.mp4

# fps filter (preferred — avoids affecting audio timing)
ffmpeg -i in.mp4 -vf "fps=30" -c:a copy out.mp4

# Convert 29.97 → 25 fps with frame blending
ffmpeg -i in.mp4 -vf "minterpolate=fps=25:mi_mode=blend" -c:a copy out.mp4

# Double frame rate to 60 fps with motion interpolation (CPU-intensive)
ffmpeg -i in.mp4 -vf "minterpolate=fps=60:mi_mode=mci" -c:a copy out.mp4

Output: (none — exits 0 on success)

Deinterlacing

Interlaced video (common in broadcast and older capture sources) stores alternating fields per frame, producing combing artifacts on progressive displays. yadif is the standard CPU deinterlacer; bwdif produces smoother motion at slightly higher CPU cost. Use the _cuda variants to keep the operation on the GPU in an NVENC pipeline.

bash
# yadif — standard deinterlacer (field-mode, frame output)
ffmpeg -i in.mp4 -vf "yadif=0:-1:0" -c:a copy out.mp4

# bwdif — better waved deinterlacer (smoother motion)
ffmpeg -i in.mp4 -vf "bwdif=0:-1:0" -c:a copy out.mp4

Output: (none — exits 0 on success)

NVENC alternative:

bash
# yadif_cuda — GPU deinterlace (Turing+)
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i in.mp4 \
       -vf "yadif_cuda=0:-1:0" \
       -c:v h264_nvenc -cq 23 -preset p4 out.mp4

# bwdif_cuda
ffmpeg -hwaccel cuda -hwaccel_output_format cuda \
       -i in.mp4 \
       -vf "bwdif_cuda=0:-1:0" \
       -c:v h264_nvenc -cq 23 -preset p4 out.mp4

Output: (none — exits 0 on success)

Video filters

Video filters are chained in -vf "filter1,filter2" order and run on the CPU by default. Filters like unsharp, eq, and drawtext have no CUDA equivalent and require a hwdownload,format=yuv420p,...,hwupload bridge when used inside a GPU pipeline.

bash
# Sharpen
ffmpeg -i in.mp4 -vf "unsharp=5:5:1.0:5:5:0.0" -c:a copy out.mp4

# Blur (boxblur)
ffmpeg -i in.mp4 -vf "boxblur=2:1" -c:a copy out.mp4

# Brightness / contrast / saturation
ffmpeg -i in.mp4 -vf "eq=brightness=0.05:contrast=1.1:saturation=1.2" -c:a copy out.mp4

# Gamma correction
ffmpeg -i in.mp4 -vf "eq=gamma=1.3" -c:a copy out.mp4

# Drawtext overlay (timestamp)
ffmpeg -i in.mp4 \
       -vf "drawtext=text='%{pts\:hms}':x=10:y=10:fontsize=24:fontcolor=white:box=1:boxcolor=black@0.5" \
       -c:a copy out.mp4

# Watermark image (overlay at top-right with padding)
ffmpeg -i in.mp4 -i watermark.png \
       -filter_complex "[0:v][1:v]overlay=W-w-10:10" \
       -c:a copy out.mp4

# Flip horizontal
ffmpeg -i in.mp4 -vf "hflip" -c:a copy out.mp4

# Rotate 90° clockwise
ffmpeg -i in.mp4 -vf "transpose=1" -c:a copy out.mp4

Output: (none — exits 0 on success)

NVENC alternative for overlay:

bash
# overlay_cuda — both inputs must be CUDA frames
ffmpeg -hwaccel cuda -hwaccel_output_format cuda -i in.mp4 \
       -hwaccel cuda -hwaccel_output_format cuda -i watermark.png \
       -filter_complex "[0:v][1:v]overlay_cuda=W-w-10:10" \
       -c:v h264_nvenc -cq 23 -preset p4 out.mp4

Output: (none — exits 0 on success)

For filters without a CUDA equivalent (unsharp, boxblur, drawtext, eq), use the hwdownload,format=yuv420p,...,hwupload bridge when staying in an NVENC pipeline.

Audio filters

Audio filters go in -af "filter1,filter2" and always run on the CPU — they are unaffected by NVENC hardware pipelines. Use loudnorm for broadcast-standard loudness normalization; use atempo (0.5–2.0×) to change playback speed without altering pitch.

bash
# Volume adjustment
ffmpeg -i in.mp4 -af "volume=0.5" out.mp4      # halve volume
ffmpeg -i in.mp4 -af "volume=6dB" out.mp4      # boost 6 dB

# Normalize loudness to EBU R128 (-23 LUFS integrated)
ffmpeg -i in.mp4 -af "loudnorm=I=-23:TP=-2:LRA=7" -c:v copy out.mp4

# Dynamic normalization (gentler, no two-pass required)
ffmpeg -i in.mp4 -af "dynaudnorm" -c:v copy out.mp4

# Fade in/out (3 s fade in at start, 3 s fade out before end)
duration=$(ffprobe -v error -show_entries format=duration -of csv=p=0 in.mp4)
ffmpeg -i in.mp4 -af "afade=t=in:d=3,afade=t=out:st=$(echo "$duration - 3" | bc):d=3" out.mp4

# Change tempo without pitch shift (0.5× to 2.0×)
ffmpeg -i in.mp4 -af "atempo=1.5" out.mp4

# Pitch shift without tempo change (semitones via asetrate + atempo)
ffmpeg -i in.mp4 -af "asetrate=44100*1.0595,aresample=44100,atempo=0.9439" out.mp4

# Bass/treble boost
ffmpeg -i in.mp4 -af "bass=gain=5:frequency=100:width_type=h:width=200,treble=gain=3" out.mp4

# Compressor
ffmpeg -i in.mp4 -af "acompressor=threshold=-12dB:ratio=4:attack=200:release=1000" out.mp4

# High-pass filter (remove rumble below 80 Hz)
ffmpeg -i in.mp4 -af "highpass=f=80" out.mp4

# Low-pass filter
ffmpeg -i in.mp4 -af "lowpass=f=12000" out.mp4

Output: (none — exits 0 on success)

Subtitles

Soft subtitles are muxed as a separate stream that players can toggle on or off; they require codec compatibility with the container (mov_text for MP4, ass for MKV). Burn-in (hardcoded) subtitles are composited into the video pixels — always visible, container-independent, but force a full video re-encode.

bash
# Extract subtitle stream to SRT
ffmpeg -i in.mkv -map 0:s:0 subtitles.srt

# Extract to ASS/SSA
ffmpeg -i in.mkv -map 0:s:0 subtitles.ass

# Mux external SRT as soft subtitle into mp4
ffmpeg -i in.mp4 -i subtitles.srt \
       -c:v copy -c:a copy -c:s mov_text \
       -metadata:s:s:0 language=eng out.mp4

# Burn-in (hardcode) subtitles — CPU only, forces re-encode
ffmpeg -i in.mp4 -vf "subtitles=subtitles.srt" \
       -c:v libx264 -crf 23 -c:a copy out.mp4

# Burn-in with NVENC
ffmpeg -i in.mp4 \
       -vf "subtitles=subtitles.srt" \
       -c:v h264_nvenc -cq 23 -preset p4 -c:a copy out.mp4

Output: (none — exits 0 on success)

Whisper transcription (FFmpeg 8.0+)

The whisper audio filter runs OpenAI's Whisper speech-to-text model directly inside the FFmpeg graph — no Python, no separate pipeline. Point it at a downloaded ggml-*.bin model from the whisper.cpp release page, choose an output format (text, srt, json), and FFmpeg writes the transcript while it processes the audio.

bash
# Generate an SRT subtitle file from a video's audio track
ffmpeg -i podcast.mp4 \
       -vn \
       -af "whisper=model=/models/ggml-medium.en.bin:format=srt:destination=subs.srt" \
       -f null -

# Pipe Whisper output into burn-in step (single command)
ffmpeg -i video.mp4 \
       -af "whisper=model=/models/ggml-base.en.bin:format=srt:destination=auto.srt" \
       -vf "subtitles=auto.srt" \
       -c:v libx264 -crf 23 -c:a copy captioned.mp4

# JSON output (timestamped segments, scriptable)
ffmpeg -i interview.wav \
       -af "whisper=model=/models/ggml-large-v3.bin:language=en:format=json:destination=transcript.json" \
       -f null -

# Run on GPU via whisper.cpp Vulkan/CUDA build (set when configuring ffmpeg)
ffmpeg -i talk.mp4 \
       -af "whisper=model=/models/ggml-medium.bin:use_gpu=1:format=srt:destination=talk.srt" \
       -f null -

Output: (none — exits 0 on success; transcript written to the destination= path)

Frames and images

FFmpeg can extract individual frames from video or assemble an image sequence back into video. Use fps=1 to pull one frame per second for thumbnails; use -frames:v 1 to grab a single frame at a specific timestamp. Building video from an image sequence is a common timelapse and animation workflow.

bash
# Extract one frame per second as JPEG
ffmpeg -i in.mp4 -vf "fps=1" frame_%04d.jpg

# Extract a single thumbnail at 10 seconds
ffmpeg -ss 10 -i in.mp4 -frames:v 1 thumbnail.jpg

# Extract best-quality keyframe near 10 s
ffmpeg -ss 10 -i in.mp4 -frames:v 1 -qscale:v 2 thumb.jpg

# Extract all keyframes only
ffmpeg -i in.mp4 -vf "select='eq(pict_type,PICT_TYPE_I)'" -vsync vfr keyframe_%04d.jpg

# Build video from image sequence (image2 demuxer)
ffmpeg -framerate 24 -i frame_%04d.jpg -c:v libx264 -pix_fmt yuv420p out.mp4

# Build video from glob of images (sorted by name)
ffmpeg -framerate 30 -pattern_type glob -i '*.png' \
       -c:v libx264 -pix_fmt yuv420p out.mp4

# Slideshow: 3 seconds per image
ffmpeg -framerate 1/3 -pattern_type glob -i '*.jpg' \
       -c:v libx264 -r 30 -pix_fmt yuv420p slideshow.mp4

Output: (none — exits 0 on success)

NVENC alternative (for image-to-video encodes):

bash
ffmpeg -framerate 24 -i frame_%04d.jpg \
       -c:v h264_nvenc -cq 23 -preset p4 -pix_fmt yuv420p out.mp4

Output: (none — exits 0 on success)

Streaming

FFmpeg can push live streams to RTMP servers (Twitch, YouTube, nginx-rtmp) or segment video into HLS playlists for adaptive bitrate delivery. Use -re to read input at native frame rate when sourcing from a file; omit it when streaming from a live capture device.

RTMP push

bash
# Push to RTMP server (e.g. nginx-rtmp or SRS)
ffmpeg -re -i in.mp4 \
       -c:v libx264 -preset veryfast -crf 23 -maxrate 3M -bufsize 6M \
       -c:a aac -b:a 128k \
       -f flv rtmp://server/live/streamkey

Output: (none — exits 0 on success)

NVENC alternative:

bash
ffmpeg -re -i in.mp4 \
       -c:v h264_nvenc -preset p1 -tune ll -rc cbr -b:v 3M -bufsize 6M \
       -zerolatency 1 \
       -c:a aac -b:a 128k \
       -f flv rtmp://server/live/streamkey

Output: (none — exits 0 on success)

HLS segmenter

bash
ffmpeg -i in.mp4 \
       -c:v libx264 -crf 23 -preset fast \
       -c:a aac -b:a 128k \
       -f hls -hls_time 6 -hls_list_size 0 \
       -hls_segment_filename "segment_%03d.ts" \
       playlist.m3u8

Output: (none — exits 0 on success)

NVENC alternative:

bash
ffmpeg -i in.mp4 \
       -c:v h264_nvenc -preset p3 -rc cbr -b:v 4M \
       -c:a aac -b:a 128k \
       -f hls -hls_time 6 -hls_list_size 0 \
       -hls_segment_filename "segment_%03d.ts" \
       playlist.m3u8

Output: (none — exits 0 on success)

Low-latency live capture and stream

bash
# Capture from webcam and stream to RTMP (CPU)
ffmpeg -f v4l2 -i /dev/video0 \
       -f alsa -i hw:0 \
       -c:v libx264 -preset ultrafast -tune zerolatency -crf 28 \
       -c:a aac -b:a 96k \
       -f flv rtmp://server/live/key

Output: (none — exits 0 on success)

NVENC alternative:

bash
ffmpeg -f v4l2 -i /dev/video0 \
       -f alsa -i hw:0 \
       -c:v h264_nvenc -preset p1 -tune ull -rc cbr -b:v 2M -zerolatency 1 \
       -c:a aac -b:a 96k \
       -f flv rtmp://server/live/key

Output: (none — exits 0 on success)

Full hardware pipeline (GPU decode → GPU filter → GPU encode)

When all inputs and filters stay in GPU memory, no PCIe copies occur — maximum throughput.

bash
# Decode h264 on GPU, scale on GPU, encode HEVC on GPU
ffmpeg \
  -hwaccel cuda -hwaccel_output_format cuda \
  -c:v h264_cuvid \
  -i in.mp4 \
  -vf "scale_cuda=1920:1080" \
  -c:v hevc_nvenc -cq 28 -preset p5 -tune hq -tag:v hvc1 \
  -c:a copy \
  out.mp4

# Full pipeline with deinterlace + scale
ffmpeg \
  -hwaccel cuda -hwaccel_output_format cuda \
  -c:v h264_cuvid -deint adaptive \
  -i in.mp4 \
  -vf "scale_cuda=1280:720" \
  -c:v h264_nvenc -cq 23 -preset p4 \
  -c:a copy \
  out.mp4

# When a CPU-only filter is needed, download/re-upload:
ffmpeg \
  -hwaccel cuda -hwaccel_output_format cuda \
  -i in.mp4 \
  -vf "scale_cuda=1920:1080,hwdownload,format=yuv420p,unsharp=5:5:1.0,hwupload=extra_hw_frames=16" \
  -c:v hevc_nvenc -cq 28 -preset p5 \
  out.mp4

Output: (none — exits 0 on success)

Vulkan acceleration (vendor-neutral GPU)

Vulkan Video lets FFmpeg use any Vulkan 1.3 GPU — NVIDIA, AMD, Intel, Arm Mali — without vendor SDKs. FFmpeg 7.1 added H.264/H.265 Vulkan encoding; 8.0 adds AV1 encode, VP9 and ProRes RAW decode, and a new class of Vulkan compute-shader codecs (FFv1 encode/decode, ProRes RAW decode) that run on any Vulkan 1.3 device — even GPUs with no fixed-function video block.

bash
# List Vulkan-backed codecs after 8.0
ffmpeg -hide_banner -encoders 2>&1 | grep vulkan
ffmpeg -hide_banner -decoders 2>&1 | grep vulkan

# Decode + encode entirely on Vulkan (works on AMD/Intel/NVIDIA)
ffmpeg -init_hw_device vulkan=vk:0 -hwaccel vulkan -hwaccel_output_format vulkan \
       -i in.mp4 \
       -c:v h264_vulkan -b:v 4M -c:a copy out.mp4

# Vulkan HEVC encode
ffmpeg -init_hw_device vulkan -hwaccel vulkan -hwaccel_output_format vulkan \
       -i in.mp4 \
       -c:v hevc_vulkan -b:v 4M -c:a copy out.mp4

# Vulkan AV1 encode (8.0+)
ffmpeg -init_hw_device vulkan -i in.mp4 \
       -c:v av1_vulkan -b:v 4M -c:a libopus -b:a 128k out.mkv

# Compute-shader FFv1 (lossless) — runs on any Vulkan 1.3 GPU
ffmpeg -init_hw_device vulkan -i master.mov \
       -c:v ffv1_vulkan -c:a copy archive.mkv

# Vulkan-side scale + encode
ffmpeg -init_hw_device vulkan -hwaccel vulkan -hwaccel_output_format vulkan \
       -i in.mp4 \
       -vf "scale_vulkan=1280:720" \
       -c:v h264_vulkan -b:v 3M out.mp4

Output (ffmpeg -encoders 2>&1 | grep vulkan on 8.0):

text
 V....D h264_vulkan          H.264/AVC Vulkan encoder (codec h264)
 V....D hevc_vulkan          H.265/HEVC Vulkan encoder (codec hevc)
 V....D av1_vulkan           AV1 Vulkan encoder (codec av1)
 V....D ffv1_vulkan          FFv1 Vulkan encoder (codec ffv1)

Multiple inputs and overlay

FFmpeg accepts multiple -i inputs and combines them via the filter_complex graph. Use this for picture-in-picture, side-by-side comparison, audio mixing, or watermarking — each input stream is addressed as [n:v] (video) or [n:a] (audio) by input index.

bash
# Picture-in-picture (small video in bottom-right corner)
ffmpeg -i main.mp4 -i pip.mp4 \
       -filter_complex "[1:v]scale=320:-2[small];[0:v][small]overlay=W-w-10:H-h-10" \
       -c:a copy out.mp4

# Side-by-side (two videos next to each other)
ffmpeg -i left.mp4 -i right.mp4 \
       -filter_complex "[0:v]pad=iw*2:ih[bg];[bg][1:v]overlay=w" \
       -c:a copy out.mp4

# Mix two audio streams at equal level
ffmpeg -i video.mp4 -i music.mp3 \
       -filter_complex "[0:a][1:a]amix=inputs=2[a]" \
       -map 0:v -map "[a]" -c:v copy out.mp4

Output: (none — exits 0 on success)

Color space, pixel format, and HDR

Pixel format determines bit depth and chroma subsampling — yuv420p (8-bit 4:2:0) is the broadest-compatible choice; yuv420p10le (10-bit) is required for HDR10. When working with HDR source material, explicitly pass color primaries, transfer characteristics, and color matrix so decoders can apply correct tone mapping.

bash
# List available pixel formats
ffmpeg -pix_fmts 2>&1 | head -20

# Detect actual color range / primaries of a source (FFmpeg 8.0+)
# Reports limited/full range, primaries, transfer, matrix to stderr
ffmpeg -i in.mp4 -vf "colordetect" -f null -

# Convert to yuv420p (broad compatibility)
ffmpeg -i in.mp4 -pix_fmt yuv420p -c:v libx264 -crf 23 out.mp4

# Convert to 10-bit
ffmpeg -i in.mp4 -pix_fmt yuv420p10le -c:v libx265 -crf 24 out.mp4

# HDR10 passthrough (copy color metadata)
ffmpeg -i hdr.mp4 -c:v libx265 -crf 24 \
       -x265-params "hdr-opt=1:repeat-headers=1:colorprim=bt2020:transfer=smpte2084:colormatrix=bt2020nc" \
       -pix_fmt yuv420p10le out.mp4

Output: (none — exits 0 on success)

NVENC HDR:

bash
# NVENC HDR10 (Ampere+ recommended for best results)
ffmpeg -i hdr.mp4 \
       -c:v hevc_nvenc -cq 24 -preset p5 -profile:v main10 \
       -pix_fmt p010le -tag:v hvc1 \
       -color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc \
       out.mp4

Output (ffmpeg -pix_fmts 2>&1 | head -20):

text
Pixel formats:
I.... = Supported Input  format for conversion
.O... = Supported Output format for conversion
..H.. = Hardware accelerated format
...P. = Paletted format
....B = Bitstream format
FLAGS NAME            NB_COMPONENTS BITS_PER_PIXEL BIT_DEPTHS
-----
IO... yuv420p                3            12      8-8-8
IO... yuyv422                3            16      8-8-8
IO... rgb24                  3            24      8-8-8
IO... bgr24                  3            24      8-8-8
IO... yuv422p                3            16      8-8-8
IO... yuv444p                3            24      8-8-8
IO... yuv410p                3             9      8-8-8
IO... yuv411p                3            12      8-8-8
IO... gray                   1             8      8
IO... monow                  1             1      1

Repair and recovery

Corrupted or truncated media files often have broken container metadata, invalid timestamps, or missing keyframes — but the raw codec data may be intact. Try a lossless remux with -err_detect ignore_err or -fflags +genpts before resorting to a full re-encode.

bash
# Re-mux broken container (common fix for "invalid data found when processing input")
ffmpeg -i broken.mp4 -c copy -err_detect ignore_err fixed.mp4

# Fix PTS / DTS timestamps
ffmpeg -i in.mp4 -c copy -fflags +genpts out.mp4

# Force keyframe every 2 seconds (useful before HLS segmenting)
ffmpeg -i in.mp4 -c:v libx264 -crf 23 \
       -x264-params "keyint=60:min-keyint=60:no-scenecut" \
       -c:a copy out.mp4

# Re-encode only if needed; otherwise copy (-c:v copy falls back gracefully)
ffmpeg -i in.mkv -c:v copy -c:a aac -b:a 192k out.mp4 2>&1 || \
    ffmpeg -i in.mkv -c:v libx264 -crf 23 -c:a aac -b:a 192k out.mp4

Output: (none — exits 0 on success)

Batch processing

Loop over files with a shell for loop for sequential processing; use GNU parallel to saturate CPU cores for CPU encodes. Consumer NVIDIA GPUs cap concurrent NVENC sessions at 2–3, so GPU batch jobs should run sequentially to avoid session-limit errors.

bash
# Convert all mkv → mp4 with CPU
for f in *.mkv; do
    ffmpeg -i "$f" -c:v libx264 -crf 23 -c:a aac -b:a 192k "${f%.mkv}.mp4"
done

# Convert all mp4 → HEVC (re-encode)
for f in *.mp4; do
    ffmpeg -i "$f" -c:v libx265 -crf 28 -c:a copy "hevc_${f}"
done

# GNU parallel — use all CPU cores concurrently (CPU encodes parallelize well)
ls *.mkv | parallel --jobs $(nproc) 'ffmpeg -i {} -c:v libx264 -crf 23 {.}.mp4'

Output: (none — exits 0 on success)

NVENC note for batch: Consumer NVIDIA GPUs support at most 2–3 concurrent NVENC sessions (driver-enforced on GeForce). Process files sequentially for NVENC, or use a Quadro/Data Center GPU where this limit is lifted.

bash
# Sequential GPU batch (safe on any NVIDIA GPU)
for f in *.mkv; do
    ffmpeg -hwaccel cuda -i "$f" \
           -c:v h264_nvenc -cq 23 -preset p4 \
           -c:a aac -b:a 192k "${f%.mkv}.mp4"
done

Output: (none — exits 0 on success)

ffplay

ffplay is a minimal media player included with FFmpeg — useful for previewing processing results without saving a file.

bash
# Play a file
ffplay input.mp4

# Play with live filter (preview deinterlace)
ffplay -vf "yadif" input.mp4

# Preview a scale filter
ffplay -vf "scale=640:-2" input.mp4

# Loop indefinitely
ffplay -loop 0 input.mp4

# Play audio only (no window)
ffplay -nodisp input.mp3

# Play video only (mute audio)
ffplay -an input.mp4

# Play from specific timestamp
ffplay -ss 00:01:00 input.mp4

# Show stats overlay (frames, fps, bitrate)
ffplay -stats input.mp4

# Hardware-accelerated playback (smooth 4K)
ffplay -hwaccel cuda input_4k.mp4

# Preview a test signal
ffplay -f lavfi -i "testsrc=size=1280x720:rate=30"

# Preview generated audio (440 Hz tone for 5 s)
ffplay -f lavfi -i "sine=frequency=440:duration=5"

Output: (none — opens ffplay window)

Sources