Combine uma imagem + um arquivo de áudio para criar um vídeo usando o FFmpeg

184

Isso deve ser bastante trivial, mas não consigo encontrar uma maneira de fazê-lo funcionar.

Quero que o FFmpeg pegue uma imagem JPEG e um arquivo de áudio como entrada e gere um arquivo de vídeo com a mesma duração que o arquivo de áudio (esticando a imagem estática por toda a duração).

Eu não ligo muito para qual codec de vídeo é usado para saída, mas é vital que eu possa usar "copiar" como codec de áudio (por exemplo, copiar o fluxo de áudio sem transcodificá-lo).

Qual é a linha de comando correta que faria isso?

Eu tentei:

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

e tentei um monte de combinações com e sem -s 640x360, -loop_input, -shortest, -t xxx, -r 0.1(artificialmente baixa taxa de quadros na esperança de que o vídeo seria mais) e-f image2

Ou eu recebo erros ou recebo um arquivo de vídeo com a duração de um quadro.

Pesquisei no Google e encontrei uma dúzia de soluções propostas (supostamente para essa mesma pergunta), nenhuma das quais funciona.

Alguém pode sugerir um comando funcional e explicar a lógica por trás dele?

matteo
fonte
Eu apenas tentei sua linha de comando e funcionou como esperado. Seu problema pode estar no formato do som. A transcodificação do som funciona?
Captain Giraffe
Com "conforme o esperado", o vídeo resultante tem a mesma duração da entrada de áudio? Você já jogou? Não é de um quadro?
Matteo
Formato de som não é o problema, a transcodificação as obras sonoras
Matteo
Eu também tinha um problema de ordem de params e isso me custou horas! Pena que esse tipo de problema não seja coberto pela ajuda. gregoire.org/2009/12/05/fun-with-ffmpeg
Paul Gregoire
3
este é melhor do que resposta escolhida, eu experimentei e é rápido e tamanho do arquivo é pequeno ..ffmpeg -y -i image.png -i audio.mp3 -c:a copy result.avi
Muhammad Umer

Respostas:

146

A ordem das opções na linha de comando é importante. O seguinte funciona para o meu caso:

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

Em um caso mais geral, onde image.jpge onde audio.wavestá sua entrada, você pode usar o seguinte comando, adaptado do wiki do 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

Isso usaria o libx264codificador e forneceria uma compressão melhor do que o codec MJPEG usado acima. O áudio é AAC, com o ffmpegcodificador AAC embutido .

matteo
fonte
5
Como os arquivos acabam sendo muito maiores que [tamanho da imagem] + [tamanho do arquivo de áudio]? Eu esperaria que a compressão de vídeo enlouquecesse com um quadro constante?
Alec Jacobson
2
Depende do codec de vídeo que você usa. Se você estiver copiando os comandos nos meus exemplos, estou usando mjpeg como o codec, que comprime cada quadro separadamente, para que não tire vantagem do fato de que todos os quadros são iguais. Além disso, acho que até mesmo outros codecs recodificariam o quadro inteiro de vez em quando, ou seja, cada N-ésimo quadro, então você obteria um arquivo muito menor, mas ainda maior do que apenas o tamanho da imagem + som. Eles fazem isso porque (a) caso contrário o decodificador seria necessário para ler o arquivo inteiro desde o início, mesmo se você só quer saltar para o último quadro, e
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.aviisso funciona melhor !!!?! ??!?!
Muhammad Umer 07/07
2
Esta resposta está sendo discutida no meta.
DavidPostill
41

Você está fazendo isso maneira mais difícil do que tem que ser. O FFmpeg é muito mais inteligente do que você acredita - sabe que você deseja que o vídeo tenha a mesma duração da sua faixa de áudio.

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

pause

Os únicos atributos que você precisa especificar são the input filenames, the output codecse the output filename(que e o ipso inclui the output container,).

Obviamente, faz sentido começar com uma imagem estática que compartilhe as mesmas dimensões que o seu eventual vídeo; se você estiver usando um editor de imagens dedicado em vez de especificar as dimensões de saída para o FFmpeg atender, precisará garantir que suas dimensões de entrada sejam pares .

