Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mp4parse/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mp4parse"
version = "0.15.0"
version = "0.16.0"
authors = [
"Ralph Giles <giles@mozilla.com>",
"Matthew Gregan <kinetik@flim.org>",
Expand Down
2 changes: 2 additions & 0 deletions mp4parse/src/boxes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ box_database!(
MovieHeaderBox 0x6d76_6864, // "mvhd"
TrackBox 0x7472_616b, // "trak"
TrackHeaderBox 0x746b_6864, // "tkhd"
TrackReferenceBox 0x7472_6566, // "tref"
AuxiliaryBox 0x6175_786C, // "auxl"
EditBox 0x6564_7473, // "edts"
MediaBox 0x6d64_6961, // "mdia"
EditListBox 0x656c_7374, // "elst"
Expand Down
92 changes: 77 additions & 15 deletions mp4parse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,19 +299,14 @@ impl Feature {
match self {
Self::Auxc
| Self::Av1c
| Self::Avis
| Self::Colr
| Self::Imir
| Self::Irot
| Self::Ispe
| Self::Pasp
| Self::Pixi => true,
Self::A1lx
| Self::A1op
| Self::Clap
| Self::Grid
| Self::Ipro
| Self::Lsel
| Self::Avis => false,
Self::A1lx | Self::A1op | Self::Clap | Self::Grid | Self::Ipro | Self::Lsel => false,
}
}
}
Expand Down Expand Up @@ -1100,6 +1095,29 @@ pub enum SampleEntry {
Unknown,
}

#[derive(Debug)]
pub struct TrackReferenceBox {
pub references: TryVec<TrackReferenceEntry>,
}

impl TrackReferenceBox {
pub fn has_auxl_reference(&self, track_id: u32) -> bool {
self.references.iter().any(|entry| match entry {
TrackReferenceEntry::Auxiliary(aux_entry) => aux_entry.track_ids.contains(&track_id),
})
}
}

#[derive(Debug)]
pub enum TrackReferenceEntry {
Auxiliary(TrackReference),
}

#[derive(Debug)]
pub struct TrackReference {
pub track_ids: TryVec<u32>,
}

/// An Elementary Stream Descriptor
/// See MPEG-4 Systems (ISO 14496-1:2010) § 7.2.6.5
#[allow(non_camel_case_types)]
Expand Down Expand Up @@ -1550,7 +1568,7 @@ impl AvifItem {
}
}

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

