Articoli approfonditi sulla tecnologia che plasma il futuro.

FFmpeg Demistificato: il Modello Mentale che Ti Manca

Smetti di copiare comandi FFmpeg alla cieca. Scopri il modello mentale di container, codec, stream e filtri con ricette pratiche che userai davvero.

Macchina che separa i flussi di film, audio e testo attraverso imbuti in un unico contenitore luminoso.

Ci siamo passati tutti. Devi convertire un video, quindi cerchi su Google e trovi una risposta su Stack Overflow con un comando che sembra scritto sbattendo la tastiera: ffmpeg -i input.mov -c:v libx264 -preset slow -crf 22 -c:a aac -b:a 128k -movflags +faststart output.mp4. Lo lanci. Funziona. Non hai la minima idea del perché, e la volta dopo che ti serve qualcosa di leggermente diverso sei di nuovo su Stack Overflow. L'ho fatto per anni, prima di sedermi finalmente a capire cosa vuole davvero FFmpeg da me.

Il fatto è che FFmpeg non è poi così complicato. Ha un modello mentale coerente che, una volta compreso, rende quasi ogni comando leggibile. Il problema è che nessuno spiega il modello: ti lanciano solo comandi addosso. Quindi cerchiamo di risolvere questo.

Container vs Codec: la prima cosa da capire

La fonte di confusione più grande con i file video è la differenza tra container e codec. Un container è il formato del file: .mp4, .mkv, .webm, .mov. È una scatola che contiene delle cose. Un codec è il modo in cui i dati video e audio effettivi all'interno di quella scatola vengono compressi: H.264, H.265, VP9, AV1, AAC, Opus.

Un file MP4 può contenere video H.264 con audio AAC, oppure video H.265 con audio Opus, o decine di altre combinazioni. Un file MKV può contenere praticamente qualsiasi cosa. Quando qualcuno dice «converti in MP4», di solito intende «metti video H.264 e audio AAC in un container MP4», ma si tratta di tre decisioni separate.

# See what's actually inside a file
$ ffprobe -hide_banner video.mkv
Input #0, matroska:
Stream #0:0: Video: hevc (Main), 1920x1080, 23.98 fps
Stream #0:1: Audio: opus, 48000 Hz, stereo
Stream #0:2: Subtitle: subrip
# This file is:
# Container: MKV (Matroska)
# Video codec: HEVC (H.265)
# Audio codec: Opus
# Plus a subtitle stream

Usa ffprobe prima di fare qualsiasi cosa. Ti dice esattamente con cosa stai lavorando. Nella metà dei casi, la «conversione» di cui hai bisogno è solo un remux: spostare gli stessi stream in un container diverso senza ricodificarli. È quasi istantaneo.

La struttura dei comandi FFmpeg

Ogni comando FFmpeg segue lo stesso schema, e una volta che lo vedi non puoi più non vederlo:

ffmpeg [global options] [input options] -i input [output options] output
# The KEY insight: options apply to the NEXT file.
# Options before -i apply to the input.
# Options after -i (before the output filename) apply to the output.
# This matters! These two commands are different:
ffmpeg -ss 00:01:00 -i video.mp4 output.mp4   # Seeks BEFORE decoding (fast)
ffmpeg -i video.mp4 -ss 00:01:00 output.mp4   # Seeks AFTER decoding (slow, precise)

La posizione conta in FFmpeg. È la cosa che fa inciampare tutti. Il significato di un'opzione può cambiare a seconda che compaia prima o dopo -i. L'esempio di -ss qui sopra è il caso più comune: metterlo prima di -i fa sì che FFmpeg posizioni direttamente il cursore nel file di input (veloce ma potenzialmente impreciso), mentre metterlo dopo fa sì che FFmpeg decodifichi tutto fino a quel punto e poi inizi a produrre output (lento ma accurato fotogramma per fotogramma).

Selezione degli stream: dire a FFmpeg cosa vuoi

I file video spesso contengono più stream: video, audio, sottotitoli, a volte più tracce audio in lingue diverse. FFmpeg usa una sintassi con specificatori di stream per permetterti di indicare stream precisi:

  • -c:v — codec per gli stream video (v = video)
  • -c:a — codec per gli stream audio (a = audio)
  • -c:s — codec per gli stream di sottotitoli (s = subtitle)
  • -c copy — copia TUTTI gli stream senza ricodificarli
  • -c:v copy -c:a aac — copia il video così com'è, ricodifica l'audio in AAC
  • -map 0:a:1 — seleziona il secondo stream audio dal primo input

