ffmprb 0.6.9 → 0.7.0

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: 3c63aad2be1497ee10ff566dafaa5a76f7e8cc87
4
- data.tar.gz: 0b6b1f15cd314f7b51fc7dbddb3b9c37f47dcdfe
3
+ metadata.gz: 0f8aefe1bb66a17ba85e93faf30b2ac540badee5
4
+ data.tar.gz: e3260e027699ad813154fc24c64049f42b39c114
5
5
  SHA512:
6
- metadata.gz: 183ba570ca74223f6f5974a969ff9f2bd74fe5a8a099e34b429901773d76d7757d8c58fb8666d9444abedc5539d978b98ef22fa1c534bb9b7ba43a14665a9701
7
- data.tar.gz: a9be63b31513b789f454931b0514c3b7601e01ac38ba71ee4a596cd82cab7b99b3547439303aace34595235e69b719550d3361830431d8091bb5df922a3c6e2b
6
+ metadata.gz: 430d988b9a2c68dbdbbe7d75f1e20d3e9c2a92c2f0f905b8c461005d5667a522e9830b1fba2f88a339b131b285765401fdc6bfdc15cd1088295a017f6859f62c
7
+ data.tar.gz: 0675dcaeabd664f44e497f72f96860437171661cae6250b223a9610105206e139c38f2b5b04a49fffd09ff0b886039d4754a47f27a31d32322418ce3e754ae4f
data/circle.yml ADDED
@@ -0,0 +1,3 @@
1
+ dependencies:
2
+ pre:
3
+ - sudo apt-add-repository -y ppa:oded-geek/multimedia; sudo apt-get update; sudo apt-get install ffmpeg
data/exe/ffmprb ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'rubygems'
5
+ gem 'ffmprb'
6
+ rescue LoadError
7
+ end
8
+
9
+ require 'ffmprb'
10
+
11
+ Ffmprb.execute
@@ -0,0 +1,23 @@
1
+ module Ffmprb
2
+
3
+ class Execution
4
+
5
+ def initialize(*params, script:)
6
+ @params = params
7
+ @script = eval("lambda{#{script}}")
8
+ end
9
+
10
+ def run
11
+ Ffmprb.process *@params, &@script
12
+ end
13
+
14
+ end
15
+
16
+ def self.execute
17
+ return STDERR.puts "Usage: (not quite usual) $ ffmprb streams... < script.ffmprb" unless
18
+ ARGV.length > 1 && ARGV.grep(/^-/).empty?
19
+
20
+ Execution.new(*ARGV, script: STDIN.read).run
21
+ end
22
+
23
+ end
data/lib/ffmprb/file.rb CHANGED
@@ -13,16 +13,9 @@ module Ffmprb
13
13
  output_fifo_file = temp_fifo(extname)
14
14
 
15
15
  Ffmprb.logger.debug "Opening #{input_fifo_file.path}>#{output_fifo_file.path} for buffering"
16
- buff = Util::IoBuffer.new(
17
- ->{
18
- Ffmprb.logger.debug "Trying to open #{input_fifo_file.path} for reading+buffering"
19
- ::File.open(input_fifo_file.path, 'r')
20
- },
21
- ->{
22
- Ffmprb.logger.debug "Trying to open #{output_fifo_file.path} for buffering+writing"
23
- ::File.open(output_fifo_file.path, 'w')
24
- }
25
- )
16
+ buff = Util::IoBuffer.new(async_opener(input_fifo_file, 'r'), async_opener(output_fifo_file, 'w'))
17
+
18
+ # NOTE the blocking cleanup thread to join for synchronisation
26
19
  thr = Util::Thread.new do
27
20
  buff.flush!
28
21
  Ffmprb.logger.debug "IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} ended"
@@ -31,7 +24,7 @@ module Ffmprb
31
24
  end
32
25
  Ffmprb.logger.debug "IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} started"
33
26
 
34
- yield buff if block_given? # XXX a hidden option
27
+ # XXX see io_buffer's XXX yield buff if block_given?
35
28
 
36
29
  OpenStruct.new in: input_fifo_file, out: output_fifo_file, thr: thr
37
30
  end
@@ -83,6 +76,15 @@ module Ffmprb
83
76
  ::File.join Dir.tmpdir, Dir::Tmpname.make_tmpname('', 'p' + extname)
84
77
  end
