Box

Created
Jan 18, 2022 04:31 PM
Tags
MP4文件由多个box组成,每个box存储不同的信息,且box之间是树状结构
Boxes start with a header which gives both size and type. The header permits compact or extended size (32 or 64 bits) and compact or extended types (32 bits or full UUIDs). The standard boxes all use compact types (32-bit) and most boxes will use the compact (32-bit) size. Typically only the Media Data Box(es) need the 64- bit size.
aligned(8) class Box (unsigned int(32) boxtype, optional unsigned int(8)[16] extended_type) { unsigned int(32) size; unsigned int(32) type = boxtype; if (size==1) { unsigned int(64) largesize; } else if (size==0) { // box extends to end of file } if (boxtype==‘uuid’) { unsigned int(8)[16] usertype = extended_type; } }
size is an integer that specifies the number of bytes in this box, including all its fields and contained boxes; if size is 1 then the actual size is in the field largesize; if size is 0, then this box is the last one in the file, and its contents extend to the end of the file (normally only used for a Media Data Box)
type identifies the box type; standard boxes use a compact type, which is normally four printable characters, to permit ease of identification, and is shown so in the boxes below. User extensions use an extended type; in this case, the type field is set to ‘uuid’.
 
aligned(8) class FullBox(unsigned int(32) boxtype, unsigned int(8) v, bit(24) f) extends Box(boxtype) { unsigned int(8) version = v; bit(24) flags = f; }
version is an integer that specifies the version of this format of the box.
flags is a map of flags
 
 
notion image
#[derive(Debug, Clone, Copy)] pub struct BoxHeader { pub name: BoxType, pub size: u64, } impl BoxHeader { pub fn new(name: BoxType, size: u64) -> Self { Self { name, size } } // TODO: if size is 0, then this box is the last one in the file pub fn read<R: Read>(reader: &mut R) -> Result<Self> { // Create and read to buf. let mut buf = [0u8; 8]; // 8 bytes for box header. reader.read(&mut buf)?; // Get size. let s = buf[0..4].try_into().unwrap(); let size = u32::from_be_bytes(s); // Get box type string. let t = buf[4..8].try_into().unwrap(); let typ = u32::from_be_bytes(t); // Get largesize if size is 1 if size == 1 { reader.read(&mut buf)?; let s = buf.try_into().unwrap(); let largesize = u64::from_be_bytes(s); Ok(BoxHeader { name: BoxType::from(typ), size: largesize - HEADER_SIZE, }) } else { Ok(BoxHeader { name: BoxType::from(typ), size: size as u64, }) } } pub fn write<W: Write>(&self, writer: &mut W) -> Result<u64> { if self.size > u32::MAX as u64 { writer.write_u32::<BigEndian>(1)?; writer.write_u32::<BigEndian>(self.name.into())?; writer.write_u64::<BigEndian>(self.size)?; Ok(16) } else { writer.write_u32::<BigEndian>(self.size as u32)?; writer.write_u32::<BigEndian>(self.name.into())?; Ok(8) } } }