Class: Ffmprb::File

Inherits:
Object
  • Object
show all
Defined in:
lib/ffmprb/file.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path:, mode:) ⇒ File

Returns a new instance of File.

Raises:



91
92
93
94
95
96
97
# File 'lib/ffmprb/file.rb', line 91

def initialize(path:, mode:)
  @path = path
  @path.close  if @path && @path.respond_to?(:close)  # NOTE specially for temp files
  path!  # NOTE early (exception) raiser
  @mode = mode.to_sym
  raise Error, "Open for read, create for write, ??? for #{@mode}"  unless %i[read write].include?(@mode)
end

Class Method Details

.buffered_fifo(extname = '.tmp') ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/ffmprb/file.rb', line 11

def buffered_fifo(extname='.tmp')
  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"
  buff = Util::IoBuffer.new(async_opener(input_fifo_file, 'r'), async_opener(output_fifo_file, 'w'))

  # NOTE the blocking cleanup thread to join for synchronisation
  thr = Util::Thread.new do
    buff.flush!
    Ffmprb.logger.debug "IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} ended"
    input_fifo_file.remove
    output_fifo_file.remove
  end
  Ffmprb.logger.debug "IoBuffering from #{input_fifo_file.path} to #{output_fifo_file.path} started"

  # XXX see io_buffer's XXX yield buff  if block_given?

  OpenStruct.new in: input_fifo_file, out: output_fifo_file, thr: thr
end

.create(path) ⇒ Object



32
33
34
35
36
# File 'lib/ffmprb/file.rb', line 32

def create(path)
  new(path: path, mode: :write).tap do |file|
    Ffmprb.logger.debug "Created file with path: #{file.path}"
  end
end

.open(path) ⇒ Object



38
39
40
41
42
# File 'lib/ffmprb/file.rb', line 38

def open(path)
  new(path: (path.respond_to?(:path)? path.path : path), mode: :read).tap do |file|
    Ffmprb.logger.debug "Opened file with path: #{file.path}"
  end
end

.temp(extname) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/ffmprb/file.rb', line 44

def temp(extname)
  file = create(Tempfile.new(['', extname]))
  Ffmprb.logger.debug "Created temp file with path: #{file.path}"

  return file  unless block_given?

  begin
    yield file
  ensure
    begin
      FileUtils.remove_entry file.path
    rescue
      Ffmprb.logger.warn "Error removing temp file with path #{file.path}: #{$!.message}"
    end
    Ffmprb.logger.debug "Removed temp file with path: #{file.path}"
  end
end

.temp_fifo(extname = '.tmp', &blk) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/ffmprb/file.rb', line 62

def temp_fifo(extname='.tmp', &blk)
  fifo_file = create(temp_fifo_path extname)
  ::File.mkfifo fifo_file.path

  return fifo_file  unless block_given?

  begin
    yield
  ensure
    fifo_file.remove
  end
end

.temp_fifo_path(extname) ⇒ Object



75
76
77
# File 'lib/ffmprb/file.rb', line 75

def temp_fifo_path(extname)
  ::File.join Dir.tmpdir, Dir::Tmpname.make_tmpname('', 'p' + extname)
end

Instance Method Details

#channel?(medium) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
118
119
120
# File 'lib/ffmprb/file.rb', line 113

def channel?(medium)
  case medium
  when :video
    image_extname? || movie_extname?
  when :audio
    sound_extname? || movie_extname?
  end
end

#exist?Boolean

Info

Returns:

  • (Boolean)


105
106
107
# File 'lib/ffmprb/file.rb', line 105

def exist?
  ::File.exist? path
end

#extnameObject



109
110
111
# File 'lib/ffmprb/file.rb', line 109

def extname
  ::File.extname path
end

#lengthObject



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/ffmprb/file.rb', line 122

def length
  return @duration  if @duration

  # NOTE first attempt
  @duration = probe['format']['duration']
  @duration &&= @duration.to_f
  return @duration  if @duration

  # NOTE a harder try
  @duration = probe(true)['frames'].reduce(0) do |sum, frame|
    sum + frame['pkt_duration_time'].to_f
  end
end

#pathObject



99
100
101
# File 'lib/ffmprb/file.rb', line 99

def path
  path!
end

#readObject

Manipulation



178
179
180
# File 'lib/ffmprb/file.rb', line 178

def read
  ::File.read path
end

#removeObject



185
186
187
188
189
# File 'lib/ffmprb/file.rb', line 185

def remove
  FileUtils.remove_entry path
  Ffmprb.logger.debug "Removed file with path: #{path}"
  @path = nil
end

#resolutionObject



136
137
138
139
# File 'lib/ffmprb/file.rb', line 136

def resolution
  v_stream = probe['streams'].first
  "#{v_stream['width']}x#{v_stream['height']}"
end

#sample(at: 0.01, video: true, audio: nil) ⇒ Object

NOTE can snap output (an image) or audio (a sound) or both

Raises:



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/ffmprb/file.rb', line 142

def sample(  # NOTE can snap output (an image) or audio (a sound) or both
  at: 0.01,
  video: true,
  audio: nil
)
  audio = File.temp('.mp3')  if audio == true
  video = File.temp('.jpg')  if video == true

  Ffmprb.logger.debug "Snap shooting files, video path: #{video ? video.path : 'NONE'}, audio path: #{audio ? audio.path : 'NONE'}"

  raise Error, "Incorrect output extname (must be .jpg)"  unless !video || video.channel?(:video) && !video.channel?(:audio)
  raise Error, "Incorrect audio extname (must be .mp3)"  unless !audio || audio.channel?(:audio) && !audio.channel?(:video)
  raise Error, "Can sample either video OR audio UNLESS a block is given"  unless block_given? || !!audio != !!video

  cmd = ['-i', path]
  cmd += ['-deinterlace', '-an', '-ss', at, '-r', 1, '-vcodec', 'mjpeg', '-f', 'mjpeg', video.path]  if video
  cmd += ['-vn', '-ss', at, '-t', 1, '-f', 'mp3', audio.path]  if audio
  Util.ffmpeg *cmd

  return video || audio  unless block_given?

  begin
    yield *[video || nil, audio || nil].compact
  ensure
    begin
      video.remove  if video
      audio.remove  if audio
      Ffmprb.logger.debug "Removed sample files"
    rescue
      Ffmprb.logger.warn "Error removing sample files: #{$!.message}"
    end
  end
end

#write(s) ⇒ Object



181
182
183
# File 'lib/ffmprb/file.rb', line 181

def write(s)
  ::File.write path, s
end