O tamanho da saída é um dos problemas mais comuns do FFmpeg; alguns codecs são mais restritos em dimensões de saída do que outros, mas nenhuma saída pode ter atributos de altura ou largura de número ímpar.

O pausecomando no final do arquivo em lote mantém a CLI aberta - a melhor maneira de depurar sua linha de comando é lendo as mensagens de erro geradas. Eles são extremamente específicos - e a melhor documentação que o FFmpeg possui - mas o trabalho duro dos desenvolvedores é desperdiçado se você permitir que a janela se feche antes de poder lê-los.

O shell de comando possui uma opção cmd /kque mantém uma janela aberta, na qual é possível executar as mesmas instruções do script em lote no prompt de comando.

FFmpeg e avconv vai ambos fazem você usa -c:apara -acodece -c:vpara -vcodec, eventualmente, mas as antigas instruções funcionar bem na constrói eu uso.

Nota Bene: Todo commit possui idiossincrasias. Se sua linha de comando estiver falhando sem motivo aparente, geralmente é útil tentar outra compilação - ou seguir a bifurcação para o libav , onde os desenvolvedores mais ativos do FFmpeg estiveram nos últimos dois anos. Sua ferramenta de transcodificação foi renomeada para avconv, mas seus arquivos em lotes devem funcionar com qualquer um deles.


fonte
Devo estar usando uma versão diferente da sua (se você tentou seu comando e funciona como você descreve), porque, como eu já mencionei na pergunta, eu já tentei exatamente o mesmo comando e recebo um vídeo com a duração de 1 quadro (uma fração de segundo), NÃO a duração do arquivo de áudio. Eu esperava que fosse inteligente, mas (na minha versão) provou que não.
Matteo
2
Ei Matteo , sim, eu executei esse código e sim, ele funciona como anunciado. Tenho certeza de que existem muitas idiotas que seriam tão descuidadas a ponto de fazer tais afirmações sem testá-las, por isso tentarei não me ofender :) Em um post completo abaixo, fornecerei links Pastebin para a saída do console do FFmpeg e o MediaInfo dados em arquivos de entrada e arquivo de saída final. Meus arquivos de entrada, meu lote e meu arquivo de saída estão em um GoogleDrive, onde podem ser baixados gratuitamente , se você quiser testá-los em sua versão do FFmpeg.
@ShinMuraoka Mine is a win-64 ffmpeg build compiled on: Jan 6 2013, at: 16:16:53Nem sua solução nem a @matteo funcionaram para mim. Além disso, baixei seus arquivos do Google Drive, mas não deu a saída esperada (o arquivo de saída era preto e continha apenas áudio). Por favor, ajude-me a descobrir o comando certo a ser usado.
Codigo_idiot
2
"nenhuma saída pode ter atributos de altura ou largura de número ímpar" Não é verdade. Defina pix_fmt como algo que não possui subamostragem de croma, como rgb24 ou yuv444p, e verifique se o codec e o contêiner o suportam e se não há mais restrições. Com relação ao pix_fmt, o FFmpeg é menos que inteligente; assume yuv420p (que possui subamostragem de croma), a menos que você diga o contrário.
Jonathan Baldwin
o que dizer de várias imagens? Preciso que a imagem mude em algum momento específico para outra imagem. Eu gostaria de poder especificá-los na linha de comando com um parâmetro de tempo para cada um.
36

Ainda mais fácil:

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

O FFmpeg tentará escolher o melhor codec automaticamente, dependendo da extensão do seu arquivo de saída.

Atualização: notei que o YouTube tem dificuldade em processar o vídeo (fica parado em 95%), acho que porque existe apenas um quadro. A solução que encontrei para deixar o YouTube feliz: adicione mais quadros. Além disso, eu adicionei -acodec copypara preservar a qualidade do áudio. Você precisa -shortestou faz um loop para sempre. (Ele pára no final do fluxo mais curto, que é o áudio, porque o loop da imagem é infinito.) A ordem das suas opções é muito importante para a velocidade, pois os filtros (e outros) são processados ​​na ordem que você especificar. Se você alterar a ordem desses parâmetros, os resultados serão dramaticamente diferentes.

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

