blob: 076b1161c3ea13d2afc9e742ea4b839c29f4a866 [file] [log] [blame]
#![allow(dead_code)]
use nom8::input::Streaming;
use nom8::prelude::*;
use nom8::{
branch::alt,
bytes::{tag, take},
error::ErrorKind,
multi::many0,
number::{be_f32, be_u16, be_u32, be_u64},
Err, IResult, Needed,
};
use std::str;
fn mp4_box(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, &[u8]> {
match be_u32(input) {
Ok((i, offset)) => {
let sz: usize = offset as usize;
if i.len() >= sz - 4 {
Ok((Streaming(&i[(sz - 4)..]), &i[0..(sz - 4)]))
} else {
Err(Err::Incomplete(Needed::new(offset as usize + 4)))
}
}
Err(e) => Err(e),
}
}
#[cfg_attr(rustfmt, rustfmt_skip)]
#[derive(PartialEq,Eq,Debug)]
struct FileType<'a> {
major_brand: &'a str,
major_brand_version: &'a [u8],
compatible_brands: Vec<&'a str>
}
#[cfg_attr(rustfmt, rustfmt_skip)]
#[allow(non_snake_case)]
#[derive(Debug,Clone)]
pub struct Mvhd32 {
version_flags: u32, // actually:
// version: u8,
// flags: u24 // 3 bytes
created_date: u32,
modified_date: u32,
scale: u32,
duration: u32,
speed: f32,
volume: u16, // actually a 2 bytes decimal
/* 10 bytes reserved */
scaleA: f32,
rotateB: f32,
angleU: f32,
rotateC: f32,
scaleD: f32,
angleV: f32,
positionX: f32,
positionY: f32,
scaleW: f32,
preview: u64,
poster: u32,
selection: u64,
current_time: u32,
track_id: u32
}
#[cfg_attr(rustfmt, rustfmt_skip)]
#[allow(non_snake_case)]
#[derive(Debug,Clone)]
pub struct Mvhd64 {
version_flags: u32, // actually:
// version: u8,
// flags: u24 // 3 bytes
created_date: u64,
modified_date: u64,
scale: u32,
duration: u64,
speed: f32,
volume: u16, // actually a 2 bytes decimal
/* 10 bytes reserved */
scaleA: f32,
rotateB: f32,
angleU: f32,
rotateC: f32,
scaleD: f32,
angleV: f32,
positionX: f32,
positionY: f32,
scaleW: f32,
preview: u64,
poster: u32,
selection: u64,
current_time: u32,
track_id: u32
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn mvhd32(i: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MvhdBox> {
let (i, version_flags) = be_u32(i)?;
let (i, created_date) = be_u32(i)?;
let (i, modified_date) = be_u32(i)?;
let (i, scale) = be_u32(i)?;
let (i, duration) = be_u32(i)?;
let (i, speed) = be_f32(i)?;
let (i, volume) = be_u16(i)?; // actually a 2 bytes decimal
let (i, _) = take(10_usize)(i)?;
let (i, scale_a) = be_f32(i)?;
let (i, rotate_b) = be_f32(i)?;
let (i, angle_u) = be_f32(i)?;
let (i, rotate_c) = be_f32(i)?;
let (i, scale_d) = be_f32(i)?;
let (i, angle_v) = be_f32(i)?;
let (i, position_x) = be_f32(i)?;
let (i, position_y) = be_f32(i)?;
let (i, scale_w) = be_f32(i)?;
let (i, preview) = be_u64(i)?;
let (i, poster) = be_u32(i)?;
let (i, selection) = be_u64(i)?;
let (i, current_time) = be_u32(i)?;
let (i, track_id) = be_u32(i)?;
let mvhd_box = MvhdBox::M32(Mvhd32 {
version_flags,
created_date,
modified_date,
scale,
duration,
speed,
volume,
scaleA: scale_a,
rotateB: rotate_b,
angleU: angle_u,
rotateC: rotate_c,
scaleD: scale_d,
angleV: angle_v,
positionX: position_x,
positionY: position_y,
scaleW: scale_w,
preview,
poster,
selection,
current_time,
track_id,
});
Ok((i, mvhd_box))
}
#[cfg_attr(rustfmt, rustfmt_skip)]
fn mvhd64(i: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MvhdBox> {
let (i, version_flags) = be_u32(i)?;
let (i, created_date) = be_u64(i)?;
let (i, modified_date) = be_u64(i)?;
let (i, scale) = be_u32(i)?;
let (i, duration) = be_u64(i)?;
let (i, speed) = be_f32(i)?;
let (i, volume) = be_u16(i)?; // actually a 2 bytes decimal
let (i, _) = take(10_usize)(i)?;
let (i, scale_a) = be_f32(i)?;
let (i, rotate_b) = be_f32(i)?;
let (i, angle_u) = be_f32(i)?;
let (i, rotate_c) = be_f32(i)?;
let (i, scale_d) = be_f32(i)?;
let (i, angle_v) = be_f32(i)?;
let (i, position_x) = be_f32(i)?;
let (i, position_y) = be_f32(i)?;
let (i, scale_w) = be_f32(i)?;
let (i, preview) = be_u64(i)?;
let (i, poster) = be_u32(i)?;
let (i, selection) = be_u64(i)?;
let (i, current_time) = be_u32(i)?;
let (i, track_id) = be_u32(i)?;
let mvhd_box = MvhdBox::M64(Mvhd64 {
version_flags,
created_date,
modified_date,
scale,
duration,
speed,
volume,
scaleA: scale_a,
rotateB: rotate_b,
angleU: angle_u,
rotateC: rotate_c,
scaleD: scale_d,
angleV: angle_v,
positionX: position_x,
positionY: position_y,
scaleW: scale_w,
preview,
poster,
selection,
current_time,
track_id,
});
Ok((i, mvhd_box))
}
#[derive(Debug, Clone)]
pub enum MvhdBox {
M32(Mvhd32),
M64(Mvhd64),
}
#[derive(Debug, Clone)]
pub enum MoovBox {
Mdra,
Dref,
Cmov,
Rmra,
Iods,
Mvhd(MvhdBox),
Clip,
Trak,
Udta,
}
#[derive(Debug)]
enum MP4BoxType {
Ftyp,
Moov,
Mdat,
Free,
Skip,
Wide,
Mdra,
Dref,
Cmov,
Rmra,
Iods,
Mvhd,
Clip,
Trak,
Udta,
Unknown,
}
#[derive(Debug)]
struct MP4BoxHeader {
length: u32,
tag: MP4BoxType,
}
fn brand_name(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, &str> {
take(4_usize).map_res(str::from_utf8).parse(input)
}
fn filetype_parser(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, FileType<'_>> {
let (i, name) = brand_name(input)?;
let (i, version) = take(4_usize)(i)?;
let (i, brands) = many0(brand_name)(i)?;
let ft = FileType {
major_brand: name,
major_brand_version: version,
compatible_brands: brands,
};
Ok((i, ft))
}
fn mvhd_box(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MvhdBox> {
let res = if input.len() < 100 {
Err(Err::Incomplete(Needed::new(100)))
} else if input.len() == 100 {
mvhd32(input)
} else if input.len() == 112 {
mvhd64(input)
} else {
Err(Err::Error(nom8::error_position!(
input,
ErrorKind::TooLarge
)))
};
println!("res: {:?}", res);
res
}
fn unknown_box_type(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MP4BoxType> {
Ok((input, MP4BoxType::Unknown))
}
fn box_type(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MP4BoxType> {
alt((
tag("ftyp").map(|_| MP4BoxType::Ftyp),
tag("moov").map(|_| MP4BoxType::Moov),
tag("mdat").map(|_| MP4BoxType::Mdat),
tag("free").map(|_| MP4BoxType::Free),
tag("skip").map(|_| MP4BoxType::Skip),
tag("wide").map(|_| MP4BoxType::Wide),
unknown_box_type,
))(input)
}
// warning, an alt combinator with 9 branches containing a tag combinator
// can make the compilation very slow. Use functions as sub parsers,
// or split into multiple alt parsers if it gets slow
fn moov_type(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MP4BoxType> {
alt((
tag("mdra").map(|_| MP4BoxType::Mdra),
tag("dref").map(|_| MP4BoxType::Dref),
tag("cmov").map(|_| MP4BoxType::Cmov),
tag("rmra").map(|_| MP4BoxType::Rmra),
tag("iods").map(|_| MP4BoxType::Iods),
tag("mvhd").map(|_| MP4BoxType::Mvhd),
tag("clip").map(|_| MP4BoxType::Clip),
tag("trak").map(|_| MP4BoxType::Trak),
tag("udta").map(|_| MP4BoxType::Udta),
))(input)
}
fn box_header(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MP4BoxHeader> {
let (i, length) = be_u32(input)?;
let (i, tag) = box_type(i)?;
Ok((i, MP4BoxHeader { length, tag }))
}
fn moov_header(input: Streaming<&[u8]>) -> IResult<Streaming<&[u8]>, MP4BoxHeader> {
let (i, length) = be_u32(input)?;
let (i, tag) = moov_type(i)?;
Ok((i, MP4BoxHeader { length, tag }))
}