Class: AviGlitch::Frames

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/aviglitch/frames.rb

Overview

Frames provides the interface to access each frame in the AVI file. It is implemented as Enumerable. You can access this object through AviGlitch#frames, for example:

avi = AviGlitch.new '/path/to/your.avi'
frames = avi.frames
frames.each do |frame|
  ## frame is a reference of an AviGlitch::Frame object
  frame.data = frame.data.gsub(/\d/, '0')
end

In the block passed into iteration method, the parameter is a reference of AviGlitch::Frame object.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(avi) ⇒ Frames

Creates a new AviGlitch::Frames object. It takes AviGlitch::Avi as an argument.



26
27
28
# File 'lib/aviglitch/frames.rb', line 26

def initialize avi
  @avi = avi
end

Instance Attribute Details

#aviObject (readonly)

Returns the value of attribute avi.



21
22
23
# File 'lib/aviglitch/frames.rb', line 21

def avi
  @avi
end

Instance Method Details

#*(times) ⇒ Object

Returns the new Frames as a times times repeated concatenation of the original Frames.



134
135
136
137
138
139
140
141
142
# File 'lib/aviglitch/frames.rb', line 134

def * times
  result = self.slice 0, 0
  frames = self.slice 0..-1
  times.times do
    result.concat frames
  end
  frames.terminate
  result
end

#+(other_frames) ⇒ Object

Returns a concatenation of the two Frames as a new Frames instance.



125
126
127
128
129
# File 'lib/aviglitch/frames.rb', line 125

def + other_frames
  r = self.to_avi
  r.frames.concat other_frames
  r.frames
end

#==(other) ⇒ Object

Returns true if other‘s frames are same as self’s frames.



380
381
382
# File 'lib/aviglitch/frames.rb', line 380

def == other
  @avi == other.avi
end

#[]=(*args) ⇒ Object

Removes frame(s) at the given index or the range (same as []). Inserts the given Frame or Frames’s contents into the removed index.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/aviglitch/frames.rb', line 192

def []= *args
  value = args.pop
  b, l = get_beginning_and_length *args
  ll = l.nil? ? 1 : l
  head = self.slice(0, b)
  rest = self.slice((b + ll)..-1)
  if l.nil? || value.kind_of?(Frame)
    head.push value
  elsif value.kind_of?(Frames)
    head.concat value
  else
    raise TypeError
  end
  new_frames = head + rest

  self.clear
  self.concat new_frames
  
  new_frames.terminate
  head.terminate
  rest.terminate
end

#at(n) ⇒ Object

Returns one Frame object at the given index.



217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/aviglitch/frames.rb', line 217

def at n
  frame = nil
  @avi.process_movi do |indices, movi|
    m = indices[n]
    unless m.nil?
      movi.pos = m[:offset] + 8
      frame = Frame.new(movi.read(m[:size]), m[:id], m[:flag])
      movi.rewind
    end
    [indices, movi]
  end
  frame
end

#clearObject

Removes all frames and returns self.



90
91
92
93
94
95
# File 'lib/aviglitch/frames.rb', line 90

def clear
  @avi.process_movi do |indices, movi|
    [[], StringIO.new]
  end
  self
end

#concat(other_frames) ⇒ Object

Appends the frames in the other Frames into the tail of self. It is destructive like Array does.

Raises:

  • (TypeError)


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/aviglitch/frames.rb', line 100

def concat other_frames
  raise TypeError unless other_frames.kind_of?(Frames)
  @avi.process_movi do |this_indices, this_movi|
    this_size = this_movi.size
    this_movi.pos = this_size
    other_frames.avi.process_movi do |other_indices, other_movi|
      while d = other_movi.read(BUFFER_SIZE) do
        this_movi.print d
      end
      other_meta = other_indices.collect do |m|
        x = m.dup
        x[:offset] += this_size
        x
      end
      this_indices.concat other_meta
      [other_indices, other_movi]
    end
    [this_indices, this_movi]
  end

  self
