ffmprb 0.12.1 → 0.12.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: {}