Skip to content

Instantly share code, notes, and snippets.

@shssoichiro
Created February 28, 2019 21:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shssoichiro/b031c3ae78d2717b8d2f786fe908d7d5 to your computer and use it in GitHub Desktop.
Save shssoichiro/b031c3ae78d2717b8d2f786fe908d7d5 to your computer and use it in GitHub Desktop.
use bitstream_io::{BigEndian, BitWriter};
use std::io;
use std::mem::size_of;
use uuid::Uuid;
use std::io::Write;
/// 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.
struct BoxAtom {
/// `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,
/// which are identified via a UUID.e
box_type: BoxType,
full_box_info: Option<FullBoxInfo>,
data: Box<dyn BoxData>,
}
#[derive(Debug, Clone, Copy)]
enum BoxType {
Compact([u8; 4]),
Extended(Uuid),
}
#[derive(Debug, Clone, Copy)]
/// Many objects also contain a version number and flags field.
struct FullBoxInfo {
/// `version` is an integer that specifies the version of this format of the box.
version: u8,
/// `flags` is a map of flags.
flags: [u8; 3],
}
trait BoxData {
fn size(&self) -> u64;
fn write<W: Write>(&self, writer: &mut BitWriter<W, BigEndian>) -> io::Result<()>;
}
#[derive(Debug, Clone)]
struct FileTypeData {
/// A brand identifier.
///
/// Each brand is a printable four-character code, registered with ISO, that identifies a precise specification.
major_brand: [u8; 4],
/// An informative integer for the minor version of the major brand.
minor_version: u32,
/// A list, to the end of the box, of brands.
///
/// Each brand is a printable four-character code, registered with ISO, that identifies a precise specification.
compatible_brands: Vec<[u8; 4]>,
}
impl BoxData for FileTypeData {
fn size(&self) -> u64 {
(size_of::<u8>() * 4 + size_of::<u32>() + size_of::<u8>() * self.compatible_brands.len())
as u64
}
fn write<W: Write>(&self, writer: &mut BitWriter<W, BigEndian>) -> io::Result<()> {
writer.write_bytes(&self.major_brand)?;
writer.write(32, self.minor_version)?;
for brand in &self.compatible_brands {
writer.write_bytes(brand)?;
}
Ok(())
}
}
impl BoxAtom {
fn file_type_box(
major_brand: [u8; 4],
minor_version: u32,
compatible_brands: Vec<[u8; 4]>,
) -> Self {
Self {
box_type: BoxType::Compact(*b"ftyp"),
full_box_info: None,
data: Box::new(FileTypeData {
major_brand,
minor_version,
compatible_brands,
}),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment