Ridimensionamento dei video con ffmpeg / avconv per adattarsi a un lettore di dimensioni statiche


65

Ho un lettore video html 5 che è largo 700 px, alto 400 px. Sto provando a usare avconvffmpeg per ridimensionare (mantenendo le proporzioni) e assicurandomi che si adatti al mio lettore.

L'input può essere un file di qualsiasi dimensione, quindi ho bisogno di ridimensionare quelli più grandi ma centrare quelli più piccoli con barre nere. Finora ho provato: -se -aspect, ho visto padessere utilizzato con l' -vfinterruttore, ma non capisco come funziona abbastanza per ottenere ciò di cui ho bisogno.

immagini

Questa è una vaga idea di ciò di cui ho bisogno. Non sono sicuro che sia possibile. È quasi come la larghezza massima / altezza massima del CSS. Mi rendo conto che questo potrebbe essere solo un miscuglio di parole, ma se qualcuno capisce di cosa sto parlando, apprezzerei l'aiuto, grazie.

comando avconv:

avconv -y -i control.avi -vcodec libx264 -b 2000k -bufsize 20M -acodec aac -strict experimental -ar 44100 -ab 256k bigbuck_out.mp4


4
Scriverò una risposta più tardi, ma ho pensato di menzionare quanto segue: ricodificare un video solo per aggiungere un pilastro fisso o letterbox è un'idea terribile. Non solo perderai qualità in quel processo (o aumenterai inutilmente le dimensioni del file), ma renderai anche impossibile sbarazzarti delle barre in seguito. Idealmente, il tuo lettore dovrebbe semplicemente occuparsene e ridimensionare il video durante la visualizzazione. Qual è il tuo caso d'uso se posso chiedere?
slhck,

Conserviamo il file originale in un bucket S3, quindi non c'è problema, e stiamo ricodificando comunque dato che accettiamo un ampio ambito di tipi di video, tutti questi devono finire come file h.264 mp4 adatti allo streaming attraverso un browser. Quindi suggeriresti di ridimensionare il video e poi creare colonne / cassette postali html / css? Grazie
Jamie Taylor,

1
Come proprietario della risposta accettata ti suggerirei di non accettare il mio post e di accettare invece la risposta di LordNeckbeard, poiché è la più recente e molto più semplice.
slhck,

@slhck, lo stavo considerando, con la tua benedizione, lo farò.
Jamie Taylor,

Risposte:


52

Un metodo semplice consiste nell'utilizzare l' force_original_aspect_ratioopzione nel filtro scala .

immagine originale
Immagine originale. Rappresenta un video con formato 640x480, formato 4: 3.

In questi esempi l'immagine originale verrà ridimensionata per adattarsi a un rapporto di formato 16: 9 mantenendo le proporzioni originali. Per fare ciò puoi:

  • Aggiungi barre nere con filtro a pad alla pillarbox o letterbox all'immagine per adattarla correttamente, oppure
  • Utilizzare il filtro di ritaglio per tagliare l'eccesso

Pillarbox o letterbox

immagine a colonne
Immagine in pila. Inserimento di un ingresso 640x480 (4: 3) in un'uscita 1280x720 (16: 9).

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output
  • Questo ingrandirà l'immagine. Se vuoi evitare l'upscaling vedi l'esempio sotto.

  • Il letterboxing si verificherebbe invece se le proporzioni di input sono più ampie delle proporzioni di output. Ad esempio, un input con un rapporto di aspetto 2,35: 1 adattato a un output 16: 9 si tradurrà in letterbox.

Come sopra ma senza upscaling

nessun potenziamento
640x480 (4: 3) input in 1280x720 (16: 9) output senza upscaling.

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

Ritaglia

inserisci qui la descrizione dell'immagine
Immagine ritagliata. Proporzioni di input 4: 3, proporzioni di output 16: 9.

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720" output

E per me aggiungere un riempimento vuoto?
Tiago Ferezin,

@TiagoFerezin Che cos'è un "riempimento vuoto"?
Llogan,

oh scusa, riempi con un altro colore invece del nero, ad esempio
Tiago Ferezin

2
@TiagoFerezin Ah, sì. Facile da fare. Negli esempi che usano il filtro pad puoi aggiungere l' coloropzione, come pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=red(o puoi usare l'esadecimale se preferisci). Vedi l' elenco dei colori .
Llogan,

61

Ecco il comando che aggiungerebbe il pilastro o il letterbox per una larghezza di output fissa. È un po 'lungo, ma dovrai specificare il riempimento in qualche modo.

Innanzitutto, nella shell definire larghezza e altezza dell'output:

width=700
height=400

Quindi eseguire il comando:

ffmpeg -i in.mp4 -filter:v "scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih), pad=$width:$height:($width-iw*min($width/iw\,$height/ih))/2:($height-ih*min($width/iw\,$height/ih))/2" out.mp4

