Como faço para gerar rapidamente GIFs animados de baixa qualidade com o ffmpeg?

3

Geramos muitos GIFs em miniatura cuja qualidade não importa tanto quanto o tempo necessário para gerá-los. Gerar GIFs de alta qualidade com o ffmpeg está muito bem coberto, mas não estou tendo muita sorte em descobrir como gerar os de baixa qualidade o mais rápido possível.

O cálculo da paleta ocupa a maior parte do tempo de execução com o seguinte comando (obtido da resposta do filtro de várias cadeias aqui: Como criar eficientemente um gif de melhor paleta de uma parte de vídeo diretamente da web ):

ffmpeg -y -threads 8 -r 24 -f image2 -start_number 1 -i "frames.%04d.jpg" -filter_complex "fps=24,scale=150:-1:flags=fast_bilinear,split=2 [a][b]; [a] palettegen [pal] fifo [b]; [b] [pal] paletteuse" output.gif

O tempo de execução desse comando com 1000 quadros é de cerca de 72 segundos. Cerca de 67 segundos disso é a passagem da paleta e, em seguida, ela passa pela geração GIF real em cerca de 5 segundos. Eu gostaria de reduzir o tempo de execução o máximo possível, e disposto a sacrificar muita qualidade de imagem pela velocidade.

    
por Rjak 08.08.2018 / 07:25

2 respostas

1

Recebi a tarefa de reduzir o tempo necessário para gerar um GIF animado o mais próximo possível de 30 quadros de comprimento com 150 pixels de largura. A maioria das seqüências que geramos tem menos de 1000 quadros. Nós tínhamos uma seqüência de 15.000 frames e nossos nós de renderização estavam levando 17 minutos para produzir esse GIF de ~ 30 quadros, o que é inaceitavelmente lento.

Estávamos usando o ffmpeg como demuxer e canalizando para imagemagick. Através de várias horas de experimentação, cheguei às seguintes conclusões:

  • O número de quadros de entrada que você solicita ao ffmpeg para processar é POR FAR a entrada mais impactante em termos de velocidade de execução. Se usar o demuxer de concatenação para ignorar quadros de entrada é uma opção, isso fará a maior diferença de desempenho. Tomando cada quinto quadro, consegui reduzir o tempo total de computação para 1 minuto e 45 segundos com alta qualidade de reescalonamento de lanczos e computação por paleta por quadro. A geração de nossa miniatura de visualização de 30 quadros agora leva menos de um segundo .

  • O algoritmo de reescalonamento foi o segundo maior impactor de desempenho (mas um segundo distante). Usando fast_bilinear em vez de lanczos salvou 150 segundos de tempo de computação em todos os 15.000 quadros.

  • A variável menos impactante foi a computação de paleta, e isso variou com o algoritmo de reescalonamento. Com mais de 15.000 quadros usando lanczos, economizamos cerca de 17 segundos de tempo de execução se eliminássemos a computação de paleta. Usando o fast_bilinear, economizamos cerca de 75 segundos de tempo de execução.

Como o algoritmo de reescalonamento e a computação de paleta eram insignificantes, acabamos mantendo-os na mais alta qualidade. Reduzimos nosso tempo de computação de 17 minutos para menos de 1 segundo, principalmente dizendo ao ffmpeg para ignorar a leitura de arquivos de entrada.

EXECUÇÃO PRINCIPAL: SKIPPING INPUT FRAMES vs SKIPPING OUTPUT FRAMES

O motivo pelo qual o processo estava demorando tanto é que a queda de quadros não ajuda o tempo de execução ao usar o demodificador image2. Se você muck com o -r flag e o fps filter, você afetará o número de frames que aparecem no GIF final, mas o ffmpeg parece ainda fazer algo com todos os 15.000 frames de entrada.

A única maneira que eu poderia encontrar para ter ffmpeg pular quadros de entrada é usando o concat demuxer.

Veja como agora gero miniaturas GIF animadas de alta qualidade em minha máquina dev em menos de um segundo pulando quadros de entrada:

# create text file which describes the ~30 input frames we want ffmpeg to process
seq -f "file 'left_frames.%04g.jpg'" 10000 500 25000 > tmp.txt

# generate the animated gif using ffmpeg only
ffmpeg -f concat -i tmp.txt -filter_complex "scale=150:-1:flags=lanczos,split=2 [a][b]; [a] palettegen [pal]; [b] fifo [b]; [b] [pal] paletteuse" output.gif
    
por 15.08.2018 / 08:02
2

Seu uso dos filtros palettegen / paletteuse está tornando o comando mais lento. A maneira mais simples de obter um GIF de baixa qualidade seria:

ffmpeg -f image2 -i "frames.%04d.jpg" output.gif

com escala adicional:

ffmpeg -f image2 -i "frames.%04d.jpg" -vf scale=150:-1 output.gif

Você também pode descartar quadros no GIF de saída, por exemplo, os quadros, para que nem todos sejam processados. Por exemplo. ter apenas 1 saída de FPS, usando um filtro fps :

ffmpeg -i "frames.%04d.jpg" -vf "fps=fps=1,scale=150:-1" output.gif
    
por 13.08.2018 / 10:43