1
0
Fork 0
mirror of https://github.com/alfg/mp4-rust.git synced 2024-06-11 01:19:21 +00:00
This commit is contained in:
sdwoodbury 2023-08-03 15:02:26 +00:00 committed by GitHub
commit f38dd38f54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 122 additions and 301 deletions

View file

@ -26,4 +26,6 @@ pub enum Error {
EntryInTrunNotFound(u32, BoxType, u32), EntryInTrunNotFound(u32, BoxType, u32),
#[error("{0} version {1} is not supported")] #[error("{0} version {1} is not supported")]
UnsupportedBoxVersion(BoxType, u8), UnsupportedBoxVersion(BoxType, u8),
#[error("{0}")]
GenericError(String),
} }

View file

@ -67,10 +67,6 @@ impl Mp4Box for Avc1Box {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"data_reference_index={} width={} height={} frame_count={}", "data_reference_index={} width={} height={} frame_count={}",
@ -206,10 +202,6 @@ impl Mp4Box for AvcCBox {
size size
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("avc_profile_indication={}", self.avc_profile_indication); let s = format!("avc_profile_indication={}", self.avc_profile_indication);
Ok(s) Ok(s)

View file

@ -33,10 +33,6 @@ impl Mp4Box for Co64Box {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("entries_count={}", self.entries.len()); let s = format!("entries_count={}", self.entries.len());
Ok(s) Ok(s)

View file

@ -39,10 +39,6 @@ impl Mp4Box for CttsBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("entries_count={}", self.entries.len()); let s = format!("entries_count={}", self.entries.len());
Ok(s) Ok(s)

View file

@ -36,10 +36,6 @@ impl Mp4Box for DataBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("type={:?} len={}", self.data_type, self.data.len()); let s = format!("type={:?} len={}", self.data_type, self.data.len());
Ok(s) Ok(s)

View file

@ -27,10 +27,6 @@ impl Mp4Box for DinfBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)
@ -68,15 +64,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for DinfBox {
current = reader.stream_position()?; current = reader.stream_position()?;
} }
if dref.is_none() { let dref = dref.ok_or(Error::BoxNotFound(BoxType::DrefBox))?;
return Err(Error::BoxNotFound(BoxType::DrefBox));
}
skip_bytes_to(reader, start + size)?; skip_bytes_to(reader, start + size)?;
Ok(DinfBox { dref })
Ok(DinfBox {
dref: dref.unwrap(),
})
} }
} }
@ -131,10 +121,6 @@ impl Mp4Box for DrefBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)
@ -248,10 +234,6 @@ impl Mp4Box for UrlBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("location={}", self.location); let s = format!("location={}", self.location);
Ok(s) Ok(s)

View file

@ -36,10 +36,6 @@ impl Mp4Box for EdtsBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)

View file

@ -47,10 +47,6 @@ impl Mp4Box for ElstBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("elst_entries={}", self.entries.len()); let s = format!("elst_entries={}", self.entries.len());
Ok(s) Ok(s)

View file

