.mov file format of QuickTime, MP4 ISO 14496-14 media: Lua parsing library

Application

QuickTime, MP4 ISO 14496-14 media

File extension

mov

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of .mov file format of QuickTime, MP4 ISO 14496-14 media using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Lua source code to parse .mov file format of QuickTime, MP4 ISO 14496-14 media

quicktime_mov.lua

-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
--
-- This file is compatible with Lua 5.3

local class = require("class")
require("kaitaistruct")
local enum = require("enum")
local stringstream = require("string_stream")
local utils = require("utils")

-- 
-- See also: Source (https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html#//apple_ref/doc/uid/TP40000939-CH203-BBCGDDDF)
QuicktimeMov = class.class(KaitaiStruct)

QuicktimeMov.AtomType = enum.Enum {
  xtra = 1484026465,
  dinf = 1684631142,
  dref = 1685218662,
  edts = 1701082227,
  elst = 1701606260,
  free = 1718773093,
  ftyp = 1718909296,
  hdlr = 1751411826,
  iods = 1768907891,
  mdat = 1835295092,
  mdhd = 1835296868,
  mdia = 1835297121,
  meta = 1835365473,
  minf = 1835626086,
  moof = 1836019558,
  moov = 1836019574,
  mvhd = 1836476516,
  smhd = 1936549988,
  stbl = 1937007212,
  stco = 1937007471,
  stsc = 1937011555,
  stsd = 1937011556,
  stsz = 1937011578,
  stts = 1937011827,
  tkhd = 1953196132,
  traf = 1953653094,
  trak = 1953653099,
  tref = 1953654118,
  udta = 1969517665,
  vmhd = 1986881636,
}

QuicktimeMov.Brand = enum.Enum {
  x_3g2a = 862401121,
  x_3ge6 = 862414134,
  x_3ge7 = 862414135,
  x_3ge9 = 862414137,
  x_3gf9 = 862414393,
  x_3gg6 = 862414646,
  x_3gg9 = 862414649,
  x_3gh9 = 862414905,
  x_3gm9 = 862416185,
  x_3gma = 862416193,
  x_3gp4 = 862416948,
  x_3gp5 = 862416949,
  x_3gp6 = 862416950,
  x_3gp7 = 862416951,
  x_3gp8 = 862416952,
  x_3gp9 = 862416953,
  x_3gr6 = 862417462,
  x_3gr9 = 862417465,
  x_3gs6 = 862417718,
  x_3gs9 = 862417721,
  x_3gt8 = 862417976,
  x_3gt9 = 862417977,
  x_3gtv = 862418038,
  x_3gvr = 862418546,
  x_3vra = 863400545,
  x_3vrb = 863400546,
  x_3vrm = 863400557,
  arri = 1095914057,
  caep = 1128351056,
  cdes = 1128555891,
  j2p0 = 1244811312,
  j2p1 = 1244811313,
  lcag = 1279476039,
  m4a = 1295270176,
  m4b = 1295270432,
  m4p = 1295274016,
  m4v = 1295275552,
  ma1a = 1296118081,
  ma1b = 1296118082,
  mfsm = 1296454477,
  mgsv = 1296520022,
  mppi = 1297109065,
  msnv = 1297305174,
  miab = 1298743618,
  miac = 1298743619,
  mian = 1298743662,
  mibu = 1298743925,
  micm = 1298744173,
  miha = 1298745409,
  mihb = 1298745410,
  mihe = 1298745413,
  mipr = 1298747506,
  ross = 1380930387,
  seau = 1397047637,
  sebk = 1397047883,
  xavc = 1480676931,
  adti = 1633973353,
  aid3 = 1634296883,
  av01 = 1635135537,
  avc1 = 1635148593,
  avci = 1635148649,
  avcs = 1635148659,
  avde = 1635148901,
  avif = 1635150182,
  avio = 1635150191,
  avis = 1635150195,
  bbxm = 1650620525,
  ca4m = 1667314797,
  ca4s = 1667314803,
  caaa = 1667326305,
  caac = 1667326307,
  cabl = 1667326572,
  cama = 1667329377,
  camc = 1667329379,
  caqv = 1667330422,
  casu = 1667330933,
  ccea = 1667458401,
  ccff = 1667458662,
  cdm1 = 1667525937,
  cdm4 = 1667525940,
  ceac = 1667588451,
  cfhd = 1667655780,
  cfsd = 1667658596,
  chd1 = 1667785777,
  chd2 = 1667785778,
  chdf = 1667785830,
  chev = 1667786102,
  chh1 = 1667786801,
  chhd = 1667786852,
  cint = 1667853940,
  clg1 = 1668048689,
  clg2 = 1668048690,
  cmf2 = 1668113970,
  cmfc = 1668114019,
  cmff = 1668114022,
  cmfl = 1668114028,
  cmfs = 1668114035,
  cmhm = 1668114541,
  cmhs = 1668114547,
  comp = 1668246896,
  csh1 = 1668507697,
  cud1 = 1668637745,
  cud2 = 1668637746,
  cud8 = 1668637752,
  cud9 = 1668637753,
  cuvd = 1668642404,
  cvid = 1668704612,
  cvvc = 1668707939,
  cwvt = 1668773492,
  da0a = 1684090977,
  da0b = 1684090978,
  da1a = 1684091233,
  da1b = 1684091234,
  da2a = 1684091489,
  da2b = 1684091490,
  da3a = 1684091745,
  da3b = 1684091746,
  dash = 1684108136,
  dby1 = 1684175153,
  dmb1 = 1684890161,
  dsms = 1685286259,
  dts1 = 1685353265,
  dts2 = 1685353266,
  dts3 = 1685353267,
  dv1a = 1685467489,
  dv1b = 1685467490,
  dv2a = 1685467745,
  dv2b = 1685467746,
  dv3a = 1685468001,
  dv3b = 1685468002,
  dvr1 = 1685484081,
  dvt1 = 1685484593,
  dxo = 1685614368,
  emsg = 1701671783,
  heic = 1751476579,
  heim = 1751476589,
  heis = 1751476595,
  heix = 1751476600,
  heoi = 1751478121,
  hevc = 1751479907,
  hevd = 1751479908,
  hevi = 1751479913,
  hevm = 1751479917,
  hevs = 1751479923,
  hevx = 1751479928,
  hvce = 1752589157,
  hvci = 1752589161,
  hvcx = 1752589176,
  hvti = 1752593513,
  ifaa = 1768317281,
  ifah = 1768317288,
  ifai = 1768317289,
  ifas = 1768317299,
  ifau = 1768317301,
  ifav = 1768317302,
  ifhd = 1768319076,
  ifhh = 1768319080,
  ifhr = 1768319090,
  ifhs = 1768319091,
  ifhu = 1768319093,
  ifhx = 1768319096,
  ifrm = 1768321645,
  ifsd = 1768321892,
  im1i = 1768763753,
  im1t = 1768763764,
  im2i = 1768764009,
  im2t = 1768764020,
  isc2 = 1769169714,
  iso2 = 1769172786,
  iso3 = 1769172787,
  iso4 = 1769172788,
  iso5 = 1769172789,
  iso6 = 1769172790,
  iso7 = 1769172791,
  iso8 = 1769172792,
  iso9 = 1769172793,
  isoa = 1769172833,
  isob = 1769172834,
  isoc = 1769172835,
  isom = 1769172845,
  j2is = 1781688691,
  j2ki = 1781689193,
  j2ks = 1781689203,
  jp2 = 1785737760,
  jpeg = 1785750887,
  jpgs = 1785751411,
  jpm = 1785752864,
  jpoi = 1785753449,
  jpsi = 1785754473,
  jpx = 1785755680,
  jpxb = 1785755746,
  jxl = 1786276896,
  jxs = 1786278688,
  jxsc = 1786278755,
  jxsi = 1786278761,
  jxss = 1786278771,
  lhte = 1818784869,
  lhti = 1818784873,
  lmsg = 1819112295,
  miaf = 1835622758,
  mif1 = 1835623985,
  mif2 = 1835623986,
  mj2s = 1835676275,
  mjp2 = 1835692082,
  mp21 = 1836069425,
  mp41 = 1836069937,
  mp42 = 1836069938,
  mp71 = 1836070705,
  mpuf = 1836086630,
  msdh = 1836278888,
  msf1 = 1836279345,
  msix = 1836280184,
  niko = 1852402543,
  nlsl = 1852601196,
  nras = 1852989811,
  oa2d = 1868640868,
  oabl = 1868653164,
  odcf = 1868850022,
  ompp = 1869443184,
  opf2 = 1869637170,
  opx2 = 1869641778,
  ovdp = 1870029936,
  ovly = 1870031993,
  paff = 1885431398,
  pana = 1885433441,
  piff = 1885955686,
  pmff = 1886217830,
  pnvi = 1886287465,
  pred = 1886545252,
  qt = 1903435808,
  relo = 1919249519,
  risx = 1919513464,
  sdv = 1935963680,
  senv = 1936027254,
  sims = 1936289139,
  sisx = 1936290680,
  siti = 1936290921,
  sitv = 1936290934,
  slh1 = 1936484401,
  slh2 = 1936484402,
  slh3 = 1936484403,
  ssss = 1936946035,
  ttml = 1953787244,
  ttwv = 1953789814,
  uhvi = 1969780329,
  unif = 1970170214,
  uvvu = 1970697845,
  v3mp = 1983081840,
  v3mt = 1983081844,
  v3nt = 1983082100,
  v3st = 1983083380,
  vvci = 1987470185,
  vvoi = 1987473257,
  vwpt = 1987539060,
  yt4 = 2037658656,
}

function QuicktimeMov:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov:_read()
  self.atoms = QuicktimeMov.AtomList(self._io, self, self._root)
end


-- 
-- See also: Source (https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-BBCGFGJG)
QuicktimeMov.MvhdBody = class.class(KaitaiStruct)

function QuicktimeMov.MvhdBody:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov.MvhdBody:_read()
  self.version = self._io:read_u1()
  self.flags = self._io:read_bytes(3)
  self.creation_time = self._io:read_u4be()
  self.modification_time = self._io:read_u4be()
  self.time_scale = self._io:read_u4be()
  self.duration = self._io:read_u4be()
  self.preferred_rate = QuicktimeMov.Fixed32(self._io, self, self._root)
  self.preferred_volume = QuicktimeMov.Fixed16(self._io, self, self._root)
  self.reserved1 = self._io:read_bytes(10)
  self.matrix = self._io:read_bytes(36)
  self.preview_time = self._io:read_u4be()
  self.preview_duration = self._io:read_u4be()
  self.poster_time = self._io:read_u4be()
  self.selection_time = self._io:read_u4be()
  self.selection_duration = self._io:read_u4be()
  self.current_time = self._io:read_u4be()
  self.next_track_id = self._io:read_u4be()
end

-- 
-- Version of this movie header atom.
-- 
-- A time value that indicates the time scale for this
-- movie - the number of time units that pass per second
-- in its time coordinate system. A time coordinate system that
-- measures time in sixtieths of a second, for example, has a
-- time scale of 60.
-- 
-- A time value that indicates the duration of the movie in
-- time scale units. Note that this property is derived from
-- the movie's tracks. The value of this field corresponds to
-- the duration of the longest track in the movie.
-- 
-- The rate at which to play this movie. A value of 1.0 indicates normal rate.
-- 
-- How loud to play this movie's sound. A value of 1.0 indicates full volume.
-- 
-- A matrix shows how to map points from one coordinate space into another.
-- 
-- The time value in the movie at which the preview begins.
-- 
-- The duration of the movie preview in movie time scale units.
-- 
-- The time value of the time of the movie poster.
-- 
-- The time value for the start time of the current selection.
-- 
-- The duration of the current selection in movie time scale units.
-- 
-- The time value for current time position within the movie.
-- 
-- Indicates a value to use for the track ID number of the next
-- track added to this movie. Note that 0 is not a valid track
-- ID value.

-- 
-- See also: Source (https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html#//apple_ref/doc/uid/TP40000939-CH203-CJBCBIFF)
QuicktimeMov.FtypBody = class.class(KaitaiStruct)

function QuicktimeMov.FtypBody:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov.FtypBody:_read()
  self.major_brand = QuicktimeMov.Brand(self._io:read_u4be())
  self.minor_version = self._io:read_bytes(4)
  self.compatible_brands = {}
  local i = 0
  while not self._io:is_eof() do
    self.compatible_brands[i + 1] = QuicktimeMov.Brand(self._io:read_u4be())
    i = i + 1
  end
end


-- 
-- Fixed-point 32-bit number.
QuicktimeMov.Fixed32 = class.class(KaitaiStruct)

function QuicktimeMov.Fixed32:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov.Fixed32:_read()
  self.int_part = self._io:read_s2be()
  self.frac_part = self._io:read_u2be()
end


-- 
-- Fixed-point 16-bit number.
QuicktimeMov.Fixed16 = class.class(KaitaiStruct)

function QuicktimeMov.Fixed16:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov.Fixed16:_read()
  self.int_part = self._io:read_s1()
  self.frac_part = self._io:read_u1()
end


QuicktimeMov.Atom = class.class(KaitaiStruct)

function QuicktimeMov.Atom:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov.Atom:_read()
  self.len32 = self._io:read_u4be()
  self.atom_type = QuicktimeMov.AtomType(self._io:read_u4be())
  if self.len32 == 1 then
    self.len64 = self._io:read_u8be()
  end
  local _on = self.atom_type
  if _on == QuicktimeMov.AtomType.moof then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.tkhd then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.TkhdBody(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.stbl then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.traf then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.minf then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.trak then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.moov then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.mdia then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.dinf then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.AtomList(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.mvhd then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.MvhdBody(_io, self, self._root)
  elseif _on == QuicktimeMov.AtomType.ftyp then
    self._raw_body = self._io:read_bytes(self.len)
    local _io = KaitaiStream(stringstream(self._raw_body))
    self.body = QuicktimeMov.FtypBody(_io, self, self._root)
  else
    self.body = self._io:read_bytes(self.len)
  end
end

QuicktimeMov.Atom.property.len = {}
function QuicktimeMov.Atom.property.len:get()
  if self._m_len ~= nil then
    return self._m_len
  end

  self._m_len = utils.box_unwrap((self.len32 == 0) and utils.box_wrap((self._io:size() - 8)) or (utils.box_unwrap((self.len32 == 1) and utils.box_wrap((self.len64 - 16)) or ((self.len32 - 8)))))
  return self._m_len
end


-- 
-- See also: Source (https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25550)
QuicktimeMov.TkhdBody = class.class(KaitaiStruct)

function QuicktimeMov.TkhdBody:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov.TkhdBody:_read()
  self.version = self._io:read_u1()
  self.flags = self._io:read_bytes(3)
  self.creation_time = self._io:read_u4be()
  self.modification_time = self._io:read_u4be()
  self.track_id = self._io:read_u4be()
  self.reserved1 = self._io:read_bytes(4)
  self.duration = self._io:read_u4be()
  self.reserved2 = self._io:read_bytes(8)
  self.layer = self._io:read_u2be()
  self.alternative_group = self._io:read_u2be()
  self.volume = self._io:read_u2be()
  self.reserved3 = self._io:read_u2be()
  self.matrix = self._io:read_bytes(36)
  self.width = QuicktimeMov.Fixed32(self._io, self, self._root)
  self.height = QuicktimeMov.Fixed32(self._io, self, self._root)
end

-- 
-- Integer that uniquely identifies the track. The value 0 cannot be used.

QuicktimeMov.AtomList = class.class(KaitaiStruct)

function QuicktimeMov.AtomList:_init(io, parent, root)
  KaitaiStruct._init(self, io)
  self._parent = parent
  self._root = root or self
  self:_read()
end

function QuicktimeMov.AtomList:_read()
  self.items = {}
  local i = 0
  while not self._io:is_eof() do
    self.items[i + 1] = QuicktimeMov.Atom(self._io, self, self._root)
    i = i + 1
  end
end