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


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

Eu quero FFmpeg para tomar uma imagem JPEG e um arquivo de áudio como entrada e gerar um arquivo de vídeo com a mesma duração que o arquivo de áudio (alongando a imagem estática para toda a duração).

Eu não me importo muito sobre o codec de vídeo que é usado para a saída, mas é vital que eu possa usar "copiar" como o codec de áudio (ou seja, copiar o fluxo de áudio sem transcodificá-lo).

Qual é a linha de comando certa que faria isso?

Eu tentei:

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

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

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

Eu pesquisei e encontrei uma dúzia de soluções propostas (supostamente para esta mesma pergunta), nenhuma das quais funciona.

Alguém pode sugerir um comando de trabalho e explicar a lógica por trás disso?


151


origem


Eu apenas tentei sua linha de comando e funcionou como esperado. Seu problema pode estar no formato de som. Será que transcodifica o trabalho de som? - Captain Giraffe
Por "como esperado", você quer dizer que o vídeo resultante tem a mesma duração que a entrada de áudio? Você já jogou? Não é um quadro de comprimento? - matteo
Formato de som não é o problema, transcodificando os trabalhos de som - matteo
Eu tive uma ordem de emissão de params também e me custou horas! Pena que esses tipos de problemas não são abordados na ajuda. gregoire.org/2009/12/05/fun-with-ffmpeg - Paul Gregoire
isso é melhor que a resposta escolhida, eu experimentei e é rápido e o tamanho do arquivo é pequeno ..ffmpeg -y -i image.png -i audio.mp3 -c:a copy result.avi - Muhammad Umer


Respostas:


A ordem das opções na linha de comando é importante. Os seguintes trabalhos para o meu caso:

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

Em um caso mais geral, onde image.jpg e audio.wav sua entrada, você pode usar o seguinte comando, adaptado de o 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 libx264 codificador e fornecer-lhe uma melhor compressão do que o codec MJPEG utilizado acima. O áudio é AAC, com o built-in ffmpeg Codificador AAC.


117



Por que os arquivos acabam sendo muito maiores que [tamanho da imagem] + [tamanho do arquivo de áudio]? Eu esperaria que a compressão de vídeo enlouqueça com um quadro constante? - Alec Jacobson
Depende do codec de vídeo que você usa. Se você estiver copiando os comandos em meus exemplos, estou usando o mjpeg como o codec, que compacta cada quadro separadamente, portanto, não tira vantagem do fato de que todos os quadros são iguais. Além disso, acho que até mesmo outros codecs recodificariam o quadro todo de vez em quando, ou seja, todo quadro N-ésimo, assim você obteria um arquivo muito menor, mas ainda muito maior do que o tamanho da imagem + som. Eles o fazem porque (a) caso contrário, o decodificador precisaria ler o arquivo inteiro desde o início, mesmo se você quiser pular para o último quadro, e - matteo
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
Esta resposta está sendo atualmente discutido em meta. - DavidPostill♦
@matteo clique em 'editar' em resposta, e no canto inferior direito haverá um botão com o nome 'comunidade qualquer' e você a alternará e salvará - TankorSmash


Você está fazendo isso caminho mais difíceis do que tem que ser. O FFmpeg é muito mais inteligente do que você acredita - sabe que você quer que o vídeo tenha o mesmo tamanho de sua faixa de áudio.

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

pause

Os únicos atributos você ter para especificar são os input filenames, a output codecs, e as output filename (qual o ipso inclui o output container,).

Claro, faz sentido começar com uma imagem fixa que compartilhe as mesmas dimensões do seu vídeo final; Se você estiver usando um editor de imagem dedicado em vez de especificar dimensões de saída para o FFmpeg atender, será necessário verifique se suas dimensões de entrada são números pares.

O tamanho da saída é um dos hang-ups 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 com números ímpares.

o pause comando no final do arquivo de lote mantém a CLI aberta - o A melhor maneira de depurar sua linha de comando é lendo as mensagens de erro isso gera. Eles são extremamente específicos - e a melhor documentação do FFmpeg - mas o trabalho duro dos desenvolvedores é um desperdício se você permitir que a janela feche antes de poder lê-los.

O shell de comando tem um interruptor cmd /k que mantém uma janela aberta onde você pode executar as mesmas instruções do seu script em lote no prompt de comando.

FFmpeg e avconv ambos farão você usar -c:apara -acodec e -c:vpara -vcodec eventualmente, mas as instruções antigas funcionam bem nas construções que eu uso.

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


32



