2021-12-21 22:28:18 +00:00
|
|
|
use super::atom_info::{AtomIdent, AtomInfo};
|
2021-09-01 21:23:50 +00:00
|
|
|
use super::read::skip_unneeded;
|
|
|
|
use super::trak::Trak;
|
2022-03-26 16:52:26 +00:00
|
|
|
#[cfg(feature = "mp4_ilst")]
|
|
|
|
use super::{
|
|
|
|
ilst::{read::parse_ilst, Ilst},
|
|
|
|
read::meta_is_full,
|
|
|
|
};
|
2022-01-27 20:53:41 +00:00
|
|
|
use crate::error::{FileDecodingError, Result};
|
2022-03-04 14:07:17 +00:00
|
|
|
use crate::file::FileType;
|
2021-09-01 21:23:50 +00:00
|
|
|
|
2021-09-03 00:01:40 +00:00
|
|
|
use std::io::{Read, Seek};
|
|
|
|
|
2021-09-01 21:23:50 +00:00
|
|
|
pub(crate) struct Moov {
|
|
|
|
pub(crate) traks: Vec<Trak>,
|
2021-12-21 22:28:18 +00:00
|
|
|
#[cfg(feature = "mp4_ilst")]
|
2021-09-01 21:23:50 +00:00
|
|
|
// Represents a parsed moov.udta.meta.ilst since we don't need anything else
|
2021-11-21 20:18:19 +00:00
|
|
|
pub(crate) meta: Option<Ilst>,
|
2021-09-01 21:23:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Moov {
|
2021-11-21 20:18:19 +00:00
|
|
|
pub(crate) fn find<R>(data: &mut R) -> Result<AtomInfo>
|
2021-09-07 05:09:16 +00:00
|
|
|
where
|
|
|
|
R: Read + Seek,
|
|
|
|
{
|
2022-02-19 15:14:14 +00:00
|
|
|
let mut moov = None;
|
2021-09-07 05:09:16 +00:00
|
|
|
|
2021-11-21 20:18:19 +00:00
|
|
|
while let Ok(atom) = AtomInfo::read(data) {
|
|
|
|
if atom.ident == AtomIdent::Fourcc(*b"moov") {
|
2022-02-19 15:14:14 +00:00
|
|
|
moov = Some(atom);
|
2021-09-07 05:09:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
skip_unneeded(data, atom.extended, atom.len)?;
|
|
|
|
}
|
|
|
|
|
2022-02-19 15:14:14 +00:00
|
|
|
if let Some(moov) = moov {
|
|
|
|
Ok(moov)
|
|
|
|
} else {
|
|
|
|
Err(FileDecodingError::new(FileType::MP4, "No \"moov\" atom found").into())
|
2021-09-07 05:09:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-22 01:20:24 +00:00
|
|
|
pub(crate) fn parse<R>(data: &mut R, read_properties: bool) -> Result<Self>
|
2021-09-01 21:23:50 +00:00
|
|
|
where
|
|
|
|
R: Read + Seek,
|
|
|
|
{
|
|
|
|
let mut traks = Vec::new();
|
2021-12-21 22:28:18 +00:00
|
|
|
#[cfg(feature = "mp4_ilst")]
|
2021-09-01 21:23:50 +00:00
|
|
|
let mut meta = None;
|
|
|
|
|
2021-11-21 20:18:19 +00:00
|
|
|
while let Ok(atom) = AtomInfo::read(data) {
|
|
|
|
if let AtomIdent::Fourcc(fourcc) = atom.ident {
|
|
|
|
match &fourcc {
|
2021-12-22 01:20:24 +00:00
|
|
|
b"trak" if read_properties => traks.push(Trak::parse(data, &atom)?),
|
2021-12-21 22:28:18 +00:00
|
|
|
#[cfg(feature = "mp4_ilst")]
|
2021-11-21 20:18:19 +00:00
|
|
|
b"udta" => {
|
|
|
|
meta = meta_from_udta(data, atom.len - 8)?;
|
2021-11-22 10:14:29 +00:00
|
|
|
},
|
2021-11-21 20:18:19 +00:00
|
|
|
_ => skip_unneeded(data, atom.extended, atom.len)?,
|
2021-10-01 21:59:53 +00:00
|
|
|
}
|
2021-11-21 20:18:19 +00:00
|
|
|
|
|
|
|
continue;
|
2021-09-01 21:23:50 +00:00
|
|
|
}
|
2021-11-21 20:18:19 +00:00
|
|
|
|
|
|
|
skip_unneeded(data, atom.extended, atom.len)?
|
2021-09-01 21:23:50 +00:00
|
|
|
}
|
|
|
|
|
2021-12-21 22:28:18 +00:00
|
|
|
Ok(Self {
|
|
|
|
traks,
|
|
|
|
#[cfg(feature = "mp4_ilst")]
|
|
|
|
meta,
|
|
|
|
})
|
2021-09-01 21:23:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-21 22:28:18 +00:00
|
|
|
#[cfg(feature = "mp4_ilst")]
|
2021-11-21 20:18:19 +00:00
|
|
|
fn meta_from_udta<R>(data: &mut R, len: u64) -> Result<Option<Ilst>>
|
2021-09-01 21:23:50 +00:00
|
|
|
where
|
|
|
|
R: Read + Seek,
|
|
|
|
{
|
|
|
|
let mut read = 8;
|
|
|
|
let mut meta = (false, 0_u64);
|
|
|
|
|
|
|
|
while read < len {
|
2021-11-21 20:18:19 +00:00
|
|
|
let atom = AtomInfo::read(data)?;
|
2021-09-01 21:23:50 +00:00
|
|
|
|
2021-11-21 20:18:19 +00:00
|
|
|
if atom.ident == AtomIdent::Fourcc(*b"meta") {
|
2021-09-01 21:23:50 +00:00
|
|
|
meta = (true, atom.len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
read += atom.len;
|
|
|
|
skip_unneeded(data, atom.extended, atom.len)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !meta.0 {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
|
|
|
|
2022-03-06 18:17:16 +00:00
|
|
|
// It's possible for the `meta` atom to be non-full,
|
|
|
|
// so we have to check for that case
|
|
|
|
let full_meta_atom = meta_is_full(data)?;
|
|
|
|
|
|
|
|
if full_meta_atom {
|
|
|
|
read = 12;
|
|
|
|
} else {
|
|
|
|
read = 8;
|
|
|
|
}
|
2021-09-01 21:23:50 +00:00
|
|
|
|
|
|
|
let mut islt = (false, 0_u64);
|
|
|
|
|
|
|
|
while read < meta.1 {
|
2021-11-21 20:18:19 +00:00
|
|
|
let atom = AtomInfo::read(data)?;
|
2021-09-01 21:23:50 +00:00
|
|
|
|
2021-11-21 20:18:19 +00:00
|
|
|
if atom.ident == AtomIdent::Fourcc(*b"ilst") {
|
2021-09-01 21:23:50 +00:00
|
|
|
islt = (true, atom.len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
read += atom.len;
|
|
|
|
skip_unneeded(data, atom.extended, atom.len)?;
|
|
|
|
}
|
|
|
|
|
2021-10-01 21:59:53 +00:00
|
|
|
if islt.0 {
|
2021-11-27 18:28:40 +00:00
|
|
|
return parse_ilst(data, islt.1 - 8).map(Some);
|
2021-09-01 21:23:50 +00:00
|
|
|
}
|
|
|
|
|
2021-10-01 21:59:53 +00:00
|
|
|
Ok(None)
|
2021-09-01 21:23:50 +00:00
|
|
|
}
|