lofty-rs/src/mp4/moov.rs

127 lines
2.6 KiB
Rust
Raw Normal View History

2021-12-21 22:28:18 +00:00
use super::atom_info::{AtomIdent, AtomInfo};
2021-12-05 22:02:22 +00:00
#[cfg(feature = "mp4_ilst")]
2021-12-10 23:43:34 +00:00
use super::ilst::{read::parse_ilst, Ilst};
2021-09-01 21:23:50 +00:00
use super::read::skip_unneeded;
use super::trak::Trak;
2022-01-27 20:53:41 +00:00
use crate::error::{FileDecodingError, Result};
use crate::types::file::FileType;
2021-09-01 21:23:50 +00:00
2021-09-03 00:01:40 +00:00
use std::io::{Read, Seek};
2021-12-21 22:28:18 +00:00
#[cfg(feature = "mp4_ilst")]
2021-09-01 21:23:50 +00:00
use byteorder::{BigEndian, ReadBytesExt};
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
pub(crate) meta: Option<Ilst>,
2021-09-01 21:23:50 +00:00
}
impl Moov {
pub(crate) fn find<R>(data: &mut R) -> Result<AtomInfo>
2021-09-07 05:09:16 +00:00
where
R: Read + Seek,
{
let mut moov = (false, None);
while let Ok(atom) = AtomInfo::read(data) {
if atom.ident == AtomIdent::Fourcc(*b"moov") {
2021-09-07 05:09:16 +00:00
moov = (true, Some(atom));
break;
}
skip_unneeded(data, atom.extended, atom.len)?;
}
if !moov.0 {
2022-01-27 20:53:41 +00:00
return Err(FileDecodingError::new(FileType::MP4, "No \"moov\" atom found").into());
2021-09-07 05:09:16 +00:00
}
Ok(moov.1.unwrap())
}
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;
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")]
b"udta" => {
meta = meta_from_udta(data, atom.len - 8)?;
2021-11-22 10:14:29 +00:00
},
_ => skip_unneeded(data, atom.extended, atom.len)?,
}
continue;
2021-09-01 21:23:50 +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")]
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 {
let atom = AtomInfo::read(data)?;
2021-09-01 21:23:50 +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);
}
// The meta atom has 4 bytes we don't care about
// Version (1)
// Flags (3)
let _version_flags = data.read_u32::<BigEndian>()?;
read = 12;
2021-09-01 21:23:50 +00:00
let mut islt = (false, 0_u64);
while read < meta.1 {
let atom = AtomInfo::read(data)?;
2021-09-01 21:23:50 +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)?;
}
if islt.0 {
return parse_ilst(data, islt.1 - 8).map(Some);
2021-09-01 21:23:50 +00:00
}
Ok(None)
2021-09-01 21:23:50 +00:00
}