Skip to content

Commit 7682d3c

Browse files
Zaggy1024kinetiknz
authored andcommitted
Add some support for AVIF sequences.
All properties not related to the `pitm` box have been moved from mp4parse_avif_get_image to mp4parse_avif_get_info. New fields for the color and alpha tracks are included in Mp4parseAvifInfo. To get the sample indices for those tracks, mp4parse_avif_get_indice_table was added as well. These changes break C API backwards compatibility due to removing fields from Mp4parseAvifImage, so the version is bumped to 0.16.0.
1 parent 75e5d59 commit 7682d3c

File tree

7 files changed

+334
-77
lines changed

7 files changed

+334
-77
lines changed

mp4parse/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mp4parse"
3-
version = "0.15.0"
3+
version = "0.16.0"
44
authors = [
55
"Ralph Giles <giles@mozilla.com>",
66
"Matthew Gregan <kinetik@flim.org>",

mp4parse/src/boxes.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ box_database!(
110110
MovieHeaderBox 0x6d76_6864, // "mvhd"
111111
TrackBox 0x7472_616b, // "trak"
112112
TrackHeaderBox 0x746b_6864, // "tkhd"
113+
TrackReferenceBox 0x7472_6566, // "tref"
114+
AuxiliaryBox 0x6175_786C, // "auxl"
113115
EditBox 0x6564_7473, // "edts"
114116
MediaBox 0x6d64_6961, // "mdia"
115117
EditListBox 0x656c_7374, // "elst"

mp4parse/src/lib.rs

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -299,19 +299,14 @@ impl Feature {
299299
match self {
300300
Self::Auxc
301301
| Self::Av1c
302+
| Self::Avis
302303
| Self::Colr
303304
| Self::Imir
304305
| Self::Irot
305306
| Self::Ispe
306307
| Self::Pasp
307308
| Self::Pixi => true,
308-
Self::A1lx
309-
| Self::A1op
310-
| Self::Clap
311-
| Self::Grid
312-
| Self::Ipro
313-
| Self::Lsel
314-
| Self::Avis => false,
309+
Self::A1lx | Self::A1op | Self::Clap | Self::Grid | Self::Ipro | Self::Lsel => false,
315310
}
316311
}
317312
}
@@ -1100,6 +1095,29 @@ pub enum SampleEntry {
11001095
Unknown,
11011096
}
11021097

1098+
#[derive(Debug)]
1099+
pub struct TrackReferenceBox {
1100+
pub references: TryVec<TrackReferenceEntry>,
1101+
}
1102+
1103+
impl TrackReferenceBox {
1104+
pub fn has_auxl_reference(&self, track_id: u32) -> bool {
1105+
self.references.iter().any(|entry| match entry {
1106+
TrackReferenceEntry::Auxiliary(aux_entry) => aux_entry.track_ids.contains(&track_id),
1107+
})
1108+
}
1109+
}
1110+
1111+
#[derive(Debug)]
1112+
pub enum TrackReferenceEntry {
1113+
Auxiliary(TrackReference),
1114+
}
1115+
1116+
#[derive(Debug)]
1117+
pub struct TrackReference {
1118+
pub track_ids: TryVec<u32>,
1119+
}
1120+
11031121
/// An Elementary Stream Descriptor
11041122
/// See MPEG-4 Systems (ISO 14496-1:2010) § 7.2.6.5
11051123
#[allow(non_camel_case_types)]
@@ -1550,7 +1568,7 @@ impl AvifItem {
15501568
}
15511569
}
15521570

