Come posso convertire un video in GIF usando ffmpeg, con una qualità ragionevole?


311

Sto convertendo il FLVfilmato in GIFfile 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

Funziona benissimo, ma il file gif di output ha una qualità molto bassa.

Qualche idea su come posso migliorare la qualità delle gif convertite?

Uscita del 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%

Grazie.


1
È divertente come le persone facciano ancora le palette con GIF quando APNG è una cosa.
Константин Ван

Risposte:


447

ffmpeg esempio

Uscita GIF da ffmpeg
183k

ffmpegpuò produrre GIF di alta qualità. Si consiglia sempre di utilizzare una versione recente: download o compilazione .

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
  • Questo esempio salterà i primi 30 secondi ( -ss 30) dell'ingresso e creerà un'uscita di 3 secondi ( -t 3).
  • filtro fps imposta la frequenza dei fotogrammi.
  • il filtro scala ridimensionerà l'output a 320 pixel di larghezza e determinerà automaticamente l'altezza preservando le proporzioni.
  • I filtri palettegen e paletteuse genereranno e utilizzeranno una tavolozza personalizzata generata dal tuo input.
  • il filtro diviso consentirà di eseguire tutto in un solo comando.
  • Ciclo di controllo con -loopopzione di output. Un valore di 0è loop infinito.

Vedi GIF di alta qualità con FFmpeg per molti altri esempi e opzioni.


convertEsempio di Imagemagick

Uscita GIF da ffmpeg
227k

Un altro metodo da riga di comando è reindirizzare da ffmpega convert(o magick) da 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

Impostazione della frequenza dei fotogrammi

Imposta la frequenza dei fotogrammi con una combinazione del fpsfiltro in ffmpege -delayin convert. Questo può complicarsi perché convertottiene solo un flusso di immagini non elaborato, quindi non viene conservato alcun fps. In secondo luogo, il -delayvalore in convertè in tick (ci sono 100 tick al secondo), non in frame al secondo. Ad esempio, con fps=12.5= 100 / 12.5 = 8 = -delay 8.

convertarrotonda il -delayvalore a un numero intero, quindi 8.4 risulta in 8 e 8.5 risulta in 9. Ciò significa che sono supportati solo alcuni frame rate quando si imposta un ritardo uniforme su tutti i frame (è possibile impostare un ritardo specifico per frame ma che è oltre questa risposta).

-delaysembra essere ignorato se usato come opzione di output, quindi deve essere usato prima -come mostrato nell'esempio.

Infine, i browser e i visualizzatori di immagini possono implementare un ritardo minimo, quindi -delaypotresti essere ignorato comunque.

Video per gentile concessione del National Fish and Wildlife Service National Conservation Training Center degli Stati Uniti.


4
Aggiunti alcuni risultati di esempio (solo fotogrammi comunque). Qui, il primo file è 4,1 MB, il secondo circa 8 MB.
slhck,

2
@LordNeckbeard, sei fantastico! molte grazie per-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin,

6
A proposito, per il convertcomando per la conversione dai frame PNG ho finito per usare convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", il che riduce un po 'la dimensione complessiva del file
Wilf

2
Okay, ce l'ho, l'ho usato scale=0:-1, quindi quando imposti la scala su 0, prenderà la scala dal video.
Mousa Alfhaily,

2
Queste domande e risposte devono essere codificate in modo permanente in un tomo (o forse solo "appuntate" per ora) perché tra cento anni da ora in poi tutte le comunicazioni saranno effettuate tramite meme. Penso che l'attività su questo post da solo ne parli.
Jonathan Neufeld,

87

Se si preferisce evitare file di immagine intermedi, i comandi forniti da LordNeckBeard possono essere inviati tra ffmpege ImageMagick in convertmodo che non siano necessari file intermedi:

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

La -f image2pipedice ffmpeg per dividere il video in immagini e renderlo adatto ad essere convogliato fuori, e -vcodec ppmspecifica il formato di uscita per essere ppm (per qualche motivo, se il formato è png, o convertnon legge tutte le immagini dal tubo, o ffmpeg fa non tutte le uscite). Il -comando for for specifica che una pipe verrà utilizzata rispettivamente per output e input.

Per ottimizzare il risultato senza salvare un file, è possibile reindirizzare l'output converta un secondo 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

La gif:-dice convertalla tubazione la sua uscita come dati gif formattato e -layers Optimizedice il secondo convertper eseguire optimize-framee optimize-transparancymetodi (vedi ImageMagick Introduzione al Animazione Optimization ). Si noti che l'output da -layers Optimizepotrebbe non fornire sempre una dimensione di file inferiore, quindi si consiglia di provare prima a convertire in gif senza ottimizzazione.

Ricorda che durante l'intero processo tutto è in memoria, quindi potresti aver bisogno di memoria sufficiente se le immagini sono abbastanza grandi.


1
Questo set di comandi funziona anche conavconv
raphael

Dovresti unire gli ultimi due comandi di conversione:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément

La gif sembra funzionare a una velocità doppia rispetto al video sorgente?
Titano,

@Titan crede che sia -r 10 nel primo comando e -delay 5 nel secondo. Ho cambiato anche il ritardo a 10 e sembra che suoni normalmente ora.
Steven Huang

2
Puoi anche evitare file di immagine intermedi usando il splitfiltro in ffmpeg. Non è necessario 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
convogliare

37

A partire da ffmpeg 2.6, possiamo fare ancora meglio:

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

Ho realizzato la mia versione dello script, che parametrizza anche la risoluzione di output e la frequenza dei fotogrammi.

L'esecuzione ./gifenc.sh input.mov output.gif 720 10produrrà GIF a 10 fps con larghezza di 720p dal filmato. Potrebbe essere necessario fare chmod +x gifenc.shper il file.

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