85
78
 
79
+ protected
80
+
81
+ def async_opener(file, mode)
82
+ ->{
83
+ Ffmprb.logger.debug "Trying to open #{file.path} for #{mode}-buffering"
84
+ ::File.open(file.path, mode)
85
+ }
86
+ end
87
+
86
88
  end
87
89
 
88
90
 
@@ -100,15 +102,35 @@ module Ffmprb
100
102
 
101
103
  # Info
102
104
 
105
+ def exist?
106
+ ::File.exist? path
107
+ end
108
+
103
109
  def extname
104
110
  ::File.extname path
105
111
  end
106
112
 
113
+ def channel?(medium)
114
+ case medium
115
+ when :video
116
+ image_extname? || movie_extname?
117
+ when :audio
118
+ sound_extname? || movie_extname?
119
+ end
120
+ end
121
+
107
122
  def length
108
- @duration ||= probe['format']['duration']
109
- return @duration.to_f if @duration
123
+ return @duration if @duration
124
+
125
+ # NOTE first attempt
126
+ @duration = probe['format']['duration']
127
+ @duration &&= @duration.to_f
128
+ return @duration if @duration
110
129
 
111
- @duration = probe(true)['frames'].reduce(0){|sum, frame| sum + frame['pkt_duration_time'].to_f}
130
+ # NOTE a harder try
131
+ @duration = probe(true)['frames'].reduce(0) do |sum, frame|
132
+ sum + frame['pkt_duration_time'].to_f
133
+ end
112
134
  end
113
135
 
114
136
  def resolution
@@ -127,9 +149,9 @@ module Ffmprb
127
149
 
128
150
  Ffmprb.logger.debug "Snap shooting files, video path: #{video ? video.path : 'NONE'}, audio path: #{audio ? audio.path : 'NONE'}"
129
151
 
130
- raise Error, "Incorrect output extname (must be .jpg)" unless !video || video.extname =~ /jpe?g$/
131
- raise Error, "Incorrect audio extname (must be .mp3)" unless !audio || audio.extname =~ /mp3$/
132
- raise Error, "Can sample either video OR audio UNLESS a block is given" unless block_given? || (!!audio != !!video)
152
+ raise Error, "Incorrect output extname (must be .jpg)" unless !video || video.channel?(:video) && !video.channel?(:audio)
153
+ raise Error, "Incorrect audio extname (must be .mp3)" unless !audio || audio.channel?(:audio) && !audio.channel?(:video)
154
+ raise Error, "Can sample either video OR audio UNLESS a block is given" unless block_given? || !!audio != !!video
133
155
 
134
156
  cmd = ['-i', path]
135
157
  cmd += ['-deinterlace', '-an', '-ss', at, '-r', 1, '-vcodec', 'mjpeg', '-f', 'mjpeg', video.path] if video
@@ -153,6 +175,13 @@ module Ffmprb
153
175
 
154
176
  # Manipulation
155
177
 
178
+ def read
179
+ ::File.read path
180
+ end
181
+ def write(s)
182
+ ::File.write path, s
183
+ end
184
+
156
185
  def remove
157
186
  FileUtils.remove_entry path
158
187
  Ffmprb.logger.debug "Removed file with path: #{path}"
@@ -170,15 +199,27 @@ module Ffmprb
170
199
  end
171
200
  end
172
201
 
173
- def probe(force=false)
174
- return @probe unless !@probe || force
202
+ def probe(harder=false)
203
+ return @probe unless !@probe || harder
175
204
  cmd = ['-v', 'quiet', '-i', path, '-print_format', 'json', '-show_format', '-show_streams']
176
- cmd << '-show_frames' if force
205
+ cmd << '-show_frames' if harder
177
206
  @probe = JSON.parse(Util::ffprobe *cmd).tap do |probe|
178
207
  raise Error, "This doesn't look like a ffprobable file" unless probe['streams']
179
208
  end
180
209
  end
181
210
 
211
+ def image_extname?
212
+ extname =~ /^\.(jpe?g|y4m)$/i
213
+ end
214
+
215
+ def sound_extname?
216
+ extname =~ /^\.(mp3|wav)$/i
217
+ end
218
+
219
+ def movie_extname?
220
+ extname =~ /^\.(mp4|flv)$/i
221
+ end
222
+
182
223
  end
183
224
 
184
225
  end
