video2gif 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/lib/video2gif/ffmpeg.rb +70 -40
- data/lib/video2gif/options.rb +11 -0
- data/lib/video2gif/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1266f3c1c715f41fa3c9d15bd11b788c74b4095d
|
4
|
+
data.tar.gz: 33c432d73a9daa08f89b1a758875a504a1c33f8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 820669a53355384b56f7060249a064bc57b1ccd000b575490e055b58ea18cd87438271bf5c0afb99fe139f0feff735a3f4dfd68d72b53dc148018345471b473b
|
7
|
+
data.tar.gz: ae0e081d4cd1ae6fa56a00259c8ffb7132f02ce3eea545cb90f36e788e857034fd3234057beaa03a2c33f30e69ce97ed9b667dace0ae097863eeb1f8625d0885
|
data/Gemfile.lock
CHANGED
data/lib/video2gif/ffmpeg.rb
CHANGED
@@ -3,15 +3,24 @@
|
|
3
3
|
|
4
4
|
module Video2gif
|
5
5
|
module FFMpeg
|
6
|
-
def self.
|
7
|
-
|
6
|
+
def self.filtergraph(options)
|
7
|
+
filtergraph = []
|
8
8
|
|
9
|
-
|
9
|
+
# Set 'fps' filter first, drop unneeded frames instead of
|
10
|
+
# processing those.
|
11
|
+
filtergraph << "fps=#{ options[:fps] || 10 }"
|
10
12
|
|
13
|
+
# Crop if needed, using either settings discovered during the
|
14
|
+
# autocrop run or manually set parameters, so we don't process
|
15
|
+
# additional parts of the image (and exclude it from palette
|
16
|
+
# generation).
|
11
17
|
if options[:autocrop]
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
filtergraph << options[:autocrop]
|
19
|
+
elsif options[:wregion] ||
|
20
|
+
options[:hregion] ||
|
21
|
+
options[:xoffset] ||
|
22
|
+
options[:yoffset]
|
23
|
+
filtergraph << 'crop=' + [
|
15
24
|
"w=#{ options[:wregion] || 'in_w' }",
|
16
25
|
"h=#{ options[:hregion] || 'in_h' }",
|
17
26
|
"x=#{ options[:xoffset] || 0 }",
|
@@ -19,29 +28,39 @@ module Video2gif
|
|
19
28
|
].join(':')
|
20
29
|
end
|
21
30
|
|
31
|
+
# If we're not attempting to convert HDR to SDR, the standard
|
32
|
+
# 'scale' filter is preferred (if we're resizing at all). Scale
|
33
|
+
# here before other filters to avoid unnecessary processing.
|
22
34
|
if options[:width] && !options[:tonemap]
|
23
|
-
|
35
|
+
filtergraph << "scale=flags=lanczos:sws_dither=none:width=#{options[:width]}:height=-1"
|
24
36
|
end
|
25
37
|
|
38
|
+
# If we're attempting to convert HDR to SDR, use a set of 'zscale'
|
39
|
+
# filters, 'format' filters, and the 'tonemap' filter. The
|
40
|
+
# 'zscale' will do the resize for us as well.
|
26
41
|
if options[:tonemap]
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
42
|
+
filtergraph << "zscale=dither=none:filter=lanczos:width=#{options[:width]}:height=-1" if options[:width]
|
43
|
+
filtergraph << 'zscale=transfer=linear:npl=100'
|
44
|
+
filtergraph << 'zscale=npl=100'
|
45
|
+
filtergraph << 'format=gbrpf32le'
|
46
|
+
filtergraph << 'zscale=primaries=bt709'
|
47
|
+
filtergraph << "tonemap=tonemap=#{options[:tonemap]}:desat=0"
|
48
|
+
filtergraph << 'zscale=transfer=bt709:matrix=bt709:range=tv'
|
49
|
+
filtergraph << 'format=yuv420p'
|
35
50
|
end
|
36
51
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
52
|
+
# Perform any desired equalization before we overlay text so that
|
53
|
+
# it won't be affected.
|
54
|
+
filtergraph << "eq=contrast=#{options[:contrast]}" if options[:contrast]
|
55
|
+
filtergraph << "eq=brightness=#{options[:brightness]}" if options[:brightness]
|
56
|
+
filtergraph << "eq=saturation=#{options[:saturation]}" if options[:saturation]
|
57
|
+
filtergraph << "eq=gamma=#{options[:gamma]}" if options[:gamma]
|
58
|
+
filtergraph << "eq=gamma_r=#{options[:gamma_r]}" if options[:gamma_r]
|
59
|
+
filtergraph << "eq=gamma_g=#{options[:gamma_g]}" if options[:gamma_g]
|
60
|
+
filtergraph << "eq=gamma_b=#{options[:gamma_b]}" if options[:gamma_b]
|
61
|
+
|
62
|
+
# If there is text to superimpose, do it here before palette
|
63
|
+
# generation to ensure the color looks appropriate.
|
45
64
|
if options[:text]
|
46
65
|
count_of_lines = options[:text].scan(/\\n/).count + 1
|
47
66
|
text = options[:text]
|
@@ -52,7 +71,7 @@ module Video2gif
|
|
52
71
|
.gsub(/\B"\b([^"\u201C\u201D\u201E\u201F\u2033\u2036\r\n]+)\b?"\B/, "\u201C\\1\u201D")
|
53
72
|
.gsub(/\B'\b([^'\u2018\u2019\u201A\u201B\u2032\u2035\r\n]+)\b?'\B/, "\u2018\\1\u2019")
|
54
73
|
|
55
|
-
|
74
|
+
filtergraph << 'drawtext=' + [
|
56
75
|
"x='#{ options[:xpos] || '(main_w/2-text_w/2)' }'",
|
57
76
|
"y='#{ options[:ypos] || "(main_h-line_h*1.5*#{count_of_lines})" }'",
|
58
77
|
"fontsize='#{ options[:textsize] || 32 }'",
|
@@ -63,21 +82,38 @@ module Video2gif
|
|
63
82
|
].join(':')
|
64
83
|
end
|
65
84
|
|
66
|
-
|
67
|
-
|
68
|
-
|
85
|
+
# Split the stream into two copies, labeled with output pads for
|
86
|
+
# the palettegen/paletteuse filters to use.
|
87
|
+
filtergraph << 'split[palettegen][paletteuse]'
|
88
|
+
|
89
|
+
# Using a copy of the stream created above labeled "palettegen",
|
90
|
+
# generate a palette from the stream using the specified number of
|
91
|
+
# colors and optimizing for moving objects in the stream. Label
|
92
|
+
# this stream's output as "palette."
|
93
|
+
filtergraph << "[palettegen]palettegen=#{options[:palette] || 256}:stats_mode=diff[palette]"
|
94
|
+
|
95
|
+
# Using a copy of the stream from the 'split' filter and the
|
96
|
+
# generated palette as inputs, apply the final palette to the GIF.
|
97
|
+
# For non-moving parts of the GIF, attempt to reuse the same
|
98
|
+
# palette from frame to frame.
|
99
|
+
filtergraph << "[paletteuse][palette]paletteuse=dither=#{options[:dither] || 'floyd_steinberg'}:diff_mode=rectangle"
|
69
100
|
|
70
|
-
|
101
|
+
filtergraph.join(',')
|
71
102
|
end
|
72
103
|
|
73
|
-
def self.
|
74
|
-
command = [
|
104
|
+
def self.ffmpeg_command(options, executable: 'ffmpeg')
|
105
|
+
command = [executable]
|
106
|
+
command << '-y' # always overwrite
|
75
107
|
command << '-analyzeduration' << '2147483647' << '-probesize' << '2147483647'
|
76
108
|
command << '-loglevel' << 'verbose'
|
77
109
|
command << '-ss' << options[:seek] if options[:seek]
|
78
110
|
command << '-t' << options[:time] if options[:time]
|
79
111
|
command << '-i' << options[:input_filename]
|
80
|
-
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.cropdetect_command(options, logger, executable: 'ffmpeg')
|
115
|
+
command = ffmpeg_command(options, executable: executable)
|
116
|
+
command << '-filtergraph' << "cropdetect=limit=#{options[:autocrop]}"
|
81
117
|
command << '-f' << 'null'
|
82
118
|
command << '-'
|
83
119
|
|
@@ -86,15 +122,9 @@ module Video2gif
|
|
86
122
|
command
|
87
123
|
end
|
88
124
|
|
89
|
-
def self.gif_command(options, logger)
|
90
|
-
command =
|
91
|
-
command << '-
|
92
|
-
command << '-analyzeduration' << '2147483647' << '-probesize' << '2147483647'
|
93
|
-
command << '-loglevel' << 'verbose'
|
94
|
-
command << '-ss' << options[:seek] if options[:seek]
|
95
|
-
command << '-t' << options[:time] if options[:time]
|
96
|
-
command << '-i' << options[:input_filename]
|
97
|
-
command << '-filter_complex' << filter_complex(options)
|
125
|
+
def self.gif_command(options, logger, executable: 'ffmpeg')
|
126
|
+
command = ffmpeg_command(options, executable: executable)
|
127
|
+
command << '-filter_complex' << filtergraph(options)
|
98
128
|
command << '-f' << 'gif'
|
99
129
|
command << options[:output_filename]
|
100
130
|
|
data/lib/video2gif/options.rb
CHANGED
@@ -57,6 +57,17 @@ module Video2gif
|
|
57
57
|
options[:palette] = p
|
58
58
|
end
|
59
59
|
|
60
|
+
parser.on('-d [ALGORITHM]',
|
61
|
+
'--[no-]dither [ALGORITHM]',
|
62
|
+
'Set the dithering algorithm for the palette generation",
|
63
|
+
"(default enabled with "floyd_steinberg")') do |d|
|
64
|
+
if d.nil?
|
65
|
+
options[:dither] = 'floyd_steinberg'
|
66
|
+
else
|
67
|
+
options[:dither] = d || 'none'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
60
71
|
parser.on('-c SIZE',
|
61
72
|
'--crop-size-w SIZE',
|
62
73
|
'Pixel size of width to select from source video, before scaling') do |s|
|
data/lib/video2gif/version.rb
CHANGED