impl AvifContext {
pub fn primary_item_is_present(&self) -> bool {
self.primary_item.is_some()
}

pub fn primary_item_coded_data(&self) -> Option<&[u8]> {
self.primary_item
.as_ref()
Expand All @@ -1593,6 +1615,10 @@ impl AvifContext {
.map(|item| self.image_bits_per_channel(item.id))
}

pub fn alpha_item_is_present(&self) -> bool {
self.alpha_item.is_some()
}

pub fn alpha_item_coded_data(&self) -> Option<&[u8]> {
self.alpha_item
.as_ref()
Expand Down Expand Up @@ -2122,6 +2148,8 @@ enum Extent {
pub enum TrackType {
Audio,
Video,
Picture,
AuxiliaryVideo,
Metadata,
Unknown,
}
Expand All @@ -2142,6 +2170,12 @@ pub enum ParseStrictness {
Strict, // Error on "should" directives
}

impl Default for ParseStrictness {
fn default() -> Self {
ParseStrictness::Normal
}
}

fn fail_with_status_if(violation: bool, status: Status) -> Result<()> {
let error = Error::from(status);
if violation {
Expand Down Expand Up @@ -2227,6 +2261,7 @@ pub struct Track {
pub stco: Option<ChunkOffsetBox>, // It is for stco or co64.
pub stss: Option<SyncSampleBox>,
pub ctts: Option<CompositionOffsetBox>,
pub tref: Option<TrackReferenceBox>,
}

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

if major_brand == AVIS_BRAND {
unsupported_features.insert(Feature::Avis);
}

let mut meta = None;
let mut image_sequence = None;
let mut media_storage = TryVec::new();
Expand Down Expand Up @@ -2776,7 +2807,7 @@ pub fn read_avif<T: Read>(f: &mut T, strictness: ParseStrictness) -> Result<Avif
premultiplied_alpha,
item_properties,
major_brand,
has_sequence: image_sequence.is_some(),
sequence: image_sequence,
unsupported_features,
})
}
Expand Down Expand Up @@ -4346,6 +4377,7 @@ fn read_trak<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
}
BoxType::EditBox => read_edts(&mut b, track)?,
BoxType::MediaBox => read_mdia(&mut b, track)?,
BoxType::TrackReferenceBox => track.tref = Some(read_tref(&mut b)?),
_ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
Expand Down Expand Up @@ -4430,6 +4462,8 @@ fn read_mdia<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {

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

fn read_tref<T: Read>(f: &mut BMFFBox<T>) -> Result<TrackReferenceBox> {
// Will likely only see trefs with one auxl
let mut references = TryVec::with_capacity(1)?;
let mut iter = f.box_iter();
while let Some(mut b) = iter.next_box()? {
match b.head.name {
BoxType::AuxiliaryBox => {
references.push(TrackReferenceEntry::Auxiliary(read_tref_auxl(&mut b)?))?
}
_ => skip_box_content(&mut b)?,
};
check_parser_state!(b.content);
}
Ok(TrackReferenceBox { references })
}

fn read_tref_auxl<T: Read>(f: &mut BMFFBox<T>) -> Result<TrackReference> {
let num_track_ids = (f.bytes_left() / std::mem::size_of::<u32>().to_u64()).try_into()?;
let mut track_ids = TryVec::with_capacity(num_track_ids)?;
for _ in 0..num_track_ids {
track_ids.push(be_u32(f)?)?;
}

Ok(TrackReference { track_ids })
}

fn read_minf<T: Read>(f: &mut BMFFBox<T>, track: &mut Track) -> Result<()> {
let mut iter = f.box_iter();
while let Some(mut b) = iter.next_box()? {
Expand Down Expand Up @@ -5830,6 +5890,8 @@ fn read_stsd<T: Read>(src: &mut BMFFBox<T>, track: &mut Track) -> Result<SampleD
if let Some(mut b) = iter.next_box()? {
let description = match track.track_type {
TrackType::Video => read_video_sample_entry(&mut b),
TrackType::Picture => read_video_sample_entry(&mut b),
TrackType::AuxiliaryVideo => read_video_sample_entry(&mut b),
TrackType::Audio => read_audio_sample_entry(&mut b),
TrackType::Metadata => Err(Error::Unsupported("metadata track")),
TrackType::Unknown => Err(Error::Unsupported("unknown track type")),
Expand Down
15 changes: 3 additions & 12 deletions mp4parse/tests/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ static AVIF_UNSUPPORTED_IMAGES: &[&str] = &[
AVIF_GRID,
AVIF_GRID_A1LX,
AVIF_LSEL,
AVIF_AVIS_MAJOR_NO_PITM,
AVIF_AVIS_MAJOR_WITH_PITM_AND_ALPHA,
"av1-avif/testFiles/Apple/multilayer_examples/animals_00_multilayer_a1lx.avif",
"av1-avif/testFiles/Apple/multilayer_examples/animals_00_multilayer_a1op.avif",
"av1-avif/testFiles/Apple/multilayer_examples/animals_00_multilayer_a1op_lsel.avif",
Expand All @@ -107,20 +105,13 @@ static AVIF_UNSUPPORTED_IMAGES: &[&str] = &[
"av1-avif/testFiles/Microsoft/Chimera_10bit_cropped_to_1920x1008.avif",
"av1-avif/testFiles/Microsoft/Chimera_10bit_cropped_to_1920x1008_with_HDR_metadata.avif",
"av1-avif/testFiles/Microsoft/Chimera_8bit_cropped_480x256.avif",
"av1-avif/testFiles/Netflix/avis/alpha_video.avif",
"av1-avif/testFiles/Xiph/abandoned_filmgrain.avif",
"av1-avif/testFiles/Xiph/fruits_2layer_thumbsize.avif",
"av1-avif/testFiles/Xiph/quebec_3layer_op2.avif",
"av1-avif/testFiles/Xiph/tiger_3layer_1res.avif",
"av1-avif/testFiles/Xiph/tiger_3layer_3res.avif",
"link-u-avif-sample-images/kimono.crop.avif",
"link-u-avif-sample-images/kimono.mirror-vertical.rotate270.crop.avif",
"link-u-avif-sample-images/star-10bpc-with-alpha.avifs",
"link-u-avif-sample-images/star-10bpc.avifs",
"link-u-avif-sample-images/star-12bpc-with-alpha.avifs",
"link-u-avif-sample-images/star-12bpc.avifs",
"link-u-avif-sample-images/star-8bpc-with-alpha.avifs",
"link-u-avif-sample-images/star-8bpc.avifs",
];
/// See https://github.com/AOMediaCodec/av1-avif/issues/150
/// https://github.com/AOMediaCodec/av1-avif/issues/174
Expand Down Expand Up @@ -346,7 +337,7 @@ fn public_api() {
assert!(a.samplesize > 0);
assert!(a.samplerate > 0.0);
}
mp4::TrackType::Metadata | mp4::TrackType::Unknown => {}
_ => {}
}
}
}
Expand Down Expand Up @@ -1201,8 +1192,8 @@ fn public_avis_major_no_pitm() {
match mp4::read_avif(input, ParseStrictness::Normal) {
Ok(context) => {
assert_eq!(context.major_brand, mp4::AVIS_BRAND);
assert!(context.unsupported_features.contains(mp4::Feature::Avis));
assert!(context.primary_item_coded_data().is_none());
assert!(context.sequence.is_some());
}
Err(e) => panic!("Expected Ok(_), found {:?}", e),
}
Expand All @@ -1214,9 +1205,9 @@ fn public_avis_major_with_pitm_and_alpha() {
match mp4::read_avif(input, ParseStrictness::Normal) {
Ok(context) => {
assert_eq!(context.major_brand, mp4::AVIS_BRAND);
assert!(context.unsupported_features.contains(mp4::Feature::Avis));
assert!(context.primary_item_coded_data().is_some());
assert!(context.alpha_item_coded_data().is_some());
assert!(context.sequence.is_some());
}
Err(e) => panic!("Expected Ok(_), found {:?}", e),
}
Expand Down
4 changes: 2 additions & 2 deletions mp4parse_capi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mp4parse_capi"
version = "0.15.0"
version = "0.16.0"
authors = [
"Ralph Giles <giles@mozilla.com>",
"Matthew Gregan <kinetik@flim.org>",
Expand All @@ -27,7 +27,7 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
byteorder = "1.2.1"
fallible_collections = { version = "0.4", features = ["std_io"] }
log = "0.4"
mp4parse = { version = "0.15.0", path = "../mp4parse", features = ["unstable-api"] }
mp4parse = { version = "0.16.0", path = "../mp4parse", features = ["unstable-api"] }
num-traits = "0.2.14"

[dev-dependencies]
Expand Down
4 changes: 3 additions & 1 deletion mp4parse_capi/examples/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ fn dump_file(filename: &str, strictness: ParseStrictness) {
}
}
}
Mp4parseTrackType::Video => {
Mp4parseTrackType::Video
| Mp4parseTrackType::Picture
| Mp4parseTrackType::AuxiliaryVideo => {
let mut video_info = Mp4parseTrackVideoInfo::default();
match mp4parse_get_track_video_info(parser, i, &mut video_info) {
Mp4parseStatus::Ok => {
Expand Down
Loading