ffmprb 0.12.1 → 0.12.2

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.
@@ -1,3 +1,93 @@
1
+
2
+ # The general idea of (a video production pipeline for) "vlogging":
3
+ # -1. think of something nice to shoot
4
+ # - maybe even write down a scenario and produce "the picture"
5
+ # 0. shoot the damn footage with your cam/mic/what-have-you
6
+ # - press Record on your GoPro (video stored on device)
7
+ # 1. upload the raw media files to a (cloud) storage
8
+ # - GoPro media storage subscription (video files accessible at)
9
+ # 2. take note of, sort and clean the raw footage up manually
10
+ # - cut and concatenate the media files into cohesive "scenes" (ffmprb script)
11
+ # 3. upload the HD renders of the raw scenes
12
+ # - to a "cache" storage (ghlr media), plus, for the public access (YouTube)
13
+ # 4. compose a video from the raw scene cuts and additional media
14
+ # - create a (ffmprb) montage script using the media
15
+ # 5. upload and premiere the video piece versions (final cut, general public)
16
+ # - to "ghlr media sharing" (fut.), plus, for public "discovery" (YouTube)
17
+ # 6. profit?
18
+
19
+ # # empty (micro) case is raw publish
20
+
21
+ # NOTE on simprender:
22
+ # a title-back-summary effect
23
+ # XXX
24
+ # -16(2) -8(2) -4(2) ^0 2(2), -4(1) [1]
25
+ # crop
26
+ # ?soundtrack?
27
+ # cut(from 24, to: 56).pace(16).reverse
28
+ # cut(from 8, to: 24).pace(8).reverse
29
+ # cut(from 0, to: 8).pace(4).reverse
30
+ # cut(from: 0, to: 4).pace(2)
31
+ # cut(from: 0, to: 4).pace(4).reverse
32
+ #
33
+ # 2.0
34
+ # crop(0.48).cut(from: M).pace(m).reverse
35
+ # ...
36
+ # crop(0.2).cut(from: 12, to: 28).pace(16).reverse
37
+ # crop(0.18).cut(from: 4, to: 12).pace(8).reverse
38
+ # crop(0.15).cut(from: 0, to: 4).pace(4).reverse
39
+ # crop(0.1).cut(from: 0, to: 4).pace(2)
40
+ # crop(0.05).cut(from: 0, to: 4).pace(4).reverse
41
+ #
42
+ # 3.0 (aka 1.11)
43
+ # crop(0.49).cut(from: M).pace(m).reverse
44
+ # ...
45
+ # crop(0.2).cut(from: 12, to: 28).pace(16).reverse
46
+ # crop(0.25).cut(from: 4, to: 12).pace(8).reverse
47
+ # crop(0.14).cut(from: 0, to: 4).pace(4).reverse
48
+
49
+ # NOTE looking good?
50
+ REV_CUT_CROP_EXP_BASE = 1.333
51
+
52
+ # NOTE unreasonable to exhaust
53
+ REV_CUT_CROP_EXP_PRE_CUTS =
54
+ (2..64).reduce [] do |a, k|
55
+ if (3.6..3600.0).include? (int = REV_CUT_CROP_EXP_BASE**k)
56
+ a << (a[-1] || 0) + int
57
+ else
58
+ a
59
+ end
60
+ end.reverse
61
+
62
+ # NOTE reasonable to look good
63
+ REV_CUT_CROP_LENGTH_MIN_S = REV_CUT_CROP_EXP_PRE_CUTS[-4]
64
+
65
+ # XXX Can also go hard on with blending to complement the rewind effect...
66
+
67
+ def rev_cut_crop_seq(length, inp)
68
+ fail "supply a block that receives the next reel and returns the next input" unless
69
+ block_given?
70
+
71
+ return unless
72
+ length > REV_CUT_CROP_LENGTH_MIN_S
73
+
74
+ REV_CUT_CROP_EXP_PRE_CUTS.each_with_index do |k, i|
75
+ next if
76
+ (n = REV_CUT_CROP_EXP_PRE_CUTS[i + 1] || 0) > length
77
+ cut = {from: n}
78
+ cut[:to] = k unless
79
+ k > length
80
+ pace = REV_CUT_CROP_EXP_BASE**(REV_CUT_CROP_EXP_PRE_CUTS.length - i + 1)
81
+ # XXX Math.log(1 + (REV_CUT_CROP_EXP_PRE_CUTS.length - i + 2) / 5.0) / 4 # NOTE magick!
82
+ crop = 0.5*(1 - Math.sqrt(1/pace)) # NOTE bitrate! (x2)
83
+ # inp = yield(inp.crop(crop).cut(cut).pace(pace).reverse)
84
+ yield inp.crop(crop).cut(cut).pace(pace).reverse
85
+ end
86
+ # XXX
87
+ # inp = yield(inp.crop(0.1).cut(from: 0, to: 4).pace(2))
88
+ # inp = yield(inp.crop(0.05).cut(from: 0, to: 4).pace(4).reverse)
89
+ end
90
+
1
91
  channel = ARGV.shift || 'default'