@ -48,10 +48,6 @@ impl Mp4Box for EmsgBox {
+ self.message_data.len() as u64 + self.message_data.len() as u64
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("id={} value={}", self.id, self.value); let s = format!("id={} value={}", self.id, self.value);
Ok(s) Ok(s)
@ -131,13 +127,17 @@ impl<W: Write> WriteBox<&mut W> for EmsgBox {
write_null_terminated_str(writer, &self.scheme_id_uri)?; write_null_terminated_str(writer, &self.scheme_id_uri)?;
write_null_terminated_str(writer, &self.value)?; write_null_terminated_str(writer, &self.value)?;
writer.write_u32::<BigEndian>(self.timescale)?; writer.write_u32::<BigEndian>(self.timescale)?;
writer.write_u32::<BigEndian>(self.presentation_time_delta.unwrap())?; writer.write_u32::<BigEndian>(self.presentation_time_delta.ok_or(
crate::error::Error::InvalidData("presentation_time_delta not found"),
)?)?;
writer.write_u32::<BigEndian>(self.event_duration)?; writer.write_u32::<BigEndian>(self.event_duration)?;
writer.write_u32::<BigEndian>(self.id)?; writer.write_u32::<BigEndian>(self.id)?;
} }
1 => { 1 => {
writer.write_u32::<BigEndian>(self.timescale)?; writer.write_u32::<BigEndian>(self.timescale)?;
writer.write_u64::<BigEndian>(self.presentation_time.unwrap())?; writer.write_u64::<BigEndian>(self.presentation_time.ok_or(
crate::error::Error::InvalidData("presentation_time not found"),
)?)?;
writer.write_u32::<BigEndian>(self.event_duration)?; writer.write_u32::<BigEndian>(self.event_duration)?;
writer.write_u32::<BigEndian>(self.id)?; writer.write_u32::<BigEndian>(self.id)?;
write_null_terminated_str(writer, &self.scheme_id_uri)?; write_null_terminated_str(writer, &self.scheme_id_uri)?;

View file

@ -30,10 +30,6 @@ impl Mp4Box for FtypBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let mut compatible_brands = Vec::new(); let mut compatible_brands = Vec::new();
for brand in self.compatible_brands.iter() { for brand in self.compatible_brands.iter() {

View file

@ -31,10 +31,6 @@ impl Mp4Box for HdlrBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("handler_type={} name={}", self.handler_type, self.name); let s = format!("handler_type={} name={}", self.handler_type, self.name);
Ok(s) Ok(s)

View file

@ -67,10 +67,6 @@ impl Mp4Box for Hev1Box {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"data_reference_index={} width={} height={} frame_count={}", "data_reference_index={} width={} height={} frame_count={}",
@ -204,10 +200,6 @@ impl Mp4Box for HvcCBox {
.sum::<u64>() .sum::<u64>()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
Ok(format!("configuration_version={} general_profile_space={} general_tier_flag={} general_profile_idc={} general_profile_compatibility_flags={} general_constraint_indicator_flag={} general_level_idc={} min_spatial_segmentation_idc={} parallelism_type={} chroma_format_idc={} bit_depth_luma_minus8={} bit_depth_chroma_minus8={} avg_frame_rate={} constant_frame_rate={} num_temporal_layers={} temporal_id_nested={} length_size_minus_one={}", Ok(format!("configuration_version={} general_profile_space={} general_tier_flag={} general_profile_idc={} general_profile_compatibility_flags={} general_constraint_indicator_flag={} general_level_idc={} min_spatial_segmentation_idc={} parallelism_type={} chroma_format_idc={} bit_depth_luma_minus8={} bit_depth_chroma_minus8={} avg_frame_rate={} constant_frame_rate={} num_temporal_layers={} temporal_id_nested={} length_size_minus_one={}",
self.configuration_version, self.configuration_version,

View file

@ -36,10 +36,6 @@ impl Mp4Box for IlstBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("item_count={}", self.items.len()); let s = format!("item_count={}", self.items.len());
Ok(s) Ok(s)
@ -153,15 +149,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for IlstItemBox {
current = reader.stream_position()?; current = reader.stream_position()?;
} }
if data.is_none() { let data = data.ok_or(Error::BoxNotFound(BoxType::DataBox))?;
return Err(Error::BoxNotFound(BoxType::DataBox));
}
skip_bytes_to(reader, start + size)?; skip_bytes_to(reader, start + size)?;
Ok(IlstItemBox { data })
Ok(IlstItemBox {
data: data.unwrap(),
})
} }
} }

View file

@ -57,10 +57,6 @@ impl Mp4Box for MdhdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"creation_time={} timescale={} duration={} language={}", "creation_time={} timescale={} duration={} language={}",

View file

@ -30,10 +30,6 @@ impl Mp4Box for MdiaBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)
@ -79,23 +75,13 @@ impl<R: Read + Seek> ReadBox<&mut R> for MdiaBox {
current = reader.stream_position()?; current = reader.stream_position()?;
} }
if mdhd.is_none() { let mdhd = mdhd.ok_or(Error::BoxNotFound(BoxType::MdhdBox))?;
return Err(Error::BoxNotFound(BoxType::MdhdBox)); let hdlr = hdlr.ok_or(Error::BoxNotFound(BoxType::HdlrBox))?;
} let minf = minf.ok_or(Error::BoxNotFound(BoxType::MinfBox))?;
if hdlr.is_none() {
return Err(Error::BoxNotFound(BoxType::HdlrBox));
}
if minf.is_none() {
return Err(Error::BoxNotFound(BoxType::MinfBox));
}
skip_bytes_to(reader, start + size)?; skip_bytes_to(reader, start + size)?;
Ok(MdiaBox { Ok(MdiaBox { mdhd, hdlr, minf })
mdhd: mdhd.unwrap(),
hdlr: hdlr.unwrap(),
minf: minf.unwrap(),
})
} }
} }

