video2gif 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 18744ed8233c2766731e647303b9b4493545d860
4
- data.tar.gz: 94cafe3965b7cf4f5800b6ebd1d5c24f457f66f1
3
+ metadata.gz: 1266f3c1c715f41fa3c9d15bd11b788c74b4095d
4
+ data.tar.gz: 33c432d73a9daa08f89b1a758875a504a1c33f8f
5
5
  SHA512:
6
- metadata.gz: 8224b9efbff707dd5e79587fb51531ce158a9bc447a0d173b903987883ee3b0c32598a4d9de309b6f16f7b551f72d21691aef4898bfde74574e657946706e015
7
- data.tar.gz: 48e256f90d5a3dcf546684708997a342bd4f12081f93b57049ac851c708a6c787dc92792da2828932c94eff27ea88247493498e4bc2e2383e55284c18a2c8f67
6
+ metadata.gz: 820669a53355384b56f7060249a064bc57b1ccd000b575490e055b58ea18cd87438271bf5c0afb99fe139f0feff735a3f4dfd68d72b53dc148018345471b473b
7
+ data.tar.gz: ae0e081d4cd1ae6fa56a00259c8ffb7132f02ce3eea545cb90f36e788e857034fd3234057beaa03a2c33f30e69ce97ed9b667dace0ae097863eeb1f8625d0885
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- video2gif (0.0.13)
4
+ video2gif (0.0.14)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -3,15 +3,24 @@
3
3
 
4
4
  module Video2gif
5
5
  module FFMpeg
6
- def self.filter_complex(options)
7
- filter_complex = []
6
+ def self.filtergraph(options)
7
+ filtergraph = []
8
8
 
9
- filter_complex << "fps=#{ options[:fps] || 10 }"
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
- filter_complex << options[:autocrop]
13
- else
14
- filter_complex << 'crop=' + [
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
- filter_complex << "scale=flags=lanczos:sws_dither=none:width=#{options[:width]}:height=-1"
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
- filter_complex << "zscale=dither=none:filter=lanczos:width=#{options[:width]}:height=-1" if options[:width]
28
- filter_complex << 'zscale=transfer=linear:npl=100'
29
- filter_complex << 'zscale=npl=100'
30
- filter_complex << 'format=gbrpf32le'
31
- filter_complex << 'zscale=primaries=bt709'
32
- filter_complex << "tonemap=tonemap=#{options[:tonemap]}:desat=0"
33
- filter_complex << 'zscale=transfer=bt709:matrix=bt709:range=tv'
34
- filter_complex << 'format=yuv420p'
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
- filter_complex << "eq=contrast=#{options[:contrast]}" if options[:contrast]
38
- filter_complex << "eq=brightness=#{options[:brightness]}" if options[:brightness]
39
- filter_complex << "eq=saturation=#{options[:saturation]}" if options[:saturation]
40
- filter_complex << "eq=gamma=#{options[:gamma]}" if options[:gamma]
41
- filter_complex << "eq=gamma_r=#{options[:gamma_r]}" if options[:gamma_r]
42
- filter_complex << "eq=gamma_g=#{options[:gamma_g]}" if options[:gamma_g]
43
- filter_complex << "eq=gamma_b=#{options[:gamma_b]}" if options[:gamma_b]
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
- filter_complex << 'drawtext=' + [
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
- filter_complex << 'split [palettegen] [paletteuse]'
67
- filter_complex << "[palettegen] palettegen=#{options[:palette] || 256}:stats_mode=diff [palette]"
68
- filter_complex << '[paletteuse] [palette] paletteuse=dither=floyd_steinberg:diff_mode=rectangle'
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
- filter_complex.join(',')
101
+ filtergraph.join(',')
71
102
  end
72
103
 
73
- def self.cropdetect_command(options, logger)
74
- command = ['ffmpeg']
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
- command << '-filter_complex' << "cropdetect=limit=#{options[:autocrop]}"
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 = ['ffmpeg']
91
- command << '-y' # always overwrite
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
 
@@ -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|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Video2gif
4
- VERSION = '0.0.13'
4
+ VERSION = '0.0.14'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: video2gif
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emily St.