end

#data_sizeObject

Returns the data size of total frames.



79
80
81
82
83
84
85
86
# File 'lib/aviglitch/frames.rb', line 79

def data_size
  size = 0
  @avi.process_movi do |indices, movi|
    size = movi.size
    [indices, movi]
  end
  size
end

#delete_at(n) ⇒ Object

Deletes one Frame at the given index.



362
363
364
# File 'lib/aviglitch/frames.rb', line 362

def delete_at n
  self.slice! n
end

#each(&block) ⇒ Object

Enumerates the frames. It returns Enumerator if a block is not given.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/aviglitch/frames.rb', line 33

def each &block
  if block_given?
    Tempfile.open('aviglitch-temp', @avi.tmpdir, binmode: true) do |newmovi|
      @avi.process_movi do |indices, movi|
        newindices = indices.select do |m|
          movi.pos = m[:offset] + 8    # 8 for id and size
          frame = Frame.new(movi.read(m[:size]), m[:id], m[:flag])
          block.call frame
          unless frame.data.nil?
            m[:offset] = newmovi.pos
            m[:size] = frame.data.size
            m[:flag] = frame.flag
            m[:id] = frame.id
            newmovi.print m[:id]
            newmovi.print [frame.data.size].pack('V')
            newmovi.print frame.data
            newmovi.print "\0" if frame.data.size % 2 == 1
            true
          else
            false
          end
        end
        [newindices, newmovi]
      end
    end
  else
    self.enum_for :each
  end
end

#firstObject

Returns the first Frame object.



233
234
235
# File 'lib/aviglitch/frames.rb', line 233

def first
  self.slice(0)
end

#first_of(frame_type) ⇒ Object

Returns the first Frame object in frame_type.



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/aviglitch/frames.rb', line 245

def first_of frame_type
  frame = nil
  @avi.process_movi do |indices, movi|
    indices.each do |m|
      movi.pos = m[:offset] + 8
      f = Frame.new(movi.read(m[:size]), m[:id], m[:flag])
      if f.is?(frame_type)
        frame = f
        break
      end
    end
    [indices, movi]
  end
  frame
end

#index(frame) ⇒ Object Also known as: find_index

Returns an index of the first found frame.



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/aviglitch/frames.rb', line 281

def index frame
  n = -1
  @avi.process_movi do |indices, movi|
    indices.each_with_index do |m, i|
      movi.pos = m[:offset] + 8
      f = Frame.new(movi.read(m[:size]), m[:id], m[:flag]) 
      if f == frame
        n = i
        break
      end
    end
    [indices, movi]
  end
  n
end

#insert(n, *args) ⇒ Object

Inserts the given Frame objects into the given index.



347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/aviglitch/frames.rb', line 347

def insert n, *args
  new_frames = self.slice(0, n)
  args.each do |f|
    new_frames.push f
  end
  new_frames.concat self.slice(n..-1)

  self.clear
  self.concat new_frames
  new_frames.terminate
  self
end

#inspectObject

:nodoc:



397
398
399
# File 'lib/aviglitch/frames.rb', line 397

def inspect #:nodoc:
  "#<#{self.class.name}:#{sprintf("0x%x", object_id)} size=#{self.size}>"
end

#lastObject

Returns the last Frame object.



239
240
241
# File 'lib/aviglitch/frames.rb', line 239

def last
  self.slice(self.size - 1)
end

#last_of(frame_type) ⇒ Object

Returns the last Frame object in frame_type.



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/aviglitch/frames.rb', line 263

def last_of frame_type
  frame = nil
  @avi.process_movi do |indices, movi|
    indices.reverse.each do |m|
      movi.pos = m[:offset] + 8
      f = Frame.new(movi.read(m[:size]), m[:id], m[:flag])
      if f.is?(frame_type)
        frame = f
        break
      end
    end
    [indices, movi]
  end
  frame
