From 2654b8e2eaf962bf6c4a4c25242199c09f684acd Mon Sep 17 00:00:00 2001 From: b01o Date: Wed, 15 Oct 2025 23:07:11 +0800 Subject: [PATCH 01/11] Collects unexpected boxes during decoding This change introduces the ability to collect and retain any unexpected boxes encountered during the decoding process. Previously, the decoder would give an Error::unexpectedBox and failing the decode process. Now, these boxes are stored in a `unexpected` Vec within their parent structures (Moov, Trak, Mdia, Minf, Stbl, etc.). This allows for more robust handling of malformed or extended MP4 files, as the application can now inspect and process unexpected boxes as needed. --- src/atom.rs | 9 ++++++++- src/meta/iprp.rs | 1 + src/meta/mod.rs | 2 ++ src/moof/mod.rs | 3 ++- src/moof/traf/mod.rs | 3 ++- src/moov/mod.rs | 20 ++++++++++++++------ src/moov/mvex/mod.rs | 3 ++- src/moov/trak/edts/mod.rs | 3 ++- src/moov/trak/mdia/minf/dinf/mod.rs | 3 ++- src/moov/trak/mdia/minf/mod.rs | 3 ++- src/moov/trak/mdia/minf/stbl/mod.rs | 3 ++- src/moov/trak/mdia/mod.rs | 3 ++- src/moov/trak/mod.rs | 3 ++- src/moov/udta/mod.rs | 5 ++++- src/test/av1.rs | 10 ++++++++++ src/test/bbb.rs | 9 +++++++++ src/test/esds.rs | 7 +++++++ src/test/flac.rs | 7 +++++++ src/test/h264.rs | 15 +++++++++++++++ src/test/heif.rs | 2 ++ src/test/hevc.rs | 7 +++++++ src/test/uncompressed.rs | 7 +++++++ src/test/vp9.rs | 7 +++++++ 23 files changed, 118 insertions(+), 17 deletions(-) diff --git a/src/atom.rs b/src/atom.rs index 01fb508..6694a84 100644 --- a/src/atom.rs +++ b/src/atom.rs @@ -175,6 +175,9 @@ macro_rules! nested { $( let mut [<$optional:lower>] = None;)* $( let mut [<$multiple:lower>] = Vec::new();)* + // aggregate unexpected boxes, if any + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { $(Any::$required(atom) => { @@ -195,7 +198,10 @@ macro_rules! nested { Any::Unknown(kind, _) => { tracing::warn!("unknown box: {:?}", kind); }, - _ => return Err(Error::UnexpectedBox(atom.kind())), + _ => { + tracing::warn!("unexpected box: {:?}", atom.kind()); + unexpected.push(atom); + } } } @@ -203,6 +209,7 @@ macro_rules! nested { $([<$required:lower>]: [<$required:lower>].ok_or(Error::MissingBox($required::KIND))? ,)* $([<$optional:lower>],)* $([<$multiple:lower>],)* + unexpected }) } diff --git a/src/meta/iprp.rs b/src/meta/iprp.rs index 160338c..1200a5d 100644 --- a/src/meta/iprp.rs +++ b/src/meta/iprp.rs @@ -8,6 +8,7 @@ use crate::*; pub struct Iprp { pub ipco: Ipco, pub ipma: Vec, + pub unexpected: Vec, } impl Atom for Iprp { diff --git a/src/meta/mod.rs b/src/meta/mod.rs index ede274a..081733f 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -158,6 +158,7 @@ mod tests { location: "".into(), }], }, + unexpected: vec![], }); expected.push(Iloc { item_locations: vec![ItemLocation { @@ -229,6 +230,7 @@ mod tests { }, ], }], + unexpected: vec![], }); expected.push(Iref { references: vec![Reference { diff --git a/src/moof/mod.rs b/src/moof/mod.rs index 3e127a6..dd59fb4 100644 --- a/src/moof/mod.rs +++ b/src/moof/mod.rs @@ -6,11 +6,12 @@ pub use traf::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Moof { pub mfhd: Mfhd, pub traf: Vec, + pub unexpected: Vec, } impl Atom for Moof { diff --git a/src/moof/traf/mod.rs b/src/moof/traf/mod.rs index 8c520b8..0f62d84 100644 --- a/src/moof/traf/mod.rs +++ b/src/moof/traf/mod.rs @@ -8,7 +8,7 @@ pub use trun::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Traf { pub tfhd: Tfhd, @@ -21,6 +21,7 @@ pub struct Traf { pub saio: Vec, pub meta: Option, pub udta: Option, + pub unexpected: Vec, } impl Atom for Traf { diff --git a/src/moov/mod.rs b/src/moov/mod.rs index 0e43a5a..3d3b401 100644 --- a/src/moov/mod.rs +++ b/src/moov/mod.rs @@ -18,6 +18,7 @@ pub struct Moov { pub mvex: Option, pub trak: Vec, pub udta: Option, + pub unexpected: Vec, } impl Atom for Moov { @@ -137,7 +138,8 @@ mod test { default_sample_description_index: 1, default_sample_duration: 3000, ..Default::default() - }] + }], + unexpected: vec![], }), trak: vec![Trak { tkhd: Tkhd { @@ -156,7 +158,8 @@ mod test { media_rate: 1, ..Default::default() }] - }) + }), + unexpected: vec![], }), meta: None, mdia: Mdia { @@ -184,7 +187,8 @@ mod test { dinf: Dinf { dref: Dref { urls: vec![Url::default()] - } + }, + unexpected: vec![], }, stbl: Stbl { stsd: Stsd { @@ -224,12 +228,16 @@ mod test { }, stco: Some(Stco::default()), ..Default::default() - } - } + }, + unexpected: vec![], + }, + unexpected: vec![], }, - udta: None + udta: None, + unexpected: vec![], }], udta: None, + unexpected: vec![], } ) } diff --git a/src/moov/mvex/mod.rs b/src/moov/mvex/mod.rs index 1ae169c..3c5cd57 100644 --- a/src/moov/mvex/mod.rs +++ b/src/moov/mvex/mod.rs @@ -6,11 +6,12 @@ pub use trex::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Mvex { pub mehd: Option, pub trex: Vec, + pub unexpected: Vec, } impl Atom for Mvex { diff --git a/src/moov/trak/edts/mod.rs b/src/moov/trak/edts/mod.rs index ebf5c2f..ef2f42c 100644 --- a/src/moov/trak/edts/mod.rs +++ b/src/moov/trak/edts/mod.rs @@ -3,10 +3,11 @@ pub use elst::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Edts { pub elst: Option, + pub unexpected: Vec, } impl Atom for Edts { diff --git a/src/moov/trak/mdia/minf/dinf/mod.rs b/src/moov/trak/mdia/minf/dinf/mod.rs index 5e65768..9d2726a 100644 --- a/src/moov/trak/mdia/minf/dinf/mod.rs +++ b/src/moov/trak/mdia/minf/dinf/mod.rs @@ -3,10 +3,11 @@ pub use dref::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Dinf { pub dref: Dref, + pub unexpected: Vec, } impl Atom for Dinf { diff --git a/src/moov/trak/mdia/minf/mod.rs b/src/moov/trak/mdia/minf/mod.rs index c57ef11..41b17a9 100644 --- a/src/moov/trak/mdia/minf/mod.rs +++ b/src/moov/trak/mdia/minf/mod.rs @@ -10,13 +10,14 @@ pub use vmhd::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Minf { pub vmhd: Option, pub smhd: Option, pub dinf: Dinf, pub stbl: Stbl, + pub unexpected: Vec, } impl Atom for Minf { diff --git a/src/moov/trak/mdia/minf/stbl/mod.rs b/src/moov/trak/mdia/minf/stbl/mod.rs index 0f9ab03..0614df8 100644 --- a/src/moov/trak/mdia/minf/stbl/mod.rs +++ b/src/moov/trak/mdia/minf/stbl/mod.rs @@ -26,7 +26,7 @@ pub use subs::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Stbl { pub stsd: Stsd, @@ -42,6 +42,7 @@ pub struct Stbl { pub subs: Vec, pub saiz: Vec, pub saio: Vec, + pub unexpected: Vec, } impl Atom for Stbl { diff --git a/src/moov/trak/mdia/mod.rs b/src/moov/trak/mdia/mod.rs index 4923b39..8ef40b0 100644 --- a/src/moov/trak/mdia/mod.rs +++ b/src/moov/trak/mdia/mod.rs @@ -8,12 +8,13 @@ pub use minf::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Mdia { pub mdhd: Mdhd, pub hdlr: Hdlr, pub minf: Minf, + pub unexpected: Vec, } impl Atom for Mdia { diff --git a/src/moov/trak/mod.rs b/src/moov/trak/mod.rs index 2772f63..8c044ea 100644 --- a/src/moov/trak/mod.rs +++ b/src/moov/trak/mod.rs @@ -8,7 +8,7 @@ pub use tkhd::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Trak { pub tkhd: Tkhd, @@ -16,6 +16,7 @@ pub struct Trak { pub meta: Option, // TODO is this suppose to be here? pub mdia: Mdia, pub udta: Option, + pub unexpected: Vec, } impl Atom for Trak { diff --git a/src/moov/udta/mod.rs b/src/moov/udta/mod.rs index 2a550f0..7e79c9d 100644 --- a/src/moov/udta/mod.rs +++ b/src/moov/udta/mod.rs @@ -4,11 +4,12 @@ pub use skip::*; use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Udta { pub meta: Option, pub skip: Option, + pub unexpected: Vec, } impl Atom for Udta { @@ -30,6 +31,7 @@ mod tests { let expected = Udta { meta: None, skip: None, + unexpected: vec![], }; let mut buf = Vec::new(); @@ -51,6 +53,7 @@ mod tests { items: vec![], }), skip: None, + unexpected: vec![], }; let mut buf = Vec::new(); diff --git a/src/test/av1.rs b/src/test/av1.rs index 7b00be3..3402fa3 100644 --- a/src/test/av1.rs +++ b/src/test/av1.rs @@ -111,6 +111,7 @@ fn av1() { assert_eq!( moov, Moov { + unexpected: vec![], mvhd: Mvhd { creation_time: 0, modification_time: 0, @@ -133,6 +134,7 @@ fn av1() { }, meta: None, mvex: Some(Mvex { + unexpected: vec![], mehd: None, trex: vec![Trex { track_id: 1, @@ -143,6 +145,7 @@ fn av1() { }] }), trak: vec![Trak { + unexpected: vec![], tkhd: Tkhd { creation_time: 0, modification_time: 0, @@ -169,6 +172,7 @@ fn av1() { edts: None, meta: None, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { creation_time: 0, modification_time: 0, @@ -181,6 +185,7 @@ fn av1() { name: "obu@GPAC2.1-DEV-rev199-g8e29f6e8b-github_master".into() }, minf: Minf { + unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, op_color: RgbColor { @@ -191,6 +196,7 @@ fn av1() { }), smhd: None, dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into() @@ -198,6 +204,7 @@ fn av1() { } }, stbl: Stbl { + unexpected: vec![], stsd: Stsd { codecs: vec![Av01 { visual: Visual { @@ -254,6 +261,7 @@ fn av1() { udta: None, }], udta: Some(Udta { + unexpected: vec![], meta: Some(Meta { hdlr: Hdlr { handler: FourCC::new(b"mdir"), @@ -270,8 +278,10 @@ fn av1() { assert_eq!( moof, Moof { + unexpected: vec![], mfhd: Mfhd { sequence_number: 1 }, traf: vec![Traf { + unexpected: vec![], tfhd: Tfhd { track_id: 1, base_data_offset: None, diff --git a/src/test/bbb.rs b/src/test/bbb.rs index ed6382f..dbe082b 100644 --- a/src/test/bbb.rs +++ b/src/test/bbb.rs @@ -218,6 +218,7 @@ fn bbb() { ..Default::default() }, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { timescale: 24000, language: "und".into(), @@ -228,12 +229,14 @@ fn bbb() { name: "(C) 2007 Google Inc. v08.13.2007.".into(), }, minf: Minf { + unexpected: vec![], smhd: None, vmhd: Vmhd { ..Default::default() } .into(), dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), @@ -298,6 +301,7 @@ fn bbb() { ..Default::default() }, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { timescale: 44100, language: "und".into(), @@ -312,6 +316,7 @@ fn bbb() { ..Default::default() }), dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), @@ -383,8 +388,10 @@ fn bbb() { assert_eq!( moof, Moof { + unexpected: vec![], mfhd: Mfhd { sequence_number: 1 }, traf: vec![Traf { + unexpected: vec![], tfhd: Tfhd { track_id: 1, sample_description_index: 1.into(), @@ -443,8 +450,10 @@ fn bbb() { assert_eq!( moof, Moof { + unexpected: vec![], mfhd: Mfhd { sequence_number: 2 }, traf: vec![Traf { + unexpected: vec![], tfhd: Tfhd { track_id: 2, sample_description_index: 1.into(), diff --git a/src/test/esds.rs b/src/test/esds.rs index 1d294f2..df01b87 100644 --- a/src/test/esds.rs +++ b/src/test/esds.rs @@ -147,6 +147,7 @@ fn esds() { ..Default::default() }, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { timescale: 12288, language: "und".into(), @@ -157,12 +158,14 @@ fn esds() { name: "(C) 2007 Google Inc. v08.13.2007.".into(), }, minf: Minf { + unexpected: vec![], smhd: None, vmhd: Vmhd { ..Default::default() } .into(), dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), @@ -227,6 +230,7 @@ fn esds() { ..Default::default() }, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { timescale: 44100, language: "und".into(), @@ -241,6 +245,7 @@ fn esds() { ..Default::default() }), dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), @@ -311,8 +316,10 @@ fn esds() { assert_eq!( moof, Moof { + unexpected: vec![], mfhd: Mfhd { sequence_number: 1 }, traf: vec![Traf { + unexpected: vec![], tfhd: Tfhd { track_id: 1, sample_description_index: 1.into(), diff --git a/src/test/flac.rs b/src/test/flac.rs index b078e9d..3563370 100644 --- a/src/test/flac.rs +++ b/src/test/flac.rs @@ -239,6 +239,7 @@ fn flac() { assert_eq!( moov, Moov { + unexpected: vec![], mvhd: Mvhd { creation_time: 3840517353, modification_time: 3840517353, @@ -261,6 +262,7 @@ fn flac() { }, meta: None, mvex: Some(Mvex { + unexpected: vec![], mehd: None, trex: vec![Trex { track_id: 1, @@ -271,6 +273,7 @@ fn flac() { }] }), trak: vec![Trak { + unexpected: vec![], tkhd: Tkhd { creation_time: 3840517353, modification_time: 3840517353, @@ -297,6 +300,7 @@ fn flac() { edts: None, meta: None, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { creation_time: 3840517353, modification_time: 3840517353, @@ -309,9 +313,11 @@ fn flac() { name: "SoundHandler".into(), }, minf: Minf { + unexpected: vec![], vmhd: None, smhd: Some(Smhd { balance: 0.into() }), dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into() @@ -319,6 +325,7 @@ fn flac() { } }, stbl: Stbl { + unexpected: vec![], stsd: Stsd { codecs: vec![Flac { audio: Audio { diff --git a/src/test/h264.rs b/src/test/h264.rs index 9f34a17..6f03e88 100644 --- a/src/test/h264.rs +++ b/src/test/h264.rs @@ -118,6 +118,7 @@ fn avcc_ext() { let moov = Moov::decode(buf).expect("failed to decode moov"); let expected = Moov { + unexpected: vec![], mvhd: Mvhd { creation_time: 0, modification_time: 0, @@ -140,6 +141,7 @@ fn avcc_ext() { }, meta: None, mvex: Some(Mvex { + unexpected: vec![], mehd: None, trex: vec![ Trex { @@ -160,6 +162,7 @@ fn avcc_ext() { }), trak: vec![ Trak { + unexpected: vec![], tkhd: Tkhd { creation_time: 0, modification_time: 0, @@ -186,6 +189,7 @@ fn avcc_ext() { edts: None, meta: None, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { creation_time: 0, modification_time: 0, @@ -198,6 +202,7 @@ fn avcc_ext() { name: "L-SMASH Video Handler".to_string(), }, minf: Minf { + unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, op_color: RgbColor { @@ -208,11 +213,13 @@ fn avcc_ext() { }), smhd: None, dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url::default()], }, }, stbl: Stbl { + unexpected: vec![], stsd: Stsd { codecs: vec![Avc1 { visual: Visual { @@ -280,6 +287,7 @@ fn avcc_ext() { udta: None, }, Trak { + unexpected: vec![], tkhd: Tkhd { creation_time: 0, modification_time: 0, @@ -306,6 +314,7 @@ fn avcc_ext() { edts: None, meta: None, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { creation_time: 0, modification_time: 0, @@ -318,14 +327,17 @@ fn avcc_ext() { name: "L-SMASH Audio Handler".into(), }, minf: Minf { + unexpected: vec![], vmhd: None, smhd: Some(Smhd::default()), dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url::default()], }, }, stbl: Stbl { + unexpected: vec![], stsd: Stsd { codecs: vec![Mp4a { audio: Audio { @@ -381,6 +393,7 @@ fn avcc_ext() { }, ], udta: Some(Udta { + unexpected: vec![], meta: None, skip: Some(Skip { zeroed: Zeroed { size: 81 }, @@ -670,10 +683,12 @@ fn avc_encrypted_segment() { assert_eq!( moof, Moof { + unexpected: vec![], mfhd: Mfhd { sequence_number: 4382715 }, traf: vec![Traf { + unexpected: vec![], tfhd: Tfhd { track_id: 1, base_data_offset: None, diff --git a/src/test/heif.rs b/src/test/heif.rs index 05f1b91..29decfa 100644 --- a/src/test/heif.rs +++ b/src/test/heif.rs @@ -129,6 +129,7 @@ fn heif() { } .into(), Iprp { + unexpected: vec![], ipco: Ipco { properties: vec![ any::Any::Hvcc(Hvcc { @@ -410,6 +411,7 @@ fn avif() { } .into(), Iprp { + unexpected: vec![], ipco: Ipco { properties: vec![ Any::Ispe(Ispe { diff --git a/src/test/hevc.rs b/src/test/hevc.rs index d6bdcdf..16c053d 100644 --- a/src/test/hevc.rs +++ b/src/test/hevc.rs @@ -215,6 +215,7 @@ fn hevc() { assert_eq!( moov, Moov { + unexpected: vec![], mvhd: Mvhd { creation_time: 0, modification_time: 0, @@ -237,6 +238,7 @@ fn hevc() { }, meta: None, mvex: Some(Mvex { + unexpected: vec![], mehd: None, trex: vec![Trex { track_id: 1, @@ -247,6 +249,7 @@ fn hevc() { }] }), trak: vec![Trak { + unexpected: vec![], tkhd: Tkhd { creation_time: 0, modification_time: 0, @@ -273,6 +276,7 @@ fn hevc() { edts: None, meta: None, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { creation_time: 0, modification_time: 0, @@ -285,6 +289,7 @@ fn hevc() { name: "VideoHandler".into() }, minf: Minf { + unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, op_color: RgbColor { @@ -295,6 +300,7 @@ fn hevc() { }), smhd: None, dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".to_string() @@ -577,6 +583,7 @@ fn hevc() { udta: None, }], udta: Some(Udta { + unexpected: vec![], meta: Some(Meta { hdlr: Hdlr { handler: FourCC::new(b"mdir"), diff --git a/src/test/uncompressed.rs b/src/test/uncompressed.rs index adbd22e..216fbd6 100644 --- a/src/test/uncompressed.rs +++ b/src/test/uncompressed.rs @@ -89,6 +89,7 @@ fn uncompressed() { assert_eq!( moov, Moov { + unexpected: vec![], mvhd: Mvhd { creation_time: 3827291266, modification_time: 3827291266, @@ -112,6 +113,7 @@ fn uncompressed() { meta: None, mvex: None, trak: [Trak { + unexpected: vec![], tkhd: Tkhd { creation_time: 3827291266, modification_time: 3827291266, @@ -138,6 +140,7 @@ fn uncompressed() { edts: None, meta: None, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { creation_time: 3827291266, modification_time: 3827291266, @@ -150,6 +153,7 @@ fn uncompressed() { name: "GPAC ISO Video Handler".into(), }, minf: Minf { + unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, op_color: RgbColor { @@ -160,6 +164,7 @@ fn uncompressed() { }), smhd: None, dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into() @@ -167,6 +172,7 @@ fn uncompressed() { } }, stbl: Stbl { + unexpected: vec![], stsd: Stsd { codecs: vec![Codec::Uncv(Uncv { visual: Visual { @@ -283,6 +289,7 @@ fn uncompressed() { }] .into(), udta: Some(Udta { + unexpected: vec![], meta: Some(Meta { hdlr: Hdlr { handler: FourCC::new(b"mdir"), diff --git a/src/test/vp9.rs b/src/test/vp9.rs index e42a137..58bcc7a 100644 --- a/src/test/vp9.rs +++ b/src/test/vp9.rs @@ -156,6 +156,7 @@ fn vp9() { assert_eq!( moov, Moov { + unexpected: vec![], mvhd: Mvhd { creation_time: 3576083626, modification_time: 3576083626, @@ -193,6 +194,7 @@ fn vp9() { )] }), mvex: Some(Mvex { + unexpected: vec![], mehd: Some(Mehd { fragment_duration: 2736000 }), @@ -205,6 +207,7 @@ fn vp9() { }] }), trak: vec![Trak { + unexpected: vec![], tkhd: Tkhd { creation_time: 3576083626, modification_time: 3576083626, @@ -231,6 +234,7 @@ fn vp9() { edts: None, meta: None, mdia: Mdia { + unexpected: vec![], mdhd: Mdhd { creation_time: 3576083626, modification_time: 3576083626, @@ -243,6 +247,7 @@ fn vp9() { name: "VideoHandler".to_string() }, minf: Minf { + unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, op_color: RgbColor { @@ -253,6 +258,7 @@ fn vp9() { }), smhd: None, dinf: Dinf { + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".to_string() @@ -260,6 +266,7 @@ fn vp9() { } }, stbl: Stbl { + unexpected: vec![], stsd: Stsd { codecs: vec![Vp09 { visual: Visual { From 0677cada951f2182bf34d767be2a4d96c363cde4 Mon Sep 17 00:00:00 2001 From: b01o Date: Wed, 15 Oct 2025 23:38:22 +0800 Subject: [PATCH 02/11] doc tweaks Adds documentation to README and library root regarding the fault-tolerant parsing feature. This explains how unexpected child boxes are handled during decoding and clarifies that they are not written back during encoding. --- README.md | 7 +++++++ src/lib.rs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index 3c1f636..9a73688 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,13 @@ Using this library does require some additional knowledge of the format otherwis See the [documentation](https://docs.rs/mp4-atom). +## Fault-Tolerant Parsing +This library implements fault-tolerant parsing for container boxes. When decoding a container box (such as `moov`, `trak`, `mdia`, etc.), if an unexpected child box is encountered, instead of failing the entire parsing operation, the unexpected box is collected in an `unexpected` field as an `Any` atom. + +All container box structures include an `unexpected: Vec` field that collects these unrecognized boxes. + +Note that when encoding, the `unexpected` boxes are **not** written back - only the explicitly defined fields are encoded. + ## Examples ### Decoding/encoding a byte buffer ```rust diff --git a/src/lib.rs b/src/lib.rs index 4b403ca..31c6178 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,13 @@ //! The simplest way to decode with this library is with [Any::decode], returning any supported atom in a giant enum. //! For encoding you will call encode on the atom directly, ex: [Moov::encode]. //! +//! ## Fault-Tolerant Parsing +//! This library implements fault-tolerant parsing for container boxes. When decoding a container box (such as `moov`, `trak`, `mdia`, etc.), if an unexpected child box is encountered, instead of failing the entire parsing operation, the unexpected box is collected in an `unexpected` field as an `Any` atom. +//! +//! All container box structures include an `unexpected: Vec` field that collects these unrecognized boxes. +//! +//! Note that when encoding, the `unexpected` boxes are **not** written back - only the explicitly defined fields are encoded. +//! //! ## Traits //! This library gates functionality behind quite a few traits: //! From cb07578ddbe3ee24fb4fba28682c63f884acef91 Mon Sep 17 00:00:00 2001 From: b01o Date: Thu, 16 Oct 2025 20:20:14 +0800 Subject: [PATCH 03/11] chore: fmt cargo fmt don't work for some reason. --- src/test/bbb.rs | 6 +++--- src/test/esds.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/bbb.rs b/src/test/bbb.rs index dbe082b..3b8cfe5 100644 --- a/src/test/bbb.rs +++ b/src/test/bbb.rs @@ -218,7 +218,7 @@ fn bbb() { ..Default::default() }, mdia: Mdia { - unexpected: vec![], + unexpected: vec![], mdhd: Mdhd { timescale: 24000, language: "und".into(), @@ -236,7 +236,7 @@ fn bbb() { } .into(), dinf: Dinf { - unexpected: vec![], + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), @@ -316,7 +316,7 @@ fn bbb() { ..Default::default() }), dinf: Dinf { - unexpected: vec![], + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), diff --git a/src/test/esds.rs b/src/test/esds.rs index df01b87..a3fb068 100644 --- a/src/test/esds.rs +++ b/src/test/esds.rs @@ -147,7 +147,7 @@ fn esds() { ..Default::default() }, mdia: Mdia { - unexpected: vec![], + unexpected: vec![], mdhd: Mdhd { timescale: 12288, language: "und".into(), @@ -165,7 +165,7 @@ fn esds() { } .into(), dinf: Dinf { - unexpected: vec![], + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), @@ -230,7 +230,7 @@ fn esds() { ..Default::default() }, mdia: Mdia { - unexpected: vec![], + unexpected: vec![], mdhd: Mdhd { timescale: 44100, language: "und".into(), @@ -245,7 +245,7 @@ fn esds() { ..Default::default() }), dinf: Dinf { - unexpected: vec![], + unexpected: vec![], dref: Dref { urls: vec![Url { location: "".into(), From 088cab768e74ff2c8104baae8c1b7dc50bb56c3f Mon Sep 17 00:00:00 2001 From: b01o Date: Thu, 16 Oct 2025 20:54:53 +0800 Subject: [PATCH 04/11] Adds fault-tolerant parsing feature Implements a new `fault-tolerant` feature that enables parsing of MP4 files with unexpected boxes. Updates documentation and tests to reflect the feature. --- Cargo.toml | 1 + README.md | 11 +++++++++-- src/atom.rs | 14 +++++++++++--- src/lib.rs | 12 +++++++++--- src/meta/iprp.rs | 1 + src/meta/mod.rs | 2 ++ src/moof/mod.rs | 1 + src/moof/traf/mod.rs | 1 + src/moov/mod.rs | 8 ++++++++ src/moov/mvex/mod.rs | 1 + src/moov/trak/edts/mod.rs | 1 + src/moov/trak/mdia/minf/dinf/mod.rs | 1 + src/moov/trak/mdia/minf/mod.rs | 1 + src/moov/trak/mdia/minf/stbl/mod.rs | 1 + src/moov/trak/mdia/mod.rs | 1 + src/moov/trak/mod.rs | 1 + src/moov/udta/mod.rs | 3 +++ src/test/av1.rs | 10 ++++++++++ src/test/bbb.rs | 9 +++++++++ src/test/esds.rs | 7 +++++++ src/test/flac.rs | 7 +++++++ src/test/h264.rs | 15 +++++++++++++++ src/test/heif.rs | 2 ++ src/test/hevc.rs | 7 +++++++ src/test/uncompressed.rs | 7 +++++++ src/test/vp9.rs | 7 +++++++ 26 files changed, 124 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af01891..71d2a04 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ serde = { version = "1", features = ["derive"], optional = true } tokio = ["dep:tokio"] bytes = ["dep:bytes"] serde = ["dep:serde", "bytes/serde"] +fault-tolerant = [] [dev-dependencies] anyhow = "1" diff --git a/README.md b/README.md index 9a73688..903577f 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,16 @@ Using this library does require some additional knowledge of the format otherwis See the [documentation](https://docs.rs/mp4-atom). ## Fault-Tolerant Parsing -This library implements fault-tolerant parsing for container boxes. When decoding a container box (such as `moov`, `trak`, `mdia`, etc.), if an unexpected child box is encountered, instead of failing the entire parsing operation, the unexpected box is collected in an `unexpected` field as an `Any` atom. +Enable the `fault-tolerant` feature to support parsing files with unexpected boxes. -All container box structures include an `unexpected: Vec` field that collects these unrecognized boxes. +```toml +[dependencies] +mp4-atom = { version = "0.9", features = ["fault-tolerant"] } +``` + +When this feature is enabled, if a container box (such as `moov`, `trak`, `mdia`, etc.) encounters an unexpected child box during decoding, instead of returning an error, the unknown box is collected in an `unexpected: Vec` field. + +When the feature is **disabled** (default), encountering an unexpected box will return an `Error::UnexpectedBox` error, ensuring strict compliance with the expected structure. Note that when encoding, the `unexpected` boxes are **not** written back - only the explicitly defined fields are encoded. diff --git a/src/atom.rs b/src/atom.rs index 6694a84..9cc8524 100644 --- a/src/atom.rs +++ b/src/atom.rs @@ -175,7 +175,7 @@ macro_rules! nested { $( let mut [<$optional:lower>] = None;)* $( let mut [<$multiple:lower>] = Vec::new();)* - // aggregate unexpected boxes, if any + #[cfg(feature = "fault-tolerant")] let mut unexpected = Vec::new(); while let Some(atom) = Any::decode_maybe(buf)? { @@ -199,8 +199,15 @@ macro_rules! nested { tracing::warn!("unknown box: {:?}", kind); }, _ => { - tracing::warn!("unexpected box: {:?}", atom.kind()); - unexpected.push(atom); + #[cfg(feature = "fault-tolerant")] + { + tracing::warn!("unexpected box: {:?}", atom.kind()); + unexpected.push(atom); + } + #[cfg(not(feature = "fault-tolerant"))] + { + return Err(Error::UnexpectedBox(atom.kind())); + } } } } @@ -209,6 +216,7 @@ macro_rules! nested { $([<$required:lower>]: [<$required:lower>].ok_or(Error::MissingBox($required::KIND))? ,)* $([<$optional:lower>],)* $([<$multiple:lower>],)* + #[cfg(feature = "fault-tolerant")] unexpected }) } diff --git a/src/lib.rs b/src/lib.rs index 31c6178..f8151f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,10 +16,16 @@ //! The simplest way to decode with this library is with [Any::decode], returning any supported atom in a giant enum. //! For encoding you will call encode on the atom directly, ex: [Moov::encode]. //! -//! ## Fault-Tolerant Parsing -//! This library implements fault-tolerant parsing for container boxes. When decoding a container box (such as `moov`, `trak`, `mdia`, etc.), if an unexpected child box is encountered, instead of failing the entire parsing operation, the unexpected box is collected in an `unexpected` field as an `Any` atom. +//! Enable the `fault-tolerant` feature to support parsing files with unexpected boxes. //! -//! All container box structures include an `unexpected: Vec` field that collects these unrecognized boxes. +//! ```toml +//! [dependencies] +//! mp4-atom = { version = "0.9", features = ["fault-tolerant"] } +//! ``` +//! +//! When this feature is enabled, if a container box (such as `moov`, `trak`, `mdia`, etc.) encounters an unexpected child box during decoding, instead of returning an error, the unknown box is collected in an `unexpected: Vec` field. +//! +//! When the feature is **disabled** (default), encountering an unexpected box will return an `Error::UnexpectedBox` error, ensuring strict compliance with the expected structure. //! //! Note that when encoding, the `unexpected` boxes are **not** written back - only the explicitly defined fields are encoded. //! diff --git a/src/meta/iprp.rs b/src/meta/iprp.rs index 1200a5d..0650f66 100644 --- a/src/meta/iprp.rs +++ b/src/meta/iprp.rs @@ -8,6 +8,7 @@ use crate::*; pub struct Iprp { pub ipco: Ipco, pub ipma: Vec, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/meta/mod.rs b/src/meta/mod.rs index 081733f..b10fc6d 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -158,6 +158,7 @@ mod tests { location: "".into(), }], }, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }); expected.push(Iloc { @@ -230,6 +231,7 @@ mod tests { }, ], }], + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }); expected.push(Iref { diff --git a/src/moof/mod.rs b/src/moof/mod.rs index dd59fb4..84ba924 100644 --- a/src/moof/mod.rs +++ b/src/moof/mod.rs @@ -11,6 +11,7 @@ use crate::*; pub struct Moof { pub mfhd: Mfhd, pub traf: Vec, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moof/traf/mod.rs b/src/moof/traf/mod.rs index 0f62d84..2304102 100644 --- a/src/moof/traf/mod.rs +++ b/src/moof/traf/mod.rs @@ -21,6 +21,7 @@ pub struct Traf { pub saio: Vec, pub meta: Option, pub udta: Option, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/mod.rs b/src/moov/mod.rs index 3d3b401..dba3ce4 100644 --- a/src/moov/mod.rs +++ b/src/moov/mod.rs @@ -18,6 +18,7 @@ pub struct Moov { pub mvex: Option, pub trak: Vec, pub udta: Option, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } @@ -139,6 +140,7 @@ mod test { default_sample_duration: 3000, ..Default::default() }], + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }), trak: vec![Trak { @@ -159,6 +161,7 @@ mod test { ..Default::default() }] }), + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }), meta: None, @@ -188,6 +191,7 @@ mod test { dref: Dref { urls: vec![Url::default()] }, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }, stbl: Stbl { @@ -229,14 +233,18 @@ mod test { stco: Some(Stco::default()), ..Default::default() }, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }, udta: None, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }], udta: None, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], } ) diff --git a/src/moov/mvex/mod.rs b/src/moov/mvex/mod.rs index 3c5cd57..43031c9 100644 --- a/src/moov/mvex/mod.rs +++ b/src/moov/mvex/mod.rs @@ -11,6 +11,7 @@ use crate::*; pub struct Mvex { pub mehd: Option, pub trex: Vec, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/trak/edts/mod.rs b/src/moov/trak/edts/mod.rs index ef2f42c..c0966c2 100644 --- a/src/moov/trak/edts/mod.rs +++ b/src/moov/trak/edts/mod.rs @@ -7,6 +7,7 @@ use crate::*; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Edts { pub elst: Option, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/trak/mdia/minf/dinf/mod.rs b/src/moov/trak/mdia/minf/dinf/mod.rs index 9d2726a..7b77ea2 100644 --- a/src/moov/trak/mdia/minf/dinf/mod.rs +++ b/src/moov/trak/mdia/minf/dinf/mod.rs @@ -7,6 +7,7 @@ use crate::*; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Dinf { pub dref: Dref, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/trak/mdia/minf/mod.rs b/src/moov/trak/mdia/minf/mod.rs index 41b17a9..a85d433 100644 --- a/src/moov/trak/mdia/minf/mod.rs +++ b/src/moov/trak/mdia/minf/mod.rs @@ -17,6 +17,7 @@ pub struct Minf { pub smhd: Option, pub dinf: Dinf, pub stbl: Stbl, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/trak/mdia/minf/stbl/mod.rs b/src/moov/trak/mdia/minf/stbl/mod.rs index 0614df8..01fc384 100644 --- a/src/moov/trak/mdia/minf/stbl/mod.rs +++ b/src/moov/trak/mdia/minf/stbl/mod.rs @@ -42,6 +42,7 @@ pub struct Stbl { pub subs: Vec, pub saiz: Vec, pub saio: Vec, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/trak/mdia/mod.rs b/src/moov/trak/mdia/mod.rs index 8ef40b0..4594b68 100644 --- a/src/moov/trak/mdia/mod.rs +++ b/src/moov/trak/mdia/mod.rs @@ -14,6 +14,7 @@ pub struct Mdia { pub mdhd: Mdhd, pub hdlr: Hdlr, pub minf: Minf, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/trak/mod.rs b/src/moov/trak/mod.rs index 8c044ea..a0f6182 100644 --- a/src/moov/trak/mod.rs +++ b/src/moov/trak/mod.rs @@ -16,6 +16,7 @@ pub struct Trak { pub meta: Option, // TODO is this suppose to be here? pub mdia: Mdia, pub udta: Option, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } diff --git a/src/moov/udta/mod.rs b/src/moov/udta/mod.rs index 7e79c9d..3324b19 100644 --- a/src/moov/udta/mod.rs +++ b/src/moov/udta/mod.rs @@ -9,6 +9,7 @@ use crate::*; pub struct Udta { pub meta: Option, pub skip: Option, + #[cfg(feature = "fault-tolerant")] pub unexpected: Vec, } @@ -31,6 +32,7 @@ mod tests { let expected = Udta { meta: None, skip: None, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }; @@ -53,6 +55,7 @@ mod tests { items: vec![], }), skip: None, + #[cfg(feature = "fault-tolerant")] unexpected: vec![], }; diff --git a/src/test/av1.rs b/src/test/av1.rs index 3402fa3..dc4fe3e 100644 --- a/src/test/av1.rs +++ b/src/test/av1.rs @@ -111,6 +111,7 @@ fn av1() { assert_eq!( moov, Moov { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mvhd: Mvhd { creation_time: 0, @@ -134,6 +135,7 @@ fn av1() { }, meta: None, mvex: Some(Mvex { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mehd: None, trex: vec![Trex { @@ -145,6 +147,7 @@ fn av1() { }] }), trak: vec![Trak { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tkhd: Tkhd { creation_time: 0, @@ -172,6 +175,7 @@ fn av1() { edts: None, meta: None, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { creation_time: 0, @@ -185,6 +189,7 @@ fn av1() { name: "obu@GPAC2.1-DEV-rev199-g8e29f6e8b-github_master".into() }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, @@ -196,6 +201,7 @@ fn av1() { }), smhd: None, dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -204,6 +210,7 @@ fn av1() { } }, stbl: Stbl { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], stsd: Stsd { codecs: vec![Av01 { @@ -261,6 +268,7 @@ fn av1() { udta: None, }], udta: Some(Udta { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], meta: Some(Meta { hdlr: Hdlr { @@ -278,9 +286,11 @@ fn av1() { assert_eq!( moof, Moof { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mfhd: Mfhd { sequence_number: 1 }, traf: vec![Traf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tfhd: Tfhd { track_id: 1, diff --git a/src/test/bbb.rs b/src/test/bbb.rs index 3b8cfe5..f200939 100644 --- a/src/test/bbb.rs +++ b/src/test/bbb.rs @@ -218,6 +218,7 @@ fn bbb() { ..Default::default() }, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { timescale: 24000, @@ -229,6 +230,7 @@ fn bbb() { name: "(C) 2007 Google Inc. v08.13.2007.".into(), }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], smhd: None, vmhd: Vmhd { @@ -236,6 +238,7 @@ fn bbb() { } .into(), dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -301,6 +304,7 @@ fn bbb() { ..Default::default() }, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { timescale: 44100, @@ -316,6 +320,7 @@ fn bbb() { ..Default::default() }), dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -388,9 +393,11 @@ fn bbb() { assert_eq!( moof, Moof { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mfhd: Mfhd { sequence_number: 1 }, traf: vec![Traf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tfhd: Tfhd { track_id: 1, @@ -450,9 +457,11 @@ fn bbb() { assert_eq!( moof, Moof { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mfhd: Mfhd { sequence_number: 2 }, traf: vec![Traf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tfhd: Tfhd { track_id: 2, diff --git a/src/test/esds.rs b/src/test/esds.rs index a3fb068..af470c6 100644 --- a/src/test/esds.rs +++ b/src/test/esds.rs @@ -147,6 +147,7 @@ fn esds() { ..Default::default() }, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { timescale: 12288, @@ -158,6 +159,7 @@ fn esds() { name: "(C) 2007 Google Inc. v08.13.2007.".into(), }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], smhd: None, vmhd: Vmhd { @@ -165,6 +167,7 @@ fn esds() { } .into(), dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -230,6 +233,7 @@ fn esds() { ..Default::default() }, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { timescale: 44100, @@ -245,6 +249,7 @@ fn esds() { ..Default::default() }), dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -316,9 +321,11 @@ fn esds() { assert_eq!( moof, Moof { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mfhd: Mfhd { sequence_number: 1 }, traf: vec![Traf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tfhd: Tfhd { track_id: 1, diff --git a/src/test/flac.rs b/src/test/flac.rs index 3563370..1e1c8e9 100644 --- a/src/test/flac.rs +++ b/src/test/flac.rs @@ -239,6 +239,7 @@ fn flac() { assert_eq!( moov, Moov { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mvhd: Mvhd { creation_time: 3840517353, @@ -262,6 +263,7 @@ fn flac() { }, meta: None, mvex: Some(Mvex { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mehd: None, trex: vec![Trex { @@ -273,6 +275,7 @@ fn flac() { }] }), trak: vec![Trak { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tkhd: Tkhd { creation_time: 3840517353, @@ -300,6 +303,7 @@ fn flac() { edts: None, meta: None, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { creation_time: 3840517353, @@ -313,10 +317,12 @@ fn flac() { name: "SoundHandler".into(), }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], vmhd: None, smhd: Some(Smhd { balance: 0.into() }), dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -325,6 +331,7 @@ fn flac() { } }, stbl: Stbl { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], stsd: Stsd { codecs: vec![Flac { diff --git a/src/test/h264.rs b/src/test/h264.rs index 6f03e88..12b6951 100644 --- a/src/test/h264.rs +++ b/src/test/h264.rs @@ -118,6 +118,7 @@ fn avcc_ext() { let moov = Moov::decode(buf).expect("failed to decode moov"); let expected = Moov { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mvhd: Mvhd { creation_time: 0, @@ -141,6 +142,7 @@ fn avcc_ext() { }, meta: None, mvex: Some(Mvex { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mehd: None, trex: vec![ @@ -162,6 +164,7 @@ fn avcc_ext() { }), trak: vec![ Trak { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tkhd: Tkhd { creation_time: 0, @@ -189,6 +192,7 @@ fn avcc_ext() { edts: None, meta: None, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { creation_time: 0, @@ -202,6 +206,7 @@ fn avcc_ext() { name: "L-SMASH Video Handler".to_string(), }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, @@ -213,12 +218,14 @@ fn avcc_ext() { }), smhd: None, dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url::default()], }, }, stbl: Stbl { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], stsd: Stsd { codecs: vec![Avc1 { @@ -287,6 +294,7 @@ fn avcc_ext() { udta: None, }, Trak { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tkhd: Tkhd { creation_time: 0, @@ -314,6 +322,7 @@ fn avcc_ext() { edts: None, meta: None, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { creation_time: 0, @@ -327,16 +336,19 @@ fn avcc_ext() { name: "L-SMASH Audio Handler".into(), }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], vmhd: None, smhd: Some(Smhd::default()), dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url::default()], }, }, stbl: Stbl { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], stsd: Stsd { codecs: vec![Mp4a { @@ -393,6 +405,7 @@ fn avcc_ext() { }, ], udta: Some(Udta { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], meta: None, skip: Some(Skip { @@ -683,11 +696,13 @@ fn avc_encrypted_segment() { assert_eq!( moof, Moof { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mfhd: Mfhd { sequence_number: 4382715 }, traf: vec![Traf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tfhd: Tfhd { track_id: 1, diff --git a/src/test/heif.rs b/src/test/heif.rs index 29decfa..0bd3f28 100644 --- a/src/test/heif.rs +++ b/src/test/heif.rs @@ -129,6 +129,7 @@ fn heif() { } .into(), Iprp { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], ipco: Ipco { properties: vec![ @@ -411,6 +412,7 @@ fn avif() { } .into(), Iprp { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], ipco: Ipco { properties: vec![ diff --git a/src/test/hevc.rs b/src/test/hevc.rs index 16c053d..d88b0b9 100644 --- a/src/test/hevc.rs +++ b/src/test/hevc.rs @@ -215,6 +215,7 @@ fn hevc() { assert_eq!( moov, Moov { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mvhd: Mvhd { creation_time: 0, @@ -238,6 +239,7 @@ fn hevc() { }, meta: None, mvex: Some(Mvex { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mehd: None, trex: vec![Trex { @@ -249,6 +251,7 @@ fn hevc() { }] }), trak: vec![Trak { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tkhd: Tkhd { creation_time: 0, @@ -276,6 +279,7 @@ fn hevc() { edts: None, meta: None, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { creation_time: 0, @@ -289,6 +293,7 @@ fn hevc() { name: "VideoHandler".into() }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, @@ -300,6 +305,7 @@ fn hevc() { }), smhd: None, dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -583,6 +589,7 @@ fn hevc() { udta: None, }], udta: Some(Udta { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], meta: Some(Meta { hdlr: Hdlr { diff --git a/src/test/uncompressed.rs b/src/test/uncompressed.rs index 216fbd6..40c6b53 100644 --- a/src/test/uncompressed.rs +++ b/src/test/uncompressed.rs @@ -89,6 +89,7 @@ fn uncompressed() { assert_eq!( moov, Moov { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mvhd: Mvhd { creation_time: 3827291266, @@ -113,6 +114,7 @@ fn uncompressed() { meta: None, mvex: None, trak: [Trak { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tkhd: Tkhd { creation_time: 3827291266, @@ -140,6 +142,7 @@ fn uncompressed() { edts: None, meta: None, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { creation_time: 3827291266, @@ -153,6 +156,7 @@ fn uncompressed() { name: "GPAC ISO Video Handler".into(), }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, @@ -164,6 +168,7 @@ fn uncompressed() { }), smhd: None, dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -172,6 +177,7 @@ fn uncompressed() { } }, stbl: Stbl { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], stsd: Stsd { codecs: vec![Codec::Uncv(Uncv { @@ -289,6 +295,7 @@ fn uncompressed() { }] .into(), udta: Some(Udta { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], meta: Some(Meta { hdlr: Hdlr { diff --git a/src/test/vp9.rs b/src/test/vp9.rs index 58bcc7a..523a81b 100644 --- a/src/test/vp9.rs +++ b/src/test/vp9.rs @@ -156,6 +156,7 @@ fn vp9() { assert_eq!( moov, Moov { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mvhd: Mvhd { creation_time: 3576083626, @@ -194,6 +195,7 @@ fn vp9() { )] }), mvex: Some(Mvex { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mehd: Some(Mehd { fragment_duration: 2736000 @@ -207,6 +209,7 @@ fn vp9() { }] }), trak: vec![Trak { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], tkhd: Tkhd { creation_time: 3576083626, @@ -234,6 +237,7 @@ fn vp9() { edts: None, meta: None, mdia: Mdia { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], mdhd: Mdhd { creation_time: 3576083626, @@ -247,6 +251,7 @@ fn vp9() { name: "VideoHandler".to_string() }, minf: Minf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], vmhd: Some(Vmhd { graphics_mode: 0, @@ -258,6 +263,7 @@ fn vp9() { }), smhd: None, dinf: Dinf { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], dref: Dref { urls: vec![Url { @@ -266,6 +272,7 @@ fn vp9() { } }, stbl: Stbl { + #[cfg(feature = "fault-tolerant")] unexpected: vec![], stsd: Stsd { codecs: vec![Vp09 { From e8aa7baa1a6acbc6e61a44d054b1f5ed3aac48f7 Mon Sep 17 00:00:00 2001 From: b01o Date: Thu, 16 Oct 2025 21:04:25 +0800 Subject: [PATCH 05/11] Adds fault tolerance tests Introduces tests to verify the behavior of the fault-tolerant feature. When enabled, the feature collects unexpected boxes during decoding. When disabled, encountering unexpected boxes results in an error. Also adds tests for multiple unexpected boxes and ensures that unexpected boxes are not encoded. --- src/test/fault_tolerant.rs | 226 +++++++++++++++++++++++++++++++++++++ src/test/mod.rs | 1 + 2 files changed, 227 insertions(+) create mode 100644 src/test/fault_tolerant.rs diff --git a/src/test/fault_tolerant.rs b/src/test/fault_tolerant.rs new file mode 100644 index 0000000..73e6754 --- /dev/null +++ b/src/test/fault_tolerant.rs @@ -0,0 +1,226 @@ +use crate::*; + +/// Test that fault-tolerant feature works as expected +/// When enabled: unexpected boxes are collected +/// When disabled: unexpected boxes cause an error +#[test] +fn test_fault_tolerant_behavior() { + // Create a buffer with a Moov box containing an unexpected child box + // Moov structure: mvhd (required) + an unknown/unexpected box + let mut buf = Vec::new(); + + // First encode a valid Moov with mvhd + let moov = Moov { + mvhd: Mvhd { + creation_time: 0, + modification_time: 0, + timescale: 1000, + duration: 0, + rate: 1.into(), + volume: 1.into(), + next_track_id: 1, + ..Default::default() + }, + meta: None, + mvex: None, + trak: vec![], + udta: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], + }; + + // Encode the moov + moov.encode(&mut buf).unwrap(); + + // Now manually insert an unexpected box into the moov + // We'll use 'mdat' which is a known box type but NOT expected inside moov + // This should trigger the unexpected box behavior + let mut moov_buf = Vec::new(); + + // Encode mvhd + moov.mvhd.encode(&mut moov_buf).unwrap(); + + // Add an mdat box (which is NOT a child of moov) + // This should be treated as unexpected + let mdat_data = vec![ + 0x00, 0x00, 0x00, 0x10, // size: 16 bytes + b'm', b'd', b'a', b't', // type: 'mdat' + 0x01, 0x02, 0x03, 0x04, // some data + 0x05, 0x06, 0x07, 0x08, + ]; + moov_buf.extend_from_slice(&mdat_data); + + // Now wrap it in a moov box + let mut final_buf = Vec::new(); + let moov_size = (moov_buf.len() + 8) as u32; // +8 for size and type + final_buf.extend_from_slice(&moov_size.to_be_bytes()); + final_buf.extend_from_slice(b"moov"); + final_buf.extend_from_slice(&moov_buf); + + // Try to decode the moov + let result = Moov::decode(&mut final_buf.as_slice()); + + #[cfg(feature = "fault-tolerant")] + { + // With fault-tolerant feature enabled, it should succeed + let decoded = result.expect("should decode successfully with fault-tolerant feature"); + + // Check that the unexpected box was collected + assert_eq!(decoded.unexpected.len(), 1, "should have 1 unexpected box"); + + // Verify the unexpected box + match &decoded.unexpected[0] { + Any::Mdat(mdat) => { + // The mdat box should be collected as unexpected + assert_eq!(mdat.data.len(), 8, "mdat data should be 8 bytes"); + } + _ => panic!( + "unexpected box should be Any::Mdat variant, got: {:?}", + decoded.unexpected[0] + ), + } + + // Other fields should be decoded correctly + assert_eq!(decoded.mvhd.timescale, 1000); + assert_eq!(decoded.trak.len(), 0); + } + + #[cfg(not(feature = "fault-tolerant"))] + { + // Without fault-tolerant feature, it should return an error + assert!( + result.is_err(), + "should fail to decode without fault-tolerant feature" + ); + + // Check that it's specifically an UnexpectedBox error + match result.unwrap_err() { + Error::UnexpectedBox(kind) => { + assert_eq!( + kind, + FourCC::new(b"mdat"), + "error should report 'mdat' as unexpected" + ); + } + other => panic!("expected UnexpectedBox error, got: {:?}", other), + } + } +} + +/// Test that multiple unexpected boxes are collected correctly +#[test] +#[cfg(feature = "fault-tolerant")] +fn test_multiple_unexpected_boxes() { + // Create a moov with multiple unexpected boxes + let mut moov_buf = Vec::new(); + + // Encode mvhd + let mvhd = Mvhd { + creation_time: 0, + modification_time: 0, + timescale: 1000, + duration: 0, + rate: 1.into(), + volume: 1.into(), + next_track_id: 1, + ..Default::default() + }; + mvhd.encode(&mut moov_buf).unwrap(); + + // Add first unexpected box (ftyp - not expected in moov) + let unexpected1 = vec![ + 0x00, 0x00, 0x00, 0x14, // size: 20 bytes + b'f', b't', b'y', b'p', // type: 'ftyp' + b'i', b's', b'o', b'm', // major brand + 0x00, 0x00, 0x02, 0x00, // minor version + b'm', b'p', b'4', b'1', // compatible brand + ]; + moov_buf.extend_from_slice(&unexpected1); + + // Add second unexpected box (mdat - not expected in moov) + let unexpected2 = vec![ + 0x00, 0x00, 0x00, 0x10, // size: 16 bytes + b'm', b'd', b'a', b't', // type: 'mdat' + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + ]; + moov_buf.extend_from_slice(&unexpected2); + + // Wrap in moov box + let mut final_buf = Vec::new(); + let moov_size = (moov_buf.len() + 8) as u32; + final_buf.extend_from_slice(&moov_size.to_be_bytes()); + final_buf.extend_from_slice(b"moov"); + final_buf.extend_from_slice(&moov_buf); + + // Decode + let decoded = Moov::decode(&mut final_buf.as_slice()) + .expect("should decode successfully with multiple unexpected boxes"); + + // Verify both unexpected boxes were collected + assert_eq!( + decoded.unexpected.len(), + 2, + "should have 2 unexpected boxes" + ); + + match &decoded.unexpected[0] { + Any::Ftyp(ftyp) => { + assert_eq!(ftyp.major_brand, FourCC::new(b"isom")); + } + _ => panic!( + "first unexpected box should be Any::Ftyp, got: {:?}", + decoded.unexpected[0] + ), + } + + match &decoded.unexpected[1] { + Any::Mdat(mdat) => { + assert_eq!(mdat.data.len(), 8); + } + _ => panic!( + "second unexpected box should be Any::Mdat, got: {:?}", + decoded.unexpected[1] + ), + } +} + +/// Test that unexpected boxes are not encoded back +#[test] +#[cfg(feature = "fault-tolerant")] +fn test_unexpected_boxes_not_encoded() { + // Create a moov with an unexpected box + let moov = Moov { + mvhd: Mvhd { + creation_time: 0, + modification_time: 0, + timescale: 1000, + duration: 0, + rate: 1.into(), + volume: 1.into(), + next_track_id: 1, + ..Default::default() + }, + meta: None, + mvex: None, + trak: vec![], + udta: None, + unexpected: vec![Any::Mdat(Mdat { + data: vec![0x01, 0x02, 0x03, 0x04], + })], + }; + + // Encode the moov + let mut buf = Vec::new(); + moov.encode(&mut buf).unwrap(); + + // Decode it back + let decoded = Moov::decode(&mut buf.as_slice()).expect("should decode"); + + // The unexpected box should NOT be present in the decoded version + // because it wasn't encoded + assert_eq!( + decoded.unexpected.len(), + 0, + "unexpected boxes should not be encoded" + ); +} diff --git a/src/test/mod.rs b/src/test/mod.rs index 09e6e0c..4b59f69 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -1,6 +1,7 @@ mod av1; mod bbb; mod esds; +mod fault_tolerant; mod flac; mod h264; mod heif; From 6b8902b1259ab3553735396ea2bf0a914d16d081 Mon Sep 17 00:00:00 2001 From: b01o Date: Fri, 17 Oct 2025 22:30:18 +0800 Subject: [PATCH 06/11] Adds unexpected field for all SampleEntry boxes --- src/moov/mod.rs | 2 ++ src/moov/trak/mdia/minf/stbl/stsd/ac3.rs | 20 +++++++++++-- src/moov/trak/mdia/minf/stbl/stsd/av01.rs | 15 ++++++++-- src/moov/trak/mdia/minf/stbl/stsd/eac3.rs | 28 ++++++++++++++++--- src/moov/trak/mdia/minf/stbl/stsd/flac.rs | 15 ++++++++-- .../trak/mdia/minf/stbl/stsd/h264/avc1.rs | 21 ++++++++++++-- .../trak/mdia/minf/stbl/stsd/hevc/hev1.rs | 26 +++++++++++++---- .../trak/mdia/minf/stbl/stsd/hevc/hvc1.rs | 18 ++++++++++-- .../trak/mdia/minf/stbl/stsd/hevc/hvcc.rs | 5 +--- src/moov/trak/mdia/minf/stbl/stsd/mod.rs | 4 +-- src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs | 17 +++++++++-- src/moov/trak/mdia/minf/stbl/stsd/opus.rs | 14 ++++++++-- src/moov/trak/mdia/minf/stbl/stsd/uncv.rs | 15 ++++++++-- src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs | 15 ++++++++-- src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs | 17 +++++++++-- src/test/av1.rs | 2 ++ src/test/bbb.rs | 4 +++ src/test/esds.rs | 4 +++ src/test/flac.rs | 2 ++ src/test/h264.rs | 4 ++- src/test/hevc.rs | 7 ++++- src/test/uncompressed.rs | 4 ++- src/test/vp9.rs | 4 ++- 23 files changed, 222 insertions(+), 41 deletions(-) diff --git a/src/moov/mod.rs b/src/moov/mod.rs index dba3ce4..5f0021a 100644 --- a/src/moov/mod.rs +++ b/src/moov/mod.rs @@ -227,6 +227,8 @@ mod test { colr: None, pasp: None, taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, diff --git a/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs b/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs index e764864..011e5ba 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs @@ -2,11 +2,13 @@ use crate::*; // See ETSI TS 102 366 V1.4.1 (2017-09) for details of AC-3 and EAC-3 -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Ac3 { pub audio: Audio, pub dac3: Ac3SpecificBox, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Ac3 { @@ -16,17 +18,25 @@ impl Atom for Ac3 { let audio = Audio::decode(buf)?; let mut dac3 = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Ac3SpecificBox(atom) => dac3 = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } Ok(Self { audio, dac3: dac3.ok_or(Error::MissingBox(Ac3SpecificBox::KIND))?, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } @@ -120,7 +130,9 @@ mod tests { acmod: 2, lfeon: false, bit_rate_code: 10 - } + }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } ); } @@ -142,6 +154,8 @@ mod tests { lfeon: false, bit_rate_code: 10, }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], }; let mut buf = Vec::new(); diff --git a/src/moov/trak/mdia/minf/stbl/stsd/av01.rs b/src/moov/trak/mdia/minf/stbl/stsd/av01.rs index efc30d2..cee3676 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/av01.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/av01.rs @@ -3,7 +3,7 @@ use crate::{Any, Atom, Buf, BufMut, DecodeMaybe, Error, FourCC, Result}; use super::{Btrt, Colr, Pasp, Taic, Visual}; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Av01 { pub visual: Visual, @@ -12,6 +12,8 @@ pub struct Av01 { pub colr: Option, pub pasp: Option, pub taic: Option, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Av01 { @@ -25,6 +27,9 @@ impl Atom for Av01 { let mut colr = None; let mut pasp = None; let mut taic = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Av1c(atom) => av1c = atom.into(), @@ -32,7 +37,11 @@ impl Atom for Av01 { Any::Colr(atom) => colr = atom.into(), Any::Pasp(atom) => pasp = atom.into(), Any::Taic(atom) => taic = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } @@ -43,6 +52,8 @@ impl Atom for Av01 { colr, pasp, taic, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs b/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs index a2316f6..a90e5b5 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs @@ -2,11 +2,13 @@ use crate::*; // See ETSI TS 102 366 V1.4.1 (2017-09) for details of AC-3 and EAC-3 -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Eac3 { pub audio: Audio, pub dec3: Ec3SpecificBox, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Eac3 { @@ -16,17 +18,25 @@ impl Atom for Eac3 { let audio = Audio::decode(buf)?; let mut dec3 = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Ec3SpecificBox(atom) => dec3 = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } Ok(Self { audio, dec3: dec3.ok_or(Error::MissingBox(Ec3SpecificBox::KIND))?, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } @@ -180,7 +190,9 @@ mod tests { num_dep_sub: 0, chan_loc: None }] - } + }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } ); } @@ -207,6 +219,8 @@ mod tests { chan_loc: None, }], }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], }; let mut buf = Vec::new(); @@ -238,6 +252,8 @@ mod tests { chan_loc: Some(0x1FF), }], }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], }; // Encode @@ -287,6 +303,8 @@ mod tests { }, ], }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], }; // Encode @@ -342,7 +360,9 @@ mod tests { num_dep_sub: 0, chan_loc: None }] - } + }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } ); } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/flac.rs b/src/moov/trak/mdia/minf/stbl/stsd/flac.rs index 082a40a..2ebd446 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/flac.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/flac.rs @@ -1,10 +1,12 @@ use crate::*; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Flac { pub audio: Audio, pub dfla: Dfla, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Flac { @@ -14,16 +16,25 @@ impl Atom for Flac { let audio = Audio::decode(buf)?; let mut dfla = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Dfla(atom) => dfla = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } Ok(Self { audio, dfla: dfla.ok_or(Error::MissingBox(Dfla::KIND))?, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs b/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs index ad0417e..10af99a 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs @@ -1,6 +1,6 @@ use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Avc1 { pub visual: Visual, @@ -9,6 +9,9 @@ pub struct Avc1 { pub colr: Option, pub pasp: Option, pub taic: Option, + + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Avc1 { @@ -22,6 +25,10 @@ impl Atom for Avc1 { let mut colr = None; let mut pasp = None; let mut taic = None; + + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Avcc(atom) => avcc = atom.into(), @@ -29,7 +36,11 @@ impl Atom for Avc1 { Any::Colr(atom) => colr = atom.into(), Any::Pasp(atom) => pasp = atom.into(), Any::Taic(atom) => taic = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom) + } } } @@ -40,6 +51,8 @@ impl Atom for Avc1 { colr, pasp, taic, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } @@ -96,6 +109,8 @@ mod tests { colr: None, pasp: None, taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: Vec::new(), }; let mut buf = Vec::new(); expected.encode(&mut buf).unwrap(); @@ -147,6 +162,8 @@ mod tests { clock_drift_rate: i32::MAX, clock_type: ClockType::CanSync, }), + #[cfg(feature = "fault-tolerant")] + unexpected: Vec::new(), }; let mut buf = Vec::new(); expected.encode(&mut buf).unwrap(); diff --git a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs index bd726de..336a579 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs @@ -1,6 +1,6 @@ use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Hev1 { pub visual: Visual, @@ -9,6 +9,9 @@ pub struct Hev1 { pub colr: Option, pub pasp: Option, pub taic: Option, + + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Hev1 { @@ -22,6 +25,10 @@ impl Atom for Hev1 { let mut colr = None; let mut pasp = None; let mut taic = None; + + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Hvcc(atom) => hvcc = atom.into(), @@ -29,7 +36,11 @@ impl Atom for Hev1 { Any::Colr(atom) => colr = atom.into(), Any::Pasp(atom) => pasp = atom.into(), Any::Taic(atom) => taic = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom) + } } } @@ -40,6 +51,8 @@ impl Atom for Hev1 { colr, pasp, taic, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } @@ -58,6 +71,10 @@ impl Atom for Hev1 { if self.taic.is_some() { self.taic.encode(buf)? } + #[cfg(feature = "fault-tolerant")] + for atom in &self.unexpected { + atom.encode(buf)?; + } Ok(()) } @@ -84,10 +101,7 @@ mod tests { configuration_version: 1, ..Default::default() }, - btrt: None, - colr: None, - pasp: None, - taic: None, + ..Default::default() }; let mut buf = Vec::new(); expected.encode(&mut buf).unwrap(); diff --git a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs index 6c7b2c9..8b9396a 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs @@ -1,6 +1,6 @@ use crate::*; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Hvc1 { pub visual: Visual, @@ -10,6 +10,9 @@ pub struct Hvc1 { pub colr: Option, pub pasp: Option, pub taic: Option, + + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Hvc1 { @@ -23,6 +26,10 @@ impl Atom for Hvc1 { let mut colr = None; let mut pasp = None; let mut taic = None; + + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Hvcc(atom) => hvcc = atom.into(), @@ -30,7 +37,11 @@ impl Atom for Hvc1 { Any::Colr(atom) => colr = atom.into(), Any::Pasp(atom) => pasp = atom.into(), Any::Taic(atom) => taic = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom) + } } } @@ -41,6 +52,9 @@ impl Atom for Hvc1 { colr, pasp, taic, + + #[cfg(feature = "fault-tolerant")] + unexpected, }) } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvcc.rs b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvcc.rs index 9fb8f9d..e45eb70 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvcc.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvcc.rs @@ -169,10 +169,7 @@ mod tests { configuration_version: 1, ..Default::default() }, - btrt: None, - colr: None, - pasp: None, - taic: None, + ..Default::default() }; let mut buf = Vec::new(); expected.encode(&mut buf).unwrap(); diff --git a/src/moov/trak/mdia/minf/stbl/stsd/mod.rs b/src/moov/trak/mdia/minf/stbl/stsd/mod.rs index afa9d78..46fda96 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/mod.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/mod.rs @@ -39,14 +39,14 @@ pub use vp9::*; use crate::*; use derive_more::From; -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Stsd { pub codecs: Vec, } /// Called a "sample entry" in the ISOBMFF specification. -#[derive(Debug, Clone, PartialEq, Eq, From)] +#[derive(Debug, Clone, PartialEq, From)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Codec { // H264 diff --git a/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs b/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs index c06662b..9e1948e 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs @@ -4,13 +4,15 @@ use crate::*; pub mod esds; pub use esds::Esds; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Mp4a { pub audio: Audio, pub esds: Esds, pub btrt: Option, pub taic: Option, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Mp4a { @@ -23,13 +25,20 @@ impl Atom for Mp4a { let mut esds = None; let mut taic = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + // Find esds in mp4a or wave while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Btrt(atom) => btrt = atom.into(), Any::Esds(atom) => esds = atom.into(), Any::Taic(atom) => taic = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } @@ -38,6 +47,8 @@ impl Atom for Mp4a { esds: esds.ok_or(Error::MissingBox(Esds::KIND))?, btrt, taic, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } @@ -90,6 +101,8 @@ mod tests { avg_bitrate: 3, }), taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], }; let mut buf = Vec::new(); expected.encode(&mut buf).unwrap(); diff --git a/src/moov/trak/mdia/minf/stbl/stsd/opus.rs b/src/moov/trak/mdia/minf/stbl/stsd/opus.rs index ad36ec0..ced4d4b 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/opus.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/opus.rs @@ -1,10 +1,12 @@ use crate::*; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Opus { pub audio: Audio, pub dops: Dops, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Opus { @@ -14,18 +16,26 @@ impl Atom for Opus { let audio = Audio::decode(buf)?; let mut dops = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); // Find esds in mp4a or wave while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Dops(atom) => dops = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } Ok(Self { audio, dops: dops.ok_or(Error::MissingBox(Dops::KIND))?, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs b/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs index 9eca10c..30f27ab 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs @@ -2,7 +2,7 @@ use crate::*; use super::{Btrt, Pasp, Visual}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Uncv { pub visual: Visual, @@ -11,6 +11,8 @@ pub struct Uncv { pub btrt: Option, pub ccst: Option, pub pasp: Option, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Uncv { @@ -24,6 +26,9 @@ impl Atom for Uncv { let mut uncc = None; let mut btrt = None; let mut pasp = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::Cmpd(atom) => cmpd = atom.into(), @@ -31,7 +36,11 @@ impl Atom for Uncv { Any::Btrt(atom) => btrt = atom.into(), Any::Ccst(atom) => ccst = atom.into(), Any::Pasp(atom) => pasp = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } @@ -42,6 +51,8 @@ impl Atom for Uncv { btrt, ccst, pasp, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs index dea5e65..a537720 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs @@ -1,11 +1,13 @@ use crate::*; // https://www.webmproject.org/vp9/mp4/ -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Vp08 { pub visual: Visual, pub vpcc: VpcC, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Vp08 { @@ -15,16 +17,25 @@ impl Atom for Vp08 { let visual = Visual::decode(buf)?; let mut vpcc = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::VpcC(atom) => vpcc = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } Ok(Self { visual, vpcc: vpcc.ok_or(Error::MissingBox(VpcC::KIND))?, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs index 6b7b41f..6a16a71 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs @@ -1,11 +1,13 @@ use crate::*; // https://www.webmproject.org/vp9/mp4/ -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Vp09 { pub visual: Visual, pub vpcc: VpcC, + #[cfg(feature = "fault-tolerant")] + pub unexpected: Vec, } impl Atom for Vp09 { @@ -15,16 +17,25 @@ impl Atom for Vp09 { let visual = Visual::decode(buf)?; let mut vpcc = None; + #[cfg(feature = "fault-tolerant")] + let mut unexpected = Vec::new(); + while let Some(atom) = Any::decode_maybe(buf)? { match atom { Any::VpcC(atom) => vpcc = atom.into(), - _ => tracing::warn!("unknown atom: {:?}", atom), + _ => { + tracing::warn!("unknown atom: {:?}", atom); + #[cfg(feature = "fault-tolerant")] + unexpected.push(atom); + } } } Ok(Self { visual, vpcc: vpcc.ok_or(Error::MissingBox(VpcC::KIND))?, + #[cfg(feature = "fault-tolerant")] + unexpected, }) } @@ -49,6 +60,8 @@ mod tests { ..Default::default() }, vpcc: VpcC::default(), + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], }; let mut buf = Vec::new(); expected.encode(&mut buf).unwrap(); diff --git a/src/test/av1.rs b/src/test/av1.rs index dc4fe3e..e93d336 100644 --- a/src/test/av1.rs +++ b/src/test/av1.rs @@ -247,6 +247,8 @@ fn av1() { colr: None, pasp: None, taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, diff --git a/src/test/bbb.rs b/src/test/bbb.rs index f200939..437ba3f 100644 --- a/src/test/bbb.rs +++ b/src/test/bbb.rs @@ -276,6 +276,8 @@ fn bbb() { v_spacing: 1, }), taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, @@ -357,6 +359,8 @@ fn bbb() { }, btrt: Some(Btrt { buffer_size_db: 0, max_bitrate: 125587, avg_bitrate: 125587 }), taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, diff --git a/src/test/esds.rs b/src/test/esds.rs index af470c6..45f77dd 100644 --- a/src/test/esds.rs +++ b/src/test/esds.rs @@ -205,6 +205,8 @@ fn esds() { v_spacing: 1 }), taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, @@ -286,6 +288,8 @@ fn esds() { }, btrt: Some(Btrt { buffer_size_db: 0, max_bitrate: 128000, avg_bitrate: 128000 }), taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, diff --git a/src/test/flac.rs b/src/test/flac.rs index 1e1c8e9..2fd56ef 100644 --- a/src/test/flac.rs +++ b/src/test/flac.rs @@ -367,6 +367,8 @@ fn flac() { }, ], }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into(),] }, diff --git a/src/test/h264.rs b/src/test/h264.rs index 12b6951..9f4a2d1 100644 --- a/src/test/h264.rs +++ b/src/test/h264.rs @@ -272,7 +272,7 @@ fn avcc_ext() { h_spacing: 1, v_spacing: 1, }), - taic: None, + ..Default::default() } .into()], }, @@ -383,6 +383,8 @@ fn avcc_ext() { avg_bitrate: 160000, }), taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, diff --git a/src/test/hevc.rs b/src/test/hevc.rs index d88b0b9..e2cbbf8 100644 --- a/src/test/hevc.rs +++ b/src/test/hevc.rs @@ -572,12 +572,17 @@ fn hevc() { max_bitrate: 25175730, avg_bitrate: 25175730 }), - colr: None, pasp: Some(Pasp { h_spacing: 1, v_spacing: 1, }), + colr: None, taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![Any::Unknown( + FourCC::new(b"fiel"), + vec![1, 0] + )], } .into()], }, diff --git a/src/test/uncompressed.rs b/src/test/uncompressed.rs index 40c6b53..3416e82 100644 --- a/src/test/uncompressed.rs +++ b/src/test/uncompressed.rs @@ -249,7 +249,9 @@ fn uncompressed() { avg_bitrate: 48 }), ccst: None, - pasp: None + pasp: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], })], }, stts: Stts { diff --git a/src/test/vp9.rs b/src/test/vp9.rs index 523a81b..24ed242 100644 --- a/src/test/vp9.rs +++ b/src/test/vp9.rs @@ -296,7 +296,9 @@ fn vp9() { transfer_characteristics: 2, matrix_coefficients: 2, codec_initialization_data: vec![] - } + }, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], } .into()], }, From 60b23836e2176bf20a5a5ca8dc9dd88f4de7209e Mon Sep 17 00:00:00 2001 From: b01o Date: Fri, 17 Oct 2025 22:41:54 +0800 Subject: [PATCH 07/11] Doc tweaks --- README.md | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 903577f..4d71313 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Enable the `fault-tolerant` feature to support parsing files with unexpected box ```toml [dependencies] -mp4-atom = { version = "0.9", features = ["fault-tolerant"] } +mp4-atom = { version = "", features = ["fault-tolerant"] } ``` When this feature is enabled, if a container box (such as `moov`, `trak`, `mdia`, etc.) encounters an unexpected child box during decoding, instead of returning an error, the unknown box is collected in an `unexpected: Vec` field. diff --git a/src/lib.rs b/src/lib.rs index f8151f0..0a6f3e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ //! //! ```toml //! [dependencies] -//! mp4-atom = { version = "0.9", features = ["fault-tolerant"] } +//! mp4-atom = { version = "", features = ["fault-tolerant"] } //! ``` //! //! When this feature is enabled, if a container box (such as `moov`, `trak`, `mdia`, etc.) encounters an unexpected child box during decoding, instead of returning an error, the unknown box is collected in an `unexpected: Vec` field. From 26b960a7b54be2a2baa8aecebb481db1313716a3 Mon Sep 17 00:00:00 2001 From: b01o Date: Fri, 17 Oct 2025 22:50:44 +0800 Subject: [PATCH 08/11] fix(hev1): unexpected boxes should not be encoded here --- src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs index 336a579..d85ee87 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs @@ -71,10 +71,6 @@ impl Atom for Hev1 { if self.taic.is_some() { self.taic.encode(buf)? } - #[cfg(feature = "fault-tolerant")] - for atom in &self.unexpected { - atom.encode(buf)?; - } Ok(()) } From b1caf951ef065f297548d3d8d69d08286853a462 Mon Sep 17 00:00:00 2001 From: b01o Date: Fri, 17 Oct 2025 22:51:36 +0800 Subject: [PATCH 09/11] Enables strict error handling when fault tolerance is off --- src/moov/trak/mdia/minf/stbl/stsd/ac3.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/av01.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/eac3.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/flac.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs | 5 ++++- src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs | 5 ++++- src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs | 4 +++- src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/opus.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/uncv.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs | 3 +++ src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs | 3 +++ 12 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs b/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs index 011e5ba..83f29b8 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/ac3.rs @@ -28,6 +28,9 @@ impl Atom for Ac3 { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/av01.rs b/src/moov/trak/mdia/minf/stbl/stsd/av01.rs index cee3676..741bef8 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/av01.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/av01.rs @@ -41,6 +41,9 @@ impl Atom for Av01 { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs b/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs index a90e5b5..e629d8d 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/eac3.rs @@ -28,6 +28,9 @@ impl Atom for Eac3 { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/flac.rs b/src/moov/trak/mdia/minf/stbl/stsd/flac.rs index 2ebd446..52d95d0 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/flac.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/flac.rs @@ -26,6 +26,9 @@ impl Atom for Flac { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs b/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs index 10af99a..c4732b1 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/h264/avc1.rs @@ -39,7 +39,10 @@ impl Atom for Avc1 { _ => { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] - unexpected.push(atom) + unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs index d85ee87..b7d021c 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hev1.rs @@ -39,7 +39,10 @@ impl Atom for Hev1 { _ => { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] - unexpected.push(atom) + unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs index 8b9396a..a93fba4 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/hevc/hvc1.rs @@ -40,7 +40,9 @@ impl Atom for Hvc1 { _ => { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] - unexpected.push(atom) + unexpected.push(atom); + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs b/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs index 9e1948e..c43d8ae 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/mp4a/mod.rs @@ -38,6 +38,9 @@ impl Atom for Mp4a { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/opus.rs b/src/moov/trak/mdia/minf/stbl/stsd/opus.rs index ced4d4b..d3e5046 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/opus.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/opus.rs @@ -27,6 +27,9 @@ impl Atom for Opus { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs b/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs index 30f27ab..45ea9eb 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/uncv.rs @@ -40,6 +40,9 @@ impl Atom for Uncv { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs index a537720..77a7204 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp08.rs @@ -27,6 +27,9 @@ impl Atom for Vp08 { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } diff --git a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs index 6a16a71..147bfbf 100644 --- a/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs +++ b/src/moov/trak/mdia/minf/stbl/stsd/vp9/vp09.rs @@ -27,6 +27,9 @@ impl Atom for Vp09 { tracing::warn!("unknown atom: {:?}", atom); #[cfg(feature = "fault-tolerant")] unexpected.push(atom); + + #[cfg(not(feature = "fault-tolerant"))] + return Err(Error::UnexpectedBox(atom.kind())); } } } From b40386e292b55dfbb4147dcf6a4814473245a3b2 Mon Sep 17 00:00:00 2001 From: b01o Date: Fri, 17 Oct 2025 23:07:41 +0800 Subject: [PATCH 10/11] fixes HEVC test to reflect fault tolerance --- src/test/hevc.rs | 777 +++++++++++++++++++++++++---------------------- 1 file changed, 407 insertions(+), 370 deletions(-) diff --git a/src/test/hevc.rs b/src/test/hevc.rs index e2cbbf8..f6c551f 100644 --- a/src/test/hevc.rs +++ b/src/test/hevc.rs @@ -211,57 +211,30 @@ fn hevc() { } ); - let moov = Moov::decode(buf).expect("failed to decode moov"); - assert_eq!( - moov, - Moov { - #[cfg(feature = "fault-tolerant")] - unexpected: vec![], - mvhd: Mvhd { - creation_time: 0, - modification_time: 0, - timescale: 1000, - duration: 0, - rate: 1.into(), - volume: 1.into(), - matrix: Matrix { - a: 65536, - b: 0, - u: 0, - c: 0, - d: 65536, - v: 0, - x: 0, - y: 0, - w: 1073741824 - }, - next_track_id: 2 - }, - meta: None, - mvex: Some(Mvex { - #[cfg(feature = "fault-tolerant")] - unexpected: vec![], - mehd: None, - trex: vec![Trex { - track_id: 1, - default_sample_description_index: 1, - default_sample_duration: 0, - default_sample_size: 0, - default_sample_flags: 0 - }] - }), - trak: vec![Trak { + // unexpected box `fiel` + #[cfg(not(feature = "fault-tolerant"))] + { + let Error::UnexpectedBox(fourcc) = Moov::decode(buf).unwrap_err() else { + unreachable!() + }; + assert_eq!(fourcc, FourCC::new(b"fiel")); + } + + #[cfg(feature = "fault-tolerant")] + { + let moov = Moov::decode(buf).expect("failed to decode moov"); + assert_eq!( + moov, + Moov { #[cfg(feature = "fault-tolerant")] unexpected: vec![], - tkhd: Tkhd { + mvhd: Mvhd { creation_time: 0, modification_time: 0, - track_id: 1, + timescale: 1000, duration: 0, - layer: 0, - alternate_group: 0, - enabled: true, - volume: 0.into(), + rate: 1.into(), + volume: 1.into(), matrix: Matrix { a: 65536, b: 0, @@ -273,348 +246,412 @@ fn hevc() { y: 0, w: 1073741824 }, - width: 1920.into(), - height: 1080.into() + next_track_id: 2 }, - edts: None, meta: None, - mdia: Mdia { + mvex: Some(Mvex { + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], + mehd: None, + trex: vec![Trex { + track_id: 1, + default_sample_description_index: 1, + default_sample_duration: 0, + default_sample_size: 0, + default_sample_flags: 0 + }] + }), + trak: vec![Trak { #[cfg(feature = "fault-tolerant")] unexpected: vec![], - mdhd: Mdhd { + tkhd: Tkhd { creation_time: 0, modification_time: 0, - timescale: 15360, + track_id: 1, duration: 0, - language: "und".into() - }, - hdlr: Hdlr { - handler: b"vide".into(), - name: "VideoHandler".into() + layer: 0, + alternate_group: 0, + enabled: true, + volume: 0.into(), + matrix: Matrix { + a: 65536, + b: 0, + u: 0, + c: 0, + d: 65536, + v: 0, + x: 0, + y: 0, + w: 1073741824 + }, + width: 1920.into(), + height: 1080.into() }, - minf: Minf { + edts: None, + meta: None, + mdia: Mdia { #[cfg(feature = "fault-tolerant")] unexpected: vec![], - vmhd: Some(Vmhd { - graphics_mode: 0, - op_color: RgbColor { - red: 0, - green: 0, - blue: 0 - } - }), - smhd: None, - dinf: Dinf { + mdhd: Mdhd { + creation_time: 0, + modification_time: 0, + timescale: 15360, + duration: 0, + language: "und".into() + }, + hdlr: Hdlr { + handler: b"vide".into(), + name: "VideoHandler".into() + }, + minf: Minf { #[cfg(feature = "fault-tolerant")] unexpected: vec![], - dref: Dref { - urls: vec![Url { - location: "".to_string() - }] - } - }, - stbl: Stbl { - stsd: Stsd { - codecs: vec![Hev1 { - visual: Visual { - data_reference_index: 1, - width: 1920, - height: 1080, - horizresolution: 72.into(), - vertresolution: 72.into(), - frame_count: 1, - compressor: "".into(), - depth: 24 - }, - hvcc: Hvcc { - configuration_version: 1, - general_profile_space: 0, - general_tier_flag: true, - general_profile_idc: 1, - general_profile_compatibility_flags: [96, 0, 0, 0], - general_constraint_indicator_flags: [144, 0, 0, 0, 0, 0], - general_level_idc: 120, - min_spatial_segmentation_idc: 0, - parallelism_type: 0, - chroma_format_idc: 1, - bit_depth_luma_minus8: 0, - bit_depth_chroma_minus8: 0, - avg_frame_rate: 0, - constant_frame_rate: 0, - num_temporal_layers: 1, - temporal_id_nested: true, - length_size_minus_one: 3, - arrays: vec![ - HvcCArray { - completeness: false, - nal_unit_type: 32, - nalus: vec![vec![ - 64, 1, 12, 1, 255, 255, 33, 96, 0, 0, 3, 0, - 144, 0, 0, 3, 0, 0, 3, 0, 120, 149, 152, 9 - ]] - }, - HvcCArray { - completeness: false, - nal_unit_type: 33, - nalus: vec![vec![ - 66, 1, 1, 33, 96, 0, 0, 3, 0, 144, 0, 0, 3, 0, - 0, 3, 0, 120, 160, 3, 192, 128, 16, 229, 150, - 86, 105, 36, 202, 240, 16, 16, 0, 0, 3, 0, 16, - 0, 0, 3, 1, 224, 128 - ]] - }, - HvcCArray { - completeness: false, - nal_unit_type: 34, - nalus: vec![vec![68, 1, 193, 114, 180, 98, 64]] - }, - HvcCArray { - completeness: false, - nal_unit_type: 39, - // It looks scary, but it's just the x265 CLI flags. - nalus: vec![vec![ - 78, 1, 5, 255, 255, 255, 255, 255, 255, 255, - 115, 44, 162, 222, 9, 181, 23, 71, 219, 187, - 85, 164, 254, 127, 194, 252, 78, 120, 50, 54, - 53, 32, 40, 98, 117, 105, 108, 100, 32, 49, 53, - 49, 41, 32, 45, 32, 50, 46, 54, 43, 52, 57, 45, - 55, 50, 49, 57, 51, 55, 54, 100, 101, 52, 50, - 97, 58, 91, 87, 105, 110, 100, 111, 119, 115, - 93, 91, 71, 67, 67, 32, 55, 46, 51, 46, 48, 93, - 91, 54, 52, 32, 98, 105, 116, 93, 32, 56, 98, - 105, 116, 43, 49, 48, 98, 105, 116, 32, 45, 32, - 72, 46, 50, 54, 53, 47, 72, 69, 86, 67, 32, 99, - 111, 100, 101, 99, 32, 45, 32, 67, 111, 112, - 121, 114, 105, 103, 104, 116, 32, 50, 48, 49, - 51, 45, 50, 48, 49, 56, 32, 40, 99, 41, 32, 77, - 117, 108, 116, 105, 99, 111, 114, 101, 119, 97, - 114, 101, 44, 32, 73, 110, 99, 32, 45, 32, 104, - 116, 116, 112, 58, 47, 47, 120, 50, 54, 53, 46, - 111, 114, 103, 32, 45, 32, 111, 112, 116, 105, - 111, 110, 115, 58, 32, 99, 112, 117, 105, 100, - 61, 49, 48, 53, 48, 49, 49, 49, 32, 102, 114, - 97, 109, 101, 45, 116, 104, 114, 101, 97, 100, - 115, 61, 51, 32, 110, 117, 109, 97, 45, 112, - 111, 111, 108, 115, 61, 56, 32, 119, 112, 112, - 32, 110, 111, 45, 112, 109, 111, 100, 101, 32, - 110, 111, 45, 112, 109, 101, 32, 110, 111, 45, - 112, 115, 110, 114, 32, 110, 111, 45, 115, 115, - 105, 109, 32, 108, 111, 103, 45, 108, 101, 118, - 101, 108, 61, 50, 32, 98, 105, 116, 100, 101, - 112, 116, 104, 61, 56, 32, 105, 110, 112, 117, - 116, 45, 99, 115, 112, 61, 49, 32, 102, 112, - 115, 61, 51, 48, 47, 49, 32, 105, 110, 112, - 117, 116, 45, 114, 101, 115, 61, 49, 57, 50, - 48, 120, 49, 48, 56, 48, 32, 105, 110, 116, - 101, 114, 108, 97, 99, 101, 61, 48, 32, 116, - 111, 116, 97, 108, 45, 102, 114, 97, 109, 101, - 115, 61, 48, 32, 108, 101, 118, 101, 108, 45, - 105, 100, 99, 61, 48, 32, 104, 105, 103, 104, - 45, 116, 105, 101, 114, 61, 49, 32, 117, 104, - 100, 45, 98, 100, 61, 48, 32, 114, 101, 102, - 61, 52, 32, 110, 111, 45, 97, 108, 108, 111, - 119, 45, 110, 111, 110, 45, 99, 111, 110, 102, - 111, 114, 109, 97, 110, 99, 101, 32, 110, 111, - 45, 114, 101, 112, 101, 97, 116, 45, 104, 101, - 97, 100, 101, 114, 115, 32, 97, 110, 110, 101, - 120, 98, 32, 110, 111, 45, 97, 117, 100, 32, - 110, 111, 45, 104, 114, 100, 32, 105, 110, 102, - 111, 32, 104, 97, 115, 104, 61, 48, 32, 110, - 111, 45, 116, 101, 109, 112, 111, 114, 97, 108, - 45, 108, 97, 121, 101, 114, 115, 32, 111, 112, - 101, 110, 45, 103, 111, 112, 32, 109, 105, 110, - 45, 107, 101, 121, 105, 110, 116, 61, 50, 53, - 32, 107, 101, 121, 105, 110, 116, 61, 50, 53, - 48, 32, 103, 111, 112, 45, 108, 111, 111, 107, - 97, 104, 101, 97, 100, 61, 48, 32, 98, 102, - 114, 97, 109, 101, 115, 61, 52, 32, 98, 45, 97, - 100, 97, 112, 116, 61, 50, 32, 98, 45, 112, - 121, 114, 97, 109, 105, 100, 32, 98, 102, 114, - 97, 109, 101, 45, 98, 105, 97, 115, 61, 48, 32, - 114, 99, 45, 108, 111, 111, 107, 97, 104, 101, - 97, 100, 61, 50, 53, 32, 108, 111, 111, 107, - 97, 104, 101, 97, 100, 45, 115, 108, 105, 99, - 101, 115, 61, 52, 32, 115, 99, 101, 110, 101, - 99, 117, 116, 61, 52, 48, 32, 114, 97, 100, - 108, 61, 48, 32, 110, 111, 45, 105, 110, 116, - 114, 97, 45, 114, 101, 102, 114, 101, 115, 104, - 32, 99, 116, 117, 61, 54, 52, 32, 109, 105, - 110, 45, 99, 117, 45, 115, 105, 122, 101, 61, - 56, 32, 114, 101, 99, 116, 32, 110, 111, 45, - 97, 109, 112, 32, 109, 97, 120, 45, 116, 117, - 45, 115, 105, 122, 101, 61, 51, 50, 32, 116, - 117, 45, 105, 110, 116, 101, 114, 45, 100, 101, - 112, 116, 104, 61, 49, 32, 116, 117, 45, 105, - 110, 116, 114, 97, 45, 100, 101, 112, 116, 104, - 61, 49, 32, 108, 105, 109, 105, 116, 45, 116, - 117, 61, 48, 32, 114, 100, 111, 113, 45, 108, - 101, 118, 101, 108, 61, 50, 32, 100, 121, 110, - 97, 109, 105, 99, 45, 114, 100, 61, 48, 46, 48, - 48, 32, 110, 111, 45, 115, 115, 105, 109, 45, - 114, 100, 32, 115, 105, 103, 110, 104, 105, - 100, 101, 32, 110, 111, 45, 116, 115, 107, 105, - 112, 32, 110, 114, 45, 105, 110, 116, 114, 97, - 61, 48, 32, 110, 114, 45, 105, 110, 116, 101, - 114, 61, 48, 32, 110, 111, 45, 99, 111, 110, - 115, 116, 114, 97, 105, 110, 101, 100, 45, 105, - 110, 116, 114, 97, 32, 115, 116, 114, 111, 110, - 103, 45, 105, 110, 116, 114, 97, 45, 115, 109, - 111, 111, 116, 104, 105, 110, 103, 32, 109, 97, - 120, 45, 109, 101, 114, 103, 101, 61, 51, 32, - 108, 105, 109, 105, 116, 45, 114, 101, 102, - 115, 61, 51, 32, 108, 105, 109, 105, 116, 45, - 109, 111, 100, 101, 115, 32, 109, 101, 61, 51, - 32, 115, 117, 98, 109, 101, 61, 51, 32, 109, - 101, 114, 97, 110, 103, 101, 61, 53, 55, 32, - 116, 101, 109, 112, 111, 114, 97, 108, 45, 109, - 118, 112, 32, 119, 101, 105, 103, 104, 116, - 112, 32, 110, 111, 45, 119, 101, 105, 103, 104, - 116, 98, 32, 110, 111, 45, 97, 110, 97, 108, - 121, 122, 101, 45, 115, 114, 99, 45, 112, 105, - 99, 115, 32, 100, 101, 98, 108, 111, 99, 107, - 61, 48, 58, 48, 32, 115, 97, 111, 32, 110, 111, - 45, 115, 97, 111, 45, 110, 111, 110, 45, 100, - 101, 98, 108, 111, 99, 107, 32, 114, 100, 61, - 52, 32, 110, 111, 45, 101, 97, 114, 108, 121, - 45, 115, 107, 105, 112, 32, 114, 115, 107, 105, - 112, 32, 110, 111, 45, 102, 97, 115, 116, 45, - 105, 110, 116, 114, 97, 32, 110, 111, 45, 116, - 115, 107, 105, 112, 45, 102, 97, 115, 116, 32, - 110, 111, 45, 99, 117, 45, 108, 111, 115, 115, - 108, 101, 115, 115, 32, 110, 111, 45, 98, 45, - 105, 110, 116, 114, 97, 32, 110, 111, 45, 115, - 112, 108, 105, 116, 114, 100, 45, 115, 107, - 105, 112, 32, 114, 100, 112, 101, 110, 97, 108, - 116, 121, 61, 48, 32, 112, 115, 121, 45, 114, - 100, 61, 50, 46, 48, 48, 32, 112, 115, 121, 45, - 114, 100, 111, 113, 61, 49, 46, 48, 48, 32, - 110, 111, 45, 114, 100, 45, 114, 101, 102, 105, - 110, 101, 32, 110, 111, 45, 108, 111, 115, 115, - 108, 101, 115, 115, 32, 99, 98, 113, 112, 111, - 102, 102, 115, 61, 48, 32, 99, 114, 113, 112, - 111, 102, 102, 115, 61, 48, 32, 114, 99, 61, - 97, 98, 114, 32, 98, 105, 116, 114, 97, 116, - 101, 61, 50, 51, 50, 48, 48, 32, 113, 99, 111, - 109, 112, 61, 48, 46, 54, 48, 32, 113, 112, - 115, 116, 101, 112, 61, 52, 32, 115, 116, 97, - 116, 115, 45, 119, 114, 105, 116, 101, 61, 48, - 32, 115, 116, 97, 116, 115, 45, 114, 101, 97, - 100, 61, 48, 32, 105, 112, 114, 97, 116, 105, - 111, 61, 49, 46, 52, 48, 32, 112, 98, 114, 97, - 116, 105, 111, 61, 49, 46, 51, 48, 32, 97, 113, - 45, 109, 111, 100, 101, 61, 49, 32, 97, 113, - 45, 115, 116, 114, 101, 110, 103, 116, 104, 61, - 49, 46, 48, 48, 32, 99, 117, 116, 114, 101, - 101, 32, 122, 111, 110, 101, 45, 99, 111, 117, - 110, 116, 61, 48, 32, 110, 111, 45, 115, 116, - 114, 105, 99, 116, 45, 99, 98, 114, 32, 113, - 103, 45, 115, 105, 122, 101, 61, 51, 50, 32, - 110, 111, 45, 114, 99, 45, 103, 114, 97, 105, - 110, 32, 113, 112, 109, 97, 120, 61, 54, 57, - 32, 113, 112, 109, 105, 110, 61, 48, 32, 110, - 111, 45, 99, 111, 110, 115, 116, 45, 118, 98, - 118, 32, 115, 97, 114, 61, 49, 32, 111, 118, - 101, 114, 115, 99, 97, 110, 61, 48, 32, 118, - 105, 100, 101, 111, 102, 111, 114, 109, 97, - 116, 61, 53, 32, 114, 97, 110, 103, 101, 61, - 48, 32, 99, 111, 108, 111, 114, 112, 114, 105, - 109, 61, 50, 32, 116, 114, 97, 110, 115, 102, - 101, 114, 61, 50, 32, 99, 111, 108, 111, 114, - 109, 97, 116, 114, 105, 120, 61, 50, 32, 99, - 104, 114, 111, 109, 97, 108, 111, 99, 61, 48, - 32, 100, 105, 115, 112, 108, 97, 121, 45, 119, - 105, 110, 100, 111, 119, 61, 48, 32, 109, 97, - 120, 45, 99, 108, 108, 61, 48, 44, 48, 32, 109, - 105, 110, 45, 108, 117, 109, 97, 61, 48, 32, - 109, 97, 120, 45, 108, 117, 109, 97, 61, 50, - 53, 53, 32, 108, 111, 103, 50, 45, 109, 97, - 120, 45, 112, 111, 99, 45, 108, 115, 98, 61, - 56, 32, 118, 117, 105, 45, 116, 105, 109, 105, - 110, 103, 45, 105, 110, 102, 111, 32, 118, 117, - 105, 45, 104, 114, 100, 45, 105, 110, 102, 111, - 32, 115, 108, 105, 99, 101, 115, 61, 49, 32, - 110, 111, 45, 111, 112, 116, 45, 113, 112, 45, - 112, 112, 115, 32, 110, 111, 45, 111, 112, 116, - 45, 114, 101, 102, 45, 108, 105, 115, 116, 45, - 108, 101, 110, 103, 116, 104, 45, 112, 112, - 115, 32, 110, 111, 45, 109, 117, 108, 116, 105, - 45, 112, 97, 115, 115, 45, 111, 112, 116, 45, - 114, 112, 115, 32, 115, 99, 101, 110, 101, 99, - 117, 116, 45, 98, 105, 97, 115, 61, 48, 46, 48, - 53, 32, 110, 111, 45, 111, 112, 116, 45, 99, - 117, 45, 100, 101, 108, 116, 97, 45, 113, 112, - 32, 110, 111, 45, 97, 113, 45, 109, 111, 116, - 105, 111, 110, 32, 110, 111, 45, 104, 100, 114, - 32, 110, 111, 45, 104, 100, 114, 45, 111, 112, - 116, 32, 110, 111, 45, 100, 104, 100, 114, 49, - 48, 45, 111, 112, 116, 32, 97, 110, 97, 108, - 121, 115, 105, 115, 45, 114, 101, 117, 115, - 101, 45, 108, 101, 118, 101, 108, 61, 53, 32, - 115, 99, 97, 108, 101, 45, 102, 97, 99, 116, - 111, 114, 61, 48, 32, 114, 101, 102, 105, 110, - 101, 45, 105, 110, 116, 114, 97, 61, 48, 32, - 114, 101, 102, 105, 110, 101, 45, 105, 110, - 116, 101, 114, 61, 48, 32, 114, 101, 102, 105, - 110, 101, 45, 109, 118, 61, 48, 32, 110, 111, - 45, 108, 105, 109, 105, 116, 45, 115, 97, 111, - 32, 99, 116, 117, 45, 105, 110, 102, 111, 61, - 48, 32, 110, 111, 45, 108, 111, 119, 112, 97, - 115, 115, 45, 100, 99, 116, 32, 114, 101, 102, - 105, 110, 101, 45, 109, 118, 45, 116, 121, 112, - 101, 61, 48, 32, 99, 111, 112, 121, 45, 112, - 105, 99, 61, 49, 128 - ]] - } - ] - }, - btrt: Some(Btrt { - buffer_size_db: 0, - max_bitrate: 25175730, - avg_bitrate: 25175730 - }), - pasp: Some(Pasp { - h_spacing: 1, - v_spacing: 1, - }), - colr: None, - taic: None, - #[cfg(feature = "fault-tolerant")] - unexpected: vec![Any::Unknown( - FourCC::new(b"fiel"), - vec![1, 0] - )], + vmhd: Some(Vmhd { + graphics_mode: 0, + op_color: RgbColor { + red: 0, + green: 0, + blue: 0 + } + }), + smhd: None, + dinf: Dinf { + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], + dref: Dref { + urls: vec![Url { + location: "".to_string() + }] } - .into()], }, - stco: Some(Stco { entries: vec![] }), - ..Default::default() + stbl: Stbl { + stsd: Stsd { + codecs: vec![Hev1 { + visual: Visual { + data_reference_index: 1, + width: 1920, + height: 1080, + horizresolution: 72.into(), + vertresolution: 72.into(), + frame_count: 1, + compressor: "".into(), + depth: 24 + }, + hvcc: Hvcc { + configuration_version: 1, + general_profile_space: 0, + general_tier_flag: true, + general_profile_idc: 1, + general_profile_compatibility_flags: [96, 0, 0, 0], + general_constraint_indicator_flags: [ + 144, 0, 0, 0, 0, 0 + ], + general_level_idc: 120, + min_spatial_segmentation_idc: 0, + parallelism_type: 0, + chroma_format_idc: 1, + bit_depth_luma_minus8: 0, + bit_depth_chroma_minus8: 0, + avg_frame_rate: 0, + constant_frame_rate: 0, + num_temporal_layers: 1, + temporal_id_nested: true, + length_size_minus_one: 3, + arrays: vec![ + HvcCArray { + completeness: false, + nal_unit_type: 32, + nalus: vec![vec![ + 64, 1, 12, 1, 255, 255, 33, 96, 0, 0, 3, 0, + 144, 0, 0, 3, 0, 0, 3, 0, 120, 149, 152, 9 + ]] + }, + HvcCArray { + completeness: false, + nal_unit_type: 33, + nalus: vec![vec![ + 66, 1, 1, 33, 96, 0, 0, 3, 0, 144, 0, 0, 3, + 0, 0, 3, 0, 120, 160, 3, 192, 128, 16, 229, + 150, 86, 105, 36, 202, 240, 16, 16, 0, 0, + 3, 0, 16, 0, 0, 3, 1, 224, 128 + ]] + }, + HvcCArray { + completeness: false, + nal_unit_type: 34, + nalus: vec![vec![68, 1, 193, 114, 180, 98, 64]] + }, + HvcCArray { + completeness: false, + nal_unit_type: 39, + // It looks scary, but it's just the x265 CLI flags. + nalus: vec![vec![ + 78, 1, 5, 255, 255, 255, 255, 255, 255, + 255, 115, 44, 162, 222, 9, 181, 23, 71, + 219, 187, 85, 164, 254, 127, 194, 252, 78, + 120, 50, 54, 53, 32, 40, 98, 117, 105, 108, + 100, 32, 49, 53, 49, 41, 32, 45, 32, 50, + 46, 54, 43, 52, 57, 45, 55, 50, 49, 57, 51, + 55, 54, 100, 101, 52, 50, 97, 58, 91, 87, + 105, 110, 100, 111, 119, 115, 93, 91, 71, + 67, 67, 32, 55, 46, 51, 46, 48, 93, 91, 54, + 52, 32, 98, 105, 116, 93, 32, 56, 98, 105, + 116, 43, 49, 48, 98, 105, 116, 32, 45, 32, + 72, 46, 50, 54, 53, 47, 72, 69, 86, 67, 32, + 99, 111, 100, 101, 99, 32, 45, 32, 67, 111, + 112, 121, 114, 105, 103, 104, 116, 32, 50, + 48, 49, 51, 45, 50, 48, 49, 56, 32, 40, 99, + 41, 32, 77, 117, 108, 116, 105, 99, 111, + 114, 101, 119, 97, 114, 101, 44, 32, 73, + 110, 99, 32, 45, 32, 104, 116, 116, 112, + 58, 47, 47, 120, 50, 54, 53, 46, 111, 114, + 103, 32, 45, 32, 111, 112, 116, 105, 111, + 110, 115, 58, 32, 99, 112, 117, 105, 100, + 61, 49, 48, 53, 48, 49, 49, 49, 32, 102, + 114, 97, 109, 101, 45, 116, 104, 114, 101, + 97, 100, 115, 61, 51, 32, 110, 117, 109, + 97, 45, 112, 111, 111, 108, 115, 61, 56, + 32, 119, 112, 112, 32, 110, 111, 45, 112, + 109, 111, 100, 101, 32, 110, 111, 45, 112, + 109, 101, 32, 110, 111, 45, 112, 115, 110, + 114, 32, 110, 111, 45, 115, 115, 105, 109, + 32, 108, 111, 103, 45, 108, 101, 118, 101, + 108, 61, 50, 32, 98, 105, 116, 100, 101, + 112, 116, 104, 61, 56, 32, 105, 110, 112, + 117, 116, 45, 99, 115, 112, 61, 49, 32, + 102, 112, 115, 61, 51, 48, 47, 49, 32, 105, + 110, 112, 117, 116, 45, 114, 101, 115, 61, + 49, 57, 50, 48, 120, 49, 48, 56, 48, 32, + 105, 110, 116, 101, 114, 108, 97, 99, 101, + 61, 48, 32, 116, 111, 116, 97, 108, 45, + 102, 114, 97, 109, 101, 115, 61, 48, 32, + 108, 101, 118, 101, 108, 45, 105, 100, 99, + 61, 48, 32, 104, 105, 103, 104, 45, 116, + 105, 101, 114, 61, 49, 32, 117, 104, 100, + 45, 98, 100, 61, 48, 32, 114, 101, 102, 61, + 52, 32, 110, 111, 45, 97, 108, 108, 111, + 119, 45, 110, 111, 110, 45, 99, 111, 110, + 102, 111, 114, 109, 97, 110, 99, 101, 32, + 110, 111, 45, 114, 101, 112, 101, 97, 116, + 45, 104, 101, 97, 100, 101, 114, 115, 32, + 97, 110, 110, 101, 120, 98, 32, 110, 111, + 45, 97, 117, 100, 32, 110, 111, 45, 104, + 114, 100, 32, 105, 110, 102, 111, 32, 104, + 97, 115, 104, 61, 48, 32, 110, 111, 45, + 116, 101, 109, 112, 111, 114, 97, 108, 45, + 108, 97, 121, 101, 114, 115, 32, 111, 112, + 101, 110, 45, 103, 111, 112, 32, 109, 105, + 110, 45, 107, 101, 121, 105, 110, 116, 61, + 50, 53, 32, 107, 101, 121, 105, 110, 116, + 61, 50, 53, 48, 32, 103, 111, 112, 45, 108, + 111, 111, 107, 97, 104, 101, 97, 100, 61, + 48, 32, 98, 102, 114, 97, 109, 101, 115, + 61, 52, 32, 98, 45, 97, 100, 97, 112, 116, + 61, 50, 32, 98, 45, 112, 121, 114, 97, 109, + 105, 100, 32, 98, 102, 114, 97, 109, 101, + 45, 98, 105, 97, 115, 61, 48, 32, 114, 99, + 45, 108, 111, 111, 107, 97, 104, 101, 97, + 100, 61, 50, 53, 32, 108, 111, 111, 107, + 97, 104, 101, 97, 100, 45, 115, 108, 105, + 99, 101, 115, 61, 52, 32, 115, 99, 101, + 110, 101, 99, 117, 116, 61, 52, 48, 32, + 114, 97, 100, 108, 61, 48, 32, 110, 111, + 45, 105, 110, 116, 114, 97, 45, 114, 101, + 102, 114, 101, 115, 104, 32, 99, 116, 117, + 61, 54, 52, 32, 109, 105, 110, 45, 99, 117, + 45, 115, 105, 122, 101, 61, 56, 32, 114, + 101, 99, 116, 32, 110, 111, 45, 97, 109, + 112, 32, 109, 97, 120, 45, 116, 117, 45, + 115, 105, 122, 101, 61, 51, 50, 32, 116, + 117, 45, 105, 110, 116, 101, 114, 45, 100, + 101, 112, 116, 104, 61, 49, 32, 116, 117, + 45, 105, 110, 116, 114, 97, 45, 100, 101, + 112, 116, 104, 61, 49, 32, 108, 105, 109, + 105, 116, 45, 116, 117, 61, 48, 32, 114, + 100, 111, 113, 45, 108, 101, 118, 101, 108, + 61, 50, 32, 100, 121, 110, 97, 109, 105, + 99, 45, 114, 100, 61, 48, 46, 48, 48, 32, + 110, 111, 45, 115, 115, 105, 109, 45, 114, + 100, 32, 115, 105, 103, 110, 104, 105, 100, + 101, 32, 110, 111, 45, 116, 115, 107, 105, + 112, 32, 110, 114, 45, 105, 110, 116, 114, + 97, 61, 48, 32, 110, 114, 45, 105, 110, + 116, 101, 114, 61, 48, 32, 110, 111, 45, + 99, 111, 110, 115, 116, 114, 97, 105, 110, + 101, 100, 45, 105, 110, 116, 114, 97, 32, + 115, 116, 114, 111, 110, 103, 45, 105, 110, + 116, 114, 97, 45, 115, 109, 111, 111, 116, + 104, 105, 110, 103, 32, 109, 97, 120, 45, + 109, 101, 114, 103, 101, 61, 51, 32, 108, + 105, 109, 105, 116, 45, 114, 101, 102, 115, + 61, 51, 32, 108, 105, 109, 105, 116, 45, + 109, 111, 100, 101, 115, 32, 109, 101, 61, + 51, 32, 115, 117, 98, 109, 101, 61, 51, 32, + 109, 101, 114, 97, 110, 103, 101, 61, 53, + 55, 32, 116, 101, 109, 112, 111, 114, 97, + 108, 45, 109, 118, 112, 32, 119, 101, 105, + 103, 104, 116, 112, 32, 110, 111, 45, 119, + 101, 105, 103, 104, 116, 98, 32, 110, 111, + 45, 97, 110, 97, 108, 121, 122, 101, 45, + 115, 114, 99, 45, 112, 105, 99, 115, 32, + 100, 101, 98, 108, 111, 99, 107, 61, 48, + 58, 48, 32, 115, 97, 111, 32, 110, 111, 45, + 115, 97, 111, 45, 110, 111, 110, 45, 100, + 101, 98, 108, 111, 99, 107, 32, 114, 100, + 61, 52, 32, 110, 111, 45, 101, 97, 114, + 108, 121, 45, 115, 107, 105, 112, 32, 114, + 115, 107, 105, 112, 32, 110, 111, 45, 102, + 97, 115, 116, 45, 105, 110, 116, 114, 97, + 32, 110, 111, 45, 116, 115, 107, 105, 112, + 45, 102, 97, 115, 116, 32, 110, 111, 45, + 99, 117, 45, 108, 111, 115, 115, 108, 101, + 115, 115, 32, 110, 111, 45, 98, 45, 105, + 110, 116, 114, 97, 32, 110, 111, 45, 115, + 112, 108, 105, 116, 114, 100, 45, 115, 107, + 105, 112, 32, 114, 100, 112, 101, 110, 97, + 108, 116, 121, 61, 48, 32, 112, 115, 121, + 45, 114, 100, 61, 50, 46, 48, 48, 32, 112, + 115, 121, 45, 114, 100, 111, 113, 61, 49, + 46, 48, 48, 32, 110, 111, 45, 114, 100, 45, + 114, 101, 102, 105, 110, 101, 32, 110, 111, + 45, 108, 111, 115, 115, 108, 101, 115, 115, + 32, 99, 98, 113, 112, 111, 102, 102, 115, + 61, 48, 32, 99, 114, 113, 112, 111, 102, + 102, 115, 61, 48, 32, 114, 99, 61, 97, 98, + 114, 32, 98, 105, 116, 114, 97, 116, 101, + 61, 50, 51, 50, 48, 48, 32, 113, 99, 111, + 109, 112, 61, 48, 46, 54, 48, 32, 113, 112, + 115, 116, 101, 112, 61, 52, 32, 115, 116, + 97, 116, 115, 45, 119, 114, 105, 116, 101, + 61, 48, 32, 115, 116, 97, 116, 115, 45, + 114, 101, 97, 100, 61, 48, 32, 105, 112, + 114, 97, 116, 105, 111, 61, 49, 46, 52, 48, + 32, 112, 98, 114, 97, 116, 105, 111, 61, + 49, 46, 51, 48, 32, 97, 113, 45, 109, 111, + 100, 101, 61, 49, 32, 97, 113, 45, 115, + 116, 114, 101, 110, 103, 116, 104, 61, 49, + 46, 48, 48, 32, 99, 117, 116, 114, 101, + 101, 32, 122, 111, 110, 101, 45, 99, 111, + 117, 110, 116, 61, 48, 32, 110, 111, 45, + 115, 116, 114, 105, 99, 116, 45, 99, 98, + 114, 32, 113, 103, 45, 115, 105, 122, 101, + 61, 51, 50, 32, 110, 111, 45, 114, 99, 45, + 103, 114, 97, 105, 110, 32, 113, 112, 109, + 97, 120, 61, 54, 57, 32, 113, 112, 109, + 105, 110, 61, 48, 32, 110, 111, 45, 99, + 111, 110, 115, 116, 45, 118, 98, 118, 32, + 115, 97, 114, 61, 49, 32, 111, 118, 101, + 114, 115, 99, 97, 110, 61, 48, 32, 118, + 105, 100, 101, 111, 102, 111, 114, 109, 97, + 116, 61, 53, 32, 114, 97, 110, 103, 101, + 61, 48, 32, 99, 111, 108, 111, 114, 112, + 114, 105, 109, 61, 50, 32, 116, 114, 97, + 110, 115, 102, 101, 114, 61, 50, 32, 99, + 111, 108, 111, 114, 109, 97, 116, 114, 105, + 120, 61, 50, 32, 99, 104, 114, 111, 109, + 97, 108, 111, 99, 61, 48, 32, 100, 105, + 115, 112, 108, 97, 121, 45, 119, 105, 110, + 100, 111, 119, 61, 48, 32, 109, 97, 120, + 45, 99, 108, 108, 61, 48, 44, 48, 32, 109, + 105, 110, 45, 108, 117, 109, 97, 61, 48, + 32, 109, 97, 120, 45, 108, 117, 109, 97, + 61, 50, 53, 53, 32, 108, 111, 103, 50, 45, + 109, 97, 120, 45, 112, 111, 99, 45, 108, + 115, 98, 61, 56, 32, 118, 117, 105, 45, + 116, 105, 109, 105, 110, 103, 45, 105, 110, + 102, 111, 32, 118, 117, 105, 45, 104, 114, + 100, 45, 105, 110, 102, 111, 32, 115, 108, + 105, 99, 101, 115, 61, 49, 32, 110, 111, + 45, 111, 112, 116, 45, 113, 112, 45, 112, + 112, 115, 32, 110, 111, 45, 111, 112, 116, + 45, 114, 101, 102, 45, 108, 105, 115, 116, + 45, 108, 101, 110, 103, 116, 104, 45, 112, + 112, 115, 32, 110, 111, 45, 109, 117, 108, + 116, 105, 45, 112, 97, 115, 115, 45, 111, + 112, 116, 45, 114, 112, 115, 32, 115, 99, + 101, 110, 101, 99, 117, 116, 45, 98, 105, + 97, 115, 61, 48, 46, 48, 53, 32, 110, 111, + 45, 111, 112, 116, 45, 99, 117, 45, 100, + 101, 108, 116, 97, 45, 113, 112, 32, 110, + 111, 45, 97, 113, 45, 109, 111, 116, 105, + 111, 110, 32, 110, 111, 45, 104, 100, 114, + 32, 110, 111, 45, 104, 100, 114, 45, 111, + 112, 116, 32, 110, 111, 45, 100, 104, 100, + 114, 49, 48, 45, 111, 112, 116, 32, 97, + 110, 97, 108, 121, 115, 105, 115, 45, 114, + 101, 117, 115, 101, 45, 108, 101, 118, 101, + 108, 61, 53, 32, 115, 99, 97, 108, 101, 45, + 102, 97, 99, 116, 111, 114, 61, 48, 32, + 114, 101, 102, 105, 110, 101, 45, 105, 110, + 116, 114, 97, 61, 48, 32, 114, 101, 102, + 105, 110, 101, 45, 105, 110, 116, 101, 114, + 61, 48, 32, 114, 101, 102, 105, 110, 101, + 45, 109, 118, 61, 48, 32, 110, 111, 45, + 108, 105, 109, 105, 116, 45, 115, 97, 111, + 32, 99, 116, 117, 45, 105, 110, 102, 111, + 61, 48, 32, 110, 111, 45, 108, 111, 119, + 112, 97, 115, 115, 45, 100, 99, 116, 32, + 114, 101, 102, 105, 110, 101, 45, 109, 118, + 45, 116, 121, 112, 101, 61, 48, 32, 99, + 111, 112, 121, 45, 112, 105, 99, 61, 49, + 128 + ]] + } + ] + }, + btrt: Some(Btrt { + buffer_size_db: 0, + max_bitrate: 25175730, + avg_bitrate: 25175730 + }), + pasp: Some(Pasp { + h_spacing: 1, + v_spacing: 1, + }), + colr: None, + taic: None, + #[cfg(feature = "fault-tolerant")] + unexpected: vec![Any::Unknown( + FourCC::new(b"fiel"), + vec![1, 0] + )], + } + .into()], + }, + stco: Some(Stco { entries: vec![] }), + ..Default::default() + } } - } - }, - udta: None, - }], - udta: Some(Udta { - #[cfg(feature = "fault-tolerant")] - unexpected: vec![], - meta: Some(Meta { - hdlr: Hdlr { - handler: FourCC::new(b"mdir"), - name: "".into() }, - items: vec![Ilst::default().into(),], - }), - skip: None, - }) - } - ); + udta: None, + }], + udta: Some(Udta { + #[cfg(feature = "fault-tolerant")] + unexpected: vec![], + meta: Some(Meta { + hdlr: Hdlr { + handler: FourCC::new(b"mdir"), + name: "".into() + }, + items: vec![Ilst::default().into(),], + }), + skip: None, + }) + } + ); - // Make sure the hev1 atom encodes/decodes to the exact same content. - let hev1 = &moov.trak[0].mdia.minf.stbl.stsd.codecs[0]; - hev1.assert_encode_decode(); + // Make sure the hev1 atom encodes/decodes to the exact same content. + // Note: We need to clear unexpected atoms because they are not encoded back + let mut hev1_for_test = moov.trak[0].mdia.minf.stbl.stsd.codecs[0].clone(); + if let Codec::Hev1(ref mut hev1) = hev1_for_test { + hev1.unexpected.clear(); + } + hev1_for_test.assert_encode_decode(); - let mut buf = Vec::new(); - ftyp.encode(&mut buf).expect("failed to encode ftyp"); - moov.encode(&mut buf).expect("failed to encode moov"); + let mut buf = Vec::new(); + ftyp.encode(&mut buf).expect("failed to encode ftyp"); + moov.encode(&mut buf).expect("failed to encode moov"); + } // assert_eq!(buf, ENCODED); } From db3a9b6631bda5dcd38f94b776990c7e92b80bdf Mon Sep 17 00:00:00 2001 From: b01o Date: Fri, 17 Oct 2025 23:23:42 +0800 Subject: [PATCH 11/11] adds a comment to clarify test behavior --- src/test/hevc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/hevc.rs b/src/test/hevc.rs index f6c551f..4eae917 100644 --- a/src/test/hevc.rs +++ b/src/test/hevc.rs @@ -648,10 +648,10 @@ fn hevc() { } hev1_for_test.assert_encode_decode(); + // Encode to verify encoding succeeds. Output will differ from ENCODED because + // unexpected boxes (like the `fiel` box) are not encoded back. let mut buf = Vec::new(); ftyp.encode(&mut buf).expect("failed to encode ftyp"); moov.encode(&mut buf).expect("failed to encode moov"); } - - // assert_eq!(buf, ENCODED); }