Cambiar el tamaño de los videos con ffmpeg / avconv para adaptarse al reproductor de tamaño estático

65

Tengo un reproductor de video html 5 que tiene 700 px de ancho y 400 px de alto. Estoy tratando de usar avconvffmpeg para cambiar el tamaño (manteniendo la relación de aspecto) y asegurándome de que se ajuste a mi reproductor.

La entrada puede ser un archivo de cualquier tamaño, por lo que necesito cambiar el tamaño de los más grandes pero centrar los más pequeños con barras negras. Hasta ahora he intentado: -sy -aspecthe visto que padse usa con el -vfinterruptor, pero no entiendo cómo funciona lo suficiente como para obtener lo que necesito.

Imágenes

Esta es una idea aproximada de lo que necesito. No estoy seguro de si es posible. Es casi como el ancho máximo / alto máximo de CSS. Me doy cuenta de que esto puede ser solo una mezcla de palabras, pero si alguien entiende lo que estoy hablando, agradecería ayuda, gracias.

comando avconv:

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

Jamie Taylor
fuente
44
Escribiré una respuesta más tarde, pero pensé en mencionar lo siguiente: volver a codificar un video solo para agregar pilares fijos o buzones es una idea terrible. No solo perderá calidad en ese proceso (o aumentará innecesariamente el tamaño del archivo), también hará que sea imposible deshacerse de las barras más adelante. Idealmente, su reproductor simplemente debería ocuparse de eso y cambiar el tamaño del video mientras lo muestra. ¿Cuál es su caso de uso si puedo preguntar?
slhck
Guardamos el archivo original en un bucket S3, así que no hay problema, y ​​estamos volviendo a codificar de todos modos ya que aceptamos una gran variedad de tipos de video, todos estos deben terminar como archivos h.264 mp4 adecuados para transmitir a través de un navegador. ¿Entonces sugeriría cambiar el tamaño del video y luego hacer html / css pillar / letterboxes? Gracias
Jamie Taylor
1
Como propietario de la respuesta aceptada, le sugiero que no acepte mi publicación y acepte la respuesta de LordNeckbeard, ya que es la más reciente y mucho más simple.
slhck
@slhck, lo estaba considerando, con tu bendición, lo haré así.
Jamie Taylor

Respuestas:

52

Un método simple es usar la force_original_aspect_ratioopción en el filtro de escala .

imagen original
Imagen original. Representa un video de 640x480, relación de aspecto 4: 3.

En estos ejemplos, la imagen original se escalará para ajustarse a una salida de relación de aspecto 16: 9 mientras se conserva la relación de aspecto original. Para hacer esto puedes:

Pillarbox o buzón

imagen en caja de pilares
Imagen en caja de pilares. Ajuste de una entrada de 640x480 (4: 3) en una salida de 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
  • Esto aumentará la imagen. Si desea evitar el aumento de escala, consulte el siguiente ejemplo.

  • En cambio, Letterboxing ocurriría si la relación de aspecto de entrada es más amplia que la relación de aspecto de salida. Por ejemplo, una entrada con una relación de aspecto de 2,35: 1 en una salida de 16: 9 dará como resultado un buzón.

Igual que el anterior pero sin escalar

sin escalamiento
Entrada de 640x480 (4: 3) en salida de 1280x720 (16: 9) sin aumento de escala.

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

Cosecha

ingrese la descripción de la imagen aquí
Imagen recortada Relación de aspecto de entrada 4: 3, relación de aspecto de salida 16: 9.

ffmpeg -i input -vf "scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720" output
lema
fuente
¿Y para que agregue un relleno en blanco?
Tiago Ferezin
@TiagoFerezin ¿Qué es un "relleno en blanco"?
lema
oh lo siento, rellena con otro color en lugar de negro, como ejemplo
Tiago Ferezin
2
@TiagoFerezin Ah, sí. Fácil de hacer. En los ejemplos que usan el filtro de almohadilla, puede agregar la coloropción, como pad=1280:720:(ow-iw)/2:(oh-ih)/2:color=red(o puede usar el hexadecimal si lo prefiere). Ver lista de colores .
lema
61

