diff --git a/Cargo.toml b/Cargo.toml index ec35a0d4..6f7dc339 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" include = ["src", "benches", "Cargo.toml", "README", "LICENSE"] [dependencies] -thiserror = "^1.0" +thiserror = "2.0" byteorder = "1" bytes = "1.1.0" num-rational = { version = "0.4.0", features = ["serde"] } @@ -21,7 +21,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" [dev-dependencies] -criterion = "0.3" +criterion = "0.7" [[bench]] name = "bench_main" diff --git a/examples/fragdump.rs b/examples/fragdump.rs new file mode 100644 index 00000000..cbc8a651 --- /dev/null +++ b/examples/fragdump.rs @@ -0,0 +1,94 @@ +use std::io::prelude::*; +use std::io; +use std::io::BufReader; +use std::env; +use std::path::Path; +use std::fs::File; +use std::io::SeekFrom; + +use mp4::Result; +use mp4::mp4box::*; + +fn main() { + let args: Vec = env::args().collect(); + + if args.len() < 3 { + println!("Usage: fragdump "); + std::process::exit(1); + } + + if let Err(err) = dump(&args[1], &args[2]) { + let _ = writeln!(io::stderr(), "{}", err); + } +} + +fn dump>(filename: &P, out: &P) -> Result<()> { + let f = File::open(filename)?; + let size = f.metadata()?.len(); + let mut reader = BufReader::new(f); + + let start = reader.seek(SeekFrom::Current(0))?; + + let mut styp = None; + let mut sidx = None; + let mut moof = None; + let mut mdat = None; + + let mut current = start; + while current < size { + let header = BoxHeader::read(&mut reader)?; + let BoxHeader { name, size: s } = header; + + match name { + BoxType::SidxBox => { + println!(" sidx in len {}", s); + sidx = Some(SidxBox::read_box(&mut reader, s)?); + } + BoxType::MoofBox => { + println!(" moof in len {}", s); + moof = Some(MoofBox::read_box(&mut reader, s)?); + } + BoxType::MdatBox => { + println!(" mdat in len {}", s); + let mut vec_mdat = vec![0; (s - 8) as usize]; + reader.read_exact(&mut vec_mdat)?; + mdat = Some(vec_mdat); + } + BoxType::StypBox => { + println!(" styp in len {}", s); + styp = Some(FtypBox::read_box(&mut reader, s)?); + } + b => { + println!("WARN: got unexpected box {:?}", b); + skip_box(&mut reader, s)?; + } + } + + current = reader.seek(SeekFrom::Current(0))?; + } + + let styp = styp.unwrap(); + let sidx = sidx.unwrap(); + let mut moof = moof.unwrap(); + let tfdt = moof.trafs[0].tfdt.as_mut().unwrap(); + tfdt.base_media_decode_time = sidx.earliest_presentation_time + 5; + let mdat = mdat.unwrap(); + +let mut vec = File::create(out)?; +// let mut vec = Vec::new(); + let t = styp.write_box(&mut vec)?; +// println!(" styp out len {} vs {}", t, vec.len()); +// let mut vec = Vec::new(); + let t = sidx.write_box(&mut vec)?; +// println!(" sidx out len {} vs {}", t, vec.len()); +// let mut vec = Vec::new(); + let t = moof.write_box(&mut vec)?; +// println!(" moof out len {} vs {}", t, vec.len()); + let mdat_hdr = BoxHeader::new(BoxType::MdatBox, mdat.len() as u64 + 8); +// let mut vec = Vec::new(); + let t = mdat_hdr.write(&mut vec)?; + let t = t + vec.write(&mdat)? as u64; +// println!(" mdat out len {} vs {}", t, vec.len()); + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index 92319e18..e276b7c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,8 +76,11 @@ pub type Result = std::result::Result; mod types; pub use types::*; -mod mp4box; -pub use mp4box::*; +// TODO +// mod mp4box; +// pub use mp4box::*; +pub mod mp4box; +pub use mp4box::Mp4Box; mod track; pub use track::{Mp4Track, TrackConfig}; diff --git a/src/mp4box/dinf.rs b/src/mp4box/dinf.rs index e365e4ae..b6ab4845 100644 --- a/src/mp4box/dinf.rs +++ b/src/mp4box/dinf.rs @@ -232,7 +232,7 @@ impl UrlBox { let mut size = HEADER_SIZE + HEADER_EXT_SIZE; if !self.location.is_empty() { - size += self.location.bytes().len() as u64 + 1; + size += self.location.len() as u64 + 1; } size diff --git a/src/mp4box/ftyp.rs b/src/mp4box/ftyp.rs index 789cd4ef..c423376d 100644 --- a/src/mp4box/ftyp.rs +++ b/src/mp4box/ftyp.rs @@ -9,11 +9,12 @@ pub struct FtypBox { pub major_brand: FourCC, pub minor_version: u32, pub compatible_brands: Vec, + pub box_type: BoxType, } impl FtypBox { pub fn get_type(&self) -> BoxType { - BoxType::FtypBox + self.box_type } pub fn get_size(&self) -> u64 { @@ -72,6 +73,7 @@ impl ReadBox<&mut R> for FtypBox { major_brand: From::from(major), minor_version: minor, compatible_brands: brands, + box_type: BoxType::FtypBox, }) } } @@ -107,6 +109,7 @@ mod tests { str::parse("avc1").unwrap(), str::parse("mp41").unwrap(), ], + box_type: BoxType::FtypBox, }; let mut buf = Vec::new(); src_box.write_box(&mut buf).unwrap(); diff --git a/src/mp4box/ilst.rs b/src/mp4box/ilst.rs index d0292a31..1a4e4332 100644 --- a/src/mp4box/ilst.rs +++ b/src/mp4box/ilst.rs @@ -166,7 +166,7 @@ impl ReadBox<&mut R> for IlstItemBox { } impl<'a> Metadata<'a> for IlstBox { - fn title(&self) -> Option> { + fn title(&'_ self) -> Option> { self.items.get(&MetadataKey::Title).map(item_to_str) } @@ -178,7 +178,7 @@ impl<'a> Metadata<'a> for IlstBox { self.items.get(&MetadataKey::Poster).map(item_to_bytes) } - fn summary(&self) -> Option> { + fn summary(&'_ self) -> Option> { self.items.get(&MetadataKey::Summary).map(item_to_str) } } @@ -187,7 +187,7 @@ fn item_to_bytes(item: &IlstItemBox) -> &[u8] { &item.data.data } -fn item_to_str(item: &IlstItemBox) -> Cow { +fn item_to_str(item: &'_ IlstItemBox) -> Cow<'_, str> { String::from_utf8_lossy(&item.data.data) } diff --git a/src/mp4box/mdat.rs b/src/mp4box/mdat.rs new file mode 100644 index 00000000..07621ab0 --- /dev/null +++ b/src/mp4box/mdat.rs @@ -0,0 +1,83 @@ +use crate::mp4box::*; + +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize)] +pub struct MdatBox { + pub data: Vec, +} + +impl Mp4Box for MdatBox { + fn box_type(&self) -> BoxType { + BoxType::MdatBox + } + + fn box_size(&self) -> u64 { + HEADER_SIZE + self.data.len() as u64 + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + Ok(String::new()) + } +} + +impl ReadBox<&mut R> for MdatBox { + fn read_box(reader: &mut R, size: u64) -> Result { + let start = box_start(reader)?; + + let mut data = vec![0; size as usize - 8]; + reader.read_exact(&mut data)?; + + skip_bytes_to(reader, start + size)?; + + Ok(Self { data }) + } +} + +impl WriteBox<&mut W> for MdatBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + writer.write_all(&self.data)?; + + Ok(size) + } +} + +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize)] +pub struct AnyBox { + pub box_type: BoxType, + pub data: Vec, +} + +impl Mp4Box for AnyBox { + fn box_type(&self) -> BoxType { + self.box_type + } + + fn box_size(&self) -> u64 { + HEADER_SIZE + self.data.len() as u64 + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + Ok(String::new()) + } +} + +impl WriteBox<&mut W> for AnyBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + writer.write_all(&self.data)?; + + Ok(size) + } +} diff --git a/src/mp4box/mod.rs b/src/mp4box/mod.rs index 4bbdd410..16147641 100644 --- a/src/mp4box/mod.rs +++ b/src/mp4box/mod.rs @@ -74,6 +74,7 @@ pub(crate) mod ftyp; pub(crate) mod hdlr; pub(crate) mod hev1; pub(crate) mod ilst; +pub mod mdat; pub(crate) mod mdhd; pub(crate) mod mdia; pub(crate) mod mehd; @@ -85,6 +86,7 @@ pub(crate) mod moov; pub(crate) mod mp4a; pub(crate) mod mvex; pub(crate) mod mvhd; +pub mod sidx; pub(crate) mod smhd; pub(crate) mod stbl; pub(crate) mod stco; @@ -115,9 +117,12 @@ pub use edts::EdtsBox; pub use elst::ElstBox; pub use emsg::EmsgBox; pub use ftyp::FtypBox; +// TODO pub use hdlr::HdlrBox; pub use hev1::Hev1Box; pub use ilst::IlstBox; +pub use mdat::AnyBox; +pub use mdat::MdatBox; pub use mdhd::MdhdBox; pub use mdia::MdiaBox; pub use mehd::MehdBox; @@ -129,6 +134,7 @@ pub use moov::MoovBox; pub use mp4a::Mp4aBox; pub use mvex::MvexBox; pub use mvhd::MvhdBox; +pub use sidx::SidxBox; pub use smhd::SmhdBox; pub use stbl::StblBox; pub use stco::StcoBox; @@ -156,12 +162,18 @@ pub const HEADER_EXT_SIZE: u64 = 4; macro_rules! boxtype { ($( $name:ident => $value:expr ),*) => { - #[derive(Clone, Copy, PartialEq, Eq)] + #[derive(Clone, Copy, PartialEq, Eq, serde::Serialize)] pub enum BoxType { $( $name, )* UnknownBox(u32), } + impl Default for BoxType { + fn default() -> BoxType { + BoxType::FreeBox + } + } + impl From for BoxType { fn from(t: u32) -> BoxType { match t { @@ -231,6 +243,7 @@ boxtype! { Tx3gBox => 0x74783367, VpccBox => 0x76706343, Vp09Box => 0x76703039, + // TODO DataBox => 0x64617461, IlstBox => 0x696c7374, NameBox => 0xa96e616d, @@ -238,7 +251,9 @@ boxtype! { CovrBox => 0x636f7672, DescBox => 0x64657363, WideBox => 0x77696465, - WaveBox => 0x77617665 + WaveBox => 0x77617665, + SidxBox => 0x73696478, + StypBox => 0x73747970 } pub trait Mp4Box: Sized { diff --git a/src/mp4box/moof.rs b/src/mp4box/moof.rs index 20c35653..1b1e9329 100644 --- a/src/mp4box/moof.rs +++ b/src/mp4box/moof.rs @@ -102,6 +102,6 @@ impl WriteBox<&mut W> for MoofBox { for traf in self.trafs.iter() { traf.write_box(writer)?; } - Ok(0) + Ok(size) } } diff --git a/src/mp4box/moov.rs b/src/mp4box/moov.rs index ac19381a..6e67a31a 100644 --- a/src/mp4box/moov.rs +++ b/src/mp4box/moov.rs @@ -1,7 +1,6 @@ use serde::Serialize; use std::io::{Read, Seek, Write}; -use crate::meta::MetaBox; use crate::mp4box::*; use crate::mp4box::{mvex::MvexBox, mvhd::MvhdBox, trak::TrakBox, udta::UdtaBox}; diff --git a/src/mp4box/mp4a.rs b/src/mp4box/mp4a.rs index a80c6c46..d7f6f25b 100644 --- a/src/mp4box/mp4a.rs +++ b/src/mp4box/mp4a.rs @@ -285,7 +285,7 @@ fn size_of_length(size: u32) -> u32 { fn write_desc(writer: &mut W, tag: u8, size: u32) -> Result { writer.write_u8(tag)?; - if size as u64 > std::u32::MAX as u64 { + if size as u64 > u32::MAX as u64 { return Err(Error::InvalidData("invalid descriptor length range")); } diff --git a/src/mp4box/sidx.rs b/src/mp4box/sidx.rs new file mode 100644 index 00000000..4d437129 --- /dev/null +++ b/src/mp4box/sidx.rs @@ -0,0 +1,127 @@ +use crate::mp4box::*; +#[derive(Debug, Clone, PartialEq, Default, serde::Serialize)] +pub struct SidxBox { + pub version: u8, + pub flags: u32, + pub reference_id: u32, + pub timescale: u32, + pub earliest_presentation_time: u64, + pub first_offset: u64, + + pub subseg_durations: Vec, +} + +impl SidxBox { + pub fn get_type(&self) -> BoxType { + BoxType::SidxBox + } + + pub fn total_duration(&self) -> u32 { + self.subseg_durations.iter().sum() + } + + pub fn timescale(&self) -> u32 { + self.timescale + } + + pub fn get_size(&self) -> u64 { + let sub_hdr_sz = match self.version { + 0 => 8, + _ => 16, + }; + + HEADER_SIZE + HEADER_EXT_SIZE + 4 + 8 + sub_hdr_sz + (self.subseg_durations.len() as u64 * 12) + } +} + +impl Mp4Box for SidxBox { + fn box_type(&self) -> BoxType { + self.get_type() + } + + fn box_size(&self) -> u64 { + self.get_size() + } + + fn to_json(&self) -> Result { + Ok(serde_json::to_string(&self).unwrap()) + } + + fn summary(&self) -> Result { + Ok(String::new()) + } +} + +impl ReadBox<&mut R> for SidxBox { + fn read_box(reader: &mut R, size: u64) -> Result { + let start = box_start(reader)?; + + let version = reader.read_u8()?; + let flags = reader.read_u24::()?; + + let reference_id = match version { + 0 => reader.read_u16::()? as u32, + _ => reader.read_u32::()?, + }; + + let timescale = match version { + 0 => reader.read_u16::()? as u32, + _ => reader.read_u32::()?, + }; + + let earliest_presentation_time = reader.read_u64::()?; + let first_offset = reader.read_u64::()?; + let _reserved = reader.read_u16::()?; + let ref_count = reader.read_u16::()?; + + let mut subseg_durations = Vec::new(); + for _ in 1..=ref_count { + let _ = reader.read_u32::()?; + let duration = reader.read_u32::()?; + + let _ = reader.read_u32::()?; + + subseg_durations.push(duration); + } + + skip_bytes_to(reader, start + size)?; + + Ok(Self { + version, + flags, + reference_id, + timescale, + earliest_presentation_time, + first_offset, + subseg_durations + }) + } +} + +impl WriteBox<&mut W> for SidxBox { + fn write_box(&self, writer: &mut W) -> Result { + let size = self.box_size(); + BoxHeader::new(self.box_type(), size).write(writer)?; + + write_box_header_ext(writer, self.version, self.flags)?; + match self.version { + 0 => writer.write_u16::(self.reference_id as u16)?, + _ => writer.write_u32::(self.reference_id)?, + } + + match self.version { + 0 => writer.write_u16::(self.timescale as u16)?, + _ => writer.write_u32::(self.timescale)?, + } + + writer.write_u64::(self.earliest_presentation_time)?; + writer.write_u64::(self.first_offset)?; + writer.write_u16::(0)?; + // writer.write_u16::(self.rest.len() as u16)?; + for _ in &self.subseg_durations { + // NOTE: Todo + } + + Ok(size) + } +} diff --git a/src/mp4box/traf.rs b/src/mp4box/traf.rs index d53d713d..67631f29 100644 --- a/src/mp4box/traf.rs +++ b/src/mp4box/traf.rs @@ -25,6 +25,9 @@ impl TrafBox { if let Some(ref trun) = self.trun { size += trun.box_size(); } + if let Some(ref tfdt) = self.tfdt { + size += tfdt.box_size(); + } size } } @@ -114,6 +117,14 @@ impl WriteBox<&mut W> for TrafBox { trun.write_box(writer)?; } + if let Some(ref tfdt) = self.tfdt { + tfdt.write_box(writer)?; + } + + if let Some(ref trun) = self.trun { + trun.write_box(writer)?; + } + Ok(size) } } diff --git a/src/mp4box/trak.rs b/src/mp4box/trak.rs index e8ae760f..5fef2d2b 100644 --- a/src/mp4box/trak.rs +++ b/src/mp4box/trak.rs @@ -1,7 +1,6 @@ use serde::Serialize; use std::io::{Read, Seek, Write}; -use crate::meta::MetaBox; use crate::mp4box::*; use crate::mp4box::{edts::EdtsBox, mdia::MdiaBox, tkhd::TkhdBox}; diff --git a/src/mp4box/trun.rs b/src/mp4box/trun.rs index efbb2b09..a313a31c 100644 --- a/src/mp4box/trun.rs +++ b/src/mp4box/trun.rs @@ -45,15 +45,19 @@ impl TrunBox { } if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_durations.len()); } if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_sizes.len()); } if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_flags.len()); } if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 { sum += 4 * self.sample_count as u64; + assert_eq!(self.sample_count as usize, self.sample_cts.len()); } sum } @@ -173,36 +177,60 @@ impl ReadBox<&mut R> for TrunBox { impl WriteBox<&mut W> for TrunBox { fn write_box(&self, writer: &mut W) -> Result { + let mut real_len = 0; let size = self.box_size(); - BoxHeader::new(self.box_type(), size).write(writer)?; + real_len += BoxHeader::new(self.box_type(), size).write(writer)?; - write_box_header_ext(writer, self.version, self.flags)?; + real_len += write_box_header_ext(writer, self.version, self.flags)?; + real_len += 4; writer.write_u32::(self.sample_count)?; if let Some(v) = self.data_offset { writer.write_i32::(v)?; + } else if TrunBox::FLAG_DATA_OFFSET & self.flags > 0 { + println!("got flag data offset but self.data_offset is None"); } + if let Some(v) = self.first_sample_flags { + real_len += 4; writer.write_u32::(v)?; + } else if TrunBox::FLAG_FIRST_SAMPLE_FLAGS & self.flags > 0 { + println!("got flag_first_sample_flags but self.first_sample_flags is None."); } if self.sample_count != self.sample_sizes.len() as u32 { return Err(Error::InvalidData("sample count out of sync")); } for i in 0..self.sample_count as usize { if TrunBox::FLAG_SAMPLE_DURATION & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_durations[i])?; } if TrunBox::FLAG_SAMPLE_SIZE & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_sizes[i])?; } if TrunBox::FLAG_SAMPLE_FLAGS & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_flags[i])?; } if TrunBox::FLAG_SAMPLE_CTS & self.flags > 0 { + real_len += 4; writer.write_u32::(self.sample_cts[i])?; } } + // sanity check + // assert_eq!(real_len, size); + // FIXME: Ugly hack, it seems that sometimes the writer writes less bytes than it expects + // which makes no fucking sense btw, anyway we detect this and fill it with zeroes. + // + // NOTE: 95% sure this is UB. + if real_len < size { + for _ in 0..(size - real_len) { + writer.write_u8(0)?; + } + } + Ok(size) } } diff --git a/src/reader.rs b/src/reader.rs index e5ac2964..49ad26e0 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -2,7 +2,10 @@ use std::collections::HashMap; use std::io::{Read, Seek}; use std::time::Duration; -use crate::meta::MetaBox; +use crate::mp4box::meta::MetaBox; +use crate::mp4box::{ + skip_box, BoxHeader, BoxType, EmsgBox, FtypBox, MoofBox, MoovBox, ReadBox, SidxBox, +}; use crate::*; #[derive(Debug)] @@ -67,6 +70,9 @@ impl Mp4Reader { let emsg = EmsgBox::read_box(&mut reader, s)?; emsgs.push(emsg); } + BoxType::SidxBox => { + let _sidx = SidxBox::read_box(&mut reader, s)?; + } _ => { // XXX warn!() skip_box(&mut reader, s)?; @@ -75,13 +81,6 @@ impl Mp4Reader { current = reader.stream_position()?; } - if ftyp.is_none() { - return Err(Error::BoxNotFound(BoxType::FtypBox)); - } - if moov.is_none() { - return Err(Error::BoxNotFound(BoxType::MoovBox)); - } - let size = current - start; let mut tracks = if let Some(ref moov) = moov { if moov.traks.iter().any(|trak| trak.tkhd.track_id == 0) { diff --git a/src/track.rs b/src/track.rs index 7eada834..bd3276db 100644 --- a/src/track.rs +++ b/src/track.rs @@ -7,6 +7,7 @@ use std::time::Duration; use crate::mp4box::traf::TrafBox; use crate::mp4box::trak::TrakBox; use crate::mp4box::trun::TrunBox; +use crate::mp4box::BoxType; use crate::mp4box::{ avc1::Avc1Box, co64::Co64Box, ctts::CttsBox, ctts::CttsEntry, hev1::Hev1Box, mp4a::Mp4aBox, smhd::SmhdBox, stco::StcoBox, stsc::StscEntry, stss::StssBox, stts::SttsEntry, tx3g::Tx3gBox, @@ -261,7 +262,7 @@ impl Mp4Track { pub fn sequence_parameter_set(&self) -> Result<&[u8]> { if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 { - match avc1.avcc.sequence_parameter_sets.get(0) { + match avc1.avcc.sequence_parameter_sets.first() { Some(nal) => Ok(nal.bytes.as_ref()), None => Err(Error::EntryInStblNotFound( self.track_id(), @@ -276,7 +277,7 @@ impl Mp4Track { pub fn picture_parameter_set(&self) -> Result<&[u8]> { if let Some(ref avc1) = self.trak.mdia.minf.stbl.stsd.avc1 { - match avc1.avcc.picture_parameter_sets.get(0) { + match avc1.avcc.picture_parameter_sets.first() { Some(nal) => Ok(nal.bytes.as_ref()), None => Err(Error::EntryInStblNotFound( self.track_id(), diff --git a/src/types.rs b/src/types.rs index 540f7fb0..8d9f0f28 100644 --- a/src/types.rs +++ b/src/types.rs @@ -695,17 +695,17 @@ pub enum MetadataKey { pub trait Metadata<'a> { /// The video's title - fn title(&self) -> Option>; + fn title(&'_ self) -> Option>; /// The video's release year fn year(&self) -> Option; /// The video's poster (cover art) fn poster(&self) -> Option<&[u8]>; /// The video's summary - fn summary(&self) -> Option>; + fn summary(&'_ self) -> Option>; } impl<'a, T: Metadata<'a>> Metadata<'a> for &'a T { - fn title(&self) -> Option> { + fn title(&'_ self) -> Option> { (**self).title() } @@ -717,13 +717,13 @@ impl<'a, T: Metadata<'a>> Metadata<'a> for &'a T { (**self).poster() } - fn summary(&self) -> Option> { + fn summary(&'_ self) -> Option> { (**self).summary() } } impl<'a, T: Metadata<'a>> Metadata<'a> for Option { - fn title(&self) -> Option> { + fn title(&'_ self) -> Option> { self.as_ref().and_then(|t| t.title()) } @@ -735,7 +735,7 @@ impl<'a, T: Metadata<'a>> Metadata<'a> for Option { self.as_ref().and_then(|t| t.poster()) } - fn summary(&self) -> Option> { + fn summary(&'_ self) -> Option> { self.as_ref().and_then(|t| t.summary()) } } diff --git a/src/writer.rs b/src/writer.rs index a83a888c..3ac06cff 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -65,6 +65,7 @@ impl Mp4Writer { major_brand: config.major_brand, minor_version: config.minor_version, compatible_brands: config.compatible_brands.clone(), + box_type: BoxType::FtypBox, }; ftyp.write_box(&mut writer)?; @@ -117,7 +118,7 @@ impl Mp4Writer { fn update_mdat_size(&mut self) -> Result<()> { let mdat_end = self.writer.stream_position()?; let mdat_size = mdat_end - self.mdat_pos; - if mdat_size > std::u32::MAX as u64 { + if mdat_size > u32::MAX as u64 { self.writer.seek(SeekFrom::Start(self.mdat_pos))?; self.writer.write_u32::(1)?; self.writer.seek(SeekFrom::Start(self.mdat_pos + 8))?;