Skip to content

Instantly share code, notes, and snippets.

@dyntopia dyntopia/mkmp4.py Secret
Created Dec 13, 2017

Embed
What would you like to do?
#!/usr/bin/env python2
import sys
import struct
def l8(n):
return struct.pack("<Q", n)
def b8(n):
return struct.pack(">Q", n)
def b4(n):
return struct.pack(">I", n)
def b2(n):
return struct.pack(">H", n)
def b1(n):
return struct.pack(">B", n)
#
# MP4 boxes
#
class Box(object):
data = []
def __init__(self, parent=None, **kwargs):
self.children = []
self.size = 0
self.parent = parent
self.data = "".join(self.data)
self.increase(len(self.data) + 4)
if parent:
parent.children.append(self)
def increase(self, size):
self.size += size
if self.parent:
self.parent.increase(size)
def get(self):
return "".join([
b4(self.size),
self.data,
"".join([c.get() for c in self.children])
])
class Ftyp(Box):
data = [
"ftyp", # type
"iso2", # major brand
b4(0), # minor version
]
class Moov(Box):
data = [
"moov", # type
]
class Mvhd(Box):
data = [
"mvhd", # type
b4(0), # version/flags
b4(0), # creation time
b4(0), # modification time
b4(1), # timescale
b4(0), # duration
b4(0), # rate
b2(0), # volume
b2(0), # reserved
b4(0), # reserved
b4(0), # reserved
b4(0), # matrix[0]
b4(0), # matrix[1]
b4(0), # matrix[2]
b4(0), # matrix[3]
b4(0), # matrix[4]
b4(0), # matrix[5]
b4(0), # matrix[6]
b4(0), # matrix[7]
b4(0), # matrix[8]
b4(0), # predefined
b4(0), # predefined
b4(0), # predefined
b4(0), # predefined
b4(0), # predefined
b4(0), # predefined
b4(1), # next track id
]
class Trak(Box):
data = [
"trak", # type
]
class Tkhd(Box):
data = [
"tkhd", # type
b4(0), # version/flags
b4(0), # creation time
b4(0), # modification time
b4(1), # track id
b4(0), # reserved
b4(0), # duration
b4(0), # reserved
b4(0), # reserved
b2(0), # layer
b2(0), # predefined
b2(0), # volume
b2(0), # reserved
b4(0), # matrix[0]
b4(0), # matrix[1]
b4(0), # matrix[2]
b4(0), # matrix[3]
b4(0), # matrix[4]
b4(0), # matrix[5]
b4(0), # matrix[6]
b4(0), # matrix[7]
b4(0), # matrix[8]
b4(0), # width
b4(0), # height
]
class Mdia(Box):
data = [
"mdia", # type
]
class Mdhd(Box):
data = [
"mdhd", # type
b4(0), # version/flags
b4(0), # creation time
b4(0), # modification time
b4(1), # timescale
b4(0), # duration
b2(0), # language
b2(0), # predefined
]
class Hdlr(Box):
data = [
"hdlr", # type
b4(0), # version/flags
b4(0), # predefined
"soun", # handler type
b4(0), # reserved
b4(0), # reserved
b4(0), # reserved
"\x00", # null-terminated name
]
class Minf(Box):
data = [
"minf", # type
]
class Smhd(Box):
data = [
"smhd", # type
b4(0), # version/flags
b2(0), # balance
b2(0), # reserved
]
class Stbl(Box):
data = [
"stbl", # type
]
class Stsd(Box):
data = [
"stsd", # type
b4(0), # version/flags
b4(1), # entry count
]
class Sinf(Box):
data = [
"sinf", # type
]
class Frma(Box):
data = [
"frma", # type
"vide", # original format
]
class Stts(Box):
data = [
"stts", # type
b4(0), # version/flags
b4(0), # entry count
]
class Stsc(Box):
data = [
"stsc", # type
b4(0), # version/flags
b4(0), # entry count
]
class Stsz(Box):
data = [
"stsz", # type
b4(0), # version/flags
b4(0), # sample size
b4(0), # sample count
]
class Stco(Box):
data = [
"stco", # type
b4(0), # version/flags
b4(0), # entry count
]
class Dinf(Box):
data = [
"dinf", # type
]
class Dref(Box):
data = [
"dref", # type
b4(0), # version/flags
b4(1), # entry count
]
class Url(Box):
data = [
"url ", # type
b4(0), # version/flags
"\x00", # url
]
class Soun(Box):
data = [
"soun", # type
b1(0), # reserved
b1(0), # reserved
b1(0), # reserved
b1(0), # reserved
b1(0), # reserved
b1(0), # reserved
b2(1), # data reference index
b2(0), # qt version
b2(0), # qt revision level
b4(0), # qt vendor
b2(0), # channel count
b2(0), # sample size
b2(0), # compression id
b2(0), # reserved
b2(0), # sample rate hi
b2(0), # sample rate lo
]
class Uuid(Box):
"""
The CodecPrivateData (cpd) is hopefully allocated immediately after
p_sample_soun and interpreted as being part of p_sample_vide when
its p_box->i_type has been changed with the frma
"""
data = [
"uuid", # type
b8(0xb03ef77033bd4bac), # 16-byte uuid type (stra)
b8(0x96c7bf25f97e2447),
b1(0), # es cat
b1(0), # reserved
b2(0), # track id
b4(0), # timescale
b8(0), # duration
b4(0), # fourcc
b4(0), # bitrate
b4(0), # max width
b4(0), # max height
b4(0), # sampling rate
b4(0), # channels
b4(0), # bits per sample
b4(0), # audio tag
b2(0), # block align
b1(0), # reserved
b1(0), # reserved
b1(0), # reserved
b1(72), # cpd len
"A" * 8, # cpd data
l8(0x1122334455667788),
"A" * 56,
]
def mkmp4():
ftyp = Ftyp()
moov = Moov()
mvhd = Mvhd(moov)
trak = Trak(moov)
tkhd = Tkhd(trak)
mdia = Mdia(trak)
mdhd = Mdhd(mdia)
hdlr = Hdlr(mdia)
minf = Minf(mdia)
smhd = Smhd(minf)
stbl = Stbl(minf)
stsd = Stsd(stbl)
soun = Soun(stsd)
for i in range(10):
uuid = Uuid(soun)
sinf = Sinf(soun)
frma = Frma(sinf)
stts = Stts(stbl)
stsc = Stsc(stbl)
stsz = Stsz(stbl)
stco = Stco(stbl)
dinf = Dinf(minf)
dref = Dref(dinf)
url = Url(dref)
return ftyp.get() + moov.get()
def main():
if len(sys.argv) != 2:
sys.exit("usage: %s filename" % sys.argv[0])
with open(sys.argv[1], "wb") as f:
f.write(mkmp4())
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.