ffmprb 0.11.3 → 0.11.4
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 +12 -0
- data/Gemfile +8 -1
- data/Gemfile.lock +121 -0
- data/README.md +10 -8
- data/TODO.md +1 -0
- data/bin/test +7 -0
- data/coverage/assets/0.10.0/application.css +799 -0
- data/coverage/assets/0.10.0/application.js +1707 -0
- data/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/coverage/assets/0.10.0/loading.gif +0 -0
- data/coverage/assets/0.10.0/magnify.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/assets/0.10.2/application.css +799 -0
- data/coverage/assets/0.10.2/application.js +1707 -0
- data/coverage/assets/0.10.2/colorbox/border.png +0 -0
- data/coverage/assets/0.10.2/colorbox/controls.png +0 -0
- data/coverage/assets/0.10.2/colorbox/loading.gif +0 -0
- data/coverage/assets/0.10.2/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.10.2/favicon_green.png +0 -0
- data/coverage/assets/0.10.2/favicon_red.png +0 -0
- data/coverage/assets/0.10.2/favicon_yellow.png +0 -0
- data/coverage/assets/0.10.2/loading.gif +0 -0
- data/coverage/assets/0.10.2/magnify.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.10.2/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc.png +0 -0
- data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
- data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_both.png +0 -0
- data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc.png +0 -0
- data/coverage/assets/0.12.2/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
- data/coverage/assets/0.12.2/application.css +1 -0
- data/coverage/assets/0.12.2/application.js +7 -0
- data/coverage/assets/0.12.2/colorbox/border.png +0 -0
- data/coverage/assets/0.12.2/colorbox/controls.png +0 -0
- data/coverage/assets/0.12.2/colorbox/loading.gif +0 -0
- data/coverage/assets/0.12.2/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.12.2/favicon_green.png +0 -0
- data/coverage/assets/0.12.2/favicon_red.png +0 -0
- data/coverage/assets/0.12.2/favicon_yellow.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.12.2/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.12.2/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.12.2/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.12.2/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.12.2/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.12.2/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/assets/0.12.2/loading.gif +0 -0
- data/coverage/assets/0.12.2/magnify.png +0 -0
- data/coverage/index.html +24412 -0
- data/ffmprb.gemspec +34 -14
- data/lib/defaults.rb +1 -1
- data/lib/ffmprb.rb +3 -3
- data/lib/ffmprb/file.rb +8 -8
- data/lib/ffmprb/file/sample.rb +2 -2
- data/lib/ffmprb/file/threaded_buffered.rb +3 -3
- data/lib/ffmprb/filter.rb +4 -1
- data/lib/ffmprb/find_silence.rb +5 -2
- data/lib/ffmprb/process.rb +5 -3
- data/lib/ffmprb/process/input.rb +1 -1
- data/lib/ffmprb/process/input/looping.rb +6 -11
- data/lib/ffmprb/process/output.rb +9 -6
- data/lib/ffmprb/util.rb +5 -3
- data/lib/ffmprb/util/proc_vis.rb +1 -1
- data/lib/ffmprb/util/thread.rb +6 -5
- data/lib/ffmprb/util/threaded_io_buffer.rb +20 -19
- data/lib/ffmprb/version.rb +2 -2
- data/tmp/output.rb +383 -0
- metadata +90 -138
- data/.gitignore +0 -10
- data/.rspec +0 -4
- data/.ruby-version +0 -1
- data/.travis.yml +0 -3
- data/circle.yml +0 -7
data/ffmprb.gemspec
CHANGED
|
@@ -6,14 +6,43 @@ require 'ffmprb/version'
|
|
|
6
6
|
Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = 'ffmprb'
|
|
8
8
|
spec.version = Ffmprb::VERSION
|
|
9
|
-
spec.authors = ["
|
|
9
|
+
spec.authors = ["Costa Shapiro"]
|
|
10
10
|
spec.email = ['costa@mouldwarp.com']
|
|
11
11
|
|
|
12
|
-
spec.summary = "ffmprb is your audio/video
|
|
12
|
+
spec.summary = "ffmprb is your audio/video manipulation pal, based on https://ffmpeg.org"
|
|
13
13
|
spec.description = "A video and audio composing DSL (Damn-Simple Language) and a micro-engine for ffmpeg and ffriends"
|
|
14
14
|
spec.homepage = Ffmprb::GEM_GITHUB_URL
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
def self.ignore_match(pattern, path)
|
|
17
|
+
path = '/' + path unless path =~ %r'^/'
|
|
18
|
+
if File.directory?(path)
|
|
19
|
+
path += '/' unless path =~ %r'/$'
|
|
20
|
+
end
|
|
21
|
+
if pattern.is_a?(Array)
|
|
22
|
+
pattern
|
|
23
|
+
else
|
|
24
|
+
[pattern]
|
|
25
|
+
end.any? do |pattern|
|
|
26
|
+
pattern = '**/' + pattern unless pattern =~ %r'^/'
|
|
27
|
+
pattern += '**' if pattern =~ %r'/$'
|
|
28
|
+
File.fnmatch(pattern, path)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
pattern =
|
|
33
|
+
if (ignore_pattern_lines = File.readlines('.gemignore') rescue nil)
|
|
34
|
+
ignore_pattern_lines.map do |line|
|
|
35
|
+
stripped = line.split(/(?<!\\)#/)[0].strip
|
|
36
|
+
stripped unless stripped.empty?
|
|
37
|
+
end.compact
|
|
38
|
+
else
|
|
39
|
+
%w[test/ spec/ features/]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# NOTE dotfiles are ignored by .glob
|
|
43
|
+
spec.files = Dir['**/*'].reject{|path| ignore_match pattern, path}
|
|
44
|
+
# TODO:rm spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
45
|
+
|
|
17
46
|
spec.bindir = 'exe'
|
|
18
47
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
19
48
|
spec.require_paths = ['lib']
|
|
@@ -23,15 +52,6 @@ Gem::Specification.new do |spec|
|
|
|
23
52
|
# NOTE make it into an optional dependency? Nah for now
|
|
24
53
|
spec.add_dependency 'thor', '~> 0.19.1'
|
|
25
54
|
|
|
26
|
-
spec.
|
|
27
|
-
|
|
28
|
-
spec.add_development_dependency 'simplecov', '>= 0.11.2'
|
|
29
|
-
spec.add_development_dependency 'guard-rspec', '>= 4.6.5'
|
|
30
|
-
spec.add_development_dependency 'guard-bundler', '>= 2.1.0'
|
|
31
|
-
spec.add_development_dependency 'rake', '>= 11.1.2'
|
|
32
|
-
spec.add_development_dependency 'rmagick', '>= 2.15.4'
|
|
33
|
-
spec.add_development_dependency 'ruby-sox', '>= 0.0.3'
|
|
34
|
-
spec.add_development_dependency 'firebase', '>= 0.2.6'
|
|
35
|
-
|
|
36
|
-
spec.post_install_message = "Have fun with your montage! To enable proc visualisation, install firebase gem and set FFMPRB_PROC_VIS_FIREBASE env." unless Ffmprb::FIREBASE_AVAILABLE
|
|
55
|
+
spec.post_install_message = "Have fun with your a/v! To enable proc visualisation, install firebase gem and set FFMPRB_PROC_VIS_FIREBASE env." unless
|
|
56
|
+
Ffmprb::FIREBASE_AVAILABLE
|
|
37
57
|
end
|
data/lib/defaults.rb
CHANGED
|
@@ -19,7 +19,7 @@ module Ffmprb
|
|
|
19
19
|
Process.input_video_fps = nil # NOTE the documented ffmpeg default is 25
|
|
20
20
|
|
|
21
21
|
Process.output_video_resolution = CGA
|
|
22
|
-
Process.output_video_fps = 16
|
|
22
|
+
Process.output_video_fps = 16 # NOTE the documented ffmpeg default is 25
|
|
23
23
|
Process.output_audio_encoder = 'libmp3lame'
|
|
24
24
|
Process.output_audio_sampling_freq = nil # NOTE Use ffmpeg default by default, specify otherwise e.g. 44100
|
|
25
25
|
|
data/lib/ffmprb.rb
CHANGED
|
@@ -25,13 +25,13 @@ module Ffmprb
|
|
|
25
25
|
name ||= blk.source_location.map(&:to_s).map{ |s| ::File.basename s.to_s, ::File.extname(s) }.join(':')
|
|
26
26
|
process = Process.new(name: name, **opts)
|
|
27
27
|
proc_vis_node process if respond_to? :proc_vis_node # XXX simply include the ProcVis if it makes into a gem
|
|
28
|
-
logger.debug
|
|
28
|
+
logger.debug{"Starting process with #{args} #{opts} in #{blk.source_location}"}
|
|
29
29
|
|
|
30
30
|
process.instance_exec *args, &blk
|
|
31
|
-
logger.debug
|
|
31
|
+
logger.debug{"Initialized process with #{args} #{opts} in #{blk.source_location}"}
|
|
32
32
|
|
|
33
33
|
process.run.tap do
|
|
34
|
-
logger.debug
|
|
34
|
+
logger.debug{"Finished process with #{args} #{opts} in #{blk.source_location}"}
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
alias :action! :process # ;)
|
data/lib/ffmprb/file.rb
CHANGED
|
@@ -17,27 +17,27 @@ module Ffmprb
|
|
|
17
17
|
->{
|
|
18
18
|
path = file.respond_to?(:path)? file.path : file
|
|
19
19
|
mode ||= file.respond_to?(mode)? file.mode.to_s[0] : 'r'
|
|
20
|
-
Ffmprb.logger.debug
|
|
20
|
+
Ffmprb.logger.debug{"Trying to open #{path} (for #{mode}-buffering or something)"}
|
|
21
21
|
::File.open(path, mode)
|
|
22
22
|
}
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def create(path)
|
|
26
26
|
new(path: path, mode: :write).tap do |file|
|
|
27
|
-
Ffmprb.logger.debug
|
|
27
|
+
Ffmprb.logger.debug{"Created file with path: #{file.path}"}
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def open(path)
|
|
32
32
|
new(path: path, mode: :read).tap do |file|
|
|
33
|
-
Ffmprb.logger.debug
|
|
33
|
+
Ffmprb.logger.debug{"Opened file with path: #{file.path}"}
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def temp(extname)
|
|
38
38
|
file = create(Tempfile.new(['', extname]))
|
|
39
39
|
path = file.path
|
|
40
|
-
Ffmprb.logger.debug
|
|
40
|
+
Ffmprb.logger.debug{"Created temp file with path: #{path}"}
|
|
41
41
|
|
|
42
42
|
return file unless block_given?
|
|
43
43
|
|
|
@@ -49,7 +49,7 @@ module Ffmprb
|
|
|
49
49
|
rescue
|
|
50
50
|
Ffmprb.logger.warn "#{$!.class.name} removing temp file with path #{path}: #{$!.message}"
|
|
51
51
|
end
|
|
52
|
-
Ffmprb.logger.debug
|
|
52
|
+
Ffmprb.logger.debug{"Removed temp file with path: #{path}"}
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
@@ -69,12 +69,12 @@ module Ffmprb
|
|
|
69
69
|
rescue
|
|
70
70
|
Ffmprb.logger.warn "#{$!.class.name} removing temp file with path #{path}: #{$!.message}"
|
|
71
71
|
end
|
|
72
|
-
Ffmprb.logger.debug
|
|
72
|
+
Ffmprb.logger.debug{"Removed temp file with path: #{path}"}
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def temp_fifo_path(extname)
|
|
77
|
-
::File.join Dir.tmpdir,
|
|
77
|
+
::File.join Dir.tmpdir, "#{rand(2**222)}p#{extname}"
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def image?(extname)
|
|
@@ -168,7 +168,7 @@ module Ffmprb
|
|
|
168
168
|
else
|
|
169
169
|
FileUtils.remove_entry path
|
|
170
170
|
end
|
|
171
|
-
Ffmprb.logger.debug
|
|
171
|
+
Ffmprb.logger.debug{"Removed file with path: #{path}"}
|
|
172
172
|
@path = nil
|
|
173
173
|
end
|
|
174
174
|
|
data/lib/ffmprb/file/sample.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Ffmprb
|
|
|
11
11
|
audio = File.temp('.wav') if audio == true
|
|
12
12
|
video = File.temp('.png') if video == true
|
|
13
13
|
|
|
14
|
-
Ffmprb.logger.debug
|
|
14
|
+
Ffmprb.logger.debug{"Snap shooting files, video path: #{video ? video.path : 'NONE'}, audio path: #{audio ? audio.path : 'NONE'}"}
|
|
15
15
|
|
|
16
16
|
fail Error, "Incorrect output extname (must be image)" unless !video || video.channel?(:video) && !video.channel?(:audio)
|
|
17
17
|
fail Error, "Incorrect audio extname (must be sound)" unless !audio || audio.channel?(:audio) && !audio.channel?(:video)
|
|
@@ -30,7 +30,7 @@ module Ffmprb
|
|
|
30
30
|
begin
|
|
31
31
|
video.unlink if video
|
|
32
32
|
audio.unlink if audio
|
|
33
|
-
Ffmprb.logger.debug
|
|
33
|
+
Ffmprb.logger.debug{"Removed sample files"}
|
|
34
34
|
rescue
|
|
35
35
|
Ffmprb.logger.warn "#{$!.class.name} removing sample files: #{$!.message}"
|
|
36
36
|
end
|
|
@@ -7,7 +7,7 @@ module Ffmprb
|
|
|
7
7
|
def threaded_buffered_fifo(extname='.tmp', reader_open_on_writer_idle_limit: nil, proc_vis: nil)
|
|
8
8
|
input_fifo_file = temp_fifo(extname)
|
|
9
9
|
output_fifo_file = temp_fifo(extname)
|
|
10
|
-
Ffmprb.logger.debug
|
|
10
|
+
Ffmprb.logger.debug{"Opening #{input_fifo_file.path}>#{output_fifo_file.path} for buffering"}
|
|
11
11
|
Util::Thread.new do
|
|
12
12
|
begin
|
|
13
13
|
io_buff = Util::ThreadedIoBuffer.new(opener(input_fifo_file, 'r'), opener(output_fifo_file, 'w'), keep_outputs_open_on_input_idle_limit: reader_open_on_writer_idle_limit)
|
|
@@ -20,13 +20,13 @@ module Ffmprb
|
|
|
20
20
|
ensure
|
|
21
21
|
Util::Thread.join_children!
|
|
22
22
|
end
|
|
23
|
-
Ffmprb.logger.debug
|
|
23
|
+
Ffmprb.logger.debug{"IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} ended"}
|
|
24
24
|
ensure
|
|
25
25
|
input_fifo_file.unlink if input_fifo_file
|
|
26
26
|
output_fifo_file.unlink if output_fifo_file
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
|
-
Ffmprb.logger.debug
|
|
29
|
+
Ffmprb.logger.debug{"IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} started"}
|
|
30
30
|
|
|
31
31
|
[input_fifo_file, output_fifo_file]
|
|
32
32
|
end
|
data/lib/ffmprb/filter.rb
CHANGED
|
@@ -262,7 +262,10 @@ module Ffmprb
|
|
|
262
262
|
end
|
|
263
263
|
|
|
264
264
|
def complex_args(*filters)
|
|
265
|
-
[
|
|
265
|
+
[].tap do |args|
|
|
266
|
+
args << '-filter_complex' << filters.join('; ') unless
|
|
267
|
+
filters.empty?
|
|
268
|
+
end
|
|
266
269
|
end
|
|
267
270
|
|
|
268
271
|
private
|
data/lib/ffmprb/find_silence.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Ffmprb
|
|
|
5
5
|
# NOTE not for streaming just yet
|
|
6
6
|
def find_silence(input_file, output_file)
|
|
7
7
|
path = "#{input_file.path}->#{output_file.path}"
|
|
8
|
-
logger.debug
|
|
8
|
+
logger.debug{"Finding silence (#{path})"}
|
|
9
9
|
silence = []
|
|
10
10
|
Util.ffmpeg('-i', input_file.path, *find_silence_detect_args, output_file.path).
|
|
11
11
|
scan(SILENCE_DETECT_REGEX).each do |mark, time|
|
|
@@ -25,7 +25,10 @@ module Ffmprb
|
|
|
25
25
|
Ffmprb.warn "Unknown silence mark: #{mark}"
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
-
logger.debug
|
|
28
|
+
logger.debug{
|
|
29
|
+
silence_map = silence.map{|t,v| "#{t}: #{v}"}
|
|
30
|
+
"Found silence (#{path}): [#{silence_map}]"
|
|
31
|
+
}
|
|
29
32
|
silence
|
|
30
33
|
end
|
|
31
34
|
|
data/lib/ffmprb/process.rb
CHANGED
|
@@ -39,7 +39,7 @@ module Ffmprb
|
|
|
39
39
|
def input_video_options
|
|
40
40
|
{
|
|
41
41
|
auto_rotate: input_video_auto_rotate,
|
|
42
|
-
fps: input_video_fps
|
|
42
|
+
fps: input_video_fps # TODO seen failing on apng (w/ffmpeg v4.x)
|
|
43
43
|
}
|
|
44
44
|
end
|
|
45
45
|
def input_audio_options
|
|
@@ -97,7 +97,10 @@ module Ffmprb
|
|
|
97
97
|
end
|
|
98
98
|
overlay in_over.volume ducked_overlay_volume
|
|
99
99
|
|
|
100
|
-
Ffmprb.logger.debug
|
|
100
|
+
Ffmprb.logger.debug{
|
|
101
|
+
ducked_overlay_volume_map = ducked_overlay_volume.map{|t,v| "#{t}: #{v}"}
|
|
102
|
+
"Ducking audio with volumes: {#{ducked_overlay_volume_map.join ', '}}"
|
|
103
|
+
}
|
|
101
104
|
end
|
|
102
105
|
|
|
103
106
|
end
|
|
@@ -157,7 +160,6 @@ module Ffmprb
|
|
|
157
160
|
thr = Util::Thread.new main: !parent do
|
|
158
161
|
proc_vis_node Thread.current
|
|
159
162
|
# NOTE yes, an exception can occur anytime, and we'll just die, it's ok, see above
|
|
160
|
-
# XXX just to return something -- no apparent practical use
|
|
161
163
|
cmd = command
|
|
162
164
|
opts = {limit: limit, timeout: timeout}
|
|
163
165
|
opts[:ignore_broken_pipes] = ignore_broken_pipes unless ignore_broken_pipes.nil?
|
data/lib/ffmprb/process/input.rb
CHANGED
|
@@ -60,7 +60,7 @@ module Ffmprb
|
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
cpy_io = File.temp_fifo(src_io.extname)
|
|
63
|
-
Ffmprb.logger.debug
|
|
63
|
+
Ffmprb.logger.debug{"(L2) Temporising the raw input (#{src_io.path}) and creating copy (#{cpy_io.path})"}
|
|
64
64
|
|
|
65
65
|
src_io.threaded_buffered_copy_to @raw.io, cpy_io
|
|
66
66
|
|
|
@@ -70,9 +70,8 @@ module Ffmprb
|
|
|
70
70
|
@raw.process.proc_vis_node dst_io
|
|
71
71
|
|
|
72
72
|
Util::Thread.new "looping input processor" do
|
|
73
|
-
|
|
73
|
+
Ffmprb.logger.debug{"(L3) Pre-processing into (#{dst_io.path})"}
|
|
74
74
|
|
|
75
|
-
Ffmprb.logger.debug "(L3) Pre-processing into (#{dst_io.path})"
|
|
76
75
|
Ffmprb.process @_unfiltered, parent: @raw.process do |unfiltered| # TODO limit:
|
|
77
76
|
|
|
78
77
|
inp = input(cpy_io)
|
|
@@ -83,10 +82,8 @@ module Ffmprb
|
|
|
83
82
|
end
|
|
84
83
|
end
|
|
85
84
|
|
|
86
|
-
# Ffmprb.logger.debug "Preprocessed (from #{src_io.path}) looping input: #{dst_io.path}, output: #{io.io.path}, and raw input copy will go through #{buff_raw_io.path} to #{@raw.io.path}..."
|
|
87
|
-
|
|
88
85
|
buff_ios = (1..times).map{File.temp_fifo intermediate_extname}
|
|
89
|
-
Ffmprb.logger.debug
|
|
86
|
+
Ffmprb.logger.debug{"Preprocessed #{dst_io.path} will be teed to #{buff_ios.map(&:path).join '; '}"}
|
|
90
87
|
Util::Thread.new "cloning buffer watcher" do
|
|
91
88
|
dst_io.threaded_buffered_copy_to(*buff_ios).tap do |io_buff|
|
|
92
89
|
Util::Thread.join_children!
|
|
@@ -94,17 +91,15 @@ module Ffmprb
|
|
|
94
91
|
end
|
|
95
92
|
end
|
|
96
93
|
|
|
97
|
-
# Ffmprb.logger.debug "Concatenation of #{buff_ios.map(&:path).join '; '} will go to #{@io.io.path} to be fed to this process"
|
|
98
|
-
|
|
99
94
|
# NOTE additional (filtered, processed and looped) input io
|
|
100
95
|
aux_io = File.temp_fifo(intermediate_extname)
|
|
101
96
|
|
|
102
97
|
# NOTE (4)
|
|
103
98
|
|
|
104
99
|
Util::Thread.new "looper" do
|
|
105
|
-
Ffmprb.logger.debug
|
|
100
|
+
Ffmprb.logger.debug{"Looping #{buff_ios.size} times"}
|
|
106
101
|
|
|
107
|
-
Ffmprb.logger.debug
|
|
102
|
+
Ffmprb.logger.debug{"(L4) Looping (#{buff_ios.map &:path}) into (#{aux_io.path})"}
|
|
108
103
|
begin # NOTE may not write its entire output, it's ok
|
|
109
104
|
Ffmprb.process parent: @raw.process, ignore_broken_pipes: false do
|
|
110
105
|
|
|
@@ -121,7 +116,7 @@ module Ffmprb
|
|
|
121
116
|
|
|
122
117
|
# NOTE (1)
|
|
123
118
|
|
|
124
|
-
Ffmprb.logger.debug
|
|
119
|
+
Ffmprb.logger.debug{"(L1) Creating a new input (#{aux_io.path}) to the process"}
|
|
125
120
|
@raw.process.input(aux_io)
|
|
126
121
|
end
|
|
127
122
|
|
|
@@ -84,7 +84,7 @@ module Ffmprb
|
|
|
84
84
|
# NOTE Image-Padding to match the target resolution
|
|
85
85
|
# TODO full screen only at the moment (see exception above)
|
|
86
86
|
|
|
87
|
-
Ffmprb.logger.debug
|
|
87
|
+
Ffmprb.logger.debug{"#{self} asking for filters of #{curr_reel.reel.io.inspect} video: #{channel(:video)}, audio: #{channel(:audio)}"}
|
|
88
88
|
@filters.concat(
|
|
89
89
|
curr_reel.reel.filters_for lbl, video: channel(:video), audio: channel(:audio)
|
|
90
90
|
)
|
|
@@ -151,7 +151,7 @@ module Ffmprb
|
|
|
151
151
|
) if channel?(:audio)
|
|
152
152
|
|
|
153
153
|
segments << new_prev_lbl
|
|
154
|
-
Ffmprb.logger.debug
|
|
154
|
+
Ffmprb.logger.debug{"Concatting segments: #{new_prev_lbl} pushed"}
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
if curr_reel.transition
|
|
@@ -264,7 +264,7 @@ module Ffmprb
|
|
|
264
264
|
end
|
|
265
265
|
process.proc_vis_edge process, main_av_o, :remove
|
|
266
266
|
process.proc_vis_edge process, main_av_inter_i
|
|
267
|
-
Ffmprb.logger.debug
|
|
267
|
+
Ffmprb.logger.debug{"Re-routed the main audio output (#{main_av_inter_i.path}->...->#{main_av_o.path}) through the process of audio ducking"}
|
|
268
268
|
|
|
269
269
|
over_a_i, over_a_o = File.threaded_buffered_fifo(Process.intermediate_channel_extname(audio: true, video: false), proc_vis: process)
|
|
270
270
|
lbl_over = "o#{idx}l#{i}"
|
|
@@ -273,10 +273,10 @@ module Ffmprb
|
|
|
273
273
|
)
|
|
274
274
|
@channel_lbl_ios["#{lbl_over}:a"] = over_a_i
|
|
275
275
|
process.proc_vis_edge process, over_a_i
|
|
276
|
-
Ffmprb.logger.debug
|
|
276
|
+
Ffmprb.logger.debug{"Routed and buffering auxiliary output fifos (#{over_a_i.path}>#{over_a_o.path}) for overlay"}
|
|
277
277
|
|
|
278
278
|
inter_i, inter_o = File.threaded_buffered_fifo(intermediate_extname, proc_vis: process)
|
|
279
|
-
Ffmprb.logger.debug
|
|
279
|
+
Ffmprb.logger.debug{"Allocated fifos to buffer media (#{inter_i.path}>#{inter_o.path}) while finding silence"}
|
|
280
280
|
|
|
281
281
|
ignore_broken_pipes_was = process.ignore_broken_pipes # XXX maybe throw an exception instead?
|
|
282
282
|
process.ignore_broken_pipes = true # NOTE audio ducking process may break the overlay pipe
|
|
@@ -285,7 +285,10 @@ module Ffmprb
|
|
|
285
285
|
process.proc_vis_edge main_av_inter_o, inter_i # XXX mark it better
|
|
286
286
|
silence = Ffmprb.find_silence(main_av_inter_o, inter_i)
|
|
287
287
|
|
|
288
|
-
Ffmprb.logger.debug
|
|
288
|
+
Ffmprb.logger.debug{
|
|
289
|
+
silence_map = silence.map{|s| "#{s.start_at}-#{s.end_at}"}
|
|
290
|
+
"Audio ducking with silence: [#{silence_map.join ', '}]"
|
|
291
|
+
}
|
|
289
292
|
|
|
290
293
|
Process.duck_audio inter_o, over_a_o, silence, main_av_o,
|
|
291
294
|
process_options: {parent: process, ignore_broken_pipes: ignore_broken_pipes_was, timeout: process.timeout},
|
data/lib/ffmprb/util.rb
CHANGED
|
@@ -18,8 +18,10 @@ module Ffmprb
|
|
|
18
18
|
sh *ffprobe_cmd, *args, limit: limit, timeout: timeout
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
# TODO warn on broken pipes incompatibility with 4.x or something
|
|
21
22
|
def ffmpeg(*args, limit: nil, timeout: cmd_timeout, ignore_broken_pipes: true)
|
|
22
|
-
args = ['-loglevel', 'debug'] + args if
|
|
23
|
+
args = ['-loglevel', 'debug'] + args if
|
|
24
|
+
Ffmprb.ffmpeg_debug
|
|
23
25
|
sh *ffmpeg_cmd, *args, output: :stderr, limit: limit, timeout: timeout, ignore_broken_pipes: ignore_broken_pipes
|
|
24
26
|
end
|
|
25
27
|
|
|
@@ -42,7 +44,7 @@ module Ffmprb
|
|
|
42
44
|
value = wait_thr.value
|
|
43
45
|
status = value.exitstatus # NOTE blocking
|
|
44
46
|
if status != 0
|
|
45
|
-
if value.signaled? && value.termsig == Signal.list['PIPE']
|
|
47
|
+
if value.signaled? && value.termsig == Signal.list['PIPE'] # TODO! this doesn't seem to work for ffmpeg 4.x (it ignores SIGPIPEs)
|
|
46
48
|
if ignore_broken_pipes
|
|
47
49
|
Ffmprb.logger.info "Ignoring broken pipe: #{cmd_str}"
|
|
48
50
|
else
|
|
@@ -54,7 +56,7 @@ module Ffmprb
|
|
|
54
56
|
end
|
|
55
57
|
end
|
|
56
58
|
end
|
|
57
|
-
Ffmprb.logger.debug
|
|
59
|
+
Ffmprb.logger.debug{"FINISHED: #{cmd_str}"}
|
|
58
60
|
|
|
59
61
|
Thread.join_children! limit, timeout: timeout
|
|
60
62
|
|
data/lib/ffmprb/util/proc_vis.rb
CHANGED
|
@@ -137,7 +137,7 @@ module Ffmprb
|
|
|
137
137
|
@proc_vis_firebase_client =
|
|
138
138
|
if proc_vis_firebase
|
|
139
139
|
url = "https://#{proc_vis_firebase}.firebaseio.com/proc/"
|
|
140
|
-
Ffmprb.logger.debug
|
|
140
|
+
Ffmprb.logger.debug{"Connecting to #{url}"}
|
|
141
141
|
begin
|
|
142
142
|
Firebase::Client.new(url).tap do
|
|
143
143
|
Ffmprb.logger.info "Connected to #{url}"
|
data/lib/ffmprb/util/thread.rb
CHANGED
|
@@ -42,12 +42,13 @@ module Ffmprb
|
|
|
42
42
|
attr_reader :name
|
|
43
43
|
|
|
44
44
|
def initialize(name="some", main: false, &blk)
|
|
45
|
+
orig_caller = caller
|
|
45
46
|
@name = name
|
|
46
47
|
@parent = Thread.current
|
|
47
48
|
@live_children = []
|
|
48
49
|
@children_mon = Monitor.new
|
|
49
50
|
@dead_children_q = Queue.new
|
|
50
|
-
Ffmprb.logger.debug
|
|
51
|
+
Ffmprb.logger.debug{"about to launch #{name}"}
|
|
51
52
|
sync_q = Queue.new
|
|
52
53
|
super() do
|
|
53
54
|
@parent.proc_vis_node self if @parent.respond_to? :proc_vis_node
|
|
@@ -57,10 +58,10 @@ module Ffmprb
|
|
|
57
58
|
Ffmprb.logger.warn "Not the main: true thread run by a not #{self.class.name} thread" unless main
|
|
58
59
|
end
|
|
59
60
|
sync_q.enq :ok
|
|
60
|
-
Ffmprb.logger.debug
|
|
61
|
+
Ffmprb.logger.debug{"#{name} thread launched"}
|
|
61
62
|
begin
|
|
62
63
|
blk.call.tap do
|
|
63
|
-
Ffmprb.logger.debug
|
|
64
|
+
Ffmprb.logger.debug{"#{name} thread done"}
|
|
64
65
|
end
|
|
65
66
|
rescue Exception
|
|
66
67
|
Ffmprb.logger.warn "#{$!.class.name} raised in #{name} thread: #{$!.message}\nBacktrace:\n\t#{$!.backtrace.join("\n\t")}"
|
|
@@ -84,7 +85,7 @@ module Ffmprb
|
|
|
84
85
|
|
|
85
86
|
def child_lives(thr)
|
|
86
87
|
@children_mon.synchronize do
|
|
87
|
-
Ffmprb.logger.debug
|
|
88
|
+
Ffmprb.logger.debug{"picking up #{thr.name} thread"}
|
|
88
89
|
@live_children << thr
|
|
89
90
|
end
|
|
90
91
|
proc_vis_edge self, thr
|
|
@@ -92,7 +93,7 @@ module Ffmprb
|
|
|
92
93
|
|
|
93
94
|
def child_dies(thr)
|
|
94
95
|
@children_mon.synchronize do
|
|
95
|
-
Ffmprb.logger.debug
|
|
96
|
+
Ffmprb.logger.debug{"releasing #{thr.name} thread"}
|
|
96
97
|
@dead_children_q.enq thr
|
|
97
98
|
fail "System Error" unless @live_children.delete thr
|
|
98
99
|
end
|