end

#mutate_keyframes_into_deltaframes!(range = nil) ⇒ Object

Mutates keyframes into deltaframes at given range, or all.



368
369
370
371
372
373
374
375
376
# File 'lib/aviglitch/frames.rb', line 368

def mutate_keyframes_into_deltaframes! range = nil
  range = 0..self.size if range.nil?
  self.each_with_index do |frame, i|
    if range.include? i
      frame.flag = 0 if frame.is_keyframe?
    end
  end
  self
end

#push(frame) ⇒ Object Also known as: <<

Appends the given Frame into the tail of self.

Raises:

  • (TypeError)


321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/aviglitch/frames.rb', line 321

def push frame
  raise TypeError unless frame.kind_of? Frame
  @avi.process_movi do |indices, movi|
    this_size = movi.size
    movi.pos = this_size
    movi.print frame.id
    movi.print [frame.data.size].pack('V')
    movi.print frame.data
    movi.print "\0" if frame.data.size % 2 == 1
    indices << {
      :id     => frame.id,
      :flag   => frame.flag,
      :offset => this_size,
      :size   => frame.data.size,
    }
    [indices, movi]
  end
  self
end

#rindex(frame) ⇒ Object

Returns an index of the first found frame, starting from the last.



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/aviglitch/frames.rb', line 303

def rindex frame
  n = -1
  @avi.process_movi do |indices, movi|
    indices.reverse.each_with_index do |m, i|
      movi.pos = m[:offset] + 8
      f = Frame.new(movi.read(m[:size]), m[:id], m[:flag])
      if f == frame
        n = indices.size - 1 - i
        break
      end
    end
    [indices, movi]
  end
  n
end

#safe_frames_count?(count) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


413
414
415
416
# File 'lib/aviglitch/frames.rb', line 413

def safe_frames_count? count #:nodoc:
  warn "[DEPRECATION] `safe_frames_count?` is deprecated."
  true
end

#sizeObject

Returns the number of frames.



65
66
67
# File 'lib/aviglitch/frames.rb', line 65

def size
  @avi.indices.size
end

#size_of(frame_type) ⇒ Object

Returns the number of the specific frame_type.



71
72
73
74
75
# File 'lib/aviglitch/frames.rb', line 71

def size_of frame_type
  @avi.indices.select { |m|
    Frame.new(nil, m[:id], m[:flag]).is? frame_type
  }.size
end

#slice(*args) ⇒ Object Also known as: []

Returns the Frame object at the given index or returns new Frames object that sliced with the given index and length or with the Range. Just like Array.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/aviglitch/frames.rb', line 149

def slice *args
  b, l = get_beginning_and_length *args
  if l.nil?
    self.at b
  else
    e = b + l - 1
    r = self.to_avi
    r.frames.each_with_index do |f, i|
      unless i >= b && i <= e
        f.data = nil
      end
    end
    r.frames
  end
end

#slice!(*args) ⇒ Object

Removes frame(s) at the given index or the range (same as slice). Returns the new Frames contains removed frames.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/aviglitch/frames.rb', line 172

def slice! *args
  b, l = get_beginning_and_length *args
  head, sliced, tail = ()
  sliced = l.nil? ? self.slice(b) : self.slice(b, l)
  head = self.slice(0, b)
  l = 1 if l.nil?
  tail = self.slice((b + l)..-1)
  self.clear
  temp = head + tail
  self.concat temp
  temp.terminate
  head.terminate
  tail.terminate
  
  sliced
end

#terminateObject

Closes the internal temp file explicitly. This instance becomes unusable.



386
387
388
389
# File 'lib/aviglitch/frames.rb', line 386

def terminate
  @avi.close
  @avi = nil
end

#to_aviObject

Generates new AviGlitch::Base instance using self.



393
394
395
# File 'lib/aviglitch/frames.rb', line 393

def to_avi
  AviGlitch::Base.new @avi.clone
end