Aquí está el comando que agregaría pilares o buzones para un ancho de salida fijo. Es un poco largo, pero tendrá que especificar el relleno de alguna manera.

Primero, en su shell defina el ancho y la altura de salida:

width=700
height=400

Luego ejecuta el 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

Esto se reduce a los elementos esenciales necesarios para cambiar el tamaño y la almohadilla: agregue sus otras opciones de video y audio como mejor le parezca. Tenga en cuenta que los números para widthy heighttienen que ser divisibles por 2 para que funcionen para la mayoría de los códecs.

Aquí está la explicación de lo que está sucediendo:

  • Escalada:
    • Primero tenemos que averiguar si escalar por ancho o alto.
    • Para hacer esto, dividimos el ancho de salida por el ancho de entrada, y la altura de salida por la altura de entrada. Esto nos dará los factores de escala para cada dimensión.
    • Luego verificamos cuál es más bajo (con min()) y elegimos solo ese factor para cambiar el tamaño.
    • Finalmente, multiplicamos el ancho y la altura de entrada por ese factor ( iw*min(…):ih*min(…)).
  • Relleno:
    • $width:$height es el ancho y la altura de salida
    • Para determinar dónde colocar el video resultante, necesitamos restar el ancho escalado del ancho máximo de salida y la altura escalada de la altura máxima de salida.
    • Los anchos y alturas escaladas son las expresiones del scalefiltro.
    • Dividimos el desplazamiento resultante por 2 para agregar bordes en ambos lados.
slhck
fuente
3
@JamieTaylor Considere agregar -movflags +faststartal ejemplo de slhck. Permitirá que su video descargado progresivamente comience a reproducirse antes de que se descargue por completo, y también vea la Guía de codificación FFmpeg y x264 y la Guía de codificación FFmpeg y AAC para obtener más instrucciones y ejemplos de codificación.
llogan
Se podría acortar el filtro de almohadilla de esto, pienso:pad=$width:$height:(ow-iw)/2:(oh-ih)/2"
jdi
1
@jdi Esto no funcionará si está reduciendo la escala, ya que dará como resultado valores negativos para ow-iw.
slhck
Gracias por el punto de partida! Sin embargo, para obtener una relación de aspecto adecuada para videos con una relación de aspecto de muestra! = 1, cada aparición de "iw" debe multiplicarse por "sar", por lo que debe reemplazar CADA aparición de "iw" con "(sar * iw)" en la expresión de filtro me funciona.
schieferstapel
@slhck Hola, lo estoy intentando en Android, pero parece que no funciona, ¿me pueden ayudar? ffmpeg -i input.mp4 -filter: v scale = 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

Me parece que debes hacer esto en tres pasos:

  1. Verifique la relación de aspecto de entrada
  2. Escale videos con un DAR> 7/4 de ancho (cambie el ancho a 700 y escale la altura para mantener la relación de aspecto), y escale aquellos con DAR <7/4 de alto
  3. Rellene el video para que encaje en el espacio 700: 400.

FFmpeg / avconv puede escalar / rellenar con filtros de video en un solo paso, transcodificando solo una vez. Por ejemplo, para tomar un video 16: 9, escale el ancho y luego escriba los resultados en un buzón:

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

... pero para el primer paso (detectar la relación de aspecto y compararlo con el 7: 4 que necesita) deberá usar un script de algún tipo.

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

... obtendrá la relación de aspecto del video, que se verá como '16: 9 'o' 4: 3 '. En un script bash, usaría algo como:

#!/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

Obviamente tendrás que adaptarlo a tus necesidades.

maldad
fuente
1
Sin embargo, es posible hacerlo en un solo paso, vea mi respuesta.
slhck
@slhck Ahora es más fácil. Ver respuesta con guitarra-salmonete.
llogan
@LordNeckbeard ¡Gracias! Hace poco vi esa opción, hace que sea mucho más fácil.
slhck