1553-
#[derive(Debug)]
1571+
#[derive(Default, Debug)]
15541572
pub struct AvifContext {
15551573
/// Level of deviation from the specification before failing the parse
15561574
strictness: ParseStrictness,
@@ -1574,13 +1592,17 @@ pub struct AvifContext {
15741592
/// Should probably only ever be [`AVIF_BRAND`] or [`AVIS_BRAND`], but other values
15751593
/// are legal as long as one of the two is the `compatible_brand` list.
15761594
pub major_brand: FourCC,
1577-
/// True if a `moov` box is present
1578-
pub has_sequence: bool,
1595+
/// Information on the sequence contained in the image, or None if not present
1596+
pub sequence: Option<MediaContext>,
15791597
/// A collection of unsupported features encountered during the parse
15801598
pub unsupported_features: UnsupportedFeatures,
15811599
}
15821600

15831601
impl AvifContext {
1602+
pub fn primary_item_is_present(&self) -> bool {
1603+
self.primary_item.is_some()
1604+
}
1605+
15841606
pub fn primary_item_coded_data(&self) -> Option<&[u8]> {
15851607
self.primary_item
15861608
.as_ref()
@@ -1593,6 +1615,10 @@ impl AvifContext {
15931615
.map(|item| self.image_bits_per_channel(item.id))
15941616
}
15951617

1618+
pub fn alpha_item_is_present(&self) -> bool {
1619+
self.alpha_item.is_some()
1620+
}
1621+
15961622
pub fn alpha_item_coded_data(&self) -> Option<&[u8]> {
15971623
self.alpha_item
15981624
.as_ref()
@@ -2122,6 +2148,8 @@ enum Extent {
21222148
pub enum TrackType {
21232149
Audio,
21242150
Video,
2151+
Picture,
2152+
AuxiliaryVideo,
21252153
Metadata,
21262154
Unknown,
21272155
}
@@ -2142,6 +2170,12 @@ pub enum ParseStrictness {
21422170
Strict, // Error on "should" directives
21432171
}
21442172

2173+
impl Default for ParseStrictness {
2174+
fn default() -> Self {
2175+
ParseStrictness::Normal
2176+
}
2177+
}
2178+
21452179
fn fail_with_status_if(violation: bool, status: Status) -> Result<()> {
21462180
let error = Error::from(status);
21472181
if violation {
@@ -2227,6 +2261,7 @@ pub struct Track {
22272261
pub stco: Option<ChunkOffsetBox>, // It is for stco or co64.
22282262
pub stss: Option<SyncSampleBox>,
22292263
pub ctts: Option<CompositionOffsetBox>,
2264+
pub tref: Option<TrackReferenceBox>,
22302265
}
22312266

22322267
impl Track {
@@ -2496,10 +2531,6 @@ pub fn read_avif<T: Read>(f: &mut T, strictness: ParseStrictness) -> Result<Avif
24962531
return Status::FtypNotFirst.into();
24972532
};
24982533

2499-
if major_brand == AVIS_BRAND {
2500-
unsupported_features.insert(Feature::Avis);
2501-
}
2502-
25032534
let mut meta = None;
25042535
let mut image_sequence = None;
25052536
let mut media_storage = TryVec::new();
@@ -2776,7 +2807,7 @@ pub fn read_avif<T: Read>(f: &mut T, strictness: ParseStrictness) -> Result<Avif
27762807
premultiplied_alpha,
27772808
item_properties,
27782809
major_brand,
2779-
has_sequence: image_sequence.is_some(),
2810+
sequence: image_sequence,
27802811
unsupported_features,
27812812
})
27822813
}
@@ -4346,6 +4377,7 @@ fn read_trak<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
43464377
}
43474378
BoxType::EditBox => read_edts(&mut b, track)?,
43484379
BoxType::MediaBox => read_mdia(&mut b, track)?,
4380+
BoxType::TrackReferenceBox => track.tref = Some(read_tref(&mut b)?),
43494381
_ => skip_box_content(&mut b)?,
43504382
};
43514383
check_parser_state!(b.content);
@@ -4430,6 +4462,8 @@ fn read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
44304462

44314463
match hdlr.handler_type.value.as_ref() {
44324464
b"vide" => track.track_type = TrackType::Video,
4465+
b"pict" => track.track_type = TrackType::Picture,
4466+
b"auxv" => track.track_type = TrackType::AuxiliaryVideo,
44334467
b"soun" => track.track_type = TrackType::Audio,
44344468
b"meta" => track.track_type = TrackType::Metadata,
44354469
_ => (),
@@ -4444,6 +4478,32 @@ fn read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
44444478
Ok(())
44454479
}
44464480

4481+
fn read_tref<T: Read>(f: &mut BMFFBox<T>) -> Result<TrackReferenceBox> {
4482+
// Will likely only see trefs with one auxl
4483+
let mut references = TryVec::with_capacity(1)?;
4484+
let mut iter = f.box_iter();
4485+
while let Some(mut b) = iter.next_box()? {
4486+
match b.head.name {
4487+
BoxType::AuxiliaryBox => {
4488+
references.push(TrackReferenceEntry::Auxiliary(read_tref_auxl(&mut b)?))?
4489+
}
4490+
_ => skip_box_content(&mut b)?,
4491+
};
4492+
check_parser_state!(b.content);
4493+
}
4494+
Ok(TrackReferenceBox { references })
4495+
}
4496+
4497+
fn read_tref_auxl<T: Read>(f: &mut BMFFBox<T>) -> Result<TrackReference> {
4498+
let num_track_ids = (f.bytes_left() / std::mem::size_of::<u32>().to_u64()).try_into()?;
4499+
let mut track_ids = TryVec::with_capacity(num_track_ids)?;
4500+
for _ in 0..num_track_ids {
4501+
track_ids.push(be_u32(f)?)?;
4502+
}
4503+
4504+
Ok(TrackReference { track_ids })
4505+
}
4506+
44474507
fn read_minf<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
44484508
let mut iter = f.box_iter();
44494509
while let Some(mut b) = iter.next_box()? {
@@ -5830,6 +5890,8 @@ fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleD
58305890
if let Some(mut b) = iter.next_box()? {
58315891
let description = match track.track_type {
58325892
TrackType::Video => read_video_sample_entry(&mut b),
5893+
TrackType::Picture => read_video_sample_entry(&mut b),
5894+
TrackType::AuxiliaryVideo => read_video_sample_entry(&mut b),
58335895
TrackType::Audio => read_audio_sample_entry(&mut b),
58345896
TrackType::Metadata => Err(Error::Unsupported("metadata track")),
58355897
TrackType::Unknown => Err(Error::Unsupported("unknown track type")),

mp4parse/tests/public.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ fn public_api() {
346346
assert!(a.samplesize > 0);
347347
assert!(a.samplerate > 0.0);
348348
}
349-
mp4::TrackType::Metadata | mp4::TrackType::Unknown => {}
349+
_ => {}
350350
}
351351
}
352352
}

mp4parse_capi/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mp4parse_capi"
3-
version = "0.15.0"
3+
version = "0.16.0"
44
authors = [
55
"Ralph Giles <giles@mozilla.com>",
66
"Matthew Gregan <kinetik@flim.org>",
@@ -27,7 +27,7 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
2727
byteorder = "1.2.1"
2828
fallible_collections = { version = "0.4", features = ["std_io"] }
2929
log = "0.4"
30-
mp4parse = { version = "0.15.0", path = "../mp4parse", features = ["unstable-api"] }
30+
mp4parse = { version = "0.16.0", path = "../mp4parse", features = ["unstable-api"] }
3131
num-traits = "0.2.14"
3232

3333
[dev-dependencies]

mp4parse_capi/examples/dump.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ fn dump_file(filename: &str, strictness: ParseStrictness) {
112112
}
113113
}
114114
}
115-
Mp4parseTrackType::Video => {
115+
Mp4parseTrackType::Video
116+
| Mp4parseTrackType::Picture
117+
| Mp4parseTrackType::AuxiliaryVideo => {
116118
let mut video_info = Mp4parseTrackVideoInfo::default();
117119
match mp4parse_get_track_video_info(parser, i, &mut video_info) {
118120
Mp4parseStatus::Ok => {

0 commit comments

Comments
 (0)