Class: Ffmprb::File
- Inherits:
-
File
show all
- Includes:
- Util::ProcVis::Node
- Defined in:
- lib/ffmprb/file.rb,
lib/ffmprb/file/sample.rb,
lib/ffmprb/file/threaded_buffered.rb
Class Attribute Summary collapse
Instance Attribute Summary collapse
#_proc_vis
Class Method Summary
collapse
Instance Method Summary
collapse
#proc_vis_edge, #proc_vis_name, #proc_vis_node
Constructor Details
#initialize(path:, mode:) ⇒ File
Returns a new instance of File.
96
97
98
99
100
101
102
103
|
# File 'lib/ffmprb/file.rb', line 96
def initialize(path:, mode:)
@mode = mode.to_sym
fail Error, "Open for read, create for write, ??? for #{@mode}" unless
%i[read write].include?(@mode)
@path = path
@path.close if @path && @path.respond_to?(:close) path! end
|
Class Attribute Details
.image_extname_regex ⇒ Object
NOTE careful when subclassing, it doesn’t inherit the attr values
13
14
15
|
# File 'lib/ffmprb/file.rb', line 13
def image_extname_regex
@image_extname_regex
end
|
.movie_extname_regex ⇒ Object
NOTE careful when subclassing, it doesn’t inherit the attr values
13
14
15
|
# File 'lib/ffmprb/file.rb', line 13
def movie_extname_regex
@movie_extname_regex
end
|
.sound_extname_regex ⇒ Object
NOTE careful when subclassing, it doesn’t inherit the attr values
13
14
15
|
# File 'lib/ffmprb/file.rb', line 13
def sound_extname_regex
@sound_extname_regex
end
|
Instance Attribute Details
#mode ⇒ Object
Returns the value of attribute mode.
94
95
96
|
# File 'lib/ffmprb/file.rb', line 94
def mode
@mode
end
|
Class Method Details
.access(path) ⇒ Object
31
32
33
34
35
|
# File 'lib/ffmprb/file.rb', line 31
def access(path)
new(path: path, mode: :read).tap do |file|
Ffmprb.logger.debug{"Accessed file with path: #{file.path}"}
end
end
|
.create(path) ⇒ Object
25
26
27
28
29
|
# File 'lib/ffmprb/file.rb', line 25
def create(path)
new(path: path, mode: :write).tap do |file|
Ffmprb.logger.debug{"Created file with path: #{file.path}"}
end
end
|
.image?(extname) ⇒ Boolean
80
81
82
|
# File 'lib/ffmprb/file.rb', line 80
def image?(extname)
!!(extname =~ image_extname_regex)
end
|
.movie?(extname) ⇒ Boolean
88
89
90
|
# File 'lib/ffmprb/file.rb', line 88
def movie?(extname)
!!(extname =~ movie_extname_regex)
end
|
.opener(file, mode = nil) ⇒ Object
NOTE must be timeout-safe
16
17
18
19
20
21
22
23
|
# File 'lib/ffmprb/file.rb', line 16
def opener(file, mode=nil)
->{
path = file.respond_to?(:path)? file.path : file
mode ||= file.respond_to?(mode)? file.mode.to_s[0] : 'r'
Ffmprb.logger.debug{"Trying to open #{path} (for #{mode}-buffering or something)"}
::File.open path, mode
}
end
|
.sound?(extname) ⇒ Boolean
84
85
86
|
# File 'lib/ffmprb/file.rb', line 84
def sound?(extname)
!!(extname =~ sound_extname_regex)
end
|
.temp(extname) ⇒ Object
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
# File 'lib/ffmprb/file.rb', line 37
def temp(extname)
file = create(Tempfile.new(['', extname]))
path = file.path
Ffmprb.logger.debug{"Created temp file with path: #{path}"}
return file unless block_given?
begin
yield file
ensure
begin
file.unlink
rescue
Ffmprb.logger.warn "#{$!.class.name} removing temp file with path #{path}: #{$!.message}"
end
Ffmprb.logger.debug{"Removed temp file with path: #{path}"}
end
end
|
.temp_fifo(extname = '.tmp', &blk) ⇒ Object
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# File 'lib/ffmprb/file.rb', line 56
def temp_fifo(extname='.tmp', &blk)
path = temp_fifo_path(extname)
mkfifo path
fifo_file = create(path)
return fifo_file unless block_given?
path = fifo_file.path
begin
yield fifo_file
ensure
begin
fifo_file.unlink
rescue
Ffmprb.logger.warn "#{$!.class.name} removing temp file with path #{path}: #{$!.message}"
end
Ffmprb.logger.debug{"Removed temp file with path: #{path}"}
end
end
|
.temp_fifo_path(extname) ⇒ Object
76
77
78
|
# File 'lib/ffmprb/file.rb', line 76
def temp_fifo_path(extname)
join Dir.tmpdir, "#{rand(2**222)}p#{extname}"
end
|
.threaded_buffered_fifo(extname = '.tmp', reader_open_on_writer_idle_limit: nil, proc_vis: nil) ⇒ Object
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
# File 'lib/ffmprb/file/threaded_buffered.rb', line 7
def threaded_buffered_fifo(extname='.tmp', reader_open_on_writer_idle_limit: nil, proc_vis: nil)
input_fifo_file = temp_fifo(extname)
output_fifo_file = temp_fifo(extname)
Ffmprb.logger.debug{"Opening #{input_fifo_file.path}>#{output_fifo_file.path} for buffering"}
Util::Thread.new do
begin
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)
if proc_vis
proc_vis.proc_vis_edge input_fifo_file, io_buff
proc_vis.proc_vis_edge io_buff, output_fifo_file
end
begin
ensure
Util::Thread.join_children!
end
Ffmprb.logger.debug{"IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} ended"}
ensure
input_fifo_file.unlink if input_fifo_file
output_fifo_file.unlink if output_fifo_file
end
end
Ffmprb.logger.debug{"IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} started"}
[input_fifo_file, output_fifo_file]
end
|
Instance Method Details
#basename ⇒ Object
119
120
121
|
# File 'lib/ffmprb/file.rb', line 119
def basename
@basename ||= File.basename(path)
end
|
#channel?(medium) ⇒ Boolean
127
128
129
130
131
132
133
134
|
# File 'lib/ffmprb/file.rb', line 127
def channel?(medium)
case medium
when :video
self.class.image?(extname) || self.class.movie?(extname)
when :audio
self.class.sound?(extname) || self.class.movie?(extname)
end
end
|
#creation_time(force = false) ⇒ Object
161
162
163
|
# File 'lib/ffmprb/file.rb', line 161
def creation_time(force=false)
Time.parse probe(force)['format']['tags']['creation_time']
end
|
#exist? ⇒ Boolean
115
116
117
|
# File 'lib/ffmprb/file.rb', line 115
def exist?
File.exist? path
end
|
#extname ⇒ Object
123
124
125
|
# File 'lib/ffmprb/file.rb', line 123
def extname
@extname ||= File.extname(path)
end
|
#fps(force = false) ⇒ Object
156
157
158
159
|
# File 'lib/ffmprb/file.rb', line 156
def fps(force=false)
v_stream = probe(force)['streams'].first
Rational v_stream['r_frame_rate'] || v_stream['avg_frame_rate']
end
|
#label ⇒ Object
105
106
107
|
# File 'lib/ffmprb/file.rb', line 105
def label
basename
end
|
#length(force = false) ⇒ Object
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
# File 'lib/ffmprb/file.rb', line 136
def length(force=false)
@duration = nil if force
return @duration if @duration
@duration = probe(force)['format']['duration']
@duration &&= @duration.to_f
return @duration if @duration
@duration = probe(true)['frames'].reduce(0) do |sum, frame|
sum + frame['pkt_duration_time'].to_f
end
end
|
#path ⇒ Object
109
110
111
|
# File 'lib/ffmprb/file.rb', line 109
def path
path!
end
|
#read ⇒ Object
168
169
170
|
# File 'lib/ffmprb/file.rb', line 168
def read
File.read path
end
|
#resolution(force = false) ⇒ Object
151
152
153
154
|
# File 'lib/ffmprb/file.rb', line 151
def resolution(force=false)
v_stream = probe(force)['streams'].first
"#{v_stream['width']}x#{v_stream['height']}"
end
|
#sample(at: 0.01, video: true, audio: true, &blk) ⇒ Object
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
# File 'lib/ffmprb/file/sample.rb', line 5
def sample(
at: 0.01,
video: true,
audio: true,
&blk
)
audio = File.temp('.wav') if audio == true
video = File.temp('.png') if video == true
Ffmprb.logger.debug{"Snap shooting files, video path: #{video ? video.path : 'NONE'}, audio path: #{audio ? audio.path : 'NONE'}"}
fail Error, "Incorrect output extname (must be image)" unless !video || video.channel?(:video) && !video.channel?(:audio)
fail Error, "Incorrect audio extname (must be sound)" unless !audio || audio.channel?(:audio) && !audio.channel?(:video)
fail Error, "Can sample either video OR audio UNLESS a block is given" unless block_given? || !!audio != !!video
cmd = %W[-i #{path}]
cmd.concat %W[-deinterlace -an -ss #{at} -vframes 1 #{video.path}] if video
cmd.concat %W[-vn -ss #{at} -t 1 #{audio.path}] if audio
Util.ffmpeg *cmd
return video || audio unless block_given?
begin
yield *[video || nil, audio || nil].compact
ensure
begin
video.unlink if video
audio.unlink if audio
Ffmprb.logger.debug{"Removed sample files"}
rescue
Ffmprb.logger.warn "#{$!.class.name} removing sample files: #{$!.message}"
end
end
end
|
#sample_audio(*audio, at: 0.01, &blk) ⇒ Object
42
43
44
|
# File 'lib/ffmprb/file/sample.rb', line 42
def sample_audio(*audio, at: 0.01, &blk)
sample at: at, video: false, audio: (audio.first || true), &blk
end
|
#sample_video(*video, at: 0.01, &blk) ⇒ Object
39
40
41
|
# File 'lib/ffmprb/file/sample.rb', line 39
def sample_video(*video, at: 0.01, &blk)
sample at: at, video: (video.first || true), audio: false, &blk
end
|
#threaded_buffered_copy_to(*dsts) ⇒ Object
36
37
38
39
40
41
42
43
44
|
# File 'lib/ffmprb/file/threaded_buffered.rb', line 36
def threaded_buffered_copy_to(*dsts)
Util::ThreadedIoBuffer.new(
self.class.opener(self, 'r'),
*dsts.map{|io| self.class.opener io, 'w'}
).tap do |io_buff|
proc_vis_edge self, io_buff
dsts.each{ |dst| proc_vis_edge io_buff, dst }
end
end
|
#unlink ⇒ Object
175
176
177
178
179
180
181
182
183
|
# File 'lib/ffmprb/file.rb', line 175
def unlink
if path.respond_to? :unlink
path.unlink
else
FileUtils.remove_entry path
end
Ffmprb.logger.debug{"Removed file with path: #{path}"}
@path = nil
end
|
#write(s) ⇒ Object
171
172
173
|
# File 'lib/ffmprb/file.rb', line 171
def write(s)
File.write path, s
end
|