FFMPEG (libx264) "altura no divisible por 2"

188

Estoy tratando de codificar un video .mp4 de un conjunto de cuadros usando FFMPEG usando el códec libx264.

Este es el comando que estoy ejecutando:

/usr/local/bin/ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4

A veces me sale el siguiente error:

[libx264 @ 0xa3b85a0] height not divisible by 2 (520x369)

Después de buscar un poco, parece que el problema tiene algo que ver con el algoritmo de escala y se puede solucionar agregando un argumento -vf.

Sin embargo, en mi caso no quiero escalar. Idealmente, quiero mantener las dimensiones exactamente iguales a los marcos. ¿Algún consejo? ¿Hay algún tipo de relación de aspecto que h264 impone?

Andy Hin
fuente
@AleksandrDubinsky Pero la respuesta de LordNeckbeard no conserva el ancho y la altura originales. Aquí debemos especificar manualmente el ancho o la altura ... y si w usa -vf scale = -2: ih o -vf scale = iw: -2 esto no será funciona si la altura y el ancho son desiguales ... Por favor, explique cómo esa respuesta es más óptima ... gracias
varmashrivastava
1
@varmashrivastava Bueno, la forma en que funciona SO es que originalmente pudo haber una pregunta, y luego Google envía a un grupo de personas con una pregunta diferente que luego secuestran la página. Es lo que es, trata de no luchar contra él. La respuesta correcta a la pregunta original es -vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2", que ni siquiera es una de las respuestas. La respuesta correcta a la pregunta de todos los demás es la de Lord Neckbeard.
Aleksandr Dubinsky
@varmashrivastava Me adelanté y arreglé la primera respuesta. Esperemos que las modificaciones no lo destrocen.
Aleksandr Dubinsky
@AleksandrDubinsky gracias ... ¿y el usuario puede usar en "scale="lugar de "pad="si no quiere píxeles de relleno coloreados?
varmashrivastava

Respuestas:

269

La respuesta a la pregunta original que no quiere escalar el video es:

-vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

Mando:

ffmpeg -r 24 -i frame_%05d.jpg -vcodec libx264 -y -an video.mp4 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2"

Básicamente, .h264 necesita dimensiones pares, por lo que este filtro:

  1. Divida la altura y el ancho originales por 2
  2. Redondearlo al píxel más cercano.
  3. Multiplíquelo nuevamente por 2, convirtiéndolo en un número par
  4. Agregue píxeles de relleno negro hasta este número

Puede cambiar el color del relleno agregando un parámetro de filtro :color=white. Ver la documentación del pad .

Andy Hin
fuente
3
No es un error. No importa que no esté realizando el escalado, ya que la salida heredará el tamaño de fotograma de la entrada.
llogan
55
Para el registro, solo estaba haciendo algo donde creé un video a partir de una imagen, y usé yuvj444p como formato de píxel; no le importaba el tamaño del video. Luego tuve que convertirlo a yuv420p, y luego me importó el tamaño del video. Busqué yuv420p en wikipedia, creo que es un formato de color de varios píxeles, que necesita que la imagen tenga un tamaño específico. Sin embargo, no estoy seguro de por qué importa comprimido.
lahwran
77
Probablemente sea mejor usar el pad en lugar de la escala, para agregar una fila / columna negra. Escalar una imagen en un píxel la desenfocará.
Glenn Maynard
55
@NickeManarin, este filtro debería funcionar para agregar 1 pixel de relleno blanco a la dimensión vertical, con el vídeo posicionado superior izquierda: -vf pad="width=iw:height=ih+1:x=0:y=0:color=white". La documentación del pad ffmpeg está aquí: ffmpeg.org/ffmpeg-filters.html#pad-1 .
Mark Berry
44
He aquí una solución que sólo añade un píxel de relleno para las dimensiones que son impares: -vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2".
danneu
250

Solo usa -2

De la documentación del filtro de escala :

Si uno de los valores está -ncon n > 1, el filtro de escala también usará un valor que mantenga la relación de aspecto de la imagen de entrada, calculada a partir de la otra dimensión especificada. Después de eso, sin embargo, se asegurará de que la dimensión calculada sea divisible por ny ajuste el valor si es necesario.

Ejemplos

Establezca el ancho en 1280, y la altura se calculará automáticamente para preservar la relación de aspecto, y la altura será divisible por 2:

-vf scale=1280:-2

Igual que el anterior, pero con una altura declarada en su lugar; dejando ancho para ser tratado por el filtro:

-vf scale=-2:720

"divisible por 2"

Según lo requerido por x264, el "divisible por 2 para ancho y alto" es necesario para las salidas YUV 4: 2: 0 de submuestreo de croma. 4: 2: 2 necesitaría "divisible por 2 para el ancho", y 4: 4: 4 no tiene estas restricciones. Sin embargo, la mayoría de los jugadores que no están basados ​​en FFmpeg solo pueden decodificar correctamente 4: 2: 0, por eso es que a menudo se ven ffmpegcomandos con la -pix_fmt yuv420popción cuando se emite video H.264.

Consideración

Desafortunadamente, no puede usar -2tanto el ancho como la altura, pero si ya especificó una dimensión, entonces usar -2es una solución simple.

