Come posso adattare un video ad una certa dimensione, ma non ingrandirlo con FFmpeg?


13

Devo adattare i video a 640x360 (il massimo che il lettore del mio telefono è in grado di gestire), pur mantenendo le proporzioni , ma voglio anche che il video rimanga invariato se è più piccolo di 640x360 (dopo tutto non ha senso scalarlo).

C'è un modo per ottenere questo comportamento usando la riga di comando di ffmpeg?


Non penso che questo possa essere fatto esclusivamente in ffmpeg, ma se sei disposto a copiarlo, puoi sicuramente farlo.
evilsoup,

L'ho già scritto, ma volevo ripulire il mio codice nel caso in cui non fosse necessario.
sashoalm,

Probabilmente è possibile con un filtro di scala che utilizza funzioni come min(…)ma sicuramente più semplice con un semplice script che analizza le dimensioni. Vedi il mio comando qui per un esempio di cosa si può fare: superuser.com/questions/547296/…
slhck

Risposte:


10

Con le versioni più recenti di ffmpeg, è possibile utilizzare l' opzione scaledel filtro force_original_aspect_ratio. Ad esempio, per adattare un video a 1280 × 720, senza l'upscaling (vedi questo post per maggiori informazioni):

ffmpeg -i input.mp4 -filter:v "scale='min(1280,iw)':min'(720,ih)':force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4

Qui, il scalefiltro viene ridimensionato a 1280 × 720 se il video in ingresso è più grande di quello. Se è più piccolo, non verrà ingrandito. Il padfiltro è necessario per portare il video in uscita a 1280 × 720, nel caso in cui le sue proporzioni o dimensioni differiscano dalle dimensioni target.


Con le versioni precedenti di ffmpeg, esiste una soluzione alquanto confusa. Innanzitutto, definire la larghezza, l'altezza e le proporzioni dell'output. Questo ci farà risparmiare un po 'di battitura.

width=640; height=360
aspect=$( bc <<< "scale=3; $width / $height") # <= floating point division

Ora, applichiamo il comando di filtro super complesso che Jim Worrall ha scritto :

ffmpeg -i input.mp4 -vf "scale = min(1\,gt(iw\,$width)+gt(ih\,$height)) * (gte(a\,$aspect)*$width + \
lt(a\,$aspect)*(($height*iw)/ih)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*iw : \
min(1\,gt(iw\,$width)+gt(ih\,$height)) * (lte(a\,$aspect)*$height + \
gt(a\,$aspect)*(($width*ih)/iw)) + not(min(1\,gt(iw\,$width)+gt(ih\,$height)))*ih" \
output.mp4

Non spiegherò davvero cosa fa tutto questo, ma fondamentalmente puoi alimentare qualsiasi video e ridurrà solo in scala, non in scala. Se sei pronto, puoi sezionare il filtro nelle sue espressioni individuali. Potrebbe essere possibile accorciare questo, ma funziona anche così.


1
+1 ma è un comando davvero orribile: P
evilsoup

Infatti, NO? Ho trascorso dieci minuti cercando di suddividerlo in parti logiche e quindi di inserire alcuni valori, ma ho rinunciato. È un po 'vecchio e forse sarebbe possibile scriverlo molto più conciso di questo però.
slhck

14

Una versione più leggibile può apparire come segue:

-filter_complex "scale=iw*min(1\,min(640/iw\,360/ih)):-1"

640 / iw è il fattore di ridimensionamento orizzontale e 360 ​​/ ih è il fattore di ridimensionamento verticale

Si desidera adattare l'immagine ridimensionata all'interno della casella di output e mantenere le proporzioni (di archiviazione). Puoi farlo selezionando il fattore di ridimensionamento più piccolo con la funzione minima: min (640 / iw, 360 / ih)

Vuoi impedire qualsiasi upscaling (ovvero un fattore di ridimensionamento> 1.0), quindi aggiungi un'altra funzione minima: min (1, min (640 / iw, 360 / ih))

Il prossimo passo è calcolare la risoluzione di output moltiplicando il fattore di scala per larghezza di input e altezza di input:
output-larghezza = iw * min (1, min (640 / iw, 360 / ih))
output-height = ih * min (1, min (640 / iw, 360 / ih))

L'ultimo passo è costruire il comando filtro. Non è necessario specificare l'altezza di output, è possibile specificare -1 e ffmpeg manterrà le proporzioni applicando lo stesso fattore di ridimensionamento della larghezza.


A + Funziona fuori dalla scatola. La soluzione della risposta selezionata non ha conservato le proporzioni. Ha schiacciato le cornici.
287352

5

Ho avuto anche lo stesso problema, ma ho risolto inserendo il video in un quadrato 640x640 (a causa dei video verticali realizzati con gli smartphone).

Quindi, usando la logica immerzi e alcune ricerche, finisco con questo:

-vf "scale=iw*min(1\,if(gt(iw\,ih)\,640/iw\,(640*sar)/ih)):(floor((ow/dar)/2))*2"

l'ultima parte è per avere un'altezza divisibile per 2 che è necessaria a molti encoder.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.