Tutorial FFmpeg – Parte prima


FFmpeg è uno di quei progetti Open Source che hanno acquistato una grande importanza per la loro utilità. Anche senza conoscerlo approfonditamente si possono ottenere facilmente ottimi risultati; però, a conoscerlo bene, possiamo fare “quasi” tutto in ambito audio e video. Molti dei programmi multimediali si basano proprio su ffmpeg; si potrebbe dire che ne sono l’interfaccia grafica, visto che ffmpeg funziona da linea di comando. Però riuscire a sfruttarlo al massimo significa saperlo usare proprio da linea di comando, cosa ostica per molti. Preparatevi perché avremo a che fare con comandi molto lunghi, che vanno via via spezzati per andare a capo e mantenere una buona leggibilità. In questo tutorial diviso in due parti cercherò di fornire gli elementi base per poter utilizzare ffmpeg.

01- Per vedere uno schema di come lavora ffmpeg, andare qui:

https://slhck.info/ffmpeg-encoding-course/#/9

Si vede che ffmpeg opera sul file iniziale (audio, video o audio e video) con una prima fase di “demuxing” che opera sul formato del file senza scendere a livello dei codec. È in questa fase che possiamo cambiare formato (container) senza dover decodificare l’intero file. Il passo successivo è lavorare a livello di codecs per decodificare prima e ricodificare (encoding) in un nuovo codec poi. Fra queste due fasi si può operare con qualsiasi filtro ci serva. Infine si ritorna a lavorare sul formato (cambiandolo o lasciandolo inalterato) nella fase finale di “muxing”. In fase di encoding si possono usare anche librerie esterne a ffmpeg, per es. vaapi; nvenc, ecc.

In pratica ffmpeg si basa principalmente su 3 librerie per le precedenti 3 fasi:

libavformat è una libreria che si occupa dei formati; libav (e libavcodec) si occupa dei codec e libavfilter si occupa degli effetti. Ci sono anche altre librerie per altri scopi, ma noi non le tratteremo.

02- Estrarre i metadati di un video con ffprobe:

ffprobe -hide_banner -loglevel warning -select_streams v \

-print_format json -show_frames -read_intervals “%+#1” \

-show_entries “frame=color_space,color_primaries,color_transfer,side_data_list,pix_fmt” \

-i name_media.mp4

(Notare gli slash per andare a capo)

Dove:

-hide_banner -loglevel warning: Toglie dal risultato visualizzato tante informazioni inutili; è consigliabile usarlo sempre. In questo esempio ci si ferma al livello di “warning”.

-select_streams v: indica di visualizzare info solo per il video (v). Per l’audio si usa “a”; per avere tutte e due non si mette questa opzione.

-print_format json: visualizza il risultato in json, utile in caso di script e parsing.

-read_intervals “%+#1”: Prende le info dal solo primo frame. Cambiando il numero si può cambiare frame.

-show_entries “…”: seleziona solo i dati che indichiamo in seguito, nel nostro esempio i dati di colore del frame.

-i “name_media.mp4”: Il nostro file di input

03- Comando generico per ffmpeg:

ffmpeg <global-options> <input-options> -i <input> <output-options> <output>

dove le global options servono per il log dell’output, file in sovrascrittura, ecc. Le input options servono per i files in lettura e le output options servono per le conversioni (codec, quality, ecc), per i filtri, per lo stream mapping; ecc

Una lista completa di tutte le opzioni, suddivise in Global (e Advanced global); Per-file main (Advanced); Video options (Advanced); Audio (Advanced); Subtitle; AVCodecContext AVOptions; ecc si trovano qui:

https://gist.github.com/tayvano/6e2d456a9897f55025e25035478a3a50

Sono un numero impressionante e ci fa capire quanto complesso sia ffmpeg. Impossibile impararle tutte, si deve ricorrere per forza alla consultazione del manuale via via che abbiamo particolari esigenze.

04- Vediamo alcuni esempi di utilizzo di ffmpeg:

04a- Il caso più semplice è la transcodifica da un formato/codec ad un altro formato/codec:

ffmpeg -i input.mp4 -c:v av1 -c:a flac output.mkv

Abbiamo preso il file “input.mp4”, caratterizzato da un suo codec e da un suo container (formato) e lo abbiamo trasformato in “output.mkv”, caratterizzato da un altro codec e un altro formato. Il codec di input.mp4 non lo conosciamo, ma non importa perché viene letto automaticamente. Se lo vogliamo conoscere in anticipo si usa ffprobe. Il formato è invece visibile dall’estensione (.mp4). A livello codec vogliamo che venga convertito nel codec video av1 (-c:v) e nel codec audio flac (-c:a). Infine imponiamo il nuovo container .mkv nella fase finale di muxing.

04b- Se vogliamo assegnare ad un file video un dato file audio, si presentano diversi casi. Se si parte da mp4 e si vuole ottenere mp4:

ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac output.mp4

Questo comando unisce uno stream video (video.mp4) con uno stream audio (il secondo file di input; audio.wav) dando il risultato “output.mp4”. La parte video non è transcodificata e subisce solo un demuxing/muxing (-c:v copy). Lo stream audio deve invece subire una transcodifica poiché MP4 non supporta audio di tipo PCM.

04c- Stesso caso ma si parte da mp4 e si vuole ottenere mkv (o mov):

ffmpeg -i video.mp4 -i audio.wav -c:v copy – c:a copy output.mkv (.mov)