Puoi leggere i dettagli sul mio Github

Presupposti: ffmpeg è installato e lo script si trova nella stessa cartella degli altri file.


3
Grazie mille per la tua sceneggiatura. L'ho appena testato e funziona benissimo!
Orschiro,

15

La risposta di @Stephane è molto buona. Ma riceverà un avviso come Buffer queue overflow, dropping.per alcuni video, e il generato gifha qualche frame abbandonato.

Ecco una versione migliore con fifofiltro da evitare Buffer queue overflowquando si utilizza il paletteusefiltro. Utilizzando il splitfiltro per evitare la creazione di file PNG di palette intermedi.

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 lo capisco correttamente, stai dividendo l'input in o1 e o2 e copiando o2 in o3. Quindi perché hai bisogno di o3? Perché non usare direttamente o2?
Chloe,

1
@Chloe Hai visto l' fifooperazione di filtro tra o2e o3? Per evitare l' Buffer queue overflowavvertimento.
alijandro,

+1 Questo funziona davvero bene per me (e risolto il problema a cui si fa riferimento).
Iain Collins,

Adoro questa soluzione. Complimenti!
Leonid Usov,

10

realizzato una sceneggiatura, testato e funzionante.

utilizzo:

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

HUN 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 è uno strumento ECCELLENTE di ScreenCapturing per Linux :)

GRAZIE MOLTO Michael Kohaupt :) Rock costante.

alcune statistiche sulla dimensione del file:

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

vedi i risultati qui.


10

Il metodoffmpeg con palette può essere eseguito in un singolo comando, senza file intermedio ..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

Questo può essere fatto grazie al splitfiltro.


10

Linux / Unix / MacOS

Seguendo l'approccio @LordNeckbeard con il ffmpegcomando, trova la seguente utile funzione Bash che può essere aggiunta al tuo ~/.bash_profilefile:

# 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 volta caricata la funzione (manualmente o da . ~/.bash_profile), dovresti avere un nuovo video2gifcomando.

Esempio di utilizzo:

video2gif input.flv

o:

video2gif input.flv 320 10

Scala a 320 larghezza con 10 fotogrammi al secondo.

Puoi anche specificare un formato video diverso (come mp4).


Mac OS

Puoi provare l' app GIF Brewery che può creare GIF da file video.


In alternativa, ci sono diversi siti Web che eseguono la conversione online gratuitamente.


il tuo script genera un errore per me per nessun file png e non ottengo alcun output gif, ma il file di input .mp4 rimane invariato
lacostenycoder

7

La risposta selezionata presuppone che desideri ridimensionare il video sorgente e cambiare i suoi fps nella gif prodotta. Se non è necessario, le seguenti operazioni:

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

Questo mi è tornato utile quando volevo una gif che ricreava fedelmente il video sorgente che stavo usando.


6

Per utenti Windows:
creare un video2gif.batfile nella directory di Windows con questi contenuti:

@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 quindi ovunque tu possa usarlo, come in questo esempio:

video2gif myvideo.mp4

Quindi hai myvideo.gifnella directory corrente.
Se myvideo.gifesiste, fai una domanda da te per sovrascriverlo.

MODIFICARE:

Suggerisco di usare questo script batch: https://github.com/NabiKAZ/video2gif


2
Vedo che hai fatto due cose qui: (1) ha scritto i comandi come uno script di comando di Windows (.BAT) e (2) ha fornito una diversa combinazione di filtri (nessuna delle altre risposte usa entrambi fps=10 e scale=-1:-1).  La risposta di Sun ci ha già fornito un file batch e quello (come gli script di shell nella risposta di Pje e nella risposta dello evangelista ) ha il vantaggio di assegnare l'elenco dei filtri a una variabile ( una volta ), ... (continua)
Scott

1
(Proseguendo) ... quindi non è necessario precisare l'elenco due volte (come fa il file batch). (Presumo che ciò crei il rischio che, se l'utente modifica lo script per modificare uno degli elenchi ma non l'altro, l'incoerenza causerà un problema.) Puoi almeno spiegare la tua scelta di filtri ( fps=10,scale=-1:-1)? (Vedi la risposta di notevole per un esempio di spiegazione di parti di un comando.)
Scott

1
@Scott Hai detto bene, quindi scrivo un nuovo utile script qui: github.com/NabiKAZ/video2gif
Nabi KAZ

4

Di seguito è riportato il file batch per gli utenti 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 di alta qualità con FFmpeg: estrazione di solo un campione

Se vuoi solo usare una variabile di input e il nome di output ha solo l'estensione GIF (pronuncia JIF), usa invece questa:

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

Come aggiungere una voce del menu contestuale "clic con il tasto destro" di Windows 7/10 per convertire il file video in gif

Alcune delle altre risposte menzionavano lo script video2gif , che ho usato. Ma potresti usare qualsiasi script.

Per creare l'opzione del menu di scelta rapida, è necessario modificare il registro. Aprire un prompt dei comandi di PowerShell, eseguendo w / admin privs. Esegui questi comandi:

$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

Ora quando fai clic con il pulsante destro del mouse su un file avrai l'opzione "Esegui Video2Gif"!

tra l'altro ho installato ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\e ho inserito lo video2gif.batscript nella cartella bin accanto a ffmpeg.exe. Ho anche aggiunto C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\binalle mie finestre PATH, ma non credo che sia necessario.

Se vuoi la possibilità di fornire allo script alcuni flag / arg della riga di comando extra, crea un nuovo file chiamato video2gif-prompt.bate fai in modo che il registro lo faccia riferimento invece di 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%

Puoi ancora premere Invio per ottenere rapidamente le impostazioni predefinite.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.