2
92
 
3
93
  abort "USAGE: gop-raw-cut-you-HD60.rb [CHANNEL]" unless
@@ -6,8 +96,8 @@ abort "USAGE: gop-raw-cut-you-HD60.rb [CHANNEL]" unless
6
96
  MEDIA_DIR = ENV['MEDIA_DIR'] or
7
97
  abort "MEDIA_DIR needed"
8
98
 
9
- time_s = Time.now.strftime('%y-%m-%d-%H-%M')
10
- title = "Topublish uploaded at #{time_s}"
99
+ now_time = Time.now
100
+ title = "XXX Topublish (uploaded at #{now_time.strftime '%y-%m-%d-%H-%M'})"
11
101
 
12
102
  require 'cgi'
13
103
 
@@ -26,14 +116,16 @@ end
26
116
  require 'fileutils'
27
117
 
28
118
  require 'ffmprb'
29
- # Ffmprb.debug = true # XXX
119
+ Ffmprb.debug = true # XXX
30
120
  Ffmprb::Util::Thread.timeout = 150
31
121
 
32
122
  int_video_opt = {resolution: Ffmprb::HD_4K, fps: 60}
33
- fin_video_opt = {resolution: Ffmprb::HD_1080p, fps: 60, encoder: 'libx264 -crf 31'} # XXX -preset veryslow
34
- YOU_VIDEO_OPT = {resolution: Ffmprb::HD_4K, fps: 60, encoder: 'libx264'}
123
+ raw_video_opt = {resolution: Ffmprb::HD_4K, fps: 60, encoder: 'libx264 -crf 15'} # XXX -preset superfast
124
+ fin_video_opt = {resolution: Ffmprb::HD_1080p, fps: 60, encoder: 'libx265 -crf 19'} # XXX 21 -preset veryslow
125
+ YOU_VIDEO_OPT = {resolution: Ffmprb::HD_4K, fps: 60, encoder: 'libx264 -crf 17'} # XXX 15 -preset superfast
35
126
 
