Como converter um vídeo em GIF usando ffmpeg, com qualidade razoável?


311

Estou convertendo FLVfilme para GIFarquivo 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 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.


1
É engraçado como as pessoas ainda fazem paletas com GIF quando o APNG é uma coisa.
Константин Ван 23/01

Respostas:


447

ffmpeg exemplo

Saída GIF de ffmpeg
183k

ffmpegpode gerar GIF de alta qualidade. É sempre recomendável usar uma versão recente: baixar ou 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 exemplo pulará os primeiros 30 segundos ( -ss 30) da entrada e criará uma saída de 3 segundos ( -t 3).
  • O filtro fps define a taxa de quadros.
  • O filtro de escala redimensionará a saída para 320 pixels de largura e determinará automaticamente a altura, preservando a proporção.
  • Os filtros palettegen e paletteuse irão gerar e usar uma paleta personalizada gerada a partir de sua entrada.
  • O filtro de divisão permitirá que tudo seja feito em um comando.
  • Controle de loop com -loopopção de saída. Um valor de 0é um loop infinito.

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


convertExemplo Imagemagick

Saída GIF de ffmpeg
227k

Outro método de linha de comando é canalizar de ffmpegpara convert(ou magick) no 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

Definir taxa de quadros

Defina a taxa de quadros com uma combinação do fpsfiltro para dentro ffmpege para -delaydentro convert. Isso pode ser complicado porque convertapenas obtém um fluxo bruto de imagens para que nenhum fps seja preservado. Em segundo lugar, o -delayvalor em convertestá em ticks (existem 100 ticks por segundo), não em quadros por segundo. Por exemplo, com fps=12.5= 100 / 12,5 = 8 = -delay 8.

convertarredonda o -delayvalor para um número inteiro, de modo que 8.4 resulta em 8 e 8.5 em 9. Isso efetivamente significa que apenas algumas taxas de quadros são suportadas ao definir um atraso uniforme em todos os quadros (um atraso específico pode ser definido por quadro, mas isso está além esta resposta).

-delayparece ser ignorado se usado como uma opção de saída, portanto, ele deve ser usado antes, -como mostrado no exemplo.

Por fim, navegadores e visualizadores de imagens podem implementar um atraso mínimo; portanto, você -delaypode ser ignorado.

Vídeo cortesia do Centro Nacional de Treinamento em Conservação do Serviço de Pesca e Vida Selvagem dos EUA.


4
Adicionado alguns resultados de exemplo (embora ainda quadros). Aqui, o primeiro arquivo tem 4,1 MB, o segundo, 8 MB.
slhck

2
@LordNeckbeard, você é demais! muito obrigado por-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin

6
By the way, para o convertcomando para converter a partir dos quadros de PNG acabei usando convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", o que reduz o tamanho total do arquivo um pouco
Wilf

2
Ok, já usei scale=0:-1, então quando você define a escala 0, ela pega a escala do vídeo.
Mousa Alfhaily

2
Essas perguntas e respostas devem ser permanentemente codificadas em um tomo (ou talvez apenas "afixadas" por enquanto), porque daqui a cem anos toda a comunicação será feita por meio de memes. Eu acho que a atividade apenas neste post fala sobre isso.
Jonathan Neufeld

87

Se você preferir evitar arquivos de imagem intermediários, os comandos fornecidos pelo LordNeckBeard podem ser canalizados entre os ffmpegImageMagick e os de convertmodo 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 image2pipecomando diz ao ffmpeg para dividir o vídeo em imagens e o torna adequado para ser canalizado e -vcodec ppmespecifica o formato de saída como ppm (por algum motivo, se o formato for png, convertele não lê todas as imagens do pipe ou o ffmpeg faz todos eles). O -comando para ambos especifica que um tubo será usado para saída e entrada, respectivamente.

Para otimizar o resultado sem salvar um arquivo, você pode canalizar a saída convertpara um 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

O gif:-instrui converta canalizar sua saída como dados formatados em gif e -layers Optimizeo segundo converta executar optimize-framee optimize-transparancymétodos (consulte a Introdução ao ImageMagick à Otimização da animação ). Observe que a saída do -layers Optimizearquivo nem sempre fornece um tamanho de arquivo menor; portanto, convém tentar converter para um gif sem otimização primeiro.

Lembre-se de que durante todo esse processo tudo está na memória; portanto, você pode precisar de memória suficiente se as imagens forem muito grandes.


1
Este conjunto de comandos também funciona comavconv
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 duas vezes a velocidade do vídeo de origem?
Titan

O @Titan acredita que é o -r 10 no primeiro comando e o -day 5 no segundo. Mudei o atraso para 10 também e parece jogar normalmente agora.
Steven Huang

2
Você também pode evitar arquivos de imagem intermediários usando o splitfiltro em ffmpeg. Não é necessário 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 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


18

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

A execução ./gifenc.sh input.mov output.gif 720 10produzirá um GIF de 10fps a 720p de largura do filme que você deu. Talvez você precise fazer chmod +x gifenc.sho 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