View file

@ -37,10 +37,6 @@ impl Mp4Box for MehdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("fragment_duration={}", self.fragment_duration); let s = format!("fragment_duration={}", self.fragment_duration);
Ok(s) Ok(s)

View file

@ -62,10 +62,6 @@ impl Mp4Box for MetaBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = match self { let s = match self {
Self::Mdir { .. } => "hdlr=ilst".to_string(), Self::Mdir { .. } => "hdlr=ilst".to_string(),

View file

@ -40,10 +40,6 @@ impl Mp4Box for MfhdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("sequence_number={}", self.sequence_number); let s = format!("sequence_number={}", self.sequence_number);
Ok(s) Ok(s)

View file

@ -44,10 +44,6 @@ impl Mp4Box for MinfBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)
@ -97,20 +93,16 @@ impl<R: Read + Seek> ReadBox<&mut R> for MinfBox {
current = reader.stream_position()?; current = reader.stream_position()?;
} }
if dinf.is_none() { let dinf = dinf.ok_or(Error::BoxNotFound(BoxType::DinfBox))?;
return Err(Error::BoxNotFound(BoxType::DinfBox)); let stbl = stbl.ok_or(Error::BoxNotFound(BoxType::StblBox))?;
}
if stbl.is_none() {
return Err(Error::BoxNotFound(BoxType::StblBox));
}
skip_bytes_to(reader, start + size)?; skip_bytes_to(reader, start + size)?;
Ok(MinfBox { Ok(MinfBox {
vmhd, vmhd,
smhd, smhd,
dinf: dinf.unwrap(), dinf,
stbl: stbl.unwrap(), stbl,
}) })
} }
} }

View file

@ -57,6 +57,7 @@
//! //!
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use serde::Serialize;
use std::convert::TryInto; use std::convert::TryInto;
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
@ -244,7 +245,12 @@ boxtype! {
pub trait Mp4Box: Sized { pub trait Mp4Box: Sized {
fn box_type(&self) -> BoxType; fn box_type(&self) -> BoxType;
fn box_size(&self) -> u64; fn box_size(&self) -> u64;
fn to_json(&self) -> Result<String>; fn to_json(&self) -> Result<String>
where
Self: Serialize,
{
serde_json::to_string(&self).map_err(|e| crate::error::Error::IoError(e.into()))
}
fn summary(&self) -> Result<String>; fn summary(&self) -> Result<String>;
} }
@ -274,11 +280,15 @@ impl BoxHeader {
reader.read_exact(&mut buf)?; reader.read_exact(&mut buf)?;
// Get size. // Get size.
let s = buf[0..4].try_into().unwrap(); let s = buf[0..4]
.try_into()
.map_err(|_e| crate::error::Error::InvalidData("could not get slice"))?;
let size = u32::from_be_bytes(s); let size = u32::from_be_bytes(s);
// Get box type string. // Get box type string.
let t = buf[4..8].try_into().unwrap(); let t = buf[4..8]
.try_into()
.map_err(|_e| crate::error::Error::InvalidData("could not get slice"))?;
let typ = u32::from_be_bytes(t); let typ = u32::from_be_bytes(t);
// Get largesize if size is 1 // Get largesize if size is 1

View file

@ -35,10 +35,6 @@ impl Mp4Box for MoofBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("trafs={}", self.trafs.len()); let s = format!("trafs={}", self.trafs.len());
Ok(s) Ok(s)
@ -80,16 +76,9 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoofBox {
current = reader.stream_position()?; current = reader.stream_position()?;
} }
if mfhd.is_none() { let mfhd = mfhd.ok_or(Error::BoxNotFound(BoxType::MfhdBox))?;
return Err(Error::BoxNotFound(BoxType::MfhdBox));
}
skip_bytes_to(reader, start + size)?; skip_bytes_to(reader, start + size)?;
Ok(MoofBox { mfhd, trafs })
Ok(MoofBox {
mfhd: mfhd.unwrap(),
trafs,
})
} }
} }

