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:



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

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') {|buff| ... } ⇒ Object

Yields:

  • (buff)


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
# 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(
    ->{
      Ffmprb.logger.debug "Trying to open #{input_fifo_file.path} for reading+buffering"
      ::File.open(input_fifo_file.path, 'r')
    },
    ->{
      Ffmprb.logger.debug "Trying to open #{output_fifo_file.path} for buffering+writing"
      ::File.open(output_fifo_file.path, 'w')
      }
    )
  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"

  yield buff  if block_given?  # XXX a hidden option

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

.create(path) ⇒ Object



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

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



45
46
47
48
49
# File 'lib/ffmprb/file.rb', line 45

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



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ffmprb/file.rb', line 51

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



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/ffmprb/file.rb', line 69

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



82
83
84
# File 'lib/ffmprb/file.rb', line 82

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

Instance Method Details

#extnameObject

Info



103
104
105
# File 'lib/ffmprb/file.rb', line 103

def extname
  ::File.extname path
end

#lengthObject



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

def length
  @duration ||= probe['format']['duration']
  return @duration.to_f  if @duration

  @duration = probe(true)['frames'].reduce(0){|sum, frame| sum + frame['pkt_duration_time'].to_f}
end

#pathObject



97
98
99
# File 'lib/ffmprb/file.rb', line 97

def path
  path!
end

#removeObject

Manipulation



156
157
158
159
160
# File 'lib/ffmprb/file.rb', line 156

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

#resolutionObject



114
115
116
117
# File 'lib/ffmprb/file.rb', line 114

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:



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/ffmprb/file.rb', line 120

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.extname =~ /jpe?g$/
  raise Error, "Incorrect audio extname (must be .mp3)"  unless !audio || audio.extname =~ /mp3$/
  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