Notare che non abbiamo cambiato il codec video (-c:v copy) ma solo il suo container. Non abbiamo nemmeno cambiato il codec audio perché .mkv (e mov) supporta audio di tipo PCM.

05- Se si vuole prendere tutti i video di un dato formato e convertirli in batch in un altro formato:

for f in $(find . -name ‘*.avi’); do ffmpeg -i “$f” -c:v copy -c:a copy “remux/{f%.*}.mkv “; done

for i in $(find . -name ‘*.avi’); do ffmpeg -fflags +genpts -i “$i” -c:v copy -c:a copy “remux/${i%.*}.mkv”; done

Dove nel secondo script compare l’opzione -fflags +genpts, che è una input options, e serve ad assegnare automaticamente un timestamp nel caso che input.mp4 non lo abbia. PTS è il presentation time stamp ed è un argomento importante (cioé come ffmpeg legge e usa il tempo nei suoi streams) ma troppo avanzato per questo tutorial. Vedere: http://dranger.com/ffmpeg/tutorial05.html.

Comunque si possono usare tanti tipi di script con ffmpeg, questi due esempi sono semplici e scritti su di un unica riga.

06- Capire i settaggi di qualità per l’output (vale per codec compressi, cioè “lossy”):

Se non si usano opzioni di qualità ffmpeg userà quelle di default. Le opzioni di qualità si dividono in quelle che agiscono sul “bitrate” (-b:v … oppure -b:a …) e quelle che agiscono sul “livello di qualità” (-q:v … oppure -q:a …). In più, ogni codec può avere le proprie opzioni di qualità. Per es. libx264/265 hanno “-cfr” (constant rate factor); ecc.

Attenzione: se si usa un tipo di opzione bitrate non si deve contemporaneamente usare il tipo quality; invece l’opzione -cfr può essere associata a questi, così come i profili di velocità.

Il rate control può essere fatto in vari modi: CBR (Constant BitRate), VBR (Variable BitRate), ABR (Average BitRate), VBV (Constrained Bitrate) il quality control con: CQP (Constant Quantization Parameter), CQ (Constant Quality). Per un approfondimento di questi metodi vedere:

https://slhck.info/video/2017/03/01/rate-control.html

Per vedere il triangolo “Velocità-Qualità-Size” vedere:

https://slhck.info/ffmpeg-encoding-course/#/32

Questo triangolo ci fornisce una visualizzazione immediata per decidere i valori che possiamo usare. Notare che si può ottenere alta qualità e file piccoli, ma a costo di un lungo tempo di encoding.

Sempre riguardo la qualità ci sono dei preset che, intuitivamente, riguardano la velocità con cui viene effettuato l’encoding:

-preset ultrafast/superfast/veryfast/faster/fast/medium/slow/slower/veryslow

Il più veloce fa meno compressione e fornisce maggiore qualità al prezzo di grossi files ottenuti. Aumentando il tempo di codifica (usato per compressioni sempre più spinte) si ottengono file più piccoli ma con minore qualità.

Per avere una panoramica dei codec e dei loro settaggi VBR, vedere le seguenti tabelle:

https://slhck.info/video/2017/02/24/vbr-settings.html

Idem per il CFR:

https://slhck.info/video/2017/02/24/crf-guide.html

07- Se si vuole sostituire la traccia audio embedded con una esterna:

ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 output.mp4

Legenda:

video.mp4 ==> stream 0 (contiene canali audio e video)

audio.wav ==> stream 1 (contiene solo canali audio)

Con questo comando ffmpeg usa la prima traccia video (v:0) del primo stream 0 (escludendo il resto) e la prima traccia audio (a:0) del secondo stream 1.

L’opzione –map lavora sui singoli stream per permettere risultati sofisticati.

08- Uso dell’opzione -map.

Questa opzione è molto importante ma si può usare solo da linea di comando; generalmente i programmi che includono ffmpeg non possono implementarla:

ffmpeg -i stream0.mp4 -i stream1.mp4 -map 0:0 -map 1:3 outoput.mp4

ffmpeg -i stream0.mp4 -i stream1.mp4 -map 0:v:0 -map 1:a:2 output.mp4

Questi due comandi danno esattamente lo stesso risultato, cioè accoppiare il canale video dello stream0 con il terzo canale audio dello stream1.

I 2 file di partenza sono così composti:

stream0.mp4 ==> 0:0 –> video

0:1 –> audio

stream1.mp4 ==> 1:0 –> video 0 ( )

1:1 –> audio 1 (0)

1:2 –> audio 2 (1)

1:3 –> audio 3 (2)

La differenza dei 2 comandi è data, nel primo caso, dal metodo assoluto di specificare stream e canali. Quindi il canale audio da accoppiare è 1:3

Nel secondo caso si usano gli streams specifiers cioè “v” per il video e “a” per l’audio. Quindi -map 0:v:0 significa il primo stream (0) del primo canale video (v:0) ; mentre -map 1:a:2 significa il secondo stream (1) e il terzo canale audio (a:2), contato a partire da 0 ma escludendo il canale video.

Insomma la differenza è che il terzo canale audio dello stream 1 è 3 se contato in maniera assoluta (che assegna 0 al canale video e 1, 2, 3 ai seguenti canali audio); mentre è 2 se contato escludendo il canale video e quindi nominando i canali audio 0, 1, 2.

Per approfondire la mappatura, vedere:

https://trac.ffmpeg.org/wiki/Map

Fine prima parte.

Andrea Paz
Andrea Paz
Articoli: 2