Làm cách nào để chuyển đổi video thành GIF bằng ffmpeg, với chất lượng hợp lý?


311

Tôi đang chuyển đổi FLVphim thành GIFtập tin với ffmpeg.

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

Nó hoạt động rất tốt, nhưng tệp gif đầu ra có chất lượng rất thấp.

Bất kỳ ý tưởng làm thế nào tôi có thể cải thiện chất lượng của gif chuyển đổi?

Đầu ra của lệnh:

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%

Cảm ơn.


1
Thật buồn cười khi mọi người vẫn làm bài tập với GIF khi APNG là một thứ.
Toàn cảnh

Câu trả lời:


447

ffmpeg thí dụ

Đầu ra GIF từ ffmpeg
183k

ffmpegcó thể xuất GIF chất lượng cao. Chúng tôi luôn khuyến nghị sử dụng phiên bản gần đây: tải xuống hoặc biên dịch .

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
  • Ví dụ này sẽ bỏ qua 30 giây đầu tiên ( -ss 30) của đầu vào và tạo đầu ra 3 giây ( -t 3).
  • bộ lọc fps đặt tốc độ khung hình.
  • bộ lọc tỷ lệ sẽ thay đổi kích thước đầu ra thành rộng 320 pixel và tự động xác định chiều cao trong khi duy trì tỷ lệ khung hình.
  • palettegenpaletteuse bộ lọc sẽ tạo ra và sử dụng một bảng màu tùy chỉnh được tạo ra từ đầu vào của bạn.
  • bộ lọc phân tách sẽ cho phép mọi thứ được thực hiện trong một lệnh.
  • Kiểm soát vòng lặp với -looptùy chọn đầu ra. Một giá trị 0là vòng lặp vô hạn.

Xem GIF chất lượng cao với FFmpeg để biết thêm nhiều ví dụ và tùy chọn.


ImageMagick convertdụ

Đầu ra GIF từ ffmpeg
227k

Một phương pháp dòng lệnh là ống từ ffmpegđến convert(hoặc magick) từ 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

Đặt tốc độ khung hình

Đặt tốc độ khung hình với sự kết hợp của fpsbộ lọc trong ffmpeg-delaytrong convert. Điều này có thể trở nên phức tạp vì convertchỉ cần có một luồng hình ảnh thô để không có khung hình / giây được bảo tồn. Thứ hai, -delaygiá trị trong convertlà trong tích tắc (có 100 ve mỗi giây), không phải trong khung hình mỗi giây. Ví dụ: với fps=12.5= 100 / 12,5 = 8 = -delay 8.

convertlàm tròn -delaygiá trị thành một số nguyên, do đó, 8.4 kết quả trong 8 và 8,5 kết quả trong 9. Điều này có nghĩa là chỉ có một số tốc độ khung hình được hỗ trợ khi đặt độ trễ đồng nhất trên tất cả các khung (có thể đặt độ trễ cụ thể cho mỗi khung hình nhưng vượt quá câu trả lời này).

-delaydường như bị bỏ qua nếu được sử dụng như một tùy chọn đầu ra, vì vậy nó phải được sử dụng trước đó -như trong ví dụ.

Cuối cùng, trình duyệt và người xem hình ảnh có thể thực hiện độ trễ tối thiểu, do đó bạn -delaycó thể bị bỏ qua.

Video lịch sự của Trung tâm đào tạo bảo tồn quốc gia về dịch vụ bảo vệ cá và động vật hoang dã Hoa Kỳ.


4
Đã thêm một số kết quả ví dụ (chỉ khung hình tĩnh). Ở đây, tệp đầu tiên là 4,1 MB, tệp thứ hai khoảng 8 MB.
slhck

2
@LordNeckbeard, bạn thật tuyệt vời! cảm ơn rất nhiều vì-vf scale=320:-1,format=rgb8,format=rgb24
Kamil Hismatullin

6
Nhân tiện, đối với convertlệnh chuyển đổi từ các khung PNG tôi đã kết thúc bằng cách sử dụng convert -delay 5 -loop 0 -dither None -colors 80 "frames/ffout*.png" -fuzz "40%" -layers OptimizeFrame "output.gif", điều này làm giảm kích thước tệp chung một chút
Wilf

2
Được rồi, tôi đã có nó, tôi đã sử dụng scale=0:-1, vì vậy khi bạn đặt tỷ lệ thành 0, nó sẽ lấy tỷ lệ từ video.
Mousa Alfh Daily

2
Câu hỏi và trả lời này phải được mã hóa vĩnh viễn trong một cuốn sách (hoặc có thể chỉ là "được ghim" ngay bây giờ) bởi vì trong một trăm năm nữa, mọi giao tiếp sẽ được thực hiện thông qua memes. Tôi nghĩ rằng hoạt động trên bài đăng này một mình nói lên điều đó.
Jonathan Neufeld

87

Nếu bạn muốn tránh các tệp hình ảnh trung gian, các lệnh do LordNeckBeard cung cấp có thể được đặt giữa ffmpegvà ImageMagick convertđể không yêu cầu các tệp trung gian:

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

