Tutorial FFmpeg – parte seconda

09- Filtri:

Per vedere tutti i filtri di ffmpeg si può dare il comando:

$ ffmpeg -filters

Il generico comando per usare i filtri:

ffmpeg -i <input> -filter:v “<filter1>,<filter2>,<filter3>, …” <output>

Ogni filtro (<filter1>; <filter2>, ecc) ha varie opzioni:

-filter:v <name option>=<option1>=<value1>:<option2>=<value2>: …

è facile ottenere stringhe molto lunghe se si usano tanti filtri e tante opzioni per ogni filtro.

Per mantenere la leggibilità della linea del comando possiamo andare a capo tramite “\”.

Alcuni esempi:

09a- Applicare il filtro audio loudnorm senza opzioni (prende quelle di default) e con alcune opzioni:

ffmpeg -i input -filter:a loudnorm output

ffmpeg -i input -filter:a loudnorm=print_format=summary:linear=true output

Il filtro loudnorm ha l’opzione 1 chiamata print_format con valore summary; ha anche l’opzione 2 chiamata linear con valore true.

09b- È possibile saltare il “<name option>=” indicando solo il valore dell’opzione. Per esempio se applichiamo il filtro scale è implicito che le due opzioni riguardano la larghezza (w=<value1>) e l’altezza (h=<value2>) del frame per cui non è necessario usarle:

ffmpeg -i input -filter:v scale=iw/2:-1 output

Si possono avere anche filtraggi complessi, cioè con più input e più filtri che interagiscono fra di loro. Poiché questo va oltre lo scopo del tutorial, metto solo la pagina del manuale di ffmpeg dove approfondirli:

https://ffmpeg.org/ffmpeg-all.html#Filtergraph-syntax-1

In definitiva per usare i filtri bisogna conoscerli e quindi studiarli nella documentazione: https://ffmpeg.org/ffmpeg-filters.html#

10- concatenare spezzoni video con il comando “concat”:

ffmpeg -i “concat:$(echo *.MTS | tr ‘ ‘ ‘|’)” out.mp4

In questo caso ho concatenato i vari file .mts (AVCHD) prodotti da un camcorder (raccolti nella stessa cartella) in un unico video mp4.

10a- Concatenare senza usare transcodifica (Demuxer):

creare una image list (mylist.txt, per esempio) dal contenuto:

file ‘path/to/file001.mp4’

file ‘path/to/file002.mp4’

file ‘path/to/file003.mp4’

Dare il comando:

$ ffmpeg -f concat -i mylist.txt -c copy output.mkv

I files saranno uniti senza re-encoding e possiamo usare anche un formato diverso (mkv, per esempio) da quello di partenza. Notare l’opzione -c copy che è generale (fa una copia bitstream) per video e audio insieme, al posto dei già visti -c:v copy e -c:a copy.

Possiamo automatizzare la creazione di mylist.txt con uno script:

for f in *.mp4; do echo “file ‘$f'” >> mylist.txt; done

10b- Concat protocol

$ ffmpeg -i “concat:input1.ts|input2.ts|input3.ts” -c copy output.ts

è obbligatorio usare lo stesso codec per tutti gli inputNN.xxx; in questo modo non abbiamo re-encoding. Se abbiamo differenti codec dobbiamo usare “-map” per concatenare i vari media:

$ ffmpeg -i input1.mp4 -i input2.webm -i input3.mov -filter_complex “[0:v:0][0:a:0][1:v:0][1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa]” -map “[outv]” -map “[outa]” output.mkv