View file

@ -51,10 +51,6 @@ impl Mp4Box for MoovBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("traks={}", self.traks.len()); let s = format!("traks={}", self.traks.len());
Ok(s) Ok(s)
@ -109,14 +105,10 @@ impl<R: Read + Seek> ReadBox<&mut R> for MoovBox {
current = reader.stream_position()?; current = reader.stream_position()?;
} }
if mvhd.is_none() { let mvhd = mvhd.ok_or(Error::BoxNotFound(BoxType::MvhdBox))?;
return Err(Error::BoxNotFound(BoxType::MvhdBox));
}
skip_bytes_to(reader, start + size)?; skip_bytes_to(reader, start + size)?;
Ok(MoovBox { Ok(MoovBox {
mvhd: mvhd.unwrap(), mvhd,
meta, meta,
udta, udta,
mvex, mvex,

View file

@ -60,10 +60,6 @@ impl Mp4Box for Mp4aBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"channel_count={} sample_size={} sample_rate={}", "channel_count={} sample_size={} sample_rate={}",
@ -188,10 +184,6 @@ impl Mp4Box for EsdsBox {
+ ESDescriptor::desc_size() as u64 + ESDescriptor::desc_size() as u64
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
Ok(String::new()) Ok(String::new())
} }

View file

@ -29,10 +29,6 @@ impl Mp4Box for MvexBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)

View file

@ -66,10 +66,6 @@ impl Mp4Box for MvhdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"creation_time={} timescale={} duration={} rate={} volume={}, matrix={}, next_track_id={}", "creation_time={} timescale={} duration={} rate={} volume={}, matrix={}, next_track_id={}",

View file

@ -42,10 +42,6 @@ impl Mp4Box for SmhdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("balance={}", self.balance.value()); let s = format!("balance={}", self.balance.value());
Ok(s) Ok(s)

View file

@ -63,10 +63,6 @@ impl Mp4Box for StblBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)

View file

@ -33,10 +33,6 @@ impl Mp4Box for StcoBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("entries={}", self.entries.len()); let s = format!("entries={}", self.entries.len());
Ok(s) Ok(s)

View file

@ -41,10 +41,6 @@ impl Mp4Box for StscBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("entries={}", self.entries.len()); let s = format!("entries={}", self.entries.len());
Ok(s) Ok(s)

View file

@ -58,10 +58,6 @@ impl Mp4Box for StsdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)

View file

@ -33,10 +33,6 @@ impl Mp4Box for StssBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("entries={}", self.entries.len()); let s = format!("entries={}", self.entries.len());
Ok(s) Ok(s)

View file

@ -35,10 +35,6 @@ impl Mp4Box for StszBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"sample_size={} sample_count={} sample_sizes={}", "sample_size={} sample_count={} sample_sizes={}",

View file