36
- GOP_MP4_RE = /\b(GX(\d\d)(\d\d\d\d)\.MP4)\b/i
127
+ GOP_FILE_PREFIX = 'GX'
128
+ GOP_MP4_RE = /\b(#{GOP_FILE_PREFIX}(\d\d)(\d\d\d\d)\.MP4)\b/i
37
129
  GOP_ZIP_URL_RE = %r[/zip/]i
38
130
 
39
131
 
@@ -43,10 +135,11 @@ def dura_to_sec(dura_str)
43
135
  end
44
136
  end
45
137
 
46
- def out_path(name)
47
- File.join MEDIA_DIR, "#{name}.mp4"
138
+ def date_media_path(date, name)
139
+ File.join MEDIA_DIR, '%04d' % date.year, '%02d' % date.month, '%02d' % date.day, "#{name}.mp4"
48
140
  end
49
141
 
142
+ raw_time = nil
50
143
 
51
144
  FileUtils.mkdir_p (tmp_dir = File.join(MEDIA_DIR, 'gop-raw-cut-you-tmp'))
52
145
  begin
@@ -56,12 +149,13 @@ begin
56
149
  warn "\nEnter lines containing GoP media D/L URLs and cut times:\n\n"
57
150
 
58
151
  av_src_cuts = []
152
+ int_av_path = nil
59
153
  dl_q = Queue.new
60
154
 
61
- shots = []
62
155
  fetcher = Thread.new do
63
156
  while (url, cuts = dl_q.deq)
64
157
  srcs = []
158
+ shot = nil
65
159
  while srcs.empty? # NOTE sometimes (zip) D/L silently fails, see below
66
160
  name =
67
161
  case CGI.unescape url
@@ -80,16 +174,28 @@ begin
80
174
  zip_lines.each do |line|
81
175
  if line =~ GOP_MP4_RE
82
176
  srcs << $1
83
- shots << $3
177
+ shot = $3
84
178
  end
85
179
  end
86
180
  end
87
181
  File.delete name
88
182
  else
89
183
  srcs << name
90
- shots << $3
184
+ shot = $3
91
185
  end
92
186
  end
187
+
188
+ # NOTE assuming srcs is not empty, for the first src
189
+ unless raw_time
190
+ raw_time =
191
+ Ffmprb::File.access(srcs[0]).creation_time ||
192
+ now_time # NOTE well...
193
+ int_av_path = date_media_path(raw_time, "#{GOP_FILE_PREFIX}-#{shot}")
194
+ # XXX
195
+ # break if
196
+ # (Ffmprb::File.access(int_av_path).length rescue 0) > 0
197
+ end
198
+
93
199
  av_src_cuts << [
94
200
  srcs.sort do |a, b|
95
201
  a_m = GOP_MP4_RE.match(a)
@@ -103,6 +209,9 @@ begin
103
209
  cuts
104
210
  ]
105
211
  end
212
+
213
+ abort "ERROR no inputs given" unless
214
+ int_av_path
106
215
  end
107
216
 
108
217
  while (url_cut = gets)
@@ -123,20 +232,17 @@ begin
123
232
  warn "\nFetching those files..."
124
233
  fetcher.join
125
234
 
126
- abort "ERROR no inputs given" if
127
- av_src_cuts.empty?
128
-
129
- out_name = "GX-#{shots.uniq.join '-'}-#{time_s}"
130
- you_out_path = "_you_#{out_name}.mp4"
131
- warn "\nCut-catting to out (#{out_name}) paths + you..."
235
+ out_path = date_media_path(now_time, "#{GOP_FILE_PREFIX}-#{raw_time.strftime '%y-%m-%d-%H-%M'}-simprender")
236
+ you_out_path = "_you_toul.mp4"
237
+ warn "\nCut-catting to cache (#{int_av_path})"
132
238
 
133
239
  pipe_cut_threads = av_src_cuts.map do |srcs, cuts|
134
240
  [
135
- (av_pipe = Ffmprb::File.temp_fifo('.flv')),
241
+ (tmp_av_stream = Ffmprb::File.temp_fifo('.flv')),
136
242
  cuts.each_slice(2).map { |from, to| {from: from, to: to} },
137
243
  Thread.new do
138
244
  Ffmprb.process do
139
- output av_pipe, video: int_video_opt do
245
+ output tmp_av_stream, video: int_video_opt do
140
246
  srcs.each do |src|
141
247
  roll input src
142
248
  end
@@ -146,47 +252,80 @@ begin
146
252
  ]
147
253
  end
148
254
 
149
- Ffmprb::File.temp_fifo('.flv') do |av_pipe|
255
+ Ffmprb::File.temp_fifo('.flv') do |av_stream|
150
256
  thr = Thread.new do
151
- Ffmprb.process do
152
- inp_cut_opts =
153
- pipe_cut_threads.map do |av_pipe, cut_opts, _|
154
- (cut_opts.empty?? [{}] : cut_opts).map do |cut_opt|
155
- [input(av_pipe), cut_opt]
156
- end
157
- end.reduce :+
158
- output av_pipe, video: YOU_VIDEO_OPT do
159
- inp_cut_opts.each do |inp, cut_opt|
160
- roll inp.cut cut_opt
257
+ unless pipe_cut_threads.empty?
258
+ FileUtils.mkdir_p File.dirname int_av_path
259
+ Ffmprb.process do
260
+ inp_cut_opts =
261
+ pipe_cut_threads.map do |tmp_av_stream, cut_opts, _|
262
+ (cut_opts.empty?? [{}] : cut_opts).map do |cut_opt|
263
+ [input(tmp_av_stream), cut_opt]
264
+ end
265
+ end.reduce :+
266
+ # XXX output int_av_path, video: raw_video_opt do
267
+ output av_stream, video: raw_video_opt do
268
+ inp_cut_opts.each do |inp, cut_opt|
269
+ roll inp.cut cut_opt
270
+ end
161
271
  end
162
272
  end
163
- # [Rational(1)/8, Rational(1)/4, Rational(1)/2, 1, 2, 4, 8].each do |r| # XXX
164
- # output out_path("#{out_name}x#{r.to_f}"), video: fin_video_opt do
165
- # inp_cut_opts.each do |inp, cut_opt|
166
- # roll inp.cut(cut_opt).pace r
167
- # end
168
- # end
169
- # end
170
273
 
171
- # XXX
172
- # output out_path("#{out_name}x-8"), video: fin_video_opt do
173
- # inp_cut_opts.each do |inp, cut_opt|
174
- # roll inp.cut(cut_opt).reverse.pace 8
175
- # end
176
- # end
177
- # output out_path("#{out_name}x8-"), video: fin_video_opt do
178
- # inp_cut_opts.each do |inp, cut_opt|
179
- # roll inp.cut(cut_opt).pace(8).reverse
180
- # end
181
- # end
274
+ # XXX this is flawed:
275
+ # the simple threads fail because of oom docker signals (9)
276
+ # (not because of broken pipes)
277
+ pipe_cut_threads.each do |tmp_av_stream, _, thr|
278
+ begin
279
+ thr.join
280
+ rescue
281
+ warn "WARN errors-a-happening: #{$!}"
282
+ end
283
+ tmp_av_stream.unlink
284
+ end
182
285
  end
286
+
287
+ # XXX
288
+ # warn "\nComposing and rendering to out (#{out_path}) + you..."
289
+ # Ffmprb.process do
290
+ # output av_stream, video: int_video_opt do
291
+ # # XXX roll in1.crop(0.25).cut(from: Ffmprb::File.access(int_av_path).length - 512).pace(16).reverse
292
+
293
+ # rev_cut_crop_seq(Ffmprb::File.access(int_av_path).length, input(int_av_path)) do |reel|
294
+ # roll reel
295
+ # end
296
+ # roll input(int_av_path)
297
+ # end
298
+ # end
299
+ # [Rational(1)/8, Rational(1)/4, Rational(1)/2, 1, 2, 4, 8].each do |r| # XXX
300
+ # output out_path("#{out_name}x#{r.to_f}"), video: fin_video_opt do
301
+ # inp_cut_opts.each do |inp, cut_opt|
302
+ # roll inp.cut(cut_opt).pace r
303
+ # end
304
+ # end
305
+ # end
306
+
307
+ # XXX
308
+ # output out_path("#{out_name}x-8"), video: fin_video_opt do
309
+ # inp_cut_opts.each do |inp, cut_opt|
310
+ # roll inp.cut(cut_opt).reverse.pace 8
311
+ # end
312
+ # end
313
+ # output out_path("#{out_name}x8-"), video: fin_video_opt do
314
+ # inp_cut_opts.each do |inp, cut_opt|
315
+ # roll inp.cut(cut_opt).pace(8).reverse
316
+ # end
317
+ # end
183
318
  end
319
+ # XXX bad romance: abort from any thread
184
320
  begin
321
+ FileUtils.mkdir_p File.dirname out_path
185
322
  Ffmprb.process do
186
- in1 = input(av_pipe)
323
+ in1 = input(av_stream)
187
324
  output you_out_path, video: YOU_VIDEO_OPT do
188
- roll in1.pace(16).reverse
189
- roll in1.pp
325
+ roll in1
326
+ end
327
+ output out_path, video: fin_video_opt do
328
+ roll in1 # XXX .pp
190
329
  end
191
330
  end
192
331
  ensure
@@ -195,18 +334,6 @@ begin
195
334
  end
196
335
 
197
336
 
198
- # XXX this is flawed:
199
- # the simple threads fail because of oom docker signals (9)
200
- # (not because of broken pipes)
201
- pipe_cut_threads.each do |av_pipe, _, thr|
202
- begin
203
- thr.join
204
- rescue
205
- warn "WARN errors-a-happening: #{$!}"
206
- end
207
- av_pipe.unlink
208
- end
209
-
210
337
  metadata = {
211
338
  snippet: {
212
339
  title: title
data/lib/defaults.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Ffmprb
2
2
 
3
3
  File.image_extname_regex = /^\.(jpe?g|a?png|y4m)$/i
4
- File.sound_extname_regex = /^\.(mp3|wav)$/i
4
+ File.sound_extname_regex = /^\.(mp3|wav|m4a)$/i
5
5
  File.movie_extname_regex = /^\.(mp4|flv|mov)$/i
6
6
 
7
7
  Filter.silence_noise_max_db = -40
data/lib/ffmprb/file.rb CHANGED
@@ -95,7 +95,8 @@ module Ffmprb
95
95
 
96
96
  def initialize(path:, mode:)
97
97
  @mode = mode.to_sym
98
- fail Error, "Open for read, create for write, ??? for #{@mode}" unless %i[read write].include?(@mode)
98
+ fail Error, "Open for read, create for write, ??? for #{@mode}" unless
99
+ %i[read write].include?(@mode)
99
100
  @path = path
100
101
  @path.close if @path && @path.respond_to?(:close) # NOTE we operate on closed files
101
102
  path! # NOTE early (exception) raiser
@@ -147,11 +148,20 @@ module Ffmprb
147
148
  end
148
149
  end
149
150
 
150
- def resolution
151
- v_stream = probe['streams'].first
151
+ def resolution(force=false)
152
+ v_stream = probe(force)['streams'].first
152
153
  "#{v_stream['width']}x#{v_stream['height']}"
153
154
  end
154
155
 
156
+ def fps(force=false)
157
+ v_stream = probe(force)['streams'].first
158
+ Rational v_stream['r_frame_rate'] || v_stream['avg_frame_rate']
159
+ end
160
+
161
+ def creation_time(force=false)
162
+ Time.parse probe(force)['format']['tags']['creation_time']
163
+ end
164
+
155
165
 
156
166
  # Manipulation
157
167
 
@@ -191,9 +201,7 @@ module Ffmprb
191
201
  fail Error, "This doesn't look like a ffprobable file" unless probe['streams']
192
202
  end
193
203
  end
194
-
195
204
  end
196
-
197
205
  end
198
206
 
199
207
  require_relative 'file/sample'
data/lib/ffmprb/filter.rb CHANGED
@@ -49,6 +49,7 @@ module Ffmprb
49
49
  inout 'asplit', inputs, outputs
50
50
  end
51
51
 
52
+ # TODO? fix "Queue input is backward in time"
52
53
  def areverse(input=nil, output=nil)
53
54
  inout 'areverse', input, output
54
55
  end
@@ -184,7 +185,7 @@ module Ffmprb
184
185
  inout 'fps=fps=%{fps}', input, output, fps: fps
185
186
  end
186
187
 
187
- def interpolate_v(fps, input=nil, output=nil)
188
+ def framerate(fps, input=nil, output=nil)
188
189
  inout 'framerate=fps=%{fps}', input, output, fps: fps
189
190
  end
190
191
  # TODO other effects like... minterpolate=fps=%{fps}:mi_mode=mci:mc_mode=aobmc:vsbmc=1
@@ -220,8 +221,11 @@ module Ffmprb
220
221
  inout 'setsar=%{ratio}', input, output, ratio: ratio
221
222
  end
222
223
 
223
- def setpts(ratio, input=nil, output=nil)
224
- inout 'setpts=%{r_fps}*PTS', input, output, r_fps: 1.0/ratio
224
+ def setpts_framerate(ratio, fps, input=nil, output=nil)
225
+ inout [
226
+ inout('setpts=%{r_fps}*PTS', r_fps: 1.0/ratio),
227
+ *framerate(fps),
228
+ ].join(', '), input, output
225
229
  end
226
230
 
227
231
  def scale(resolution, input=nil, output=nil)
@@ -19,13 +19,15 @@ module Ffmprb
19
19
  end
20
20
 
21
21
  def filters_for(lbl, video:, audio:)
22
+ fail Error, "pacing requires fps" unless
23
+ video.fps
22
24
 
23
25
  # Pacing
24
26
 
25
27
  lbl_aux = "pc#{lbl}"
26
28
  super(lbl_aux, video: video, audio: audio) +
27
29
  [
28
- *((video && channel?(:video))? Filter.setpts(@ratio, "#{lbl_aux}:v", "#{lbl}:v"): nil),
30
+ *((video && channel?(:video))? Filter.setpts_framerate(@ratio, video.fps, "#{lbl_aux}:v", "#{lbl}:v"): nil),
29
31
  *((audio && channel?(:audio))? Filter.atempo(@ratio, "#{lbl_aux}:a", "#{lbl}:a"): nil)
30
32
  ]
31
33
  end
@@ -89,19 +89,13 @@ module Ffmprb
89
89
  # NOTE mapping input to this lbl
90
90
 
91
91
  lbl = "o#{idx}rl#{i}"
92
- lbl_aux = "t#{lbl}"
93
92
 
94
93
  # NOTE Image-Padding to match the target resolution
95
94
  # TODO full screen only at the moment (see exception above)
96
95
 
97
96
  Ffmprb.logger.debug{"#{self} asking for filters of #{curr_reel.reel.io.inspect} video: #{channel(:video)}, audio: #{channel(:audio)}"}
98
- @filters.concat(
99
- [
100
- *curr_reel.reel.filters_for(lbl_aux, video: channel(:video), audio: channel(:audio)),
101
- *(channel?(:video)? Filter.interpolate_v(video_fps, "#{lbl_aux}:v", "#{lbl}:v"): nil),
102
- *(channel?(:audio)? Filter.anull("#{lbl_aux}:a", "#{lbl}:a"): nil)
103
- ]
104
- )
97
+ # NOTE may require changes if fps is different (and ffmpeg freezes)
98
+ @filters.concat curr_reel.reel.filters_for(lbl, video: channel(:video), audio: channel(:audio))
105
99
  end
106
100
 
107
101
  trim_prev_at = curr_reel.after || (curr_reel.transition && 0)
@@ -398,9 +392,6 @@ module Ffmprb
398
392
  (@overlays ||= []) <<
399
393
  OpenStruct.new(reel: reel, at: at, duck: duck)
400
394
  end
401
-
402
395
  end
403
-
404
396
  end
405
-
406
397
  end
@@ -134,6 +134,7 @@ module Ffmprb
134
134
  end
135
135
  end
136
136
 
137
+ # TODO ...or... "output label"! (implement intermediate "outputs" through this)
137
138
  def input_label(input)
138
139
  @inputs.index input
139
140
  end
@@ -59,7 +59,8 @@ module Ffmprb
59
59
  @parent.child_lives self
60
60
  Ffmprb.logger.warn "Not the main: false thread run by a #{self.class.name} thread" if main
61
61
  else
62
- Ffmprb.logger.warn "Not the main: true thread run by a not #{self.class.name} thread" unless main
62
+ Ffmprb.logger.warn "Not the main: true thread run by a not #{self.class.name} thread" unless
63
+ main
63
64
  end
64
65
  sync_q.enq :ok
65
66
  Ffmprb.logger.debug{"#{name} thread launched"}
@@ -99,7 +100,8 @@ module Ffmprb
99
100
  @children_mon.synchronize do
100
101
  Ffmprb.logger.debug{"releasing #{thr.name} thread"}
101
102
  @dead_children_q.enq thr
102
- fail "System Error" unless @live_children.delete thr
103
+ fail "System Error" unless
104
+ @live_children.delete thr
103
105
  end
104
106
  proc_vis_edge self, thr, :remove
105
107
  end
@@ -112,7 +114,8 @@ module Ffmprb
112
114
  @dead_children_q.deq
113
115
  end
114
116
  Ffmprb.logger.debug "joining the late #{thr.name} thread"
115
- fail "System Error" unless thr.join(timeout) # NOTE should not block
117
+ fail "System Error" unless
118
+ thr.join(timeout) # NOTE should not block
116
119
  end
117
120
  end
118
121
  end
@@ -1,6 +1,6 @@
1
1
  module Ffmprb
2
2
 
3
- VERSION = '0.12.1'
3
+ VERSION = '0.12.2'
4
4
 
5
5
  GEM_GITHUB_URL = 'https://github.com/costa/ffmprb'
6
6
 
@@ -0,0 +1,2 @@
1
+ 14 examples, 1 failures in 36.6918 seconds
2
+ ./spec/ffmprb_spec.rb:485
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffmprb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.12.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Costa Shapiro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-02 00:00:00.000000000 Z
11
+ date: 2023-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mkfifo
@@ -189,6 +189,7 @@ files:
189
189
  - exp/youtubby/README.md
190
190
  - exp/youtubby/bin/up-deps
191
191
  - exp/youtubby/docker-compose.yml
192
+ - exp/youtubby/exp/gop-raw-cut-rcc-join-you-HD60.rb
192
193
  - exp/youtubby/exp/gop-raw-cut-you-HD60
193
194
  - exp/youtubby/exp/gop-raw-cut-you-HD60.rb
194
195
  - exp/youtubby/exp/media-upload
@@ -234,6 +235,7 @@ files:
234
235
  - tmp/exp/src/SAM_3132.MP4
235
236
  - tmp/ffmprb-0.11.4.gem
236
237
  - tmp/output.rb
238
+ - tmp/rspec_guard_result
237
239
  homepage: https://github.com/costa/ffmprb
238
240
  licenses: []
239
241
  metadata: {}