Combina una imagen + un archivo de audio para hacer un video usando FFmpeg

184

Esto debería ser bastante trivial, pero no puedo encontrar una manera de hacerlo funcionar.

Quiero que FFmpeg tome una imagen JPEG y un archivo de audio como entrada y genere un archivo de video de la misma duración que el archivo de audio (estirando la imagen fija durante toda la duración).

No me importa mucho qué códec de video se usa para la salida, pero es vital que pueda usar "copiar" como códec de audio (es decir, copiar la secuencia de audio sin transcodificarla).

¿Cuál es la línea de comando correcta que haría eso?

Lo intenté:

ffmpeg -i image8.jpg -i sound11.amr -acodec copy test.avi

y probado un montón de combinaciones con y sin -s 640x360, -loop_input, -shortest, -t xxx, -r 0.1(velocidad de fotogramas artificialmente bajo, con la esperanza de que el vídeo sería más largo) y-f image2

O recibo errores u obtengo un archivo de video de la duración de un cuadro.

Busqué en Google y encontré una docena de soluciones propuestas (supuestamente para esta misma pregunta), ninguna de las cuales funciona.

¿Alguien puede sugerir un comando de trabajo y explicar la lógica detrás de él?

matteo
fuente
Acabo de probar su línea de comando y funcionó como se esperaba. Su problema podría estar en el formato de sonido. ¿Funciona la transcodificación del sonido?
Capitán Giraffe
Por "como se esperaba", ¿quiere decir que el video resultante tiene la misma duración que la entrada de audio? ¿Lo has jugado? ¿No es de un cuadro de largo?
matteo
El formato de sonido no es el problema, la transcodificación del sonido funciona
matteo
¡También tuve un problema con el orden de los parámetros y me costó horas! Lástima que este tipo de problemas no estén cubiertos en la ayuda. gregoire.org/2009/12/05/fun-with-ffmpeg
Paul Gregoire
3
esta es mejor que la respuesta elegida, experimenté y es rápido y el tamaño del archivo es pequeño ...ffmpeg -y -i image.png -i audio.mp3 -c:a copy result.avi
Muhammad Umer

Respuestas:

146

El orden de opciones en la línea de comando es importante. Lo siguiente funciona para mi caso:

ffmpeg -loop 1 -y -i image8.jpg -i sound11.amr -shortest -acodec copy -vcodec mjpeg result.avi

En un caso más general, donde image.jpgy audio.wavson su entrada, puede usar el siguiente comando, adaptado de la wiki de FFmpeg :

ffmpeg -loop 1 -i image.jpg -i audio.wav -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -shortest out.mp4

Esto usaría el libx264codificador y le proporcionaría una mejor compresión que el códec MJPEG utilizado anteriormente. El audio es AAC, con el ffmpegcodificador AAC incorporado .

matteo
fuente
55
¿Cómo es que los archivos terminan siendo mucho más grandes que [tamaño de imagen] + [tamaño de archivo de audio]? ¿Esperaría que la compresión de video se vuelva loca con un marco constante?
Alec Jacobson el
2
Depende del códec de video que use. Si está copiando los comandos en mis ejemplos, estoy usando mjpeg como códec, que comprime cada cuadro por separado, por lo que no aprovecha el hecho de que todos los cuadros son iguales. Además, creo que incluso otros códecs recodificarían el cuadro completo de vez en cuando, es decir, cada enésimo fotograma, por lo que obtendría un archivo mucho más pequeño pero aún más grande que el tamaño de la imagen + sonido. Lo hacen porque (a) de lo contrario, el decodificador necesitaría leer todo el archivo desde el principio, incluso si solo desea saltar al último cuadro, y
matteo
2
Option shortest (finish encoding within shortest input) cannot be applied to input file image.jpg -- you are trying to apply an input option to an output file or vice versa. Move this option before the file it belongs to.
wim
2
use ffmpeg -y -i image.png -i audio.mp3 -c:a copy result.aviesto funciona mejor !!!?! ??!?!
Muhammad Umer
2
Esta respuesta se está discutiendo actualmente en meta.
DavidPostill
41

Lo estás haciendo mucho más difícil de lo que tiene que ser. FFmpeg es mucho más inteligente de lo que le das crédito: sabe que quieres que el video tenga la misma duración que tu pista de audio.

ffmpeg -i still.png -i narrate.wav -acodec libvo_aacenc -vcodec libx264 final.flv

pause

Los únicos atributos que tiene que especificar son el input filenames, el output codecsy el output filename(que eo ipso incluye el output container,).

Por supuesto, tiene sentido comenzar con una imagen fija que comparta las mismas dimensiones que su video final; Si está utilizando un editor de imágenes dedicado en lugar de especificar las dimensiones de salida para que FFmpeg cumpla, debe asegurarse de que sus dimensiones de entrada sean números pares .

El tamaño de salida es uno de los problemas más comunes de FFmpeg; algunos códecs están más restringidos en dimensiones de salida que otros, pero ninguna salida puede tener atributos de altura o anchura de números impares.

