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.



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

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.



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

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

#+(other_frames) ⇒ Object

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



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

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.



368
369
370
# File 'lib/aviglitch/frames.rb', line 368

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.



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/aviglitch/frames.rb', line 185

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
end

#at(n) ⇒ Object

Returns one Frame object at the given index.



206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/aviglitch/frames.rb', line 206

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.



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

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)


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

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.



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

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.



350
351
352
# File 'lib/aviglitch/frames.rb', line 350

def delete_at n
  self.slice! n
end

#each(&block) ⇒ Object

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



32
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
# File 'lib/aviglitch/frames.rb', line 32

def each &block
  if block_given?
    Tempfile.open('temp', 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.



222
223
224
# File 'lib/aviglitch/frames.rb', line 222

def first
  self.slice(0)
end

#first_of(frame_type) ⇒ Object

Returns the first Frame object in frame_type.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/aviglitch/frames.rb', line 234

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.



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/aviglitch/frames.rb', line 270

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.



336
337
338
339
340
341
342
343
344
345
346
# File 'lib/aviglitch/frames.rb', line 336

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
  self
end

#inspectObject

:nodoc:



378
379
380
# File 'lib/aviglitch/frames.rb', line 378

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

#lastObject

Returns the last Frame object.



228
229
230
# File 'lib/aviglitch/frames.rb', line 228

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

#last_of(frame_type) ⇒ Object

Returns the last Frame object in frame_type.



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/aviglitch/frames.rb', line 252

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.



356
357
358
359
360
361
362
363
364
# File 'lib/aviglitch/frames.rb', line 356

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)


310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/aviglitch/frames.rb', line 310

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.



292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/aviglitch/frames.rb', line 292

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)


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

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

#sizeObject

Returns the number of frames.



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

def size
  @avi.indices.size
end

#size_of(frame_type) ⇒ Object

Returns the number of the specific frame_type.



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

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.



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

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.



170
171
172
173
174
175
176
177
178
179
180
# File 'lib/aviglitch/frames.rb', line 170

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
  self.concat head + tail
  sliced
end

#to_aviObject

Generates new AviGlitch::Base instance using self.



374
375
376
# File 'lib/aviglitch/frames.rb', line 374

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