ffmprb 0.12.2 → 0.12.3
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 +4 -4
- data/Dockerfile +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +9 -9
- data/README.md +7 -2
- data/coverage/index.html +1547 -1228
- data/exp/present/exp/present.rb +1 -1
- data/exp/youtubby/exp/gop-raw-cut-you-HD60.rb +1 -0
- data/exp/youtubby/google_youtube.rb +3 -3
- data/ffmprb.gemspec +2 -0
- data/lib/ffmprb/file/sample.rb +15 -7
- data/lib/ffmprb/filter.rb +12 -4
- data/lib/ffmprb/process/input/chain_base.rb +5 -0
- data/lib/ffmprb/process/input/cut.rb +0 -4
- data/lib/ffmprb/process/input.rb +4 -4
- data/lib/ffmprb/process.rb +21 -13
- data/lib/ffmprb/util.rb +8 -6
- data/lib/ffmprb/version.rb +1 -1
- metadata +3 -4
- data/tmp/rspec_guard_result +0 -2
data/exp/present/exp/present.rb
CHANGED
|
@@ -22,9 +22,9 @@ def google_youtube(cb_uri, user_id, &blk)
|
|
|
22
22
|
Google::Apis::YoutubeV3::AUTH_YOUTUBE,
|
|
23
23
|
Google::Auth::Stores::FileTokenStore.new(file: GOOGLE_CREDENTIAL_STORE)
|
|
24
24
|
)
|
|
25
|
-
youtube.client_options.
|
|
26
|
-
youtube.client_options.
|
|
27
|
-
youtube.client_options.
|
|
25
|
+
youtube.client_options.send_timeout =
|
|
26
|
+
youtube.client_options.open_timeout =
|
|
27
|
+
youtube.client_options.read_timeout = YOUTUBE_TIMEOUT
|
|
28
28
|
youtube.authorization =
|
|
29
29
|
if (credentials = authorizer.get_credentials(user_id))
|
|
30
30
|
credentials
|
data/ffmprb.gemspec
CHANGED
|
@@ -47,6 +47,8 @@ Gem::Specification.new do |spec|
|
|
|
47
47
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
48
48
|
spec.require_paths = ['lib']
|
|
49
49
|
|
|
50
|
+
spec.required_ruby_version = '>= 2.6' # TODO check 3.X
|
|
51
|
+
|
|
50
52
|
# NOTE I'm not happy with this dependency, and there's nothing crossplatform (= for windoze too) at the moment
|
|
51
53
|
spec.add_dependency 'mkfifo', '~> 0.1.1'
|
|
52
54
|
# NOTE make it into an optional dependency? Nah for now
|
data/lib/ffmprb/file/sample.rb
CHANGED
|
@@ -2,8 +2,11 @@ module Ffmprb
|
|
|
2
2
|
|
|
3
3
|
class File
|
|
4
4
|
|
|
5
|
+
AUDIO_SAMPLE_MIN = 0.5
|
|
6
|
+
|
|
5
7
|
def sample(
|
|
6
8
|
at: 0.01,
|
|
9
|
+
duration: 0,
|
|
7
10
|
video: true,
|
|
8
11
|
audio: true,
|
|
9
12
|
&blk
|
|
@@ -11,15 +14,22 @@ module Ffmprb
|
|
|
11
14
|
audio = File.temp('.wav') if audio == true
|
|
12
15
|
video = File.temp('.png') if video == true
|
|
13
16
|
|
|
14
|
-
Ffmprb.logger.debug{"Snap shooting files, video
|
|
17
|
+
Ffmprb.logger.debug{"Snap shooting files, video: #{video && video.path}, audio: #{audio && audio.path}"}
|
|
15
18
|
|
|
16
|
-
fail Error, "Incorrect output extname (must be image)" unless
|
|
17
|
-
|
|
18
|
-
fail Error, "
|
|
19
|
+
fail Error, "Incorrect output extname (must be image)" unless
|
|
20
|
+
!video || video.channel?(:video) && !video.channel?(:audio)
|
|
21
|
+
fail Error, "Incorrect audio extname (must be sound)" unless
|
|
22
|
+
!audio || audio.channel?(:audio) && !audio.channel?(:video)
|
|
23
|
+
fail Error, "Can sample either video OR audio UNLESS a block is given" unless
|
|
24
|
+
block_given? || !!audio != !!video
|
|
25
|
+
fail Error, "Can sample video just for 0 sec (an image snapshot)" unless
|
|
26
|
+
!video || duration == 0
|
|
19
27
|
|
|
20
28
|
cmd = %W[-i #{path}]
|
|
21
29
|
cmd.concat %W[-deinterlace -an -ss #{at} -vframes 1 #{video.path}] if video
|
|
22
|
-
|
|
30
|
+
audio_duration = [AUDIO_SAMPLE_MIN, duration].max
|
|
31
|
+
audio_at = [0, at - audio_duration / 2].max
|
|
32
|
+
cmd.concat %W[-vn -ss #{audio_at} -t #{audio_duration} #{audio.path}] if audio
|
|
23
33
|
Util.ffmpeg *cmd
|
|
24
34
|
|
|
25
35
|
return video || audio unless block_given?
|
|
@@ -42,7 +52,5 @@ module Ffmprb
|
|
|
42
52
|
def sample_audio(*audio, at: 0.01, &blk)
|
|
43
53
|
sample at: at, video: false, audio: (audio.first || true), &blk
|
|
44
54
|
end
|
|
45
|
-
|
|
46
55
|
end
|
|
47
|
-
|
|
48
56
|
end
|
data/lib/ffmprb/filter.rb
CHANGED
|
@@ -304,10 +304,18 @@ module Ffmprb
|
|
|
304
304
|
end
|
|
305
305
|
|
|
306
306
|
|
|
307
|
-
def complex_args(*filters)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
307
|
+
def complex_args(*filters, script_file: nil)
|
|
308
|
+
if filters.empty?
|
|
309
|
+
[]
|
|
310
|
+
else
|
|
311
|
+
filter_complex_opt = filters.join('; ')
|
|
312
|
+
if script_file
|
|
313
|
+
script_file.write filter_complex_opt
|
|
314
|
+
script_file.close
|
|
315
|
+
['-filter_complex_script', script_file.path]
|
|
316
|
+
else
|
|
317
|
+
['-filter_complex', filter_complex_opt]
|
|
318
|
+
end
|
|
311
319
|
end
|
|
312
320
|
end
|
|
313
321
|
|
data/lib/ffmprb/process/input.rb
CHANGED
|
@@ -40,8 +40,8 @@ module Ffmprb
|
|
|
40
40
|
attr_reader :process
|
|
41
41
|
|
|
42
42
|
def initialize(io, process, video:, audio:)
|
|
43
|
-
@io = self.class.resolve(io)
|
|
44
43
|
@process = process
|
|
44
|
+
@io = self.class.resolve(io)
|
|
45
45
|
@channels = {
|
|
46
46
|
video: video && @io.channel?(:video) && OpenStruct.new(video),
|
|
47
47
|
audio: audio && @io.channel?(:audio) && OpenStruct.new(audio)
|
|
@@ -76,18 +76,18 @@ module Ffmprb
|
|
|
76
76
|
Filter.copy "#{in_lbl}:v", "#{lbl}:v"
|
|
77
77
|
end
|
|
78
78
|
elsif video
|
|
79
|
-
fail Error, "No video stream to provide"
|
|
79
|
+
fail Error, "No video stream to provide ('#{io.path}')"
|
|
80
80
|
end),
|
|
81
81
|
*(if audio && channel?(:audio)
|
|
82
82
|
Filter.anull "#{in_lbl}:a", "#{lbl}:a"
|
|
83
83
|
elsif audio
|
|
84
|
-
fail Error, "No audio stream to provide"
|
|
84
|
+
fail Error, "No audio stream to provide ('#{io.path}')"
|
|
85
85
|
end)
|
|
86
86
|
]
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def channel?(medium)
|
|
90
|
-
|
|
90
|
+
!!channel(medium)
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def channel(medium)
|
data/lib/ffmprb/process.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'tempfile'
|
|
2
|
+
|
|
1
3
|
module Ffmprb
|
|
2
4
|
|
|
3
5
|
class Process
|
|
@@ -161,11 +163,12 @@ module Ffmprb
|
|
|
161
163
|
thr = Util::Thread.new main: !parent do
|
|
162
164
|
proc_vis_node Thread.current
|
|
163
165
|
# NOTE yes, an exception can occur anytime, and we'll just die, it's ok, see above
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
command do |cmd|
|
|
167
|
+
opts = {limit: limit, timeout: timeout}
|
|
168
|
+
opts[:ignore_broken_pipes] = ignore_broken_pipes unless ignore_broken_pipes.nil?
|
|
169
|
+
Util.ffmpeg(*cmd, **opts).tap do |res|
|
|
170
|
+
Util::Thread.join_children! limit, timeout: timeout
|
|
171
|
+
end
|
|
169
172
|
end
|
|
170
173
|
proc_vis_node Thread.current, :remove
|
|
171
174
|
end
|
|
@@ -175,23 +178,28 @@ module Ffmprb
|
|
|
175
178
|
private
|
|
176
179
|
|
|
177
180
|
def command
|
|
178
|
-
|
|
181
|
+
fail "Miserably" unless
|
|
182
|
+
block_given?
|
|
183
|
+
Tempfile.create do |tmp_file|
|
|
184
|
+
yield input_args(tmp_file) + filter_args(tmp_file) + output_args(tmp_file)
|
|
185
|
+
end
|
|
179
186
|
end
|
|
180
187
|
|
|
181
|
-
def input_args
|
|
182
|
-
filter_args # NOTE must run first
|
|
188
|
+
def input_args(script_file=nil)
|
|
189
|
+
filter_args script_file # NOTE must run first
|
|
183
190
|
@input_args ||= @inputs.map(&:args).reduce(:+)
|
|
184
191
|
end
|
|
185
192
|
|
|
186
|
-
# NOTE must run first
|
|
187
|
-
def filter_args
|
|
193
|
+
# NOTE must run first (which is excusable just because it's private)
|
|
194
|
+
def filter_args(script_file=nil)
|
|
188
195
|
@filter_args ||= Filter.complex_args(
|
|
189
|
-
|
|
196
|
+
*@outputs.map(&:filters).reduce(:+),
|
|
197
|
+
script_file: script_file
|
|
190
198
|
)
|
|
191
199
|
end
|
|
192
200
|
|
|
193
|
-
def output_args
|
|
194
|
-
filter_args # NOTE must run first
|
|
201
|
+
def output_args(script_file=nil)
|
|
202
|
+
filter_args script_file # NOTE must run first
|
|
195
203
|
@output_args ||= @outputs.map(&:args).reduce(:+)
|
|
196
204
|
end
|
|
197
205
|
|
data/lib/ffmprb/util.rb
CHANGED
|
@@ -24,12 +24,14 @@ module Ffmprb
|
|
|
24
24
|
def ffmpeg(*args, limit: nil, timeout: cmd_timeout, ignore_broken_pipes: true)
|
|
25
25
|
args = %w[-loglevel debug] + args if
|
|
26
26
|
Ffmprb.ffmpeg_debug
|
|
27
|
-
sh
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
sh(
|
|
28
|
+
*ffmpeg_cmd, *args,
|
|
29
|
+
output: :stderr,
|
|
30
|
+
limit: limit,
|
|
31
|
+
timeout: timeout,
|
|
32
|
+
ignore_broken_pipes: ignore_broken_pipes,
|
|
33
|
+
broken_pipe_error_re: FFMPEG_BROKEN_PIPE_ERROR_RE
|
|
34
|
+
)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def sh(*cmd, input: nil, output: :stdout, limit: nil, timeout: cmd_timeout, ignore_broken_pipes: false, broken_pipe_error_re: nil)
|
data/lib/ffmprb/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.12.3
|
|
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-
|
|
11
|
+
date: 2023-03-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: mkfifo
|
|
@@ -235,7 +235,6 @@ files:
|
|
|
235
235
|
- tmp/exp/src/SAM_3132.MP4
|
|
236
236
|
- tmp/ffmprb-0.11.4.gem
|
|
237
237
|
- tmp/output.rb
|
|
238
|
-
- tmp/rspec_guard_result
|
|
239
238
|
homepage: https://github.com/costa/ffmprb
|
|
240
239
|
licenses: []
|
|
241
240
|
metadata: {}
|
|
@@ -248,7 +247,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
248
247
|
requirements:
|
|
249
248
|
- - ">="
|
|
250
249
|
- !ruby/object:Gem::Version
|
|
251
|
-
version: '
|
|
250
|
+
version: '2.6'
|
|
252
251
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
253
252
|
requirements:
|
|
254
253
|
- - ">="
|
data/tmp/rspec_guard_result
DELETED