Questo è ridotto agli elementi essenziali essenziali necessari per ridimensionare e pad: aggiungere le altre opzioni audio e video come meglio credi. Nota che i numeri per widthe heightdevono essere divisibili per 2 per funzionare con la maggior parte dei codec.

Ecco la spiegazione di ciò che sta succedendo:

  • Scaling:
    • Per prima cosa dobbiamo capire se ridimensionare in base alla larghezza o all'altezza.
    • Per fare ciò, dividiamo la larghezza di output per la larghezza di input e l'altezza di output per l'altezza di input. Questo ci darà i fattori di scala per ogni dimensione.
    • Quindi controlliamo quale è più basso (con min()) e scegliamo solo quel fattore per il ridimensionamento.
    • Infine, moltiplichiamo sia la larghezza che l'altezza di input per quel fattore ( iw*min(…):ih*min(…)).
  • Imbottitura:
    • $width:$height è la larghezza e l'altezza dell'output
    • Per capire dove posizionare il video risultante, dobbiamo sottrarre la larghezza ridimensionata dalla larghezza massima di output e l'altezza ridimensionata dalla massima altezza di output.
    • Le larghezze e le altezze ridimensionate sono le espressioni del scalefiltro.
    • Dividiamo l'offset risultante per 2 per aggiungere i bordi su entrambi i lati.

3
@JamieTaylor Valuta di aggiungere -movflags +faststartl'esempio di slhck. Permetterà al tuo video scaricato progressivamente di iniziare la riproduzione prima che sia completamente scaricato, e vedi anche la Guida alla codifica FFmpeg e x264 e la Guida alla codifica FFmpeg e AAC per ulteriori istruzioni ed esempi di codifica.
Llogan,

Potresti accorciare il filtro pad a questo, penso:pad=$width:$height:(ow-iw)/2:(oh-ih)/2"
jdi

1
@jdi Questo non funzionerà se si esegue il downscaling, perché comporterà valori negativi per ow-iw.
slhck,

Grazie per il punto di partenza! Tuttavia, per ottenere le proporzioni appropriate per i video con proporzioni campione! = 1, ogni occorrenza di "iw" deve essere moltiplicata per "sar", quindi sostituendo OGNI occorrenza di "iw" con "(sar * iw)" nell'espressione del filtro funziona per me.
schieferstapel,

@slhck Ehi, ci sto provando su Android ma non sembra funzionare, mi puoi aiutare !!! ffmpeg -i input.mp4-filtro: scala v = 640 * min (700 / 640.400 / 360): 360 * min (700 / 640.400 / 360), pad = 700: 400: (700-640 * min (700 / 640.400 / 360)) / 2: (400-360 * min (700 / 640.400 / 360)) / 2 output.mp4
Nisarg

8

Mi sembra che tu debba farlo in tre passaggi:

  1. Controllare le proporzioni di input
  2. Ridimensiona i video con un DAR> 7/4 in larghezza (cambia la larghezza in 700 e ridimensiona l'altezza per mantenere le proporzioni), e ridimensiona quelli con DAR <7/4 in altezza
  3. Riempi il video in modo che si adatti allo spazio 700: 400.

FFmpeg / avconv può eseguire il ridimensionamento / riempimento con i filtri video in un solo passaggio, trascodificando una sola volta. Ad esempio, per girare un video in formato 16: 9, ridimensionarlo in larghezza e quindi letterbox i risultati:

ffmpeg -i input.avi -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
-c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k output.mp4

... ma per il primo passo (rilevare le proporzioni e confrontarlo con il 7: 4 richiesto) dovrai usare uno script di qualche tipo.

ffprobe input.avi 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0-9]*\)].*/\1/p'

... ti darà le proporzioni del video, che apparirà come '16: 9 'o' 4: 3 '. In uno script bash, userei qualcosa del tipo:

#!/bin/bash

##  Get the aspect ratio in the form x/y
dar=$(ffprobe test0.mp4 2>&1 | sed -n '/Video:/s/.*DAR \([0-9]*:[0:9]*\)].*/\1/p' | sed 's|:|/|')
##  use bc to do x/y*100 (bash can't handle floats)
DAR=$(bc <<< 'scale=2; $dar*100')

##  ${DAR%.00} will remove the trailing .00 left by bc
if [ ${DAR%.00} -ge 175 ]; then
    ffmpeg -i "$1" -filter:v 'scale=700:-1,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
else
    ffmpeg -i "$1" -filter:v 'scale=-1:400,pad=700:400:(ow-iw)/2:(oh-ih)/2' \
    -c:v libx264 -b:v 2000k -bufsize 20M -c:a aac -strict experimental -ar 44100 -b:a 256k "${1%.*}.mp4
fi

exit 0

Ovviamente dovrai adattarlo alle tue esigenze.


1
È possibile farlo in un solo passaggio, vedi la mia risposta.
slhck,

@slhck Ora è più facile. Vedi la risposta con la triglia di chitarra.
Llogan,

@LordNeckbeard Grazie! Recentemente ho visto questa opzione, lo rende davvero molto più semplice.
slhck,
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.