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

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

Geramos muitos GIFs em miniatura cuja qualidade não importa tanto quanto o tempo necessário para gerá-los. A geração de GIFs de alta qualidade com ffmpeg é muito bem abordada, mas não estou tendo muita sorte em descobrir como gerar GIFs 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 (retirado da resposta do filtro de cadeia múltipla aqui:Como criar com eficiência um gif da melhor paleta a partir de uma parte de vídeo direto 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 frames é de cerca de 72 segundos. Cerca de 67 segundos disso é a passagem da paleta e, em seguida, passa pela geração real do GIF em cerca de 5 segundos. Eu gostaria de reduzir ao máximo todo o tempo de execução e estou disposto a sacrificar muita qualidade de imagem pela velocidade.

Responder1

O uso dos filtros palettegen/ paletteuseestá tornando o comando mais lento. A maneira simples de obter um GIF de qualidade inferior 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, ou seja, fazer uma amostra dos quadros, para que nem todos sejam processados. Por exemplo, para ter apenas 1 saída FPS, usando um fpsfiltro:

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

Responder2

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 e 150 pixels de largura. A maioria das sequências que geramos tem menos de 1.000 quadros. Tínhamos uma sequência de 15.000 quadros e nossos nós de renderização estavam demorando17 minutospara produzir este GIF de aproximadamente 30 quadros, que é inaceitavelmente lento.

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

  • O número de quadros de entrada que você pede ao ffmpeg para processar éDE LONGEa entrada mais impactante em termos de velocidade de execução. Se usar o demuxer concat para pular quadros de entrada for uma opção, isso fará a maior diferença no desempenho. Ao capturar cada quinto quadro, consegui reduzir o tempo total de computação para1 minuto e 45 segundoscom redimensionamento de lanczos de alta qualidade e cálculo de paleta por quadro.A geração de nossa miniatura de visualização de 30 quadros agora leva menos de 1 segundo.

  • O algoritmo de redimensionamento foi o segundo maior impactador de desempenho (mas um segundo distante). Usar fast_bilinear em vez de lanczos economizou 150 segundos de tempo de computação em todos os 15.000 quadros.

  • A variável menos impactante foi o cálculo da paleta, e isso variou com o algoritmo de redimensionamento. Mais de 15.000 quadros usando lanczos, economizamos cerca de 17 segundos de tempo de execução se eliminássemos o cálculo da paleta. Usando fast_bilinear, economizamos cerca de 75 segundos de tempo de execução.

Como o algoritmo de redimensionamento e o cálculo da paleta eram insignificantes, acabamos mantendo-os com a mais alta qualidade. Reduzimos nosso tempo de cálculo de 17 minutos para menos de 1 segundo, principalmente dizendo ao ffmpeg para pular a leitura dos arquivos de entrada.

PRINCIPAL CONCLUSÃO: SALTAR QUADROS DE ENTRADA vs SALTAR QUADROS DE SAÍDA

A razão pela qual nosso processo demorou tanto é que a queda de quadros não ajuda no tempo de execução ao usar o desmultiplicador image2. Se você mexer no -rsinalizador e no fpsfiltro, afetará o número de quadros que aparecem no GIF final, mas o ffmpeg parece ainda fazer algo com todos os 15.000 quadros de entrada.

A única maneira que encontrei para fazer com que o ffmpeg pule os quadros de entrada é usando o concatdesmultiplicador.

Veja como agora eu gero miniaturas GIF animadas de alta qualidade em minha máquina de desenvolvimento em menos de 1 segundo, ignorando os 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

informação relacionada