@ -39,10 +39,6 @@ impl Mp4Box for SttsBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("entries={}", self.entries.len()); let s = format!("entries={}", self.entries.len());
Ok(s) Ok(s)

View file

@ -36,10 +36,6 @@ impl Mp4Box for TfdtBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("base_media_decode_time={}", self.base_media_decode_time); let s = format!("base_media_decode_time={}", self.base_media_decode_time);
Ok(s) Ok(s)

View file

@ -59,10 +59,6 @@ impl Mp4Box for TfhdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("track_id={}", self.track_id); let s = format!("track_id={}", self.track_id);
Ok(s) Ok(s)

View file

@ -125,10 +125,6 @@ impl Mp4Box for TkhdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"creation_time={} track_id={} duration={} layer={} volume={} matrix={} width={} height={}", "creation_time={} track_id={} duration={} layer={} volume={} matrix={} width={} height={}",

View file

@ -38,10 +38,6 @@ impl Mp4Box for TrafBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)

View file

@ -43,10 +43,6 @@ impl Mp4Box for TrakBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = String::new(); let s = String::new();
Ok(s) Ok(s)

View file

@ -34,10 +34,6 @@ impl Mp4Box for TrexBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"track_id={} default_sample_duration={}", "track_id={} default_sample_duration={}",

View file

@ -68,10 +68,6 @@ impl Mp4Box for TrunBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("sample_size={}", self.sample_count); let s = format!("sample_size={}", self.sample_count);
Ok(s) Ok(s)

View file

@ -61,10 +61,6 @@ impl Mp4Box for Tx3gBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!("data_reference_index={} horizontal_justification={} vertical_justification={} rgba={}{}{}{}", let s = format!("data_reference_index={} horizontal_justification={} vertical_justification={} rgba={}{}{}{}",
self.data_reference_index, self.horizontal_justification, self.data_reference_index, self.horizontal_justification,

View file

@ -34,10 +34,6 @@ impl Mp4Box for UdtaBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
Ok(String::new()) Ok(String::new())
} }

View file