Thông báo -f image2pipecho ffmpeg chia video thành hình ảnh và làm cho nó phù hợp để được loại bỏ và -vcodec ppmchỉ định định dạng đầu ra là ppm (vì một số lý do nếu định dạng là png, convertkhông đọc được tất cả hình ảnh từ đường ống hoặc ffmpeg không không xuất ra tất cả). Các -lệnh cho cả hai chỉ định rằng một đường ống sẽ được sử dụng cho đầu ra và đầu vào tương ứng.

Để tối ưu hóa kết quả mà không lưu tệp, bạn có thể chuyển đầu ra từ lệnh convertthứ hai convert:

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

Thông báo gif:-cho convertđường ống đầu ra của nó dưới dạng dữ liệu được định dạng gif và báo -layers Optimizecho lần thứ hai convertthực hiện optimize-frameoptimize-transparancyphương thức (xem Giới thiệu ImageMagick về Tối ưu hóa hoạt hình ). Lưu ý rằng đầu ra từ -layers Optimizecó thể không phải lúc nào cũng cung cấp kích thước tệp nhỏ hơn, vì vậy bạn có thể muốn thử chuyển đổi sang gif mà không cần tối ưu hóa trước.

Hãy nhớ rằng trong toàn bộ quá trình này, mọi thứ đều nằm trong bộ nhớ nên bạn có thể cần đủ bộ nhớ nếu hình ảnh khá lớn.


1
Nhóm lệnh này cũng hoạt động vớiavconv
raphael

Bạn nên hợp nhất hai lệnh chuyển đổi cuối cùng:convert -delay 5 -loop 0 -layers Optimize - output.gif
Clément

Gif dường như đang chạy ở tốc độ gấp 2 lần video nguồn?
Titan

@Titan tin rằng đó là -r 10 trong lệnh đầu tiên và -delay 5 trong lần thứ hai. Tôi cũng đã thay đổi độ trễ thành 10 và dường như nó vẫn chơi bình thường.
Steven Huang

2
Bạn cũng có thể tránh các tệp hình ảnh trung gian bằng cách sử dụng splitbộ lọc trong ffmpeg. Không cần ống gì cả: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

Kể từ ffmpeg 2.6, chúng ta có thể làm tốt hơn nữa:

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

Tôi đã tạo phiên bản kịch bản của riêng mình, cũng tham số hóa độ phân giải đầu ra và tốc độ khung hình.

Chạy ./gifenc.sh input.mov output.gif 720 10sẽ tạo ra GIF 10fps rộng 720p từ bộ phim bạn đã cho. Bạn có thể cần phải làm chmod +x gifenc.shcho các tập tin.

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

Bạn có thể đọc chi tiết trên Github của tôi

Giả định: ffmpeg được cài đặt và tập lệnh nằm trong cùng thư mục với các tệp khác.


3
Cảm ơn bạn rất nhiều cho kịch bản của bạn. Tôi chỉ thử nghiệm nó và nó hoạt động tuyệt vời!
orschiro

15

Câu trả lời từ @Stephane là rất tốt. Nhưng nó sẽ nhận được cảnh báo như Buffer queue overflow, dropping.đối với một số video và phần được tạo gifcó một số khung bị bỏ.

Đây là một phiên bản tốt hơn với fifobộ lọc để tránh Buffer queue overflowkhi sử dụng paletteusebộ lọc. Bằng cách sử dụng splitbộ lọc để tránh việc tạo tệp PNG bảng trung gian.

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

Nếu tôi hiểu điều đó một cách chính xác, bạn đang chia đầu vào thành o1 và o2 và sao chép o2 thành o3. Vậy tại sao bạn cần o3? Tại sao không chỉ sử dụng o2 trực tiếp?
Chloe

1
@Chloe Bạn có thấy fifohoạt động của bộ lọc giữa o2o3không? Để tránh Buffer queue overflowcảnh báo.
alijandro

+1 Điều này hoạt động thực sự tốt đối với tôi (và giải quyết vấn đề được tham chiếu).
Iain Collins

Tôi hoàn toàn thích giải pháp này. Thanh danh!
Leonid Usov

10

làm một kịch bản, thử nghiệm và làm việc.

sử dụng:

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

CÓ 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 là một công cụ TUYỆT VỜI TUYỆT VỜI cho Linux :)

CẢM ƠN MỘT Michael Kohaupt :) Đá ổn định.

một số thống kê kích thước tập tin:

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

xem kết quả tại đây


10

Các ffmpegvới bảng phương pháp có thể được chạy trong một lệnh duy nhất, mà không cần trung gian .pngtập tin.

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

Điều này có thể được thực hiện nhờ splitbộ lọc.


10

Linux / Unix / macOS

Theo cách tiếp cận @LordNeckbeard bằng ffmpeglệnh, vui lòng tìm hàm Bash hữu ích sau đây có thể được thêm vào ~/.bash_profiletệp của bạn :

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

