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