data/lib/ffmprb/filter.rb CHANGED
@@ -18,8 +18,7 @@ module Ffmprb
18
18
  inout "afade=out:d=#{duration}", input, output
19
19
  end
20
20
 
21
- # NOTE inputs order matters
22
- def amix(inputs, output=nil)
21
+ def amix_to_first(inputs, output=nil)
23
22
  inout "amix=#{[*inputs].length}:duration=first", inputs, output
24
23
  end
25
24
 
@@ -169,7 +168,7 @@ module Ffmprb
169
168
  filters.concat [
170
169
  *afade_out(blend_duration, "#{inputs.first}:a", "#{aux_lbl}:a"),
171
170
  *afade_in(blend_duration, "#{inputs.last}:a", "#{auxx_lbl}:a"),
172
- *amix(["#{auxx_lbl}:a", "#{aux_lbl}:a"], "#{output}:a")
171
+ *amix_to_first(["#{auxx_lbl}:a", "#{aux_lbl}:a"], "#{output}:a")
173
172
  ] if audio
174
173
  end
175
174
  end
@@ -182,8 +181,9 @@ module Ffmprb
182
181
  inout "volume='#{volume_exp volume}':eval=frame", input, output
183
182
  end
184
183
 
185
- def volume_exp(volume) # NOTE volume is an ordered Hash
186
- return volume unless volume.respond_to?(:each)
184
+ def volume_exp(volume)
185
+ return volume unless volume.is_a?(Hash)
186
+
187
187
  raise Error, "volume cannot be empty" if volume.empty?
188
188
 
189
189
  prev_at = 0.0
@@ -0,0 +1,29 @@
1
+ module Ffmprb
2
+
3
+ def self.find_silence(input_file, output_file)
4
+ logger.debug "Finding silence (#{input_file.path}->#{output_file.path})"
5
+ filters = Filter.silencedetect
6
+ options = ['-i', input_file.path, *Filter.complex_options(filters), output_file.path]
7
+ silence = []
8
+ Util.ffmpeg(*options).split("\n").each do |line|
9
+ next unless line =~ /^\[silencedetect\s.*\]\s*silence_(\w+):\s*(\d+\.?d*)/
10
+ case $1
11
+ when 'start'
12
+ silence << OpenStruct.new(start_at: $2.to_f)
13
+ when 'end'
14
+ if silence.empty?
15
+ silence << OpenStruct.new(start_at: 0.0, end_at: $2.to_f)
16
+ else
17
+ raise Error, "ffmpeg is being stupid: silence_end with no silence_start" if silence.last.end_at
18
+ silence.last.end_at = $2.to_f
19
+ end
20
+ else
21
+ Ffmprb.warn "Unknown silence mark: #{$1}"
22
+ end
23
+ end
24
+
25
+ logger.debug "Found silence (#{input_file.path}->#{output_file.path}): [#{silence.map{|t,v| "#{t}: #{v}"}}]"
26
+ silence
27
+ end
28
+
29
+ end
@@ -105,12 +105,11 @@ module Ffmprb
105
105
 
106
106
 
107
107
  def initialize(io, only: nil)
108
- @io = io
108
+ @io = resolve(io)
109
109
  @channels = [*only]
110
110
  @channels = nil if @channels.empty?
111
111
  raise Error, "Inadequate A/V channels" if
112
- @io.respond_to?(:channel?) &&
113
- [:video, :audio].any?{|medium| !@io.channel?(medium) && channel?(medium, true)}
112
+ [:video, :audio].any?{|medium| !@io.channel?(medium) && channel?(medium, true)}
114
113
  end
115
114
 
116
115
  def options
@@ -121,7 +120,7 @@ module Ffmprb
121
120
 
122
121
  # Channelling
123
122
 
124
- if @io.respond_to?(:filters_for) # NOTE assuming @io.respond_to?(:channel?)
123
+ if @io.respond_to?(:filters_for)
125
124
  lbl_aux = "au#{lbl}"
126
125
  @io.filters_for(lbl_aux, process: process, video: video, audio: audio) +