Il flag -c copy è quello più importante da conoscere. Dice a FFmpeg di copiare i dati dello stream direttamente senza ricodificarli. È praticamente istantaneo e senza perdite: stai solo spostando dati da un container a un altro. Ogni volta che non devi cambiare il codec, usa -c copy.

# Remux MKV to MP4 without re-encoding (instant)
ffmpeg -i input.mkv -c copy output.mp4
# Copy video but re-encode audio (fast — only audio is processed)
ffmpeg -i input.mkv -c:v copy -c:a aac -b:a 192k output.mp4
# Extract just the audio stream
ffmpeg -i video.mp4 -vn -c:a copy audio.aac
# -vn means "no video" — drop the video stream entirely

Ricette pratiche che userai davvero

Ecco i comandi che uso continuamente. Ognuno è spiegato, così puoi modificarlo in base alle tue esigenze specifiche.

Comprimere un video per il web

ffmpeg -i raw_video.mov \
-c:v libx264 \
-preset slow \
-crf 23 \
-c:a aac -b:a 128k \
-movflags +faststart \
web_video.mp4
# -c:v libx264     → encode video with H.264
# -preset slow     → slower encoding = smaller file (options: ultrafast to veryslow)
# -crf 23          → quality level (18=near lossless, 23=default, 28=low quality)
# -c:a aac         → encode audio as AAC
# -b:a 128k        → audio bitrate 128 kbps
# -movflags +faststart → move metadata to start of file for streaming

Il valore CRF (Constant Rate Factor) è la manopola più importante per la qualità. Numeri più bassi significano qualità più alta e file più grandi. Per la maggior parte dei video web, CRF 20-25 è il punto ideale. Io di solito uso 22 per tutto ciò che deve avere un bell'aspetto e 26 per i video di sfondo o secondari, dove la qualità conta meno.

Tagliare un video senza ricodificarlo

# Extract from 1:30 to 3:45 — no re-encoding, nearly instant
ffmpeg -ss 00:01:30 -to 00:03:45 -i input.mp4 -c copy trimmed.mp4
# If you need frame-accurate cuts (slower):
ffmpeg -i input.mp4 -ss 00:01:30 -to 00:03:45 \
-c:v libx264 -crf 18 -c:a copy trimmed.mp4

Generare miniature

# Single thumbnail at the 10-second mark
ffmpeg -ss 00:00:10 -i video.mp4 -frames:v 1 thumb.jpg
# One thumbnail every 30 seconds
ffmpeg -i video.mp4 -vf "fps=1/30" thumbs/thumb_%04d.jpg
# Resize to 320px wide, maintain aspect ratio
ffmpeg -ss 00:00:10 -i video.mp4 -frames:v 1 \
-vf "scale=320:-1" thumb_small.jpg

Creare una GIF da una clip video

# Good quality GIF with palette generation (two-pass)
ffmpeg -ss 00:00:05 -t 3 -i video.mp4 \
-vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1]; \
[s0]palettegen[p];[s1][p]paletteuse" \
output.gif
# -t 3              → duration: 3 seconds
# fps=15            → 15 frames per second (keep GIFs small)
# scale=480:-1      → resize to 480px wide
# palettegen/use    → generate optimal color palette (much better quality)

Capire i filtri: la funzione potente

I filtri sono il punto in cui FFmpeg passa da «strumento utile» a «assurdamente potente». Il flag -vf (video filter) e il flag -af (audio filter) ti permettono di concatenare operazioni di elaborazione. I filtri si separano con virgole per l'elaborazione sequenziale, o con punti e virgola per i grafi di filtri complessi.

# Chain multiple filters: resize, then add padding for exact dimensions
ffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease,\
pad=1280:720:(ow-iw)/2:(oh-ih)/2:black" output.mp4
# Normalize audio volume
ffmpeg -i input.mp4 -af "loudnorm" -c:v copy output.mp4
# Speed up a video 2x (with audio pitch correction)
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -af "atempo=2.0" fast.mp4
# Add text overlay
ffmpeg -i input.mp4 \
-vf "drawtext=text='DRAFT':fontsize=72:fontcolor=red:x=10:y=10" \
watermarked.mp4