El pausecomando al final del archivo por lotes mantiene abierta la CLI: la mejor manera de depurar su línea de comando es leer los mensajes de error que genera. Son extremadamente específicos, y la mejor documentación que tiene FFmpeg, pero el arduo trabajo de los desarrolladores se desperdicia si permite que la ventana se cierre antes de poder leerlos.

El shell de comandos tiene un interruptor cmd /kque mantiene una ventana abierta donde puede ejecutar las mismas instrucciones del script por lotes en el símbolo del sistema.

FFmpeg y avconv te harán usar -c:apara -acodecy -c:vpara -vcodeceventualmente, pero las viejas instrucciones funcionan bien en las compilaciones que uso.

Nota Bene: Cada commit tiene idiosincracias. Si su línea de comando falla sin razón aparente, a menudo es útil intentar otra compilación, o seguir la bifurcación hasta libav , donde los desarrolladores más activos de FFmpeg han estado durante los últimos años. Su herramienta de transcodificación ha cambiado su nombre a avconv, pero sus archivos por lotes deberían funcionar con cualquiera de ellos.


fuente
Debo estar usando una versión diferente a la suya (si ha probado su comando y funciona como lo describe), porque, como ya mencioné en la pregunta, ya había probado exactamente el mismo comando y obtengo un video de la duración de 1 cuadro (una fracción de segundo), NO la duración del archivo de audio. Esperaba que fuera inteligente, pero (en mi versión) resultó no serlo.
matteo
2
Hola Matteo , sí, ejecuté ese código, y sí, funciona como se anuncia. Estoy seguro de que hay un montón de imbéciles que serían tan descuidados como para hacer tales afirmaciones sin probarlos, así que intentaré no ofenderme :) En una publicación completa a continuación, proporcionaré enlaces de Pastebin a la salida de la consola FFmpeg y MediaInfo datos en archivos de entrada y archivo de salida final. Mis archivos de entrada, mi archivo por lotes, mi archivo de salida están en un GoogleDrive donde se pueden descargar libremente , si desea probarlos en su compilación FFmpeg.
@ShinMuraoka Mine is a win-64 ffmpeg build compiled on: Jan 6 2013, at: 16:16:53Ni su solución ni la solución @matteo funcionaron para mí. Además, descargué sus archivos de Google Drive, pero no dio el resultado esperado (el archivo de salida era negro y solo contenía audio). Por favor, ayúdame a descubrir el comando correcto que se utilizará.
coding_idiot
2
"ninguna salida puede tener atributos de altura o anchura de número impar" No es cierto. Establezca pix_fmt en algo que no tenga submuestreo de croma, como rgb24 o yuv444p, luego asegúrese de que el códec y el contenedor lo admitan y no tengan más restricciones. Con respecto a pix_fmt, FFmpeg es menos que inteligente; asume yuv420p (que tiene submuestreo de croma) a menos que le indique lo contrario.
Jonathan Baldwin
¿Qué pasa con múltiples imágenes? Necesito que la imagen cambie en algún momento específico a otra imagen. Me gustaría poder especificarlos en la línea de comando con un parámetro de tiempo para cada uno.
36

Aún más fácil:

ffmpeg -i ep1.png -i ep1.wav ep1.flv

FFmpeg intentará elegir el mejor códec automáticamente, dependiendo de la extensión de su archivo de salida.

Actualización: Noté que YouTube tiene dificultades para procesar el video (se atasca al 95%) Creo que solo hay un cuadro. La solución que encontré para hacer feliz a YouTube: agregar más marcos. Además, agregué -acodec copypara preservar la calidad de audio. Necesitas -shortesto se repite para siempre. (Se detiene al final de la transmisión más corta, que es el audio, porque el bucle de la imagen es infinito). El orden de sus opciones es muy importante para la velocidad, ya que los filtros (y demás) se procesan en el orden que especifique. Si cambia el orden de estos parámetros, los resultados son dramáticamente diferentes.

ffmpeg -r 1 -loop 1 -i ep1.jpg -i ep1.wav -acodec copy -r 1 -shortest -vf scale=1280:720 ep1.flv

Observe también que configuro la velocidad de fotogramas dos veces, eso no es un accidente: la primera velocidad de fotogramas es para la entrada, la segunda es para la salida. Si hace esto correctamente, solo debe haber un cuadro por segundo de video, lo que significa que codifica relativamente rápido. También configuré la resolución a 720p aquí, lo que significa que debería obtener audio HD en YouTube :-)