127
126
  [
@@ -136,8 +135,8 @@ module Ffmprb
136
135
  in_lbl = process[self]
137
136
  raise Error, "Data corruption" unless in_lbl
138
137
  [
139
- *(video && channel?(:video)? Filter.copy("#{in_lbl}:v", "#{lbl}:v"): nil),
140
- *(audio && channel?(:audio)? Filter.anull("#{in_lbl}:a", "#{lbl}:a"): nil)
138
+ *(video && @io.channel?(:video) && channel?(:video)? Filter.copy("#{in_lbl}:v", "#{lbl}:v"): nil),
139
+ *(audio && @io.channel?(:audio) && channel?(:audio)? Filter.anull("#{in_lbl}:a", "#{lbl}:a"): nil)
141
140
  ]
142
141
  end
143
142
  end
@@ -162,13 +161,23 @@ module Ffmprb
162
161
  Loud.new self, volume: vol
163
162
  end
164
163
 
165
- # XXX? protected
166
-
167
164
  def channel?(medium, force=false)
168
- return @channels && @channels.include?(medium) if force
165
+ return !!@channels && @channels.include?(medium) && @io.channel?(medium) if force
166
+
167
+ (!@channels || @channels.include?(medium)) && @io.channel?(medium)
168
+ end
169
+
170
+ protected
169
171
 
170
- (!@channels || @channels.include?(medium)) &&
171
- (!@io.respond_to?(:channel?) || @io.channel?(medium))
172
+ def resolve(io)
173
+ return io unless io.is_a? String
174
+
175
+ case io
176
+ when /^\/\w/
177
+ File.open io
178
+ else
179
+ raise Error, "Cannot resolve input: #{io}"
180
+ end
172
181
  end
173
182
 
174
183
  end
@@ -5,13 +5,15 @@ module Ffmprb
5
5
  class Output
6
6
 
7
7
  def initialize(io, only: nil, resolution: Ffmprb::QVGA, fps: 30)
8
- @io = io
8
+ @io = resolve(io)
9
9
  @channels = [*only]
10
10
  @channels = nil if @channels.empty?
11
11
  @resolution = resolution
12
12
  @fps = 30
13
13
  end
14
14
 
15
+ # XXX This method is exceptionally long at the moment. This is not too grand.
16
+ # However, structuring the code should be undertaken with care, as not to harm the composition clarity.
15
17
  def options(process)
16
18
  # XXX TODO manage stream labels through process
17
19
  raise Error, "Nothing to roll..." if @reels.select(&:reel).empty?
@@ -21,7 +23,6 @@ module Ffmprb
21
23
 
22
24
  # Concatting
23
25
  segments = []
24
- Ffmprb.logger.debug "Concatting segments: start"
25
26
 
26
27
  @reels.each_with_index do |curr_reel, i|
27
28
 
@@ -55,7 +56,6 @@ module Ffmprb
55
56
  # NOTE make sure previous reel rolls _long_ enough AND then _just_ enough
56
57
 
57
58
  prev_lbl = segments.pop
58
- Ffmprb.logger.debug "Concatting segments: #{prev_lbl} popped"
59
59
 
60
60
  lbl_pad = "bl#{prev_lbl}#{i}"
61
61
  # NOTE generously padding the previous segment to support for all the cases
@@ -141,7 +141,6 @@ module Ffmprb
141
141
  end
142
142
 
143
143
  segments << lbl # NOTE can be nil
144
- Ffmprb.logger.debug "Concatting segments: #{lbl} pushed"
145
144
  end
146
145
 
147
146
  segments.compact!
@@ -174,7 +173,7 @@ module Ffmprb
174
173
  filters +=
175
174
  Filter.copy("#{lbl_out}:v", "#{lbl_nxt}:v") if channel?(:video)
176
175
  filters +=
177
- Filter.amix(["#{lbl_out}:a", "#{lbl_over}:a"], "#{lbl_nxt}:a") if channel?(:audio)
176
+ Filter.amix_to_first(["#{lbl_out}:a", "#{lbl_over}:a"], "#{lbl_nxt}:a") if channel?(:audio)
178
177
 
179
178
  lbl_out = lbl_nxt
180
179
  end
@@ -281,15 +280,28 @@ module Ffmprb
281
280
  add_reel reel, after, transition, (onto == :full_screen)
282
281
  end
283
282
 
284
- # XXX? protected
285
-
286
283
  def channel?(medium, force=false)
287
- return @channels && @channels.include?(medium) if force
284
+ return !!@channels && @channels.include?(medium) && @io.channel?(medium) if force
288
285
 
289
- (!@channels || @channels.include?(medium)) &&
286
+ (!@channels || @channels.include?(medium)) && @io.channel?(medium) &&
290
287
  reels_channel?(medium)
291
288
  end
292
289
 
290
+ protected
291
+
292
+ def resolve(io)
293
+ return io unless io.is_a? String
294
+
295
+ case io
296
+ when /^\/\w/
297
+ File.create(io).tap do |file|
298
+ Ffmprb.logger.warn "Output file exists (#{file.path}), will overwrite" if file.exist?
299
+ end
300
+ else
301
+ raise Error, "Cannot resolve output: #{io}"
302
+ end
303
+ end
304
+
293
305
  private
294
306
 
295
307
  def reels_channel?(medium)
@@ -70,6 +70,8 @@ module Ffmprb
70
70
  while s = @q.deq
71
71
  next if broken
72
72
  written = 0
73
+ tries = 1
74
+ logged_tries = 1/2
73
75
  while !broken
74
76
  raise @terminate if @terminate.kind_of?(Exception)
75
77
  begin
@@ -77,15 +79,17 @@ module Ffmprb
77
79
  written = output.write_nonblock(s) if output # NOTE will only be nil if @terminate is an exception
78
80
  break if written == s.length # NOTE kinda optimisation
79
81
  s = s[written..-1]
80
- rescue Errno::EAGAIN
81
- Ffmprb.logger.debug "IoBuffer writer (to #{output.path}) retrying"
82
- sleep 0.01
83
- rescue Errno::EWOULDBLOCK
84
- Ffmprb.logger.debug "IoBuffer writer (to #{output.path}) taking a break"
82
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK
83
+ if tries == 2 * logged_tries
84
+ Ffmprb.logger.debug "IoBuffer writer (to #{output.path}) retrying... (#{tries} writes): #{$!.class}"
85
+ logged_tries = tries
86
+ end
85
87
  sleep 0.01
86
88
  rescue Errno::EPIPE
87
89
  broken = true
88
90
  Ffmprb.logger.debug "IoBuffer writer (to #{output.path}) broken"
91
+ ensure
92
+ tries += 1
89
93
  end
90
94
  end
91
95
  end
@@ -187,14 +191,21 @@ module Ffmprb
187
191
 
188
192
  @output_thr = Util::Thread.new("buffer writer output helper") do
189
193
  Ffmprb.logger.debug "Opening buffer output"
194
+ tries = 1
195
+ logged_tries = 1/2
190
196
  begin
191
197
  Timeout::timeout(self.class.timeout/2) do
192
198
  @output = @output.call
193
199
  Ffmprb.logger.debug "Opened buffer output: #{@output.path}"
194
200
  end
195
201
  rescue Timeout::Error
196
- Ffmprb.logger.info "A little bit of timeout in the buffer writer helper thread"
202
+ if tries == 2 * logged_tries
203
+ Ffmprb.logger.info "A little bit of timeout in the buffer writer helper thread (##{tries})"
204
+ logged_tries = tries
205
+ end
197
206
  retry unless @terminate.kind_of?(Exception)
207
+ ensure
208
+ tries += 1
198
209
  end
199
210
  end
200
211
  end
data/lib/ffmprb/util.rb CHANGED
@@ -13,12 +13,12 @@ module Ffmprb
13
13
  attr_accessor :ffmpeg_cmd, :ffprobe_cmd
14
14
 
15
15
  def ffprobe(*args)
16
- sh ffprobe_cmd, *args
16
+ sh *ffprobe_cmd, *args
17
17
  end
18
18
 
19
19
  def ffmpeg(*args)
20
20
  args = ['-loglevel', 'debug'] + args if Ffmprb.debug
21
- sh ffmpeg_cmd, '-y', *args, output: :stderr
21
+ sh *ffmpeg_cmd, '-y', *args, output: :stderr
22
22
  end
23
23
 
24
24
  def sh(*cmd, output: :stdout, log: :stderr)
@@ -1,3 +1,3 @@
1
1
  module Ffmprb
2
- VERSION = "0.6.9"
2
+ VERSION = "0.7.0"
3
3
  end
data/lib/ffmprb.rb CHANGED
@@ -1,12 +1,12 @@
1
+ require 'ffmprb/execution'
1
2
  require 'ffmprb/file'
2
3
  require 'ffmprb/filter'
4
+ require 'ffmprb/find_silence'
3
5
  require 'ffmprb/process'
4
6
  require 'ffmprb/util'
5
7
  require 'ffmprb/version'
6
8
 
7
9
  require 'logger'
8
- require 'time'
9
- require 'timeout'
10
10
 
11
11
  module Ffmprb
12
12
 
@@ -19,8 +19,8 @@ module Ffmprb
19
19
  class Error < StandardError
20
20
  end
21
21
 
22
- Util.ffmpeg_cmd = 'ffmpeg'
23
- Util.ffprobe_cmd = 'ffprobe'
22
+ Util.ffmpeg_cmd = ['ffmpeg']
23
+ Util.ffprobe_cmd = ['ffprobe']
24
24
 
25
25
  Process.duck_audio_hi = 0.9
26
26
  Process.duck_audio_lo = 0.1
@@ -34,14 +34,18 @@ module Ffmprb
34
34
 
35
35
  class << self
36
36
 
37
+ # NOTE the form with the block returns the result of #run
38
+ # NOTE the form without the block returns the process (before it is run)
37
39
  def process(*args, &blk)
38
40
  logger.debug "Starting process with #{args} in #{blk.source_location}"
39
- Process.new.tap do |process|
40
- if blk
41
- process.instance_exec *args, &blk
42
- process.run
43
- logger.debug "Finished process with #{args} in #{blk.source_location}"
44
- end
41
+ process = Process.new
42
+ return process unless blk
43
+
44
+ process.instance_exec *args, &blk
45
+ logger.debug "Initialized process with #{args} in #{blk.source_location}"
46
+
47
+ process.run.tap do
48
+ logger.debug "Finished process with #{args} in #{blk.source_location}"
45
49
  end
46
50
  end
47
51
  alias :action! :process # ;)
@@ -59,32 +63,6 @@ module Ffmprb
59
63
  @logger = logger
60
64
  end
61
65
 
62
- def find_silence(input_file, output_file)
63
- logger.debug "Finding silence (#{input_file.path}->#{output_file.path})"
64
- filters = Filter.silencedetect
65
- options = ['-i', input_file.path, *Filter.complex_options(filters), output_file.path]
66
- silence = []
67
- Util.ffmpeg(*options).split("\n").each do |line|
68
- next unless line =~ /^\[silencedetect\s.*\]\s*silence_(\w+):\s*(\d+\.?d*)/
69
- case $1
70
- when 'start'
71
- silence << OpenStruct.new(start_at: $2.to_f)
72
- when 'end'
73
- if silence.empty?
74
- silence << OpenStruct.new(start_at: 0.0, end_at: $2.to_f)
75
- else
76
- raise Error, "ffmpeg is being stupid: silence_end with no silence_start" if silence.last.end_at
77
- silence.last.end_at = $2.to_f
78
- end
79
- else
80
- Ffmprb.warn "Unknown silence mark: #{$1}"
81
- end
82
- end
83
-
84
- logger.debug "Found silence (#{input_file.path}->#{output_file.path}): [#{silence.map{|t,v| "#{t}: #{v}"}}]"
85
- silence
86
- end
87
-
88
66
  end
89
67
 
90
68
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffmprb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.9
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - showbox.com
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2015-07-26 00:00:00.000000000 Z
12
+ date: 2015-07-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mkfifo
@@ -126,7 +126,8 @@ dependencies:
126
126
  description: A DSL (Damn-Simple Language) and a micro-engine for ffmpeg and ffriends
127
127
  email:
128
128
  - costa@showbox.com
129
- executables: []
129
+ executables:
130
+ - ffmprb
130
131
  extensions: []
131
132
  extra_rdoc_files: []
132
133
  files:
@@ -143,10 +144,14 @@ files:
143
144
  - bin/rake
144
145
  - bin/rspec
145
146
  - bin/setup
147
+ - circle.yml
148
+ - exe/ffmprb
146
149
  - ffmprb.gemspec
147
150
  - lib/ffmprb.rb
151
+ - lib/ffmprb/execution.rb
148
152
  - lib/ffmprb/file.rb
149
153
  - lib/ffmprb/filter.rb
154
+ - lib/ffmprb/find_silence.rb
150
155
  - lib/ffmprb/process.rb
151
156
  - lib/ffmprb/process/input.rb
152
157
  - lib/ffmprb/process/output.rb