Eu devo estar usando uma versão diferente do youurs (se você já tentou o seu comando e funciona como você descreve), porque, como já mencionei na pergunta, eu já tinha tentado o mesmo comando e recebi um vídeo da duração de 1 frame (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 não ser. - matteo
Ei Matteosim, eu executei esse código e, sim, ele funciona como anunciado. Tenho certeza que existem muitos halfwits que seriam tão descuidados a ponto de fazer tais alegações sem testá-los, então tentarei não ficar ofendido :) Em um post completo abaixo eu fornecerei os links do Pastebin para a saída do console FFmpeg e MediaInfo dados em arquivos de entrada e arquivo de saída final. Meus arquivos de entrada, meu arquivo de lote, meu arquivo de saída estão em um GoogleDrive onde eles estão grátis para download, se você gostaria de testá-los contra o seu build FFmpeg.
@ShinMuraoka Mine is a win-64 ffmpeg build compiled on: Jan 6 2013, at: 16:16:53 Nem sua solução nem a solução @matteo funcionaram para mim. Além disso, eu fiz o download dos seus arquivos do Google Drive, mas isso não deu a saída esperada (o arquivo de saída era preto contendo apenas áudio). Por favor, ajude-me a descobrir o comando certo a ser usado. - coding_idiot
"nenhuma saída pode ter atributos de altura ou largura com números ímpares" Não é verdade. Configure o pix_fmt para algo que não tenha subamostragem de crominância, como rgb24 ou yuv444p, então certifique-se de que o codec e o contêiner o suportem e não tenham mais restrições. Com relação ao pix_fmt, o FFmpeg é menos que inteligente; Ele assume yuv420p (que tem subamostragem de croma), a menos que você diga o contrário. - Jonathan Baldwin
E quanto a 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.


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 preso em 95%), acho que há apenas um quadro. A solução que encontrei para deixar o YouTube feliz: adicione mais frames. Além disso, eu adicionei-acodec copy para preservar a qualidade de áudio. Você precisa -shortest ou loops para sempre. (Ele para no final do fluxo mais curto, que é o áudio, porque o loop da imagem é infinito.) A ordem de 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

Note também que eu configurei a taxa de quadros duas vezes, isso não é um acidente - a primeira taxa de quadros é para a entrada, 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 de forma relativamente rápida. Também defini a resolução para 720p aqui, o que significa que você deve obter áudio HD no YouTube :-)


28



Também é possível que o seu arquivo de áudio não seja compatível com o seu contêiner .flv. Nesse caso, você deve tentar um contêiner diferente (saída), como .webm, .avi ou qualquer outro formato, até encontrar um formato de contêiner compatível com seu arquivo de áudio. - PJ Brunet
Usado isso para um .JPG e .MP3 para fazer um MP4 - funcionou perfeitamente. O FLV que criei a partir do JPG / MP3 não parecia funcionar - o que pode ser o aviso prévio.
A versão atualizada funciona, para o Youtube. Eu pensei que estava preso em 95%, mas finalmente funcionou. - Basj
tenho 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
E quanto a 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.


A versão que funcionou para mim:

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

Finalize a opção -shortest deve estar na frente do arquivo de saída, se não recebo o erro abaixo:

A opção mais curta (concluir a codificação dentro da 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.


13



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


A partir do ffmpeg manpage:

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

Como você descobriu, as opções do arquivo devem vir antes do arquivo a que se aplicam.

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


7



E quanto a 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.


Isso funcionou para mim

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

Eu encontrei vcodec libx264 criou arquivos muito menores do que mpjeg (10 MB em vez de 100 MB).


4



-shortest é uma opção de saída e pode ser ignorada como uma opção de entrada como você está usando. - LordNeckbeard


Eu estava tentando fazer o que @matteo, mas sem o áudio e @Colonel PanicA solução 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).


1



-shortest é uma opção de saída, mas você está usando isso como uma opção de entrada. Movê-lo antes do arquivo de saída e você pode eliminar o -t 10, mas a sua resposta será praticamente a mesma que as outras. - LordNeckbeard


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


0



Você pode explicar como o comando que você adicionou funciona? - neelsg
Esta resposta não é muito diferente das outras "respostas a comentários" aqui. - LordNeckbeard


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

Você pode definir a pasta de entrada e saída, e também o formato em que você quer que o vídeo esteja. Neste caso, configurei para AVI.

Esta resposta Combine uma imagem + um arquivo de áudio para criar 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

0





Tente este comando. Isso é 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"

-1



Este é um comando incompleto que não poderia funcionar. Embora eu possa consertar e depurar seu comando, não farei seu trabalho para você, então edite sua resposta e corrija-a. Também percebi que o tamanho do seu vídeo não é o desejado pelo matteo. - karel