Module: Ffmprb::Filter

Defined in:
lib/ffmprb/filter.rb

Defined Under Namespace

Classes: Error

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.silence_noise_max_dbObject

Returns the value of attribute silence_noise_max_db.



9
10
11
# File 'lib/ffmprb/filter.rb', line 9

def silence_noise_max_db
  @silence_noise_max_db
end

Class Method Details

.afade_in(duration, input = nil, output = nil) ⇒ Object



15
16
17
# File 'lib/ffmprb/filter.rb', line 15

def afade_in(duration, input=nil, output=nil)
  inout "afade=in:d=%{duration}:curve=hsin", input, output, duration: duration
end

.afade_out(duration, input = nil, output = nil) ⇒ Object



19
20
21
# File 'lib/ffmprb/filter.rb', line 19

def afade_out(duration, input=nil, output=nil)
  inout "afade=out:d=%{duration}:curve=hsin", input, output, duration: duration
end

.alphamerge(inputs, output = nil) ⇒ Object



11
12
13
# File 'lib/ffmprb/filter.rb', line 11

def alphamerge(inputs, output=nil)
  inout "alphamerge", inputs, output
end

.amix_to_first_same_volume(inputs, output = nil) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/ffmprb/filter.rb', line 23

def amix_to_first_same_volume(inputs, output=nil)
  filters = []
  new_inputs = inputs.map do |input|
    if input == inputs.first
      input
    else
      "apd#{input}".tap do |lbl_aux|
        filters +=
          inout("apad", input, lbl_aux)  # NOTE we'll see if we really need this filter separate
      end
    end
  end
  filters +
    inout("amix=%{inputs_count}:duration=shortest:dropout_transition=0, volume=%{inputs_count}",
      new_inputs, output, inputs_count: (inputs.empty?? nil : inputs.size))
end

.anull(input = nil, output = nil) ⇒ Object



40
41
42
# File 'lib/ffmprb/filter.rb', line 40

def anull(input=nil, output=nil)
  inout "anull", input, output
end

.anullsink(input = nil) ⇒ Object



44
45
46
# File 'lib/ffmprb/filter.rb', line 44

def anullsink(input=nil)
  inout "anullsink", input, nil
end

.asplit(inputs = nil, outputs = nil) ⇒ Object



48
49
50
# File 'lib/ffmprb/filter.rb', line 48

def asplit(inputs=nil, outputs=nil)
  inout "asplit", inputs, outputs
end

.atrim(st, en = nil, input = nil, output = nil) ⇒ Object



52
53
54
55
# File 'lib/ffmprb/filter.rb', line 52

def atrim(st, en=nil, input=nil, output=nil)
  inout "atrim=%{start_end}, asetpts=PTS-STARTPTS", input, output,
    start_end: [st, en].compact.join(':')
end

.blank_source(duration, resolution, fps, output = nil) ⇒ Object



57
58
59
# File 'lib/ffmprb/filter.rb', line 57

def blank_source(duration, resolution, fps, output=nil)
  color_source '0x000000@0', duration, resolution, fps, output
end

.blend_a(duration, inputs, output = nil) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
# File 'lib/ffmprb/filter.rb', line 214

def blend_a(duration, inputs, output=nil)
  fail Error, "must be given 2 inputs"  unless inputs.size == 2

  aux_lbl = "blnd#{inputs[0]}"
  auxx_lbl = "x#{aux_lbl}"
  [
    *afade_out(duration, inputs[0], aux_lbl),
    *afade_in(duration, inputs[1], auxx_lbl),
    *amix_to_first_same_volume([auxx_lbl, aux_lbl], output)
  ]
end

.blend_v(duration, resolution, fps, inputs, output = nil) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/ffmprb/filter.rb', line 199

def blend_v(duration, resolution, fps, inputs, output=nil)
  fail Error, "must be given 2 inputs"  unless inputs.size == 2

  aux_lbl = "blnd#{inputs[0]}"
  auxx_lbl = "x#{aux_lbl}"
  [
    *white_source(duration, resolution, fps, aux_lbl),
    *inout([
      *alphamerge([inputs[0], aux_lbl]),
      *fade_out_alpha(duration)
    ].join(', '), nil, auxx_lbl),
    *overlay(0, 0, [inputs[1], auxx_lbl], output),
  ]
end

.color_source(color, duration, resolution, fps, output = nil) ⇒ Object



61
62
63
64
# File 'lib/ffmprb/filter.rb', line 61

def color_source(color, duration, resolution, fps, output=nil)
  inout "color=%{color}:d=%{duration}:s=%{resolution}:r=%{fps}", nil, output,
    color: color, duration: duration, resolution: resolution, fps: fps
