¿Cómo genero rápidamente GIF animados de baja calidad con ffmpeg?

¿Cómo genero rápidamente GIF animados de baja calidad con ffmpeg?

Generamos muchos GIF en miniatura cuya calidad no importa tanto como el tiempo que lleva generarlos. La generación de GIF de alta calidad con ffmpeg está muy bien tratada, pero no tengo mucha suerte para descubrir cómo generar archivos de baja calidad lo más rápido posible.

El cálculo de la paleta ocupa la mayor parte del tiempo de ejecución con el siguiente comando (tomado de la respuesta del gráfico de filtro de cadenas múltiples aquí:Cómo crear eficientemente un gif con la mejor paleta a partir de una porción de video directamente desde la 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

El tiempo de ejecución de ese comando con 1000 fotogramas es de unos 72 segundos. Aproximadamente 67 segundos de eso son el pase de paleta, y luego pasa por la generación real del GIF en aproximadamente 5 segundos. Me gustaría reducir al máximo el tiempo de ejecución y estoy dispuesto a sacrificar mucha calidad de imagen por velocidad.

Respuesta1

El uso de los filtros palettegen/ paletteusehace que el comando se ejecute más lento. La forma sencilla de lograr un GIF de menor calidad sería:

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

Con escala adicional:

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

También puede eliminar fotogramas en el GIF de salida, es decir, tomar muestras de los fotogramas, para que no se procesen todos. Por ejemplo, para tener solo salida de 1 FPS, usando un fpsfiltro:

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

Respuesta2

Me encargaron reducir la cantidad de tiempo que llevaba generar un GIF animado lo más cerca posible de 30 fotogramas de largo y 150 píxeles de ancho. La mayoría de las secuencias que generamos tienen menos de 1000 fotogramas. Teníamos una secuencia de 15.000 cuadros y nuestros nodos de renderizado estaban tomando17 minutospara producir este GIF de ~30 fotogramas, que es inaceptablemente lento.

Estábamos usando ffmpeg como demuxer y canalizando a imagemagick. Después de varias horas de experimentación, llegué a las siguientes conclusiones:

  • El número de fotogramas de entrada que le pide a ffmpeg que procese esCON MUCHOla entrada más impactante en términos de velocidad de ejecución. Si usar el demuxer concat para omitir cuadros de entrada es una opción, esto marcará la mayor diferencia en el rendimiento. Al tomar cada quinto fotograma, pude reducir el tiempo total de cálculo a1 minuto 45 segundoscon reescalado de lanczos de alta calidad y cálculo de paleta por cuadro.Generar nuestra miniatura de vista previa de 30 cuadros ahora toma menos de 1 segundo.

  • El algoritmo de reescalado fue el siguiente factor de mayor impacto en el rendimiento (pero en un lejano segundo lugar). El uso de fast_bilinear en lugar de lanczos ahorró 150 segundos de tiempo de cálculo en los 15.000 fotogramas.

  • La variable de menor impacto fue el cálculo de la paleta, y esto varió con el algoritmo de reescalado. Más de 15.000 cuadros usando lanczos, ahorramos alrededor de 17 segundos de tiempo de ejecución si eliminamos el cálculo de la paleta. Usando fast_bilinear, ahorramos alrededor de 75 segundos de tiempo de ejecución.

Debido a que el algoritmo de cambio de escala y el cálculo de la paleta eran insignificantes, terminamos manteniéndolos en la más alta calidad. Hemos reducido nuestro tiempo de cálculo de 17 minutos a menos de 1 segundo, principalmente diciéndole a ffmpeg que omita la lectura de archivos de entrada.

CONCLUSIÓN CLAVE: SALTAR MARCOS DE ENTRADA versus SALTAR MARCOS DE SALIDA

La razón por la que nuestro proceso tomó tanto tiempo es que la caída de fotogramas no ayuda al tiempo de ejecución cuando se utiliza el demuxer image2. Si juegas con la -rbandera y el fpsfiltro, afectarás la cantidad de fotogramas que aparecen en el GIF final, pero ffmpeg parece seguir haciendo algo con los 15.000 fotogramas de entrada.

La única forma que pude encontrar para que ffmpeg omita los cuadros de entrada es mediante el concatdemuxer.

Así es como ahora genero miniaturas GIF animadas de alta calidad en mi máquina de desarrollo en menos de 1 segundo omitiendo los fotogramas 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

información relacionada