PJ Brunet
fuente
También es posible que su archivo de audio no sea compatible con su contenedor .flv. En ese caso, debe probar un contenedor (de salida) diferente, como .webm, .avi o cualquier formato, hasta que encuentre un formato contenedor que sea compatible con su archivo de audio.
PJ Brunet
1
Usé esto para un .JPG y .MP3 para hacer que un MP4 funcionara perfectamente. El FLV que creé a partir del JPG / MP3 no parecía funcionar, lo que puede ser según la advertencia de comentarios anteriores.
2
La versión actualizada funciona, para Youtube. Pensé que estaba atascado al 95%, pero finalmente funcionó.
Basj
tengo esto: No pixel format specified, yuvj420p for H.264 encoding chosen. Use -pix_fmt yuv420p for compatibility with outdated media players. [libx264 @ 0x2b5c940] height not divisible by 2 (700x457)... esto funciona:ffmpeg -r 1 -loop 1 -i ep1.jpg -i ep1.wav -acodec copy -r 1 -shortest -vf scale=1280:-2 video.mp4
NineCattoRules
¿Qué pasa con múltiples imágenes? Necesito que la imagen cambie en algún momento específico a otra imagen. Me gustaría poder especificarlos en la línea de comando con un parámetro de tiempo para cada uno.
14

La versión que funcionó para mí:

 ffmpeg -loop 1 -y -i pic.jpg -i sound.amr -shortest video.mp4

Compruebe que la opción -shortestdebe estar delante del archivo de salida; de lo contrario, aparece el siguiente error:

La opción más corta (finalizar la codificación dentro de la entrada más corta) no se puede aplicar al archivo de entrada pic.jpg: está intentando aplicar una opción de entrada a un archivo de salida o viceversa. Mueva esta opción antes del archivo al que pertenece. Error al analizar las opciones para el archivo de entrada pic.jpg.

fguillen
fuente
Gracias por esto. La mayoría de las otras respuestas no funcionaron para mí (usando ffmpeg en Alpine Linux). Esta respuesta tiene el comando más corto que funcionó perfectamente para mí.
DannyB
8

Desde la página de manual de ffmpeg:

ffmpeg [[infile options][-i infile]]... {[outfile options] outfile}...

Como descubrió, las opciones de archivo deben aparecer antes que el archivo al que se aplican.

Sin embargo, esto no es un error, solo un mecanismo por el cual puede especificar a qué argumentos infile se aplican.

ComputerDruid
fuente
¿Qué pasa con múltiples imágenes? Necesito que la imagen cambie en algún momento específico a otra imagen. Me gustaría poder especificarlos en la línea de comando con un parámetro de tiempo para cada uno.
4

Esto funciono para mi

ffmpeg -loop 1 -shortest -y -i image.jpg -i audio.mp3 -acodec copy -vcodec libx264 video.avi

Encontré que vcodec libx264creó archivos mucho más pequeños que mpjeg(10 MB en lugar de 100 MB).

Coronel Panic
fuente
1
-shortestes una opción de salida y puede ignorarse como una opción de entrada mientras la está usando.
llogan
1

Estaba tratando de hacer como @matteo , pero sin el audio, y la solución de @Colonel Panic funcionó mejor:

ffmpeg -loop 1 -shortest -y -i still.png -vcodec libx264 -t 10 video.avi

Solo tuve que agregar un argumento de duración en segundos ( -t 10).


fuente
-shortestes una opción de salida, pero la está usando como una opción de entrada. Muévalo antes del archivo de salida y podrá eliminarlo -t 10, pero su respuesta será más o menos la misma que las demás.
llogan
0

ffmpeg -loop 1 -i img.jpg -i audio.wav -c:v libx264 -c:a aac -strict experimental -b:a 192k -shortest out.mp4


fuente
55
¿Puedes explicar cómo funciona el comando que agregaste?
neelsg
Esta respuesta no es muy diferente de las otras "respuestas de comentarios" simples aquí.
llogan
0

En caso de que alguien quiera convertirlos por lotes, intente esto.

Puede configurar la carpeta de entrada y salida, y también el formato en el que desea que esté el video. En este caso, lo configuro en AVI.

Esta respuesta Combinar una imagen + un archivo de audio para hacer un video usando FFmpeg me ayudó mucho.

 @echo off
 set "sourcedir=C:\Users\CodeHard\Desktop\BOX\Newfolder"  
 set "outputdir=C:\Users\CodeHard\Desktop\BOX\Converted" 

 PUSHD "%sourcedir%"

 for %%F in (*.mp3) DO ffmpeg -r 1 -loop 1 -i abc.jpeg -i "%%F" -acodec copy -r 1 -shortest -vf scale=1280:720 "%outputdir%\%%F.avi"  

 POPD
Suraj Jain
fuente
-1

Prueba este comando. Me ha funcionado.

-y -i /storage/emulated/0/images.jpg -i /storage/emulated/0/audio.wav -acodec aac -vcodec mpeg4 -s 480*320 -f mp4 -r 2 /storage/emulated/0/output.mp4"
Phani Varma
fuente
2
Este es un comando incompleto que no podría funcionar. Aunque puedo arreglar y depurar tu comando, no haré tu trabajo por ti, así que edita tu respuesta y corrígelo tú mismo. También noté que el tamaño de tu video no es lo que Matteo quería.
karel