class WahWah::Mp4::Atom

Constants

EXTENDED_HEADER_SIZE
FLAGGED_ATOMS
HEADER_SIZE
HEADER_SIZE_FIELD_SIZE
VERSIONED_ATOMS

Attributes

type[R]

Public Class Methods

find(file_io, *atom_path) click to toggle source
# File lib/wahwah/mp4/atom.rb, line 16
def self.find(file_io, *atom_path)
  file_io.rewind

  atom_type = atom_path.shift

  until file_io.eof?
    atom = new(file_io)

    next unless atom.valid?
    file_io.seek(atom.size, IO::SEEK_CUR); next unless atom.type == atom_type

    return atom if atom_path.empty?
    return atom.find(*atom_path)
  end

  # Return empty atom if can not found
  new(StringIO.new(''))
end
new() click to toggle source

An atom header consists of the following fields:

Atom size: A 32-bit integer that indicates the size of the atom, including both the atom header and the atom’s contents, including any contained atoms. Normally, the size field contains the actual size of the atom.

Type: A 32-bit integer that contains the type of the atom. This can often be usefully treated as a four-character field with a mnemonic value .

# File lib/wahwah/mp4/atom.rb, line 44
def initialize
  @size, @type = @file_io.read(HEADER_SIZE)&.unpack('Na4')
  return unless valid?

  # If the size field of an atom is set to 1, the type field is followed by a 64-bit extended size field,
  # which contains the actual size of the atom as a 64-bit unsigned integer.
  @size = @file_io.read(EXTENDED_HEADER_SIZE).unpack('Q>').first - EXTENDED_HEADER_SIZE if @size == 1

  # If the size field of an atom is set to 0, which is allowed only for a top-level atom,
  # designates the last atom in the file and indicates that the atom extends to the end of the file.
  @size = @file_io.size if @size == 0
  @size = @size - HEADER_SIZE
end

Public Instance Methods

children() click to toggle source
# File lib/wahwah/mp4/atom.rb, line 74
def children
  @children ||= parse_children_atoms
end
find(*atom_path) click to toggle source
# File lib/wahwah/mp4/atom.rb, line 62
def find(*atom_path)
  child_atom_index = data.index(atom_path.first)

  # Return empty atom if can not found
  return self.class.new(StringIO.new('')) if child_atom_index.nil?

  # Because before atom type field there are 4 bytes of size field,
  # So the child_atom_index should reduce 4.
  self.class.find(StringIO.new(data[child_atom_index - HEADER_SIZE_FIELD_SIZE..-1]), *atom_path)
end
valid?() click to toggle source
# File lib/wahwah/mp4/atom.rb, line 58
def valid?
  !@size.nil? && @size >= HEADER_SIZE
end

Private Instance Methods

parse_children_atoms() click to toggle source
# File lib/wahwah/mp4/atom.rb, line 79
def parse_children_atoms
  children_atoms = []
  atoms_data = data

  # Some atoms data contain extra content before child atom data.
  # So reduce those extra content to get child atom data.
  atoms_data = atoms_data[4..-1] if VERSIONED_ATOMS.include? type # Skip 4 bytes for version
  atoms_data = atoms_data[4..-1] if FLAGGED_ATOMS.include? type # Skip 4 bytes for flag
  atoms_data_io = StringIO.new(atoms_data)

  until atoms_data_io.eof?
    atom = self.class.new(atoms_data_io)
    children_atoms.push(atom)

    atom.skip
  end

  children_atoms
end