Observe também que eu defino a taxa de quadros duas vezes, isso não é um acidente - a primeira taxa de quadros é para a entrada e a segunda é para a saída. Se você fizer isso corretamente, deve haver apenas um quadro por segundo de vídeo, o que significa que ele codifica relativamente rápido. Também defino a resolução para 720p aqui, o que significa que você deve obter áudio HD no YouTube :-)

PJ Brunet
fonte
Também é possível que seu arquivo de áudio não seja compatível com seu contêiner .flv. Nesse caso, você deve apenas tentar um contêiner (saída) diferente, como .webm, .avi ou qualquer outro formato, até encontrar um formato de contêiner compatível com seu arquivo de áudio.
PJ Brunet
11
Usei isso para um .JPG e .MP3 para fazer um MP4 - funcionou perfeitamente. O FLV que criei a partir do JPG / MP3 parecia não funcionar - o que pode ser o aviso de comentários anteriores.
2
A versão atualizada funciona, para o Youtube. Eu pensei que estava preso em 95%, mas finalmente funcionou.
Basj 28/02
conseguiu isso: 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)... isso funciona:ffmpeg -r 1 -loop 1 -i ep1.jpg -i ep1.wav -acodec copy -r 1 -shortest -vf scale=1280:-2 video.mp4
NineCattoRules 3/17/17
o que dizer de várias imagens? Preciso que a imagem mude em algum momento específico para outra imagem. Eu gostaria de poder especificá-los na linha de comando com um parâmetro de tempo para cada um.
14

A versão que funcionou para mim:

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

Faça o checkout da opção -shortestdeve estar na frente do arquivo de saída, caso contrário, recebo o erro abaixo:

A opção mais curta (concluir a codificação na entrada mais curta) não pode ser aplicada ao arquivo de entrada pic.jpg - você está tentando aplicar uma opção de entrada a um arquivo de saída ou vice-versa. Mova esta opção antes do arquivo ao qual pertence. Erro ao analisar as opções do arquivo de entrada pic.jpg.

fguillen
fonte
Obrigado por isso. A maioria das outras respostas não funcionou para mim (usando ffmpeg no Alpine linux). Esta resposta tem o comando mais curto que funcionou perfeitamente para mim.
DannyB
8

Na página de manual do ffmpeg:

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

Como você descobriu, as opções de infile devem vir antes do infile ao qual se aplicam.

Isso não é um bug, no entanto, apenas um mecanismo pelo qual você pode especificar a quais argumentos infile se aplicam.

ComputerDruid
fonte
o que dizer de várias imagens? Preciso que a imagem mude em algum momento específico para outra imagem. Eu gostaria de poder especificá-los na linha de comando com um parâmetro de tempo para cada um.
4

Isso funcionou para mim

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

Descobri que o vcodec libx264criou arquivos muito menores que mpjeg(10 MB em vez de 100 MB).

Coronel Panic
fonte
11
-shortesté uma opção de saída e pode ser ignorada como uma opção de entrada enquanto você a usa.
Llogan
1

Eu estava tentando fazer como @matteo , mas sem o áudio, e a solução do @Colonel Panic funcionou melhor:

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

Eu só tive que adicionar um argumento de duração em segundos ( -t 10).


fonte
-shortesté uma opção de saída, mas você a está usando como uma opção de entrada. Mova-o antes do arquivo de saída e você poderá eliminá-lo -t 10, mas sua resposta será praticamente a mesma que as outras.
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


fonte
5
Você pode explicar como o comando que você adicionou funciona?
22414 neelsg #
Esta resposta não é muito diferente das outras "respostas-comentários" simples aqui.
Llogan
0

Caso alguém queira convertê-los em lote, tente isso.

Você pode definir a pasta de entrada e saída, e também o formato em que deseja que o vídeo esteja. Nesse caso, defino-o como AVI.

Esta resposta Combinar uma imagem + um arquivo de áudio para fazer um vídeo usando o FFmpeg me ajudou muito.

 @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
fonte
-1

Tente este comando. É trabalhado para mim.

-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
fonte
2
Este é um comando incompleto que não poderia funcionar. Embora eu possa consertar e depurar seu comando, não farei seu trabalho por você; portanto, edite sua resposta e corrija você mesmo. Notei também que o tamanho do seu vídeo não é o que a matteo queria.
249 karel