class AviGlitch::Frames

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.

Attributes

avi[R]

Public Class Methods

new(avi) click to toggle source

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

# File lib/aviglitch/frames.rb, line 26
def initialize avi
  @avi = avi
end

Public Instance Methods

*(times) click to toggle source

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

# 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) click to toggle source

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

# File lib/aviglitch/frames.rb, line 125
def + other_frames
  r = self.to_avi
  r.frames.concat other_frames
  r.frames
end
<<(frame)

Alias for push

Alias for: push
==(other) click to toggle source

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

# File lib/aviglitch/frames.rb, line 380
def == other
  @avi == other.avi
end
[](*args)

Alias for slice

Alias for: slice
[]=(*args) click to toggle source

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

# 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) click to toggle source

Returns one Frame object at the given index.

# 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
clear() click to toggle source

Removes all frames and returns self.

# File lib/aviglitch/frames.rb, line 90
def clear
  @avi.process_movi do |indices, movi|
    [[], StringIO.new]
  end
  self
end
concat(other_frames) click to toggle source

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

# 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_size() click to toggle source

Returns the data size of total frames.

# 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) click to toggle source

Deletes one Frame at the given index.

# File lib/aviglitch/frames.rb, line 362
def delete_at n
  self.slice! n
end
each(&block) click to toggle source

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

# 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
find_index(frame)

Alias for index

Alias for: index
first() click to toggle source

Returns the first Frame object.

# File lib/aviglitch/frames.rb, line 233
def first
  self.slice(0)
end
first_of(frame_type) click to toggle source

Returns the first Frame object in frame_type.

# 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) click to toggle source

Returns an index of the first found frame.

# 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
Also aliased as: find_index
insert(n, *args) click to toggle source

Inserts the given Frame objects into the given index.

# 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
last() click to toggle source

Returns the last Frame object.

# File lib/aviglitch/frames.rb, line 239
def last
  self.slice(self.size - 1)
end
last_of(frame_type) click to toggle source

Returns the last Frame object in frame_type.

# 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) click to toggle source

Mutates keyframes into deltaframes at given range, or all.

# 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) click to toggle source

Appends the given Frame into the tail of self.

# 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
Also aliased as: <<
rindex(frame) click to toggle source

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

# 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
size() click to toggle source

Returns the number of frames.

# File lib/aviglitch/frames.rb, line 65
def size
  @avi.indices.size
end
size_of(frame_type) click to toggle source

Returns the number of the specific frame_type.

# 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) click to toggle source

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.

# 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
Also aliased as: []
slice!(*args) click to toggle source

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

# 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
terminate() click to toggle source

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

# File lib/aviglitch/frames.rb, line 386
def terminate
  @avi.close
  @avi = nil
end
to_avi() click to toggle source

Generates new AviGlitch::Base instance using self.

# File lib/aviglitch/frames.rb, line 393
def to_avi
  AviGlitch::Base.new @avi.clone
end