Bagaimana cara mengonversi video ke GIF menggunakan ffmpeg, dengan kualitas yang masuk akal?

311

Saya mengkonversi FLVfilm ke GIFfile dengan ffmpeg.

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

Ini berfungsi dengan baik, tetapi file keluaran gif memiliki kualitas yang sangat rendah.

Ada ide bagaimana saya bisa meningkatkan kualitas gif yang dikonversi?

Output dari perintah:

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%

Terima kasih.

Kamil Hismatullin
sumber
1
Sungguh lucu bagaimana orang-orang masih melakukan kerja sama dengan GIF ketika APNG adalah suatu hal.
Константин Ван

Jawaban:

447

ffmpeg contoh

Output GIF dari ffmpeg
183rb

ffmpegdapat menghasilkan GIF berkualitas tinggi. Selalu disarankan untuk menggunakan versi terbaru: unduh atau kompilasi .

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
  • Contoh ini akan melewati 30 detik pertama ( -ss 30) dari input dan membuat output 3 detik ( -t 3).
  • filter fps menetapkan kecepatan bingkai.
  • filter skala akan mengubah ukuran output menjadi lebar 320 piksel dan secara otomatis menentukan ketinggian sambil mempertahankan rasio aspek.
  • palettegen dan paletteuse filter akan menghasilkan dan menggunakan palet kustom yang dihasilkan dari masukan Anda.
  • filter split akan memungkinkan semuanya dilakukan dalam satu perintah.
  • Kontrol perulangan dengan -loopopsi keluaran. Nilai dari 0adalah perulangan tak terbatas.

Lihat GIF berkualitas tinggi dengan FFmpeg untuk lebih banyak contoh dan opsi.


convertContoh Imagagagick

Output GIF dari ffmpeg
227rb

Metode baris perintah lainnya adalah menyalurkan dari ffmpegke convert(atau magick) dari 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

Mengatur kecepatan bingkai

Setel kecepatan bingkai dengan kombinasi fpsfilter masuk ffmpegdan -delaymasuk convert. Ini bisa menjadi rumit karena converthanya mendapatkan aliran gambar mentah sehingga tidak ada fps yang dipertahankan. Kedua, -delaynilai dalam convertadalah dalam kutu (ada 100 kutu per detik), bukan dalam bingkai per detik. Misalnya, dengan fps=12.5= 100 / 12.5 = 8 = -delay 8.

convertmembulatkan -delaynilai menjadi bilangan bulat, jadi 8,4 menghasilkan 8 dan 8,5 hasil dalam 9. Ini secara efektif berarti bahwa hanya beberapa frame rate yang didukung ketika mengatur penundaan seragam pada semua frame (penundaan tertentu dapat diatur per frame tetapi itu di luar jawaban ini).

-delaytampaknya diabaikan jika digunakan sebagai opsi keluaran, jadi itu harus digunakan sebelumnya -seperti yang ditunjukkan dalam contoh.

Terakhir, peramban dan pemirsa gambar mungkin menerapkan penundaan minimum, jadi Anda -delaymungkin tetap akan diabaikan.

Video milik Pusat Pelatihan Konservasi Nasional Layanan Ikan & Margasatwa AS.

llogan
sumber
4
Menambahkan beberapa hasil contoh (hanya frame saja). Di sini, file pertama adalah 4,1 MB, yang kedua sekitar 8 MB.
slhck
2
@ LordNeckbeard, Anda luar biasa! terima kasih banyak untuk-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin
6
By the way, untuk convertperintah untuk mengkonversi dari frame PNG akhirnya saya gunakan convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", yang mengurangi ukuran file keseluruhan cukup sedikit
Wilf
2
Oke, saya mengerti, dulu scale=0:-1, jadi ketika Anda mengatur skala 0, ia akan mengambil skala dari video.
Mousa Alfhaily
2
T&J ini harus dikodekan secara permanen dalam buku tebal (atau mungkin hanya "disematkan" untuk saat ini) karena dalam seratus tahun dari sekarang semua komunikasi akan dilakukan melalui meme. Saya pikir kegiatan di posting ini saja berbicara tentang itu.
Jonathan Neufeld
87

Jika Anda memilih untuk menghindari file gambar perantara, perintah yang disediakan oleh LordNeckBeard dapat disalurkan antara ffmpegdan ImageMagick convertsehingga tidak ada file menengah yang diperlukan:

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

