Questão Como faço para converter um vídeo para GIF usando ffmpeg, com qualidade razoável?


Estou convertendo .flv filme para .gif arquivo com ffmpeg.

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

Ele funciona muito bem, mas o arquivo gif de saída tem uma qualidade muito baixa.

Alguma idéia de como eu posso melhorar a qualidade do gif convertido?

Saída do 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%

Obrigado.


247


origem




Respostas:


ffmpeg agora pode gerar GIF de maior qualidade. Se você estiver usando uma versão mais antiga, considere baixando uma construção estática recente ou compilação ffmpeg.

ffmpeg exemplo

gif with ffmpeg
203k

Este exemplo irá ignorar os primeiros 30 segundos da entrada e criar uma saída de 3 segundos. Ele dimensionará a saída para 320 pixels de largura e determinará automaticamente a altura, preservando a proporção. o palettegen e paletteuse filtros irá gerar e usar uma paleta personalizada gerada a partir de sua fonte.

  1. Gere uma paleta:

    ffmpeg -y -ss 30 -t 3 -i input.flv \
    -vf fps=10,scale=320:-1:flags=lanczos,palettegen palette.png
    
  2. Saída do GIF usando a paleta:

    ffmpeg -ss 30 -t 3 -i input.flv -i palette.png -filter_complex \
    "fps=10,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
    

Vejo GIF de alta qualidade com FFmpeg para muitos mais exemplos e opções.


convert exemplo

Outro método de linha de comando seria exportar o filme para quadros usando ffmpeg então faça o GIF com convert do ImageMagick (ou GraphicsMagick).

ffmpeg and convert
24k

  1. Quadros de exportação:

     mkdir frames
     ffmpeg -i input -vf scale=320:-1:flags=lanczos,fps=10 frames/ffout%03d.png
    
  2. Então use convert (ou gm convert se você preferir GraphicsMagick) para fazer seu GIF animado:

     convert -loop 0 frames/ffout*.png output.gif
    

Com convert você pode controlar o atraso entre quadros com -delay se desejado.


374



Adicionado alguns resultados de exemplo (apenas ainda quadros). Aqui, o primeiro arquivo é de 4,1 MB, o segundo, de 8 MB. - slhck
@ LordNeckbeard, você é demais! muito obrigado por -vf scale=320:-1,format=rgb8,format=rgb24 - Kamil Hismatullin
By the way, para o convert comando para converter a partir dos quadros PNG acabei usando convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", o que reduz um pouco o tamanho geral do arquivo - Wilf
Eu acho que o convert comando deve estar usando -delay 10 (0,1 segundo entre quadros) para corresponder ao -r 10 (10 fps) taxa de quadros que você está alimentando para ffmpeg. Quando eu uso -delay 5, Vejo o gif jogar em velocidade dupla. - Jack O'Connor
Ok, eu entendi, eu usei scale=0:-1, quando você define a escala para 0, levará a escala do vídeo. - Mousa Alfhaily


Se você preferir evitar arquivos de imagem intermediários, os comandos fornecidos pelo LordNeckBeard podem ser canalizados entre ffmpeg e ImageMagick's convert para que nenhum arquivo intermediário seja necessário:

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

o -f image2pipe diz ao ffmpeg para dividir o vídeo em imagens e torná-lo adequado para ser canalizado, e -vcodec ppm especifica o formato de saída para ser ppm (por algum motivo, se o formato for png, convert não lê todas as imagens do pipe, ou o ffmpeg não produz todas elas. o - para ambos os comandos especifica que um pipe será usado para saída e entrada, respectivamente.

Para otimizar o resultado sem salvar um arquivo, você pode canalizar a saída convert para um segundo convert comando:

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

o gif:- conta convert para canalizar sua saída como dados formatados gif e -layers Optimize conta o segundo convert atuar optimize-frame e optimize-transparancy métodos (veja o ImageMagick Introdução à otimização de animação). Observe que a saída do -layers Optimize nem sempre pode fornecer um tamanho de arquivo menor, portanto, convém tentar converter um gif sem otimização primeiro, para ter certeza.

Lembre-se que durante todo este processo tudo está na memória, então você pode precisar de memória suficiente se as imagens forem muito grandes.


79



Este conjunto de comandos também funciona com avconv - raphael
Você deve mesclar os dois últimos comandos de conversão: convert -delay 5 -loop 0 -layers Optimize - output.gif - Clément
O gif parece estar rodando a 2x a velocidade do vídeo de origem? - Titan
@Titan acredita que é o -r 10 no primeiro comando e o -delay 5 no segundo. Eu mudei o atraso para 10 também e parece jogar normalmente agora. - Steven Huang
Você também pode evitar arquivos de imagem intermediários usando o split filtrar no ffmpeg. Não há necessidade 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


A partir do ffmpeg 2.6, podemos fazer ainda melhor:

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 


29





Fiz minha própria versão do script, que também parametriza a resolução de saída e a taxa de quadros.

Corrida ./gifenc.sh input.mov output.gif 720 10 irá gerar 720p de largura 10fps GIF do filme que você deu. Você pode precisar fazer chmod +x gifenc.sh para o arquivo.

#!/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"

Você pode ler os detalhes no meu Github

Suposições: ffmpeg está instalado, e o script está na mesma pasta que os outros arquivos.


13



Muito obrigado pelo seu roteiro. Eu apenas testei e funciona muito bem! - orschiro


fez um script, testou e funciona.

uso:

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

TENHA 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

btw: vokoscreen é uma excelente ferramenta de captura de tela para Linux :)

Muito obrigado Michael Kohaupt :) Rock constante.

algumas estatísticas de tamanho de arquivo:

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

Veja o resulta aqui.


7





A resposta do @Stephane é muito boa. Mas vai receber um aviso como Buffer queue overflow, dropping. para alguns vídeos, e os gerados gif tem algum quadro derrubado.

Aqui está uma versão melhor com fifo filtrar para evitar Buffer queue overflow quando usando paletteuse filtro. Usando split filtrar para evitar a criação do arquivo PNG da paleta intermediária.

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

7





Linux / Unix / macOS

Segue Abordagem @ LordNeckbeard com ffmpeg comando, por favor, encontrar a seguinte função Bash útil que pode ser adicionado em seu ~/bash_profile Arquivo:

# 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"
}

Depois que o arquivo é carregado (. ~/.bash_profile), você deve ter novos video2gif comando.

Exemplo de uso:

video2gif input.flv

ou:

video2gif input.flv 320 10

Escala para 320 de largura com 10 quadros por segundo.

Você também pode especificar um formato de vídeo diferente (como mp4).


Mac OS

Podes tentar Cervejaria GIF aplicativo que pode criar GIFs de arquivos de vídeo.


Alternativamente, existem vários sites que estão fazendo a conversão online gratuitamente.


6



Tangencial / offtopic: Para qualquer um que esteja se perguntando por que o Community editou isso, foi para HTTPSify o link na primeira linha da resposta. (A transição HTTPS do Stack Overflow está bem encaminhada!) - i336_


o ffmpeg com paleta método pode ser executado em um único comando, sem intermediário .png Arquivo.

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

Isso pode ser feito graças ao split filtro.


6





Abaixo está o arquivo em lotes para usuários do 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

Fonte: GIF de alta qualidade com FFmpeg: Extraindo apenas uma amostra

Se você quiser apenas usar uma variável de entrada e o nome da saída tiver apenas a extensão GIF (pronunciado JIF), use isso:

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

3