ffmprb 0.6.9 → 0.7.0

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 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