lema
fuente
14
Creo que esto debe ser marcado como la respuesta correcta debido a que no hay "trucos" involucrados. Deseo votar en más de una ocasión
LucaM
1
¿Por qué -vf scale=-2:-2no funciona? En mi caso, quiero preservar el tamaño del archivo original tanto como sea posible. Lo que funcionó para mí fue -vf scale=-2:ih. Pero no funciona si ambos h / w son desiguales.
Pascal
2
@tuner El valor resultante de -2depende del valor declarado de la otra dimensión.
llogan
3
en mi caso esto me dio el siguiente error: Size values less than -1 are not acceptable.pero la respuesta de @Zbyszek funcionó perfectamente.
Julien
64

Si desea establecer un ancho de salida y tener una salida con la misma relación que la original

scale=720:-1 

y no caer con este problema, entonces puedes usar

scale="720:trunc(ow/a/2)*2"

(Solo para personas que buscan cómo hacerlo con el escalado)

Zbyszek
fuente
16
Y para una altura fija esscale="trunc(oh*a/2)*2:720"
Tom
20

El problema con las scalesoluciones aquí es que distorsionan la imagen / video fuente, que casi nunca es lo que quieres.

En cambio, he encontrado que la mejor solución es agregar una almohadilla de 1 píxel a la dimensión impar. (Por defecto, el relleno es negro y difícil de notar).

El problema con las otras padsoluciones es que no se generalizan sobre dimensiones arbitrarias porque siempre se rellenan.

Esta solución solo agrega una almohadilla de 1 píxel a la altura y / o el ancho si son impares:

-vf pad="width=ceil(iw/2)*2:height=ceil(ih/2)*2"

Esto es ideal porque siempre hace lo correcto incluso cuando no se necesita relleno.

danneu
fuente
Las soluciones de escala alteran el recuento de píxeles en 1 como máximo. Eso apenas distorsiona la imagen. Si le preocupa la velocidad de filtrado, úselo scale=iw+mod(iw,2):ih+mod(ih,2):flags=neighbor. Esto solo puede aumentar cada dimensión en 1, si es necesario, y duplicará la última fila / columna.
Gyan
@Gyan que ha pasado mucho tiempo desde que tuve el problema que esta resuelto (mi respuesta fue extraído de un comentario que hice hace mucho tiempo), pero recuerdo que la escala por un solo píxel hizo introducir artefactos visuales notables en algunas condiciones por lo que me molesta en primer lugar. No recuerdo exactamente, ¿tal vez una cantidad desproporcionada de desenfoque de un solo cambio de píxel? ¿Quizás solo en algunos formatos de video / imagen? Todo lo que puedo decir es que procesé miles de videos con esta solución y fue la transformación favorable.
danneu
19

Probablemente se deba al hecho de que el video H264 generalmente se convierte de RGB a espacio YUV como 4: 2: 0 antes de aplicar la compresión (aunque la conversión de formato en sí misma es un algoritmo de compresión con pérdida que genera un ahorro de espacio del 50%).

YUV-420 comienza con una imagen RGB (Rojo Verde Azul) y la convierte en YUV (básicamente un canal de intensidad y dos canales de "tono"). Los canales de tono se submuestrean creando una muestra de tono por cada cuadrado de 2X2 de ese tono.

Si tiene un número impar de píxeles RGB, ya sea horizontal o verticalmente, tendrá datos incompletos para la última columna o fila de píxeles en el espacio de matiz submuestreado del marco YUV.

Adisak
fuente
2
Otro hecho interesante ... cuando decodifica con material de Microsoft Media Foundation, necesita usar múltiplos de 16 para H264. Entonces, el video 1080P en realidad se decodifica en un búfer que tiene 1088 de altura (aunque ignora las últimas 8 líneas).
Adisak
2

LordNeckbeard tiene la respuesta correcta, muy rápido

-vf scale=1280:-2

Para Android, no olvides agregar

"-preset ultrafast" and|or "-threads n"
Fallouter
fuente
No necesita declarar hilos: eso se trata automáticamente. Creo que la lentitud de Andriod al codificar a H.264 se debe a que las personas usan el popular "WritingMinds / ffmpeg-android" que usa --disable-asmen su script de construcción x264 . Esto resulta en una lentitud innecesaria y significativa (puede verificar el registro ffmpeg y si se muestra, using cpu capabilties: none!entonces eso es malo). No estoy seguro de por qué agregaron eso, pero no soy un desarrollador de Android.
llogan
1

También puede usar la bitandfunción en lugar de trunc:

mordida (x, 65534)

hará lo mismo trunc(x/2)*2y es más transparente en mi opinión.
(Considere 65534 un número mágico aquí;))


Mi tarea consistía en escalar automáticamente muchos archivos de video a la mitad de la resolución .

scale=-2,ih/2conducir a imágenes ligeramente borrosas

razón:

  • vídeos de entrada tenían su relación de aspecto de la pantalla (DAR) conjunto
  • scale escala las dimensiones reales del marco
  • durante la vista previa, los tamaños de los nuevos videos deben corregirse usando DAR, lo que en caso de video de baja resolución (360x288, DAR 16: 9) puede provocar desenfoque

solución:

-vf "scale='bitand(oh*dar, 65534)':'bitand(ih/2, 65534)', setsar=1"

explicación:

  • output_height = input_height / 2
  • output_width = output_height * original_display_aspect_ratio
  • tanto output_width y output_height están ahora redondeado al más cercano divisible número más pequeño por 2
  • setsar=1significa que las dimensiones de salida ahora son finales, no se debe aplicar la corrección de la relación de aspecto

Alguien puede encontrar esto útil.

endigo
fuente