Ia -f image2pipememberitahu ffmpeg untuk membagi video menjadi gambar dan membuatnya cocok untuk disalurkan, dan -vcodec ppmmenentukan format output menjadi ppm (untuk beberapa alasan jika formatnya adalah png, convertapakah tidak membaca semua gambar dari pipa, atau ffmpeg tidak tidak menampilkan semuanya). Untuk -kedua perintah menentukan bahwa pipa akan digunakan untuk output dan input masing-masing.

Untuk mengoptimalkan hasil tanpa menyimpan file, Anda dapat mengirim output dari convertke convertperintah kedua :

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

Ia gif:-memberitahu convertuntuk memipakan outputnya sebagai data yang diformat gif dan -layers Optimizememberitahu yang kedua convertuntuk melakukan optimize-framedan optimize-transparancymetode (lihat Pengantar ImageMagick untuk Optimasi Animasi ). Perhatikan bahwa output dari the -layers Optimizetidak selalu memberikan ukuran file yang lebih kecil, jadi Anda mungkin ingin mencoba mengonversi ke gif tanpa optimasi terlebih dahulu untuk memastikan.

Ingatlah bahwa selama seluruh proses ini semuanya ada dalam memori sehingga Anda mungkin perlu memori yang cukup jika gambarnya cukup besar.

nyata
sumber
1
Serangkaian perintah ini juga berfungsi denganavconv
raphael
Anda harus menggabungkan dua perintah konversi terakhir:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément
GIF tampaknya berjalan pada kecepatan 2x dari sumber video?
Titan
@Titan percaya bahwa -r 10 di perintah pertama dan -delay 5 di perintah kedua. Saya mengubah penundaan ke 10 juga dan tampaknya bermain normal sekarang.
Steven Huang
2
Anda juga dapat menghindari file gambar menengah dengan menggunakan splitfilter di ffmpeg. Tidak perlu 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
memasang
37

Pada ffmpeg 2.6, kita bisa melakukan yang lebih baik:

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
sumber
18

Saya membuat versi skrip saya sendiri, yang parameter juga resolusi resolusi dan frame rate.

Menjalankan ./gifenc.sh input.mov output.gif 720 10akan menghasilkan 720p lebar 10fps GIF dari film yang Anda berikan. Anda mungkin perlu melakukannya chmod +x gifenc.shuntuk file tersebut.

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

Anda dapat membaca detailnya di Github saya

Asumsi: ffmpeg diinstal, dan skrip berada di folder yang sama dengan file lainnya.

thevangelist
sumber
3
Terima kasih banyak untuk skripmu. Saya baru saja mengujinya dan itu bekerja hebat!
orschiro
15

Jawaban dari @Stephane sangat bagus. Tapi itu akan mendapatkan peringatan seperti Buffer queue overflow, dropping.untuk beberapa video, dan gifbeberapa frame yang dihasilkan turun.

Ini adalah versi yang lebih baik dengan fifofilter yang harus dihindari Buffer queue overflowsaat menggunakan paletteusefilter. Dengan menggunakan splitfilter untuk menghindari pembuatan file PNG palet menengah.

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
sumber
Jika saya memahaminya dengan benar, Anda membagi input menjadi o1 dan o2, dan menyalin o2 ke o3. Jadi mengapa Anda membutuhkan o3? Mengapa tidak menggunakan o2 secara langsung?
Chloe
1
@ Chloe Apakah Anda melihat fifooperasi filter antara o2dan o3? Untuk menghindari Buffer queue overflowperingatan.
alijandro
+1 Ini berfungsi sangat baik untuk saya (dan menyelesaikan masalah yang dirujuk).
Iain Collins
Saya sangat menyukai solusi ini. Pujian!
Leonid Usov
10

membuat skrip, diuji, dan berfungsi.

pemakaian:

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

PUNYA SENANG :)

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 adalah alat ScreenCapturing yang SANGAT BAIK untuk Linux :)

Terima kasih banyak Michael Kohaupt :) Rock mantap.

beberapa statistik ukuran file:

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

lihat hasilnya di sini.

mencumbui
sumber
10

The ffmpegdengan palet metode dapat dijalankan dalam satu perintah, tanpa perantara .pngberkas.

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

Ini bisa dilakukan berkat splitfilter.

Stephane
sumber
10

Linux / Unix / macOS

Mengikuti pendekatan @LordNeckbeard dengan ffmpegperintah, silakan temukan fungsi Bash berguna berikut yang dapat ditambahkan ke ~/.bash_profilefile Anda :

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

