¿Cómo puedo ajustar un video a un tamaño determinado, pero no subirlo con FFmpeg?

13

Necesito ajustar los videos a 640x360 (el máximo que el reproductor de mi teléfono puede manejar), al mismo tiempo que conserva la relación de aspecto , pero también quiero que el video no cambie si es más pequeño que 640x360 (no tiene sentido aumentarlo después de todo).

¿Hay alguna manera de obtener este comportamiento usando la línea de comando de ffmpeg?

sashoalm
fuente
No creo que esto se pueda hacer únicamente en ffmpeg, pero si estás dispuesto a escribirlo, definitivamente se puede hacer.
evilsoup
Ya lo he escrito, pero quería limpiar mi código en caso de que no sea necesario.
sashoalm
Probablemente sea posible con un filtro de escala que utiliza funciones como, min(…)pero definitivamente más fácil con un script simple que analiza las dimensiones. Ver mi mando aquí para ver un ejemplo de lo que puede hacerse: superuser.com/questions/547296/...
slhck

Respuestas:

9

Con las versiones más recientes de ffmpeg, puede usar la opción scaledel filtro force_original_aspect_ratio. Por ejemplo, para ajustar un video a 1280 × 720, sin escalar (consulte esta publicación para obtener más información):

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

Aquí, el scalefiltro se escala a 1280 × 720 si el video de entrada es más grande que eso. Si es más pequeño, no se ampliará. El padfiltro es necesario para llevar el video de salida a 1280 × 720, en caso de que su relación de aspecto o tamaño difiera del tamaño objetivo.


Con versiones anteriores de ffmpeg, hay una solución un tanto extraña. Primero, defina el ancho, la altura y la relación de aspecto de su salida. Esto nos ahorrará algo de tipeo.

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

Ahora, apliquemos el comando de filtro súper complejo que escribió Jim Worrall :

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

Realmente no voy a explicar qué hace todo esto, pero básicamente puedes alimentar cualquier video, y solo disminuirá, no aumentará. Si lo desea, puede diseccionar el filtro en sus expresiones individuales. Es posible acortar esto, pero también funciona así.

slhck
fuente
1
+1 pero ese es un comando realmente horrible: P
evilsoup
¿Yo se, verdad? Pasé diez minutos tratando de dividirlo en partes lógicas y luego insertando algunos valores, pero me di por vencido. Es un poco viejo y tal vez sería posible escribirlo de manera mucho más concisa que esto.
slhck
13

Una versión más legible puede verse así:

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

640 / iw es el factor de escala horizontal y 360 / ih es el factor de escala vertical

Desea ajustar la imagen a escala dentro del cuadro de salida y mantener la relación de aspecto (almacenamiento). Para ello, seleccione el factor de escala más pequeño con la función mínima: min (640 / iw, 360 / ih)

Desea evitar cualquier aumento de escala (es decir, un factor de escala> 1.0) para agregar otra función mínima: min (1, min (640 / iw, 360 / ih))

El siguiente paso es calcular la resolución de salida multiplicando el factor de escala con ancho de entrada y altura de entrada:
ancho de salida = iw * min (1, min (640 / iw, 360 / ih))
altura de salida = ih * min (1, min (640 / iw, 360 / ih))

El último paso es construir el comando de filtro. No es necesario especificar la altura de salida, puede especificar -1 y ffmpeg mantendrá la relación de aspecto aplicando el mismo factor de escala que para el ancho.

immerzl
fuente
A + Funciona fuera de la caja. La solución de la respuesta seleccionada no conservó la relación de aspecto. Apretó los marcos.
287352
5

También tuve el mismo problema, pero lo resolví ajustando el video en un cuadrado de 640x640 (debido a los videos verticales hechos con teléfonos inteligentes).

Entonces, usando la lógica immerzi y algunas investigaciones, termino con esto:

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

La última parte es para tener una altura divisible por 2 que es necesaria para muchos codificadores.

Shebuka
fuente