Il sistema di filtri è abbastanza profondo da meritare un articolo a parte, ma l'intuizione chiave è questa: i filtri elaborano i frame decodificati. Questo significa che non puoi usare -c copy con i filtri: il video deve essere decodificato, filtrato e ricodificato. Se il tuo comando usa -vf, metti in conto il tempo per una ricodifica completa.

Accelerazione hardware: usa la tua GPU

Se codifichi video regolarmente, l'accelerazione hardware può velocizzare le cose di 5-10 volte. Le GPU moderne hanno hardware di codifica dedicato che FFmpeg può usare.

# NVIDIA GPU (NVENC)
ffmpeg -i input.mp4 -c:v h264_nvenc -preset p4 -crf 23 output.mp4
# Apple Silicon (VideoToolbox)
ffmpeg -i input.mp4 -c:v h264_videotoolbox -b:v 5M output.mp4
# Intel Quick Sync (QSV)
ffmpeg -i input.mp4 -c:v h264_qsv -preset medium output.mp4
# Check what's available on your system:
ffmpeg -encoders 2>/dev/null | grep -E '(nvenc|videotoolbox|qsv|vaapi)'

Un avvertimento: gli encoder hardware sono più veloci ma di solito producono file leggermente più grandi a parità di qualità visiva rispetto alla codifica software (libx264). Per le trascodifiche una tantum in cui la qualità conta, la codifica software è ancora migliore. Per l'elaborazione batch o lo streaming in tempo reale, l'accelerazione hardware è la scelta chiara. Io uso libx264 per le codifiche finali di produzione e NVENC per tutto il resto.

Errori comuni e come evitarli

  • Ricodificare quando non serve. Se stai solo tagliando, estraendo l'audio o cambiando container, usa -c copy. Non c'è motivo di passare 20 minuti a ricodificare un video da cui stai togliendo solo 30 secondi.
  • Usare un valore CRF troppo basso. CRF 18 produce file enormi con miglioramenti di qualità che la maggior parte delle persone non riesce a vedere. Parti da 23 e scendi solo se vedi artefatti. Per la maggior parte dei contenuti web, 23-25 è più che sufficiente.
  • Dimenticare -movflags +faststart. Senza questo, i metadati dell'MP4 finiscono alla fine del file, il che significa che i browser non possono iniziare la riproduzione finché l'intero file non è stato scaricato. Aggiungilo sempre per i video web.
  • Non controllare prima l'input. Esegui ffprobe prima di scrivere il comando. Conoscere i codec di input, la risoluzione e la struttura degli stream rende tutto più semplice.
  • Mandare tutto nel vuoto. Se FFmpeg sembra bloccato, potrebbe star aspettando che tu risponda a una domanda (per esempio se sovrascrivere un file esistente). Aggiungi -y per sovrascrivere automaticamente, oppure -n per non sovrascrivere mai.

Il cheat sheet

Questo è quello che tengo in un file di testo sul desktop. Coprono circa il 90% di ciò che mi serve giorno per giorno:

# Probe a file
ffprobe -hide_banner input.mp4
# Remux (change container, no re-encode)
ffmpeg -i input.mkv -c copy output.mp4
# Compress for web
ffmpeg -i input.mov -c:v libx264 -crf 23 -preset medium \
-c:a aac -b:a 128k -movflags +faststart output.mp4
# Extract audio only
ffmpeg -i video.mp4 -vn -c:a copy audio.m4a
# Trim without re-encoding
ffmpeg -ss 00:01:00 -to 00:02:30 -i input.mp4 -c copy clip.mp4
# Resize to 720p
ffmpeg -i input.mp4 -vf "scale=-1:720" -c:a copy output.mp4
# Convert to GIF
ffmpeg -ss 5 -t 3 -i input.mp4 \
-vf "fps=12,scale=400:-1" output.gif
# Concatenate files (same codec)
echo "file 'part1.mp4'" > list.txt
echo "file 'part2.mp4'" >> list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy combined.mp4

FFmpeg non è uno strumento che si padroneggia in un giorno. Ma una volta che capisci il modello mentale (i container contengono stream, gli stream hanno codec, le opzioni si applicano al file successivo, i filtri richiedono la ricodifica), la documentazione inizia ad avere senso. Smetti di copiare comandi alla cieca e inizi a comporli con intenzione. E, sinceramente, questo passaggio da «è magia» a «ah, ecco cosa sta facendo» è uno dei momenti più soddisfacenti che uno sviluppatore possa avere.