Setelah fungsi dimuat (secara manual atau dari . ~/.bash_profile), Anda harus memiliki video2gifperintah baru .

Contoh penggunaan:

video2gif input.flv

atau:

video2gif input.flv 320 10

Skala hingga 320 lebar dengan 10 bingkai per detik.

Anda juga dapat menentukan format video yang berbeda (seperti mp4).


macOS

Anda dapat mencoba aplikasi GIF Brewery yang dapat membuat GIF dari file video.


Atau ada beberapa situs web yang melakukan konversi online gratis.

kenorb
sumber
skrip Anda menimbulkan kesalahan bagi saya tentang tidak ada file png dan saya tidak mendapatkan output gif, tetapi file input .mp4 tetap tidak berubah
lacostenycoder
7

Jawaban yang dipilih mengasumsikan Anda ingin skala video sumber dan mengubah fps di gif yang dihasilkan. Jika Anda tidak perlu melakukan ini, berikut ini berfungsi:

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

Ini sangat berguna ketika saya menginginkan gif yang dengan setia menciptakan kembali video sumber yang saya gunakan.

Jet Blue
sumber
6

Untuk pengguna windows:
buat video2gif.batfile di direktori windows dengan konten ini:

@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

Dan kemudian di mana saja Anda dapat menggunakannya seperti contoh ini:

video2gif myvideo.mp4

Maka Anda miliki myvideo.gifdi direktori saat ini.
Jika myvideo.gifada, tanyakan dari Anda untuk menimpanya.

SUNTING:

Saya sarankan gunakan skrip batch ini: https://github.com/NabiKAZ/video2gif

Nabi KAZ
sumber
2
Saya melihat bahwa Anda telah melakukan dua hal di sini: (1) menulis perintah sebagai skrip perintah Windows (.BAT), dan (2) memberikan kombinasi filter yang berbeda (tidak ada jawaban lain yang menggunakan keduanya fps=10 dan scale=-1:-1).  Jawaban Sun sudah memberi kami file batch, dan yang itu (seperti skrip shell dalam jawaban pje dan jawaban thevangelist ) memiliki keuntungan karena ia memberikan daftar filter ke variabel ( sekali ), ... (Lanjutkan)
Scott
1
(Lanjutkan) ... jadi tidak perlu mengeja daftar dua kali (seperti file batch Anda). (Saya menduga bahwa ini menciptakan risiko bahwa, jika pengguna mengedit skrip untuk mengubah salah satu daftar tetapi tidak yang lain, ketidakkonsistenan akan menyebabkan masalah.) Dapatkah Anda setidaknya menjelaskan pilihan filter Anda ( fps=10,scale=-1:-1)? (Lihat jawaban nyata untuk contoh penjelasan bagian-bagian dari suatu perintah.)
Scott
1
@Scott Anda berkata benar, jadi saya menulis skrip baru yang bermanfaat di sini: github.com/NabiKAZ/video2gif
Nabi KAZ
4

Di bawah ini adalah file batch untuk pengguna 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

Sumber: GIF berkualitas tinggi dengan FFmpeg: Mengekstrak hanya sampel

Jika Anda hanya ingin menggunakan satu variabel input dan memiliki nama output hanya memiliki ekstensi GIF (diucapkan JIF), maka gunakan ini sebagai gantinya:

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
Matahari
sumber
3

Bagaimana cara menambahkan entri menu konteks windows 7/10 "klik kanan" untuk mengonversi file video Anda menjadi gif

Beberapa jawaban lain menyebutkan skrip video2gif , yang saya gunakan. Tapi, Anda bisa menggunakan skrip apa pun.

Untuk membuat opsi menu konteks, Anda perlu mengedit registri Anda. Buka prompt perintah powershell, jalankan dengan admin privs. Jalankan perintah ini:

$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

Sekarang ketika Anda mengklik kanan file Anda akan memiliki opsi "Jalankan Video2Gif"!

btw saya menginstal ffmpeg ke C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\dan menempatkan video2gif.batskrip di direktori bin tepat di sebelah ffmpeg.exe. Saya juga menambahkan C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\binke windows saya PATH, tapi saya rasa Anda tidak perlu melakukannya.

Jika Anda ingin opsi untuk dapat menyediakan beberapa flag / args baris perintah tambahan ke skrip, kemudian buat file baru dengan nama video2gif-prompt.bat, dan minta registri untuk merujuknya alih-alih 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%

Anda masih bisa menekan enter untuk mendapatkan default dengan cepat.

chris
sumber