¿Cómo convierto un video a GIF usando ffmpeg, con una calidad razonable?

311

Estoy convirtiendo FLVpelícula a GIFarchivo con ffmpeg.

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000  output.gif

Funciona muy bien, pero el archivo gif de salida tiene una calidad muy baja.

¿Alguna idea de cómo puedo mejorar la calidad de los gif convertidos?

Salida de comando:

ffmpeg -i input.flv -ss 00:00:00.000 -pix_fmt rgb24 -r 10 -s 320x240 -t 00:00:10.000  output.gif
ffmpeg version 0.8.5-6:0.8.5-0ubuntu0.12.10.1, Copyright (c) 2000-2012 the Libav developers
  built on Jan 24 2013 14:52:53 with gcc 4.7.2
*** THIS PROGRAM IS DEPRECATED ***
This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.flv':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2013-02-14 04:00:07
  Duration: 00:00:18.85, start: 0.000000, bitrate: 3098 kb/s
    Stream #0.0(und): Video: h264 (High), yuv420p, 1280x720, 2905 kb/s, 25 fps, 25 tbr, 50 tbn, 50 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
    Stream #0.1(und): Audio: aac, 44100 Hz, stereo, s16, 192 kb/s
    Metadata:
      creation_time   : 2013-02-14 04:00:07
[buffer @ 0x92a8ea0] w:1280 h:720 pixfmt:yuv420p
[scale @ 0x9215100] w:1280 h:720 fmt:yuv420p -> w:320 h:240 fmt:rgb24 flags:0x4
Output #0, gif, to 'output.gif':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2013-02-14 04:00:07
    encoder         : Lavf53.21.1
    Stream #0.0(und): Video: rawvideo, rgb24, 320x240, q=2-31, 200 kb/s, 90k tbn, 10 tbc
    Metadata:
      creation_time   : 1970-01-01 00:00:00
Stream mapping:
  Stream #0.0 -> #0.0
Press ctrl-c to stop encoding
frame=  101 fps= 32 q=0.0 Lsize=    8686kB time=10.10 bitrate=7045.0kbits/s dup=0 drop=149    
video:22725kB audio:0kB global headers:0kB muxing overhead -61.778676%

Gracias.

Kamil Hismatullin
fuente
1
Es curioso cómo la gente todavía hace trabajos de paleta con GIF cuando APNG es una cosa.
Константин Ван

Respuestas:

447

ffmpeg ejemplo

Salida GIF de ffmpeg
183k

ffmpegpuede generar GIF de alta calidad. Siempre se recomienda usar una versión reciente: descargar o compilar .

ffmpeg -ss 30 -t 3 -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif
  • Este ejemplo omitirá los primeros 30 segundos ( -ss 30) de la entrada y creará una salida de 3 segundos ( -t 3).
  • El filtro fps establece la velocidad de fotogramas.
  • El filtro de escala cambiará el tamaño de la salida a 320 píxeles de ancho y determinará automáticamente la altura mientras conserva la relación de aspecto.
  • Los filtros palettegen y paletteuse generarán y usarán una paleta personalizada generada a partir de su entrada.
  • El filtro dividido permitirá que todo se haga en un solo comando.
  • Control de bucle con -loopopción de salida. Un valor de 0es bucle infinito.

Ver GIF de alta calidad con FFmpeg para muchos más ejemplos y opciones.


convertEjemplo de Imagemagick

Salida GIF de ffmpeg
227k

Otro método de línea de comandos es a la tubería de ffmpega convert(o magick) de ImageMagick.

 ffmpeg -i input.mp4 -vf "fps=10,scale=320:-1:flags=lanczos" -c:v pam -f image2pipe - | convert -delay 10 - -loop 0 -layers optimize output.gif

Establecer velocidad de fotogramas

Establezca la velocidad de fotogramas con una combinación del fpsfiltro hacia adentro ffmpegy hacia -delayadentro convert. Esto puede complicarse porque convertsolo obtiene una secuencia cruda de imágenes para que no se conserven fps. En segundo lugar, el -delayvalor en convertestá en ticks (hay 100 ticks por segundo), no en cuadros por segundo. Por ejemplo, con fps=12.5= 100 / 12.5 = 8 = -delay 8.

convertredondea el -delayvalor a un número entero, por lo que 8.4 da como resultado 8 y 8.5 da como resultado 9. Esto efectivamente significa que solo se admiten algunas velocidades de cuadros cuando se establece un retraso uniforme en todos los cuadros (se puede establecer un retraso específico por cuadro, pero eso está más allá esta respuesta)