Khi chức năng được tải (thủ công hoặc từ . ~/.bash_profile), bạn sẽ có video2giflệnh mới .

Ví dụ sử dụng:

video2gif input.flv

hoặc là:

video2gif input.flv 320 10

Tỷ lệ lên 320 chiều rộng với 10 khung hình mỗi giây.

Bạn cũng có thể chỉ định một định dạng video khác (chẳng hạn như mp4).


hệ điều hành Mac

Bạn có thể dùng thử ứng dụng GIF Bia có thể tạo GIF từ các tệp video.


Ngoài ra, có một số trang web đang thực hiện chuyển đổi trực tuyến miễn phí.


tập lệnh của bạn gây ra lỗi cho tôi về việc không có tệp png và tôi không nhận được đầu ra gif, nhưng tệp đầu vào .mp4 vẫn không thay đổi
lacostenycoder

7

Câu trả lời được chọn giả định rằng bạn muốn chia tỷ lệ video nguồn và thay đổi khung hình / giây của nó trong gif được tạo. Nếu bạn không cần phải làm điều này, các công việc sau đây:

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

Điều này rất hữu ích khi tôi muốn một gif trung thực tái tạo video nguồn tôi đang sử dụng.


6

Đối với người dùng windows:
tạo video2gif.battệp trong thư mục windows với các nội dung sau:

@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

Và sau đó bất cứ nơi nào bạn có thể sử dụng nó sẽ giống như ví dụ này:

video2gif myvideo.mp4

Sau đó, bạn có myvideo.giftrong thư mục hiện tại.
Nếu myvideo.gifcó tồn tại, câu hỏi từ bạn để ghi đè lên nó.

BIÊN TẬP:

Tôi đề nghị sử dụng tập lệnh bó này: https://github.com/NabiKAZ/video2gif


2
Tôi thấy rằng bạn đã thực hiện hai điều ở đây: (1) đã viết các lệnh dưới dạng tập lệnh lệnh Windows (.BAT) và (2) cung cấp một tổ hợp bộ lọc khác nhau (không có câu trả lời nào khác sử dụng cả hai fps=10scale=-1:-1).  Câu trả lời của Sun đã cung cấp cho chúng tôi một tệp bó và một tệp (như các tập lệnh shell trong câu trả lời của pjecâu trả lời của nhà truyền giáo ) có lợi thế là nó gán danh sách các bộ lọc cho một biến ( một lần ), một (Cont'd)
Scott

1
(Tiếp theo), do đó, không cần phải đánh vần danh sách hai lần (như tệp bó của bạn). (Tôi cho rằng điều này tạo ra rủi ro rằng, nếu người dùng chỉnh sửa tập lệnh để thay đổi một trong các danh sách nhưng không phải danh sách khác, sự không nhất quán sẽ gây ra sự cố.) Ít nhất bạn có thể giải thích sự lựa chọn bộ lọc của mình ( fps=10,scale=-1:-1) không? (Xem câu trả lời đáng chú ý để biết ví dụ về giải thích các phần của lệnh.)
Scott

1
@Scott Bạn đã nói đúng, vì vậy tôi viết một tập lệnh hữu ích mới tại đây: github.com/NabiKAZ/video2gif
Nabi KAZ

4

Dưới đây là tệp bó cho người dùng 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

Nguồn: GIF chất lượng cao với FFmpeg: Trích xuất chỉ một mẫu

Nếu bạn chỉ muốn sử dụng một biến đầu vào và có tên đầu ra chỉ có phần mở rộng GIF (phát âm là JIF), thì hãy sử dụng thay thế này:

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

Cách thêm một mục nhập menu ngữ cảnh "nhấp chuột phải" vào cửa sổ 7/10 để chuyển đổi tệp video của bạn sang gif

Một số câu trả lời khác đề cập đến tập lệnh video2gif mà tôi đã sử dụng. Nhưng, bạn có thể sử dụng bất kỳ kịch bản.

Để tạo tùy chọn menu ngữ cảnh, bạn cần chỉnh sửa sổ đăng ký của mình. Mở một dấu nhắc lệnh powershell, chạy w / admin private. Thực hiện các lệnh này:

$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

Bây giờ khi bạn nhấp chuột phải vào một tệp, bạn sẽ có tùy chọn "Chạy Video2Gif"!

btw Tôi đã cài đặt ffmpeg C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\và đặt video2gif.battập lệnh vào thư mục bin ngay bên cạnh ffmpeg.exe. Tôi cũng đã thêm vào C:\dev\ffmpeg\ffmpeg-3.4.2-win64-static\bincửa sổ của mình PATH, nhưng tôi không nghĩ bạn cần phải làm vậy.

Nếu bạn muốn tùy chọn có thể cung cấp thêm một số cờ / đối số dòng lệnh bổ sung cho tập lệnh, thì hãy tạo một tệp mới có tên video2gif-prompt.batvà yêu cầu đăng ký tham chiếu nó thay vì 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%

Bạn vẫn có thể nhấn enter để nhanh chóng nhận được mặc định.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.