end

.complex_options(*filters) ⇒ Object



262
263
264
# File 'lib/ffmprb/filter.rb', line 262

def complex_options(*filters)
  ['-filter_complex', filters.join('; ')]  unless filters.empty?
end

.concat_a(inputs, output = nil) ⇒ Object



79
80
81
82
# File 'lib/ffmprb/filter.rb', line 79

def concat_a(inputs, output=nil)
  inout "concat=%{inputs_count}:v=0:a=1", inputs, output,
    inputs_count: (inputs.empty?? nil : inputs.size)
end

.concat_av(inputs, output = nil) ⇒ Object



84
85
86
87
# File 'lib/ffmprb/filter.rb', line 84

def concat_av(inputs, output=nil)
  inout "concat=%{inputs_count}:v=1:a=1", inputs, output,
    inputs_count: (inputs.empty? || inputs.size % 2 != 0 ? nil : inputs.size/2)  # XXX meh
end

.concat_v(inputs, output = nil) ⇒ Object



74
75
76
77
# File 'lib/ffmprb/filter.rb', line 74

def concat_v(inputs, output=nil)
  inout "concat=%{inputs_count}:v=1:a=0", inputs, output,
    inputs_count: (inputs.empty?? nil : inputs.size)
end

.copy(input = nil, output = nil) ⇒ Object



89
90
91
# File 'lib/ffmprb/filter.rb', line 89

def copy(input=nil, output=nil)
  inout "copy", input, output
end

.crop(crop, input = nil, output = nil) ⇒ Object

TODO unused at the moment



94
95
96
# File 'lib/ffmprb/filter.rb', line 94

def crop(crop, input=nil, output=nil)
  inout "crop=x=%{left}:y=%{top}:w=%{width}:h=%{height}", input, output, crop
end

.crop_prop(crop, input = nil, output = nil) ⇒ Object



98
99
100
101
# File 'lib/ffmprb/filter.rb', line 98

def crop_prop(crop, input=nil, output=nil)
  inout "crop=%{crop_exp}", input, output,
    crop_exp: crop_prop_exps(crop).join(':')
end

.crop_prop_exps(crop) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/ffmprb/filter.rb', line 103

def crop_prop_exps(crop)
  exps = []

  if crop[:left]
    exps << "x=in_w*#{crop[:left]}"
  end

  if crop[:top]
    exps << "y=in_h*#{crop[:top]}"
  end

  if crop[:right] && crop[:left]
    fail Error, "Must specify two of {left, right, width} at most"  if crop[:width]
    crop[:width] = 1 - crop[:right] - crop[:left]
  elsif crop[:width]
    if !crop[:left] && crop[:right]
      crop[:left] = 1 - crop[:width] - crop[:right]
      exps << "x=in_w*#{crop[:left]}"
    end
  end
  exps << "w=in_w*#{crop[:width]}"

  if crop[:bottom] && crop[:top]
    fail Error, "Must specify two of {top, bottom, height} at most"  if crop[:height]
    crop[:height] = 1 - crop[:bottom] - crop[:top]
  elsif crop[:height]
    if !crop[:top] && crop[:bottom]
      crop[:top] = 1 - crop[:height] - crop[:bottom]
      exps << "y=in_h*#{crop[:top]}"
    end
  end
  exps << "h=in_h*#{crop[:height]}"

  exps
end

.fade_out_alpha(duration, input = nil, output = nil) ⇒ Object



66
67
68
# File 'lib/ffmprb/filter.rb', line 66

def fade_out_alpha(duration, input=nil, output=nil)
  inout "fade=out:d=%{duration}:alpha=1", input, output, duration: duration
end

.fps(fps, input = nil, output = nil) ⇒ Object



70
71
72
# File 'lib/ffmprb/filter.rb', line 70

def fps(fps, input=nil, output=nil)
  inout "fps=fps=%{fps}", input, output, fps: fps
end

.nullsink(input = nil) ⇒ Object

NOTE might be very useful with UGC: def cropdetect



141
142
143
# File 'lib/ffmprb/filter.rb', line 141

def nullsink(input=nil)
  inout "nullsink", input, nil
end

.overlay(x = 0, y = 0, inputs = nil, output = nil) ⇒ Object



145
146
147
# File 'lib/ffmprb/filter.rb', line 145

def overlay(x=0, y=0, inputs=nil, output=nil)
  inout "overlay=x=%{x}:y=%{y}:eof_action=pass", inputs, output, x: x, y: y
end

.pad(resolution, input = nil, output = nil) ⇒ Object