Questo è un comando complesso e lascio a voi la sua decifrazione! (se non ci riuscite guardate qui: https://slhck.info/ffmpeg-encoding-course/#/42).

11- Trimming.

Tagliare via i primi secondi e gli ultimi da una clip senza fare re-encoding (e cambiare anche container, se si vuole):

ffmpeg -ss 00:00:00:02 -i input.mp4 -to 00:00:01:31 -c:v copy -c:a copy output.mov

“-ss” indica il tempo in cui partire (tempo di avvio). Prima di quel tempo tutto viene tagliato via (nel nostro esempio i primi 2 secondi). “-to” indica il tempo in cui si ferma il trim (tempo di fine): i tempi successivi sono tagliati via. Questo implica di conoscere la durata esatta del file per cui possiamo scegliere il momento esatto del taglio.

Usando “-t” al posto di “-to” si indica il tempo che deve durare il file, non c’è bisogno di sapere la durata del file ed eliminare una parte precisa alla fine del video; indichiamo solo la partenza e la durata che noi vogliamo imporre al file in output, tutto l’eccesso viene eliminato. Questo può essere utile in uno script senza sapere la lunghezza precisa del file.

ffmpeg -ss 00:00:00:02 -i input.mp4 -t 00:00:02:00 -c:v copy -c:a copy output.mov

Se il parametro -ss … è messo prima di “-i input.mp4” la ricerca del punto di taglio (seek) sarà più veloce. Se messo dopo -i allora sarà molto più lento perché verranno analizzati tutti i frame dall’inizio. In pratica nel primo caso il file video viene saltato fino a che non si arriva al punto indicato da “-ss”; può essere una lettura meno precisa, specie con codec compressi. Nel secondo caso il file video viene letto, frame per frame, fino al punto indicato da “-ss”, per cui la lettura è sempre precisa.

[NOTA: Con i codec con compressione “interframe”, il taglio viene bene (senza ricodificare…) solo in corrispondenza dei keyframes (I-frames); altrimenti taglia nel keyframe più vicino ma è costretto a fare un encoding per tener conto dei frames interpolati mancanti (B-frames)]

Per approfondire i problemi di tagli e di seeking vedere:

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

12- Accelerazione hardware (GPU):

12a- Decoder

ffmpeg ha i decodificatori interni per l’accelerazione hardware che si chiamano “hwaccel”. Questi sono abilitati tramite l’opzione “-hwaccel”. Se il decodificatore rileva uno stream con codoec o profilo adatto allora userà l’accelerazione hardware automaticamente. Se lo stream non è adatto allora avvierà la normale decodificazione software. Se occorre specificare il dispositivo hardware (per es. se abbiamo più di una GPU) lo possiamo fare tramite l’opzione “-hwaccel-device”. Per es. io ho un unica scheda video AMD RX 5700XT che viene riconosciuta da Linux come “pci-0000:0c:00.0” oppure, come si vede nella cartella “/dev/dri” come “card1” oppure come “renderD128”. Quindi possiamo usare l’opzione:

-hwaccel-device renderD128

Come detto il tutto avviene automaticamente se è possibile. Possiamo anche usare un decoder esterno tramite wrapper; in questo caso dobbiamo far sapere il tipo di codec che stiamo usando tramite l’opzione “-c:v av1_cuvid” (per Nvidia), “h264_qsv” (per Intel). Ricordiamoci che stiamo parlando di decoder, non di encoder. Possiamo conoscere tutti i decoders supportati (sia hardware che software) tramite il comando: “ffmpeg -decoders“. Si ottengono centinaia di decoder perché ffmpge riesce a leggere quasi tutti i codec esistenti. Notare però che ci sono codec apposta per Nvidia (cuvid) e Intel (qsv), ma non per AMD. Quindi con una scheda AMD non potremo avere decodifica hardware con un wrapper. Altro aspetto importante nell’usare un wrapper esterno è che dobbiamo conoscere in anticipo il codec da decodificare e impostarlo come abbiamo visto prima. Non succede che il codec venga riconosciuto e accelerato in hardware automaticamente.

Infine possiamo usare i filtri accelerati dalla GPU, ma per la maggior parte dei filtri (Vulkan; OpenCL; CUDA) dobbiamo racchiudere il comando del filtro tra le opzioni “-hwupload” e “-hwdownload” che servono a spostare i dati dei frame dalla RAM di sistema alla vram della GPU (dove viene applicato il filtro) per poi ritornare alla RAM di sistema.

Al di là del funzionamento automatico dell’accelerazione hardware in ffmpeg, possiamo usare delle specifiche API che sono entrate nell’uso comune: Vdpau; Vaapi; Vulkan; Cuda (nvenc/nvdec); ecc.

VDPAU: si installa la libreria “libvdpau” che è proprietaria e poi si può usare l’accelerazione hardware in ffmpeg tramite la sua libreria interna “libavcodec”. È possibile decodificare in hardware h264/5; mpeg 1/2/4; VC-1; VP9 e AV1.

VAAPI: essendo una libreria Open Source è integrata in ffmpeg nella libreria “libva”. Questa libreria userà i profili (se specificati) QSV per schede Intel e UVD/VCE per schede AMD. Non è compatibile con Nvidia. I profili sono gli stessi di vdpau.

VULKAN: è in pieno sviluppo e supporta i codec h264; Hevc e AV1 con tutte le marche di schede video. Per usarlo bisogna specificarlo (non è automatico) inizializzando il device hardware tramite l’opzione “-init_hw_device”.

Si può fare un test per verificarne il funzionamento:

ffmpeg -init_hw_device “vulkan=vk:0” -hwaccel vulkan -hwaccel_output_format vulkan -i input.mp4 -f null – -benchmark

Questo test non produce un risultato, ma verifica solo il funzionamento. Notare che in questo caso dobbiamo specificare “-hwaccel vulkan” invece del solo “-hwaccel”. Per ora sono supportati solo i codec: h264; hevc e AV1. Per approfondimenti (sempre in divenire) vedere: https://ffmpeg.org/ffmpeg-filters.html#Vulkan-Video-Filters

OPENCL: può essere supportato direttamente dai driver delle schede video. AMD può usare ROCm; il driver specifico (open o proprietario) o usare il framework AMF. Il tutto è in fase di rivoluzione e senza molta stabilità.

AMF/UVD/VCE: La decodifica in hardware di AMD è problematica e in divenire. UVD (per schede fino a Polaris/Vega) funziona con vdpau e vaapi. VCE (per schede Navi e successive) funziona con vaapi. AMF non funziona (in Linux) per la decodifica ma solo per la codifica. Un esempio di decodifica software e codifica hardware potrebbe essere:

ffmpeg -i input.mkv -c:v av1_amf output.mp4

CUDA (nvenc/nvdec): è una soluzione proprietaria e richiede l’installazione dell’SDK di Cuda. Un esempio di uso (presente anche un codifica software):

ffmpeg -hwaccel nvdec -c:v av1 -i input_av1.mp4 output.ts

12b- Encoder

L’uso di encoder hardware è molto più semplice e immediato, perché funziona senza opzioni particolari: basta usare i precisi preset dei codecs. L’unico passo da fare è installare le relative API o frameworks. Alcuni esempi:

ffmpeg -i input -c:v h264_nvenc -profile high444p -pixel_format yuv444p -preset default output.mp4

ffmpeg -s 1920×1080 -pix_fmt yuv420p -i input.yuv -c:v av1_amf output.mp4

ffmpeg -i input.mkv -vf scale=1280×720 -c:v h264_amf output.mp4

Nel primo esempio è stato utilizzato h264_nvenc; nel secondo av1_amf e nel terzo h264_amf.

Gli encoders (hardware e software) utilizzabili da ffmpeg si trovano con il comando:

$ ffmpeg -encoders

Si vede che sono molti, ma non quanto i decoders.

Abbiamo terminato. Per ultimo alcuni link utili per approfondire:

13- Un sito che raccoglie i comandi più usati:

https://gist.github.com/steven2358/ba153c642fe2bb1e47485962df07c730

14- Un repository git con molti script per ffmpeg:

https://github.com/NapoleonWils0n/ffmpeg-scripts

15- Due tutorial su ffmpeg più approfonditi del mio (in inglese):

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

https://github.com/leandromoreira/ffmpeg-libav-tutorial

Andrea Paz
Andrea Paz
Articoli: 4