use super::atom_info::{AtomIdent, AtomInfo};
use super::ilst::read::parse_ilst;
use super::ilst::Ilst;
use super::read::{meta_is_full, nested_atom, skip_unneeded, AtomReader};
use crate::error::Result;
use crate::macros::decode_err;
use std::io::{Read, Seek};
pub(crate) struct Moov {
pub(crate) traks: Vec<AtomInfo>,
pub(crate) meta: Option<Ilst>,
}
impl Moov {
pub(super) fn find<R>(reader: &mut AtomReader<R>) -> Result<AtomInfo>
where
R: Read + Seek,
{
let mut moov = None;
while let Ok(atom) = reader.next() {
if atom.ident == AtomIdent::Fourcc(*b"moov") {
moov = Some(atom);
break;
}
skip_unneeded(reader, atom.extended, atom.len)?;
}
moov.ok_or_else(|| decode_err!(MP4, "No \"moov\" atom found"))
}
pub(super) fn parse<R>(reader: &mut AtomReader<R>, read_properties: bool) -> Result<Self>
where
R: Read + Seek,
{
let mut traks = Vec::new();
let mut meta = None;
while let Ok(atom) = reader.next() {
if let AtomIdent::Fourcc(fourcc) = atom.ident {
match &fourcc {
b"trak" if read_properties => {
if let Some(mdia) = nested_atom(reader, atom.len, b"mdia")? {
traks.push(mdia);
}
},
b"udta" => {
meta = meta_from_udta(reader, atom.len - 8)?;
},
_ => skip_unneeded(reader, atom.extended, atom.len)?,
}
continue;
}
skip_unneeded(reader, atom.extended, atom.len)?
}
Ok(Self { traks, meta })
}
}
fn meta_from_udta<R>(reader: &mut AtomReader<R>, len: u64) -> Result<Option<Ilst>>
where
R: Read + Seek,
{
let mut read = 8;
let mut meta = (false, 0_u64);
while read < len {
let atom = reader.next()?;
if atom.ident == AtomIdent::Fourcc(*b"meta") {
meta = (true, atom.len);
break;
}
read += atom.len;
skip_unneeded(reader, atom.extended, atom.len)?;
}
if !meta.0 {
return Ok(None);
}
let full_meta_atom = meta_is_full(reader)?;
if full_meta_atom {
read = 12;
} else {
read = 8;
}
let mut islt = (false, 0_u64);
while read < meta.1 {
let atom = reader.next()?;
if atom.ident == AtomIdent::Fourcc(*b"ilst") {
islt = (true, atom.len);
break;
}
read += atom.len;
skip_unneeded(reader, atom.extended, atom.len)?;
}
if islt.0 {
return parse_ilst(reader, islt.1 - 8).map(Some);
}
Ok(None)
}