149
150
151
152
153
154
155
156
# File 'lib/ffmprb/filter.rb', line 149

def pad(resolution, input=nil, output=nil)
  width, height = resolution.to_s.split('x')
  inout [
    inout("pad=%{width}:%{height}:(%{width}-iw*min(%{width}/iw\\,%{height}/ih))/2:(%{height}-ih*min(%{width}/iw\\,%{height}/ih))/2",
      width: width, height: height),
    *setsar(1)  # NOTE the scale & pad formulae damage SAR a little, unfortunately
  ].join(', '), input, output
end

.scale(resolution, input = nil, output = nil) ⇒ Object



162
163
164
165
166
167
168
# File 'lib/ffmprb/filter.rb', line 162

def scale(resolution, input=nil, output=nil)
  width, height = resolution.to_s.split('x')
  inout [
    inout("scale=iw*min(%{width}/iw\\,%{height}/ih):ih*min(%{width}/iw\\,%{height}/ih)", width: width, height: height),
    *setsar(1)  # NOTE the scale & pad formulae damage SAR a little, unfortunately
  ].join(', '), input, output
end

.scale_pad(resolution, input = nil, output = nil) ⇒ Object



170
171
172
173
174
175
# File 'lib/ffmprb/filter.rb', line 170

def scale_pad(resolution, input=nil, output=nil)
  inout [
    *scale(resolution),
    *pad(resolution)
  ].join(', '), input, output
end

.scale_pad_fps(resolution, _fps, input = nil, output = nil) ⇒ Object



177
178
179
180
181
182
# File 'lib/ffmprb/filter.rb', line 177

def scale_pad_fps(resolution, _fps, input=nil, output=nil)
  inout [
    *scale_pad(resolution),
    *fps(_fps)
  ].join(', '), input, output
end

.setsar(ratio, input = nil, output = nil) ⇒ Object



158
159
160
# File 'lib/ffmprb/filter.rb', line 158

def setsar(ratio, input=nil, output=nil)
  inout "setsar=%{ratio}", input, output, ratio: ratio
end

.silencedetect(input = nil, output = nil) ⇒ Object



184
185
186
187
# File 'lib/ffmprb/filter.rb', line 184

def silencedetect(input=nil, output=nil)
  inout "silencedetect=d=1:n=%{silence_noise_max_db}dB", input, output,
    silence_noise_max_db: silence_noise_max_db
end

.silent_source(duration, output = nil) ⇒ Object



189
190
191
# File 'lib/ffmprb/filter.rb', line 189

def silent_source(duration, output=nil)
  inout "aevalsrc=0:d=%{duration}", nil, output, duration: duration
end

.split(inputs = nil, outputs = nil) ⇒ Object

NOTE might be very useful with transitions: def smartblur



195
196
197
# File 'lib/ffmprb/filter.rb', line 195

def split(inputs=nil, outputs=nil)
  inout "split", inputs, outputs
end

.trim(st, en = nil, input = nil, output = nil) ⇒ Object



226
227
228
229
# File 'lib/ffmprb/filter.rb', line 226

def trim(st, en=nil, input=nil, output=nil)
  inout "trim=%{start_end}, setpts=PTS-STARTPTS", input, output,
    start_end: [st, en].compact.join(':')
end

.volume(volume, input = nil, output = nil) ⇒ Object



231
232
233
234
# File 'lib/ffmprb/filter.rb', line 231

def volume(volume, input=nil, output=nil)
  inout "volume='%{volume_exp}':eval=frame", input, output,
    volume_exp: volume_exp(volume)
end

.volume_exp(volume) ⇒ Object



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/ffmprb/filter.rb', line 236

def volume_exp(volume)
  return volume  unless volume.is_a?(Hash)

  fail Error, "volume cannot be empty"  if volume.empty?

  prev_at = 0.0
  prev_vol = volume[prev_at] || 1.0
  exp = "#{volume[volume.keys.last]}"
  volume.each do |at, vol|
    vol_exp =
      if (vol - prev_vol).abs < 0.001
        vol
      else
        "(#{vol - prev_vol}*t + #{prev_vol*at - vol*prev_at})/#{at - prev_at}"
      end
    exp = "if(between(t, #{prev_at}, #{at}), #{vol_exp}, #{exp})"
    prev_at = at
    prev_vol = vol
  end
  exp
end

.white_source(duration, resolution, fps, output = nil) ⇒ Object



258
259
260
# File 'lib/ffmprb/filter.rb', line 258

def white_source(duration, resolution, fps, output=nil)
  color_source '0xFFFFFF@1', duration, resolution, fps, output
end