From 9e6e4962f2346a3fbd96ab3e6c331858ef6ec0d1 Mon Sep 17 00:00:00 2001 From: Felix Kaaman Date: Thu, 7 Jan 2021 20:32:49 +0100 Subject: Initial commit --- src/lib.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/lib.rs (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..0630a15 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,129 @@ +#![allow(dead_code)] + +use std::io; + +use byteorder::{BigEndian, ByteOrder}; +use bytes::{BufMut, BytesMut}; +pub use four_cc::FourCC; + +mod boxes; + +pub use boxes::*; + +fn get_total_box_size(boks: &B) -> u64 { + let size = boks.content_size(); + + if boks.get_full_box_header().is_some() { + size + FullBoxHeader::SIZE + 8 + } else { + size + 8 + } +} + +fn write_box_header(header: &mut [u8], size: u64) -> usize { + if size > u32::MAX as _ { + BigEndian::write_u32(&mut header[..], 1); + header[4..8].copy_from_slice(&B::NAME.0); + BigEndian::write_u64(&mut header[8..], size); + + 16 + } else { + BigEndian::write_u32(&mut header[..], size as u32); + header[4..8].copy_from_slice(&B::NAME.0); + + 8 + } +} + +fn write_full_box_header(header: &mut [u8], box_header: FullBoxHeader) -> usize { + header[0] = box_header.version; + BigEndian::write_u24(&mut header[1..], box_header.flags); + + 4 +} + +#[derive(Copy, Clone)] +pub struct FullBoxHeader { + version: u8, + flags: u32, +} + +impl FullBoxHeader { + pub const SIZE: u64 = 4; + + pub fn new(version: u8, flags: u32) -> Self { + FullBoxHeader { version, flags } + } +} + +#[derive(Debug, thiserror::Error)] +pub enum Mp4BoxError { + #[error("Failed to write box: {0}")] + IoError(#[from] io::Error), +} + +/// A trait interface for a MP4 box. +pub trait Mp4Box { + const NAME: FourCC; + + fn get_full_box_header(&self) -> Option { + None + } + + fn flags(&self) -> Option { + self.get_full_box_header().map(|h| h.flags) + } + + /// The size of the contents of the box. + fn content_size(&self) -> u64; + + fn size(&self) -> u64 { + get_total_box_size::(&self) + } + + fn write_box_contents(&self, writer: &mut BytesMut) -> Result<(), Mp4BoxError>; + + fn write(&self, writer: &mut BytesMut) -> Result<(), Mp4BoxError> { + let mut header = [0u8; 20]; + + /* println!( + "{}: {}/{}", + std::any::type_name::(), + self.size(), + self.content_size() + ); */ + + let mut size = write_box_header::(&mut header, self.size()); + if let Some(box_header) = self.get_full_box_header() { + size += write_full_box_header(&mut header[size..], box_header); + } + + writer.put_slice(&header[..size]); + + self.write_box_contents(writer)?; + + Ok(()) + } +} + +pub struct MediaDataBox<'a> { + pub data: &'a [u8], +} + +impl<'a> Mp4Box for MediaDataBox<'a> { + const NAME: FourCC = FourCC(*b"mdat"); + + fn get_full_box_header(&self) -> Option { + Some(FullBoxHeader::new(0, 0)) + } + + fn content_size(&self) -> u64 { + self.data.len() as _ + } + + fn write_box_contents(&self, writer: &mut BytesMut) -> Result<(), Mp4BoxError> { + writer.put_slice(&self.data); + + Ok(()) + } +} -- cgit v1.2.3-70-g09d2