-delayparece ignorarse si se usa como una opción de salida, por lo que debe usarse antes -como se muestra en el ejemplo.

Por último, los navegadores y los visores de imágenes pueden implementar un retraso mínimo, por lo que -delaypuede ser ignorado de todos modos.

Video cortesía del Centro Nacional de Capacitación para la Conservación del Servicio de Pesca y Vida Silvestre de EE. UU.

lema
fuente
44
Se agregaron algunos resultados de ejemplo (aunque solo marcos). Aquí, el primer archivo es de 4.1 MB, el segundo alrededor de 8 MB.
slhck
2
@ LordNeckbeard, eres increíble! muchas gracias por-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin
66
Por cierto, para el convertcomando para convertir de los marcos PNG que terminé usando convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", lo que reduce bastante el tamaño general del archivo
Wilf
2
Bien, lo tengo, lo usé scale=0:-1, así que cuando configuras la escala 0, tomará la escala del video.
Mousa Alfhaily
2
Estas preguntas y respuestas deben estar codificadas de forma permanente en un tomo (o tal vez simplemente "anclado" por ahora) porque dentro de cien años toda la comunicación se realizará a través de memes. Creo que la actividad en esta publicación solo habla de eso.
Jonathan Neufeld
87

Si prefiere evitar archivos de imagen intermedios, los comandos proporcionados por LordNeckBeard se pueden canalizar entre los de ffmpegImageMagick convertpara que no se requieran archivos intermedios:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - output.gif

El -f image2pipele dice a ffmpeg que divida el video en imágenes y lo haga adecuado para ser canalizado, y -vcodec ppmespecifica que el formato de salida sea ppm (por alguna razón si el formato es png, o convertno lee todas las imágenes de la tubería, o ffmpeg sí lo hace) no sacarlos todos). El -para ambos comandos especifica que se utilizará una tubería para la salida y la entrada, respectivamente.

Para optimizar el resultado sin guardar un archivo, puede canalizar la salida desde convertun segundo convertcomando:

ffmpeg -i input.flv -vf scale=320:-1 -r 10 -f image2pipe -vcodec ppm - | convert -delay 5 -loop 0 - gif:- | convert -layers Optimize - output.gif

El gif:-le dice convertque canalice su salida como datos con formato gif y -layers Optimizele dice al segundo convertque realice optimize-framey los optimize-transparancymétodos (vea la Introducción de ImageMagick a la optimización de la animación ). Tenga en cuenta que es posible que la salida del -layers Optimizearchivo no siempre proporcione un tamaño de archivo más pequeño, por lo que puede intentar convertir a un gif sin optimización primero para asegurarse.

Recuerde que durante todo este proceso todo está en la memoria, por lo que puede necesitar suficiente memoria si las imágenes son bastante grandes.

notable
fuente
1
Este conjunto de comandos también funciona conavconv
raphael
Debe fusionar los dos últimos comandos de conversión:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément
¿El gif parece estar funcionando a 2 veces la velocidad del video fuente?
Titán
@Titan cree que es el -r 10 en el primer comando y el -delay 5 en el segundo. Cambié el retraso a 10 también y parece que ahora juega normalmente.
Steven Huang el
2
También puede evitar archivos de imagen intermedios utilizando el splitfiltro en ffmpeg. No hay necesidad de canalizar nada:ffmpeg -ss 30 -t 3 -i "input.flv fps=10,scale=320:-1:flags=lanczos,split[x][z];[z]palettegen[y];[x][y]paletteuse" output.gif
Ajedi32
37

A partir de ffmpeg 2.6, podemos hacerlo aún mejor:

palette="/tmp/palette.png"
filters="fps=15,scale=320:-1:flags=lanczos"

ffmpeg -i input.flv -vf "$filters,palettegen" -y $palette
ffmpeg -i input.flv -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y output.gif

HT

pje
fuente
18

Hice mi propia versión del script, que también parametriza la resolución de salida y la velocidad de fotogramas.

La ejecución ./gifenc.sh input.mov output.gif 720 10generará 720p de ancho 10fps GIF de la película que le diste Es posible que deba hacer chmod +x gifenc.shpor el archivo.

#!/bin/sh

palette="/tmp/palette.png"

filters="fps=$4,scale=$3:-1:flags=lanczos"

ffmpeg -v warning -i "$1" -vf "$filters,palettegen" -y "$palette"
ffmpeg -v warning -i "$1" -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y "$2"

Puedes leer los detalles en mi Github

Suposiciones: ffmpeg está instalado y el script está en la misma carpeta que los otros archivos.

thevangelist
fuente
3
Muchas gracias por tu guión. ¡Lo acabo de probar y funciona muy bien!
orschiro
15

La respuesta de @Stephane es muy buena. Pero recibirá una advertencia como Buffer queue overflow, dropping.para algunos videos, y el generado giftiene algún marco caído.

Aquí hay una mejor versión con fifofiltro para evitar Buffer queue overflowal usar el paletteusefiltro. Mediante el uso de splitfiltro para evitar la creación de un archivo PNG de paleta intermedia.

ffmpeg -i input.mp4 -filter_complex 'fps=10,scale=320:-1:flags=lanczos,split [o1] [o2];[o1] palettegen [p]; [o2] fifo [o3];[o3] [p] paletteuse' out.gif
alijandro
fuente
Si entiendo eso correctamente, está dividiendo la entrada en o1 y o2, y copiando o2 a o3. Entonces, ¿por qué necesitas o3? ¿Por qué no simplemente usar o2 directamente?
Chloe
1
@Chloe ¿Viste la fifooperación de filtro entre o2y o3? Para evitar la Buffer queue overflowadvertencia.
alijandro
+1 Esto funciona muy bien para mí (y resolvió el problema al que se hace referencia).
Iain Collins
Me encanta esta solución. ¡Prestigio!
Leonid Usov
10

hizo un guión, probó y funciona.

uso:

./avi2gif.sh ./vokoscreen-2015-05-28_12-41-56.avi

TENGO PHUN :)

vim avi2gif.sh

#!/bin/sh

INPUT=$1

# default settings, modify if you want.

START_AT_SECOND=0; # in seconds, if you want to skip the first 30 seconds put 30 here

LENGTH_OF_GIF_VIDEO=9999999; # in seconds, how long the gif animation should be

echo "Generate a palette:"
ffmpeg -y -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png

echo "Output the GIF using the palette:"
ffmpeg -ss $START_AT_SECOND -t $LENGTH_OF_GIF_VIDEO -i $INPUT -i palette.png -filter_complex "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" $INPUT.gif

por cierto: vokoscreen es una EXCELENTE herramienta de captura de pantalla para Linux :)

MUCHAS GRACIAS Michael Kohaupt :) Rock constante.

algunas estadísticas de tamaño de archivo:

5.3M = vokoscreen-2015-04-28_15-43-17.avi -> vokoscreen-2015-05-28_12-41-56.avi.gif = 1013K

Vea los resultados aquí.

besuquearse
fuente
10

El métodoffmpeg con paleta se puede ejecutar en un solo comando, sin archivo intermediario ..png

ffmpeg -y -ss 30 -t 3 -i input.flv -filter_complex \
"fps=10,scale=320:-1:flags=lanczos[x];[x]split[x1][x2]; \
[x1]palettegen[p];[x2][p]paletteuse" output.gif

Esto se puede hacer gracias al splitfiltro.

Stephane
fuente
10

Linux / Unix / macOS

Siguiendo el enfoque de @LordNeckbeard con el ffmpegcomando, encuentre la siguiente función Bash útil que se puede agregar a su ~/.bash_profilearchivo:

# Convert video to gif file.
# Usage: video2gif video_file (scale) (fps)
video2gif() {
  ffmpeg -y -i "${1}" -vf fps=${3:-10},scale=${2:-320}:-1:flags=lanczos,palettegen "${1}.png"
  ffmpeg -i "${1}" -i "${1}.png" -filter_complex "fps=${3:-10},scale=${2:-320}:-1:flags=lanczos[x];[x][1:v]paletteuse" "${1}".gif
  rm "${1}.png"
}

Una vez que se carga la función (manualmente o desde . ~/.bash_profile), debe tener un nuevo video2gifcomando.

Ejemplo de uso:

video2gif input.flv

o:

video2gif input.flv 320 10

Escale a 320 de ancho con 10 cuadros por segundo.

También puede especificar un formato de video diferente (como mp4).


Mac OS

Puede probar la aplicación GIF Brewery que puede crear GIF a partir de archivos de video.


Alternativamente, hay varios sitios web que realizan conversiones en línea de forma gratuita.

kenorb
fuente
su script genera un error para mí acerca de que no hay un archivo png y no obtengo salida de gif, pero el archivo de entrada .mp4 permanece sin cambios
lacostenycoder
7

La respuesta seleccionada asume que desea escalar el video fuente y cambiar sus fps en el gif producido. Si no necesita hacer esto, lo siguiente funciona:

src="input.flv"
dest="output.gif"
palette="/tmp/palette.png"

ffmpeg -i $src -vf palettegen -y $palette
ffmpeg -i $src -i $palette -lavfi paletteuse -y $dest

Esto fue útil cuando quería un gif que recreara fielmente el video fuente que estaba usando.

Jet Blue
fuente
6

Para usuarios de Windows:
cree un video2gif.batarchivo en el directorio de Windows con este contenido:

@echo off
set arg1=%1
set arg2=%arg1:~0,-4%
ffmpeg -y -i %arg1% -vf fps=10,scale=-1:-1:flags=lanczos,palettegen %TEMP%\palette.png
ffmpeg -i %arg1% -i %TEMP%\palette.png -filter_complex "fps=10,scale=-1:-1:flags=lanczos[x];[x][1:v]paletteuse" %arg2%.gif
del /f %TEMP%\palette.png

Y luego, en cualquier lugar donde pueda usarlo, sea como este ejemplo:

video2gif myvideo.mp4

Entonces tienes myvideo.gifen el directorio actual.
Si myvideo.gifexiste, pregunta de usted para sobrescribirlo.

EDITAR:

Sugiero usar este script por lotes: https://github.com/NabiKAZ/video2gif

Nabi KAZ
fuente
2
Veo que ha hecho dos cosas aquí: (1) escribió los comandos como un script de comandos de Windows (.BAT) y (2) proporcionó una combinación diferente de filtros (ninguna de las otras respuestas usa ambos fps=10 y scale=-1:-1).  La respuesta de Sun ya nos dio un archivo por lotes, y ese (como los scripts de shell en la respuesta de pje y la respuesta de vangelist ) tiene la ventaja de que asigna la lista de filtros a una variable ( una vez ), ... (Continúa)
Scott
1
(Cont.) ... por lo que no es necesario deletrear la lista dos veces (como lo hace su archivo por lotes). (Supongo que esto crea un riesgo de que, si el usuario edita el script para cambiar una de las listas pero no la otra, la inconsistencia causará un problema). ¿Puede al menos explicar su elección de filtros ( fps=10,scale=-1:-1)? (Consulte la respuesta de notable para ver un ejemplo de una explicación de las partes de un comando.)
Scott,
1
@Scott Dijiste correcto, así que escribo un nuevo script útil aquí: github.com/NabiKAZ/video2gif
Nabi KAZ
4

A continuación se muestra el archivo por lotes para usuarios de Windows:

gifenc.bat:

set start_time=0
set duration=60
set palette="c:\temp\palette.png"
set filters="fps=15,scale=-1:-1:flags=lanczos"
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette%
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %2

Fuente: GIF de alta calidad con FFmpeg: extracción de solo una muestra

Si solo desea usar una variable de entrada y el nombre de salida tiene solo la extensión GIF (pronunciado JIF), use esto en su lugar:

set start_time=0
set duration=60
set palette="c:\temp\palette.png"
set filters="fps=15,scale=-1:-1:flags=lanczos"
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -vf "%filters%,palettegen" -y %palette%
set var1=%1
set var2=%var1:~0,-4%
ffmpeg -v warning -ss %start_time% -t %duration% -i %1 -i %palette% -lavfi "%filters% [x]; [x][1:v] paletteuse" -y %var2%.gif
Dom
fuente
3

Cómo agregar una entrada de menú contextual "clic derecho" de Windows 7/10 para convertir su archivo de video a gif

Algunas de las otras respuestas mencionaron el script video2gif , que utilicé. Pero, podrías usar cualquier script.

Para crear la opción del menú contextual, debe editar su registro. Abra un símbolo del sistema de PowerShell, ejecutando w / admin privs. Ejecute estos comandos:

$key = "Registry::HKEY_CLASSES_ROOT\`*\shell\Run Video2Gif"
New-Item -Path $key"\Command" -Value "C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat `"%1`"" -Force

¡Ahora, cuando hace clic derecho en un archivo, tendrá la opción "Ejecutar Video2Gif"!

Por cierto, instalé ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\y puse el video2gif.batscript en el directorio bin justo al lado ffmpeg.exe. También agregué C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bina mis ventanas PATH, pero no creo que sea necesario.

Si desea la opción de poder proporcionar algunos indicadores / argumentos adicionales de la línea de comandos al script, video2gif-prompt.batcree un nuevo archivo llamado y haga que el registro lo consulte en lugar de video2gif.bat:

@echo off
set /p inp=Enter extrta args, if desired:
C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bin\video2gif.bat %* %inp%

Todavía puede presionar enter para obtener rápidamente los valores predeterminados.

Chris
fuente