Skip to content

Commit b293867

Browse files
committed
Support unknown (zero) sized mdat boxes in AVIF.
1 parent a432900 commit b293867

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

mp4parse/src/lib.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,7 +2275,7 @@ impl<'a, T: Read> BoxIter<'a, T> {
22752275
match r {
22762276
Ok(h) => Ok(Some(BMFFBox {
22772277
head: h,
2278-
content: self.src.take(h.size - h.offset),
2278+
content: self.src.take(h.size.saturating_sub(h.offset)),
22792279
})),
22802280
Err(Error::UnexpectedEOF) => Ok(None),
22812281
Err(e) => Err(e),
@@ -2337,7 +2337,13 @@ fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
23372337
let name = BoxType::from(be_u32(src)?);
23382338
let size = match size32 {
23392339
// valid only for top-level box and indicates it's the last box in the file. usually mdat.
2340-
0 => return Err(Error::Unsupported("unknown sized box")),
2340+
0 => {
2341+
if name == BoxType::MediaDataBox {
2342+
0
2343+
} else {
2344+
return Err(Error::Unsupported("unknown sized box"));
2345+
}
2346+
}
23412347
1 => {
23422348
let size64 = be_u64(src)?;
23432349
if size64 < BoxHeader::MIN_LARGE_SIZE {
@@ -2375,7 +2381,7 @@ fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
23752381
} else {
23762382
None
23772383
};
2378-
assert!(offset <= size);
2384+
assert!(offset <= size || size == 0);
23792385
Ok(BoxHeader {
23802386
name,
23812387
size,
@@ -2536,7 +2542,26 @@ pub fn read_avif<T: Read>(f: &mut T, strictness: ParseStrictness) -> Result<Avif
25362542
}
25372543
BoxType::MediaDataBox => {
25382544
let file_offset = b.offset();
2539-
let data = b.read_into_try_vec()?;
2545+
let data = if b.head.size == 0 {
2546+
// Unknown sized `mdat`, read in chunks until EOF.
2547+
const BUF_SIZE: usize = 64 * 1024;
2548+
let mut data = TryVec::with_capacity(BUF_SIZE)?;
2549+
loop {
2550+
let got = fallible_collections::try_read_up_to(
2551+
b.content.get_mut(),
2552+
BUF_SIZE as u64,
2553+
&mut data,
2554+
)?;
2555+
if got == 0 {
2556+
// Mark `content` as consumed.
2557+
b.content.set_limit(0);
2558+
break;
2559+
}
2560+
}
2561+
data
2562+
} else {
2563+
b.read_into_try_vec()?
2564+
};
25402565
media_storage.push(DataBox::from_mdat(file_offset, data))?;
25412566
}
25422567
_ => skip_box_content(&mut b)?,

mp4parse/tests/public.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static IMAGE_AVIF_IMIR_MISSING_ESSENTIAL: &str = "tests/imir-missing-essential.a
6565
static IMAGE_AVIF_IROT_MISSING_ESSENTIAL: &str = "tests/irot-missing-essential.avif";
6666
static IMAGE_AVIF_LSEL_MISSING_ESSENTIAL: &str = "tests/corrupt/lsel-missing-essential.avif";
6767
static IMAGE_AVIF_CLAP_MISSING_ESSENTIAL: &str = "tests/clap-missing-essential.avif";
68+
static IMAGE_AVIF_UNKNOWN_MDAT_SIZE: &str = "tests/unknown_mdat.avif";
6869
static AVIF_TEST_DIRS: &[&str] = &["tests", "av1-avif/testFiles", "link-u-avif-sample-images"];
6970

7071
// These files are
@@ -910,6 +911,19 @@ fn public_avif_alpha_premultiplied() {
910911
});
911912
}
912913

914+
#[test]
915+
fn public_avif_unknown_mdat() {
916+
let input = &mut File::open(IMAGE_AVIF_UNKNOWN_MDAT_SIZE).expect("Unknown file");
917+
let context = mp4::read_avif(input, ParseStrictness::Normal).expect("read_avif failed");
918+
assert_eq!(
919+
context.primary_item_coded_data().unwrap(),
920+
[
921+
0x12, 0x00, 0x0A, 0x07, 0x38, 0x00, 0x06, 0x90, 0x20, 0x20, 0x69, 0x32, 0x0C, 0x16,
922+
0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x79, 0x4C, 0xD2, 0x02
923+
]
924+
);
925+
}
926+
913927
#[test]
914928
fn public_avif_bug_1655846() {
915929
let input = &mut File::open(IMAGE_AVIF_CORRUPT).expect("Unknown file");

mp4parse/tests/unknown_mdat.avif

294 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)