@ -38,10 +38,6 @@ impl Mp4Box for VmhdBox {
self.get_size() self.get_size()
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
let s = format!( let s = format!(
"graphics_mode={} op_color={}{}{}", "graphics_mode={} op_color={}{}{}",

View file

@ -74,10 +74,6 @@ impl Mp4Box for Vp09Box {
0x6A 0x6A
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
Ok(format!("{self:?}")) Ok(format!("{self:?}"))
} }

View file

@ -31,10 +31,6 @@ impl Mp4Box for VpccBox {
HEADER_SIZE + HEADER_EXT_SIZE + 8 HEADER_SIZE + HEADER_EXT_SIZE + 8
} }
fn to_json(&self) -> Result<String> {
Ok(serde_json::to_string(&self).unwrap())
}
fn summary(&self) -> Result<String> { fn summary(&self) -> Result<String> {
Ok(format!("{self:?}")) Ok(format!("{self:?}"))
} }

View file

@ -75,33 +75,24 @@ impl<R: Read + Seek> Mp4Reader<R> {
current = reader.stream_position()?; current = reader.stream_position()?;
} }
if ftyp.is_none() { let ftyp = ftyp.ok_or(Error::BoxNotFound(BoxType::FtypBox))?;
return Err(Error::BoxNotFound(BoxType::FtypBox)); let moov = moov.ok_or(Error::BoxNotFound(BoxType::MoovBox))?;
}
if moov.is_none() {
return Err(Error::BoxNotFound(BoxType::MoovBox));
}
let size = current - start; let size = current - start;
let mut tracks = if let Some(ref moov) = moov { if moov.traks.iter().any(|trak| trak.tkhd.track_id == 0) {
if moov.traks.iter().any(|trak| trak.tkhd.track_id == 0) { return Err(Error::InvalidData("illegal track id 0"));
return Err(Error::InvalidData("illegal track id 0")); }
} let mut tracks: HashMap<u32, Mp4Track> = moov
moov.traks .traks
.iter() .iter()
.map(|trak| (trak.tkhd.track_id, Mp4Track::from(trak))) .map(|trak| (trak.tkhd.track_id, Mp4Track::from(trak)))
.collect() .collect();
} else {
HashMap::new()
};
// Update tracks if any fragmented (moof) boxes are found. // Update tracks if any fragmented (moof) boxes are found.
if !moofs.is_empty() { if !moofs.is_empty() {
let mut default_sample_duration = 0; let mut default_sample_duration = 0;
if let Some(ref moov) = moov { if let Some(ref mvex) = &moov.mvex {
if let Some(ref mvex) = &moov.mvex { default_sample_duration = mvex.trex.default_sample_duration
default_sample_duration = mvex.trex.default_sample_duration
}
} }
for (moof, moof_offset) in moofs.iter().zip(moof_offsets) { for (moof, moof_offset) in moofs.iter().zip(moof_offsets) {
@ -120,8 +111,8 @@ impl<R: Read + Seek> Mp4Reader<R> {
Ok(Mp4Reader { Ok(Mp4Reader {
reader, reader,
ftyp: ftyp.unwrap(), ftyp,
moov: moov.unwrap(), moov,
moofs, moofs,
emsgs, emsgs,
size, size,

View file

@ -346,7 +346,10 @@ impl Mp4Track {
} }
fn ctts_index(&self, sample_id: u32) -> Result<(usize, u32)> { fn ctts_index(&self, sample_id: u32) -> Result<(usize, u32)> {
let ctts = self.trak.mdia.minf.stbl.ctts.as_ref().unwrap(); let ctts = self.trak.mdia.minf.stbl.ctts.as_ref().ok_or(
// todo: is this the correct error to return here?
crate::error::Error::BoxNotFound(BoxType::CttsBox),
)?;
let mut sample_count: u32 = 1; let mut sample_count: u32 = 1;
for (i, entry) in ctts.entries.iter().enumerate() { for (i, entry) in ctts.entries.iter().enumerate() {
let next_sample_count = let next_sample_count =
@ -369,30 +372,36 @@ impl Mp4Track {
} }
/// return `(traf_idx, sample_idx_in_trun)` /// return `(traf_idx, sample_idx_in_trun)`
fn find_traf_idx_and_sample_idx(&self, sample_id: u32) -> Option<(usize, usize)> { fn find_traf_idx_and_sample_idx(&self, sample_id: u32) -> Result<Option<(usize, usize)>> {
let global_idx = sample_id - 1; let global_idx = sample_id - 1;
let mut offset = 0; let mut offset = 0;
for traf_idx in 0..self.trafs.len() { for traf_idx in 0..self.trafs.len() {
if let Some(trun) = &self.trafs[traf_idx].trun { if let Some(trun) = &self.trafs[traf_idx].trun {
let sample_count = trun.sample_count; let sample_count = trun.sample_count;
if sample_count > (global_idx - offset) { if sample_count > (global_idx - offset) {
return Some((traf_idx, (global_idx - offset) as _)); return Ok(Some((traf_idx, (global_idx - offset) as _)));
} }
offset = offset offset =
.checked_add(sample_count) offset
.expect("attempt to sum trun sample_count with overflow"); .checked_add(sample_count)
.ok_or(crate::error::Error::InvalidData(
"attempt to sum trun sample_count with overflow",
))?;
} }
} }
None Ok(None)
} }
fn sample_size(&self, sample_id: u32) -> Result<u32> { fn sample_size(&self, sample_id: u32) -> Result<u32> {
if !self.trafs.is_empty() { if !self.trafs.is_empty() {
if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id)? {
if let Some(size) = self.trafs[traf_idx] if let Some(size) = self.trafs[traf_idx]
.trun .trun
.as_ref() .as_ref()
.unwrap() .ok_or(crate::error::Error::BoxInTrafNotFound(
traf_idx as u32,
BoxType::TrunBox,
))?
.sample_sizes .sample_sizes
.get(sample_idx) .get(sample_idx)
{ {
@ -439,7 +448,7 @@ impl Mp4Track {
pub fn sample_offset(&self, sample_id: u32) -> Result<u64> { pub fn sample_offset(&self, sample_id: u32) -> Result<u64> {
if !self.trafs.is_empty() { if !self.trafs.is_empty() {
if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { if let Ok(Some((traf_idx, sample_idx))) = self.find_traf_idx_and_sample_idx(sample_id) {
let mut sample_offset = self.trafs[traf_idx] let mut sample_offset = self.trafs[traf_idx]
.tfhd .tfhd
.base_data_offset .base_data_offset
@ -472,7 +481,13 @@ impl Mp4Track {
let stsc_index = self.stsc_index(sample_id)?; let stsc_index = self.stsc_index(sample_id)?;
let stsc = &self.trak.mdia.minf.stbl.stsc; let stsc = &self.trak.mdia.minf.stbl.stsc;
let stsc_entry = stsc.entries.get(stsc_index).unwrap(); let stsc_entry =
stsc.entries
.get(stsc_index)
.ok_or(crate::error::Error::GenericError(format!(
"stsc entry not found for sample_id: {}, stsc_idx: {}",
sample_id, stsc_index
)))?;
let first_chunk = stsc_entry.first_chunk; let first_chunk = stsc_entry.first_chunk;
let first_sample = stsc_entry.first_sample; let first_sample = stsc_entry.first_sample;
@ -503,7 +518,7 @@ impl Mp4Track {
if !self.trafs.is_empty() { if !self.trafs.is_empty() {
let mut base_start_time = 0; let mut base_start_time = 0;
let mut default_sample_duration = self.default_sample_duration; let mut default_sample_duration = self.default_sample_duration;
if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { if let Ok(Some((traf_idx, sample_idx))) = self.find_traf_idx_and_sample_idx(sample_id) {
let traf = &self.trafs[traf_idx]; let traf = &self.trafs[traf_idx];
if let Some(tfdt) = &traf.tfdt { if let Some(tfdt) = &traf.tfdt {
base_start_time = tfdt.base_media_decode_time; base_start_time = tfdt.base_media_decode_time;
@ -557,24 +572,29 @@ impl Mp4Track {
} }
} }
fn sample_rendering_offset(&self, sample_id: u32) -> i32 { fn sample_rendering_offset(&self, sample_id: u32) -> Result<i32> {
if !self.trafs.is_empty() { if !self.trafs.is_empty() {
if let Some((traf_idx, sample_idx)) = self.find_traf_idx_and_sample_idx(sample_id) { if let Ok(Some((traf_idx, sample_idx))) = self.find_traf_idx_and_sample_idx(sample_id) {
if let Some(cts) = self.trafs[traf_idx] if let Some(cts) = self.trafs[traf_idx]
.trun .trun
.as_ref() .as_ref()
.and_then(|trun| trun.sample_cts.get(sample_idx)) .and_then(|trun| trun.sample_cts.get(sample_idx))
{ {
return *cts as i32; return Ok(*cts as i32);
} }
} }
} else if let Some(ref ctts) = self.trak.mdia.minf.stbl.ctts { } else if let Some(ref ctts) = self.trak.mdia.minf.stbl.ctts {
if let Ok((ctts_index, _)) = self.ctts_index(sample_id) { if let Ok((ctts_index, _)) = self.ctts_index(sample_id) {
let ctts_entry = ctts.entries.get(ctts_index).unwrap(); let ctts_entry =
return ctts_entry.sample_offset; ctts.entries
.get(ctts_index)
.ok_or(crate::error::Error::InvalidData(
"ctts not found after ctts_index was returned",
))?;
return Ok(ctts_entry.sample_offset);
} }
} }
0 Ok(0)
} }
fn is_sync_sample(&self, sample_id: u32) -> bool { fn is_sync_sample(&self, sample_id: u32) -> bool {
@ -610,8 +630,8 @@ impl Mp4Track {
reader.seek(SeekFrom::Start(sample_offset))?; reader.seek(SeekFrom::Start(sample_offset))?;
reader.read_exact(&mut buffer)?; reader.read_exact(&mut buffer)?;
let (start_time, duration) = self.sample_time(sample_id).unwrap(); // XXX let (start_time, duration) = self.sample_time(sample_id)?; // XXX
let rendering_offset = self.sample_rendering_offset(sample_id); let rendering_offset = self.sample_rendering_offset(sample_id)?;
let is_sync = self.is_sync_sample(sample_id); let is_sync = self.is_sync_sample(sample_id);
Ok(Some(Mp4Sample { Ok(Some(Mp4Sample {
@ -840,9 +860,16 @@ impl Mp4TrackWriter {
Ok(self.trak.tkhd.duration) Ok(self.trak.tkhd.duration)
} }
fn chunk_count(&self) -> u32 { fn chunk_count(&self) -> Result<u32> {
let co64 = self.trak.mdia.minf.stbl.co64.as_ref().unwrap(); let co64 = self
co64.entries.len() as u32 .trak
.mdia
.minf
.stbl
.co64
.as_ref()
.ok_or(crate::error::Error::BoxNotFound(BoxType::Co64Box))?;
Ok(co64.entries.len() as u32)
} }
fn update_sample_to_chunk(&mut self, chunk_id: u32) { fn update_sample_to_chunk(&mut self, chunk_id: u32) {
@ -861,9 +888,17 @@ impl Mp4TrackWriter {
self.trak.mdia.minf.stbl.stsc.entries.push(entry); self.trak.mdia.minf.stbl.stsc.entries.push(entry);
} }
fn update_chunk_offsets(&mut self, offset: u64) { fn update_chunk_offsets(&mut self, offset: u64) -> Result<()> {
let co64 = self.trak.mdia.minf.stbl.co64.as_mut().unwrap(); let co64 = self
.trak
.mdia
.minf
.stbl
.co64
.as_mut()
.ok_or(crate::error::Error::BoxNotFound(BoxType::Co64Box))?;
co64.entries.push(offset); co64.entries.push(offset);
Ok(())
} }
fn write_chunk<W: Write + Seek>(&mut self, writer: &mut W) -> Result<()> { fn write_chunk<W: Write + Seek>(&mut self, writer: &mut W) -> Result<()> {
@ -874,8 +909,8 @@ impl Mp4TrackWriter {
writer.write_all(&self.chunk_buffer)?; writer.write_all(&self.chunk_buffer)?;
self.update_sample_to_chunk(self.chunk_count() + 1); self.update_sample_to_chunk(self.chunk_count()? + 1);
self.update_chunk_offsets(chunk_offset); self.update_chunk_offsets(chunk_offset)?;
self.chunk_buffer.clear(); self.chunk_buffer.clear();
self.chunk_samples = 0; self.chunk_samples = 0;
@ -908,7 +943,15 @@ impl Mp4TrackWriter {
// mp4a.esds.es_desc.dec_config.max_bitrate // mp4a.esds.es_desc.dec_config.max_bitrate
// mp4a.esds.es_desc.dec_config.avg_bitrate // mp4a.esds.es_desc.dec_config.avg_bitrate
} }
if let Ok(stco) = StcoBox::try_from(self.trak.mdia.minf.stbl.co64.as_ref().unwrap()) { if let Ok(stco) = StcoBox::try_from(
self.trak
.mdia
.minf
.stbl
.co64
.as_ref()
.ok_or(crate::error::Error::BoxNotFound(BoxType::Co64Box))?,
) {
self.trak.mdia.minf.stbl.stco = Some(stco); self.trak.mdia.minf.stbl.stco = Some(stco);
self.trak.mdia.minf.stbl.co64 = None; self.trak.mdia.minf.stbl.co64 = None;
} }