Pressupostos: o ffmpeg está instalado e o script está na mesma pasta que os outros arquivos.


3
Muito obrigado pelo seu script. Acabei de testar e funciona muito bem!
Orschiro

15

A resposta de @Stephane é muito boa. Mas ele receberá um aviso, como Buffer queue overflow, dropping.em alguns vídeos, e o gerado giftem algum quadro descartado.

Aqui está uma versão melhor com fifofiltro para evitar Buffer queue overflowao usar o paletteusefiltro. Usando o splitfiltro 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

Se bem entendi, você está dividindo a entrada em o1 e o2 e copiando o2 para o3. Então, por que você precisa da o3? Por que não usar apenas o2 diretamente?
Chloe

1
@Chloe Você viu a fifooperação de filtro entre o2e o3? Para evitar o Buffer queue overflowaviso.
Alijandro 23/10

+1 Isso funciona muito bem para mim (e resolveu o problema mencionado).
Iain Collins

Eu absolutamente amo essa solução. Parabéns!
Leonid Usov 27/07

10

fez um script, testado e funciona.

uso:

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

TEM 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 ScreenCapturing 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 os resultados aqui.


10

O métodoffmpeg with palette pode ser executado em um único comando, sem arquivo intermediário ..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

Isso pode ser feito graças ao splitfiltro.


10

Linux / Unix / macOS

Seguindo a abordagem @LordNeckbeard com o ffmpegcomando, encontre a seguinte função Bash útil que pode ser adicionada ao seu ~/.bash_profilearquivo:

# 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 a função é carregada (manualmente ou de . ~/.bash_profile), você deve ter um novo video2gifcomando.

Exemplo de uso:

video2gif input.flv

ou:

video2gif input.flv 320 10

Escale para 320 de largura com 10 quadros por segundo.

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


Mac OS

Você pode experimentar o aplicativo GIF Brewery, que pode criar GIFs a partir de arquivos de vídeo.


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


seu script gera um erro para mim sobre nenhum arquivo png e não recebo saída gif, mas o arquivo de entrada .mp4 permanece inalterado
lacostenycoder 8/03

7

A resposta selecionada pressupõe que você deseja dimensionar o vídeo de origem e alterar seus fps no gif produzido. Se você não precisar fazer isso, o seguinte 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

Isso foi útil quando eu queria um gif que recriasse fielmente o vídeo fonte que eu estava usando.


6

Para usuários do Windows:
crie um video2gif.batarquivo no diretório windows com este conteúdo:

@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

E então, em qualquer lugar que você possa usá-lo, fique como este exemplo:

video2gif myvideo.mp4

Então você tem myvideo.gifno diretório atual.
Se myvideo.gifhouver, faça uma pergunta sua para substituí-la.

EDITAR:

Sugiro usar este script em lote: https://github.com/NabiKAZ/video2gif


2
Vejo que você fez duas coisas aqui: (1) escreveu os comandos como um script de comando do Windows (.BAT) e (2) forneceu uma combinação diferente de filtros (nenhuma das outras respostas usa ambos fps=10 e scale=-1:-1).  A resposta da Sun já nos forneceu um arquivo em lotes, e aquele (como os scripts de shell na resposta do pje e na resposta doangelist ) tem a vantagem de atribuir a lista de filtros a uma variável ( uma vez ),… (continua)
Scott

1
(Continua) ... portanto, não é necessário digitar a lista duas vezes (como o seu arquivo em lotes). (Presumo que isso crie um risco de que, se o usuário editar o script para alterar uma das listas, mas não a outra, a inconsistência causará um problema.) Você pode pelo menos explicar sua escolha de filtros ( fps=10,scale=-1:-1)? (Veja a resposta do notável para obter um exemplo de explicação de partes de um comando.) #
Scott Scott

1
@ Scott Você disse correta, então eu escrever um novo script útil aqui: github.com/NabiKAZ/video2gif
Nabi KAZ

4

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ê deseja apenas usar uma variável de entrada e o nome da saída possuir apenas a extensão GIF (pronuncia-se JIF), use-a em seu 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

3

Como adicionar uma entrada do menu de contexto do Windows 7/10 "clique com o botão direito do mouse" para converter seu arquivo de vídeo em gif

Algumas das outras respostas mencionaram o script video2gif , que eu usei. Mas você pode usar qualquer script.

Para criar a opção do menu de contexto, você precisa editar seu registro. Abra um prompt de comando do PowerShell, executando w / admin privs. Execute estes 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

Agora, quando você clicar com o botão direito do mouse em um arquivo, terá a opção "Executar Video2Gif"!

btw eu instalei o ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\e coloquei o video2gif.batscript no diretório bin ao lado de ffmpeg.exe. Eu também adicionei C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\binàs minhas janelas PATH, mas acho que você não precisa.

Se você deseja a opção de fornecer alguns sinalizadores / argumentos de linha de comando extras para o script, crie um novo arquivo chamado video2gif-prompt.bate faça com que o registro faça referência a ele em vez 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%

Você ainda pode pressionar Enter para obter rapidamente os padrões.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.