Skip to content

Commit

Permalink
Change travel_while to return an optional BoxHolder.
Browse files Browse the repository at this point in the history
  • Loading branch information
mindeng committed Jul 13, 2024
1 parent 7956486 commit 699f666
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 12 deletions.
20 changes: 17 additions & 3 deletions src/bbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,21 +182,27 @@ impl<'a> BoxHolder<'a> {
}
}

type BoxResult<'a> = IResult<&'a [u8], Option<BoxHolder<'a>>>;

/// Parses every top level box while `predicate` returns true, then returns the
/// last parsed box.
pub fn travel_while<'a, F>(input: &'a [u8], mut predicate: F) -> IResult<&'a [u8], BoxHolder<'a>>
pub fn travel_while<'a, F>(input: &'a [u8], mut predicate: F) -> BoxResult<'a>
where
F: FnMut(&BoxHolder<'a>) -> bool,
{
let mut remain = input;
loop {
if remain.is_empty() {
return Ok((remain, None));
}

let (rem, bbox) = BoxHolder::parse(remain)?;
// Sanity check, to avoid infinite loops caused by unexpected errors.
assert!(rem.len() < remain.len());
remain = rem;

if !predicate(&bbox) {
break Ok((rem, bbox));
return Ok((remain, Some(bbox)));
}
}
}
Expand Down Expand Up @@ -347,6 +353,7 @@ mod tests {
bbox.box_type() != "mdat"
})
.unwrap();
let bbox = bbox.unwrap();

assert_eq!(bbox.header.box_type, "mdat");
assert_eq!(remain, b"");
Expand All @@ -369,6 +376,7 @@ mod tests {
},
)
.unwrap();
let bbox = bbox.unwrap();
assert_eq!(bbox.box_type(), "iloc");
assert_eq!(remain, b"");

Expand All @@ -392,6 +400,7 @@ mod tests {
bbox.box_type() != "moov"
})
.unwrap();
let bbox = bbox.unwrap();

assert_eq!(bbox.header.box_type, "moov");
assert_eq!(remain, b"");
Expand All @@ -411,6 +420,8 @@ mod tests {
bbox.box_type() != "meta"
})
.unwrap();
let bbox = bbox.unwrap();

assert_eq!(bbox.box_type(), "meta");
assert_eq!(remain, b"");

Expand Down Expand Up @@ -444,6 +455,7 @@ mod tests {
bbox.box_type() != "moov"
})
.unwrap();
let bbox = bbox.unwrap();

assert_eq!(bbox.header.box_type, "moov");
assert_eq!(remain, b"");
Expand All @@ -463,6 +475,8 @@ mod tests {
bbox.box_type() != "udta"
})
.unwrap();
let bbox = bbox.unwrap();

assert_eq!(bbox.box_type(), "udta");
assert_eq!(remain, b"");

Expand Down Expand Up @@ -499,7 +513,7 @@ mod tests {
// sub-boxes in trak
assert_eq!(boxes, ["tkhd", "edts", "mdia"],);

let mdia = bbox;
let mdia = bbox.unwrap();
let mut boxes = Vec::new();
let (remain, _) = travel_while(mdia.body_data(), |bbox| {
// println!("got {}", bbox.header.box_type);
Expand Down
6 changes: 6 additions & 0 deletions src/bbox/ilst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,11 @@ mod tests {
f.read_to_end(&mut buf).unwrap();

let (_, bbox) = travel_while(&buf, |b| b.box_type() != "moov").unwrap();
let bbox = bbox.unwrap();
let (_, bbox) = travel_while(bbox.body_data(), |b| b.box_type() != "meta").unwrap();
let bbox = bbox.unwrap();
let (_, bbox) = travel_while(bbox.body_data(), |b| b.box_type() != "ilst").unwrap();
let bbox = bbox.unwrap();

let (rem, ilst) = IlstBox::parse_box(bbox.data).unwrap();
println!("ilst: {ilst:?}");
Expand Down Expand Up @@ -170,8 +173,11 @@ mod tests {
f.read_to_end(&mut buf).unwrap();

let (_, moov) = travel_while(&buf, |b| b.box_type() != "moov").unwrap();
let moov = moov.unwrap();
let (_, meta) = travel_while(moov.body_data(), |b| b.box_type() != "meta").unwrap();
let meta = meta.unwrap();
let (_, ilst) = travel_while(meta.body_data(), |b| b.box_type() != "ilst").unwrap();
let ilst = ilst.unwrap();

let (rem, ilst) = IlstBox::parse_box(ilst.data).unwrap();
assert_eq!(rem.len(), 0);
Expand Down
6 changes: 6 additions & 0 deletions src/bbox/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ mod tests {
f.read_to_end(&mut buf).unwrap();

let (_, moov) = travel_while(&buf, |b| b.box_type() != "moov").unwrap();
let moov = moov.unwrap();
let (_, meta) = travel_while(moov.body_data(), |b| b.box_type() != "meta").unwrap();
let meta = meta.unwrap();
let (_, keys) = travel_while(meta.body_data(), |b| b.box_type() != "keys").unwrap();
let keys = keys.unwrap();

assert_eq!(moov.box_size(), moov_size);
assert_eq!(meta.box_size(), meta_size);
Expand Down Expand Up @@ -131,8 +134,11 @@ mod tests {
f.read_to_end(&mut buf).unwrap();

let (_, moov) = travel_while(&buf, |b| b.box_type() != "moov").unwrap();
let moov = moov.unwrap();
let (_, meta) = travel_while(moov.body_data(), |b| b.box_type() != "meta").unwrap();
let meta = meta.unwrap();
let (_, keys) = travel_while(meta.body_data(), |b| b.box_type() != "keys").unwrap();
let keys = keys.unwrap();

assert_eq!(moov.box_size(), moov_size);
assert_eq!(meta.box_size(), meta_size);
Expand Down
1 change: 1 addition & 0 deletions src/bbox/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ mod tests {
bbox.box_type() != "meta"
})
.unwrap();
let bbox = bbox.unwrap();

assert_eq!(bbox.data.len() as u64, bbox.box_size());
let (remain, meta) = MetaBox::parse_box(bbox.data).unwrap();
Expand Down
2 changes: 2 additions & 0 deletions src/bbox/mvhd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ mod tests {
f.read_to_end(&mut buf).unwrap();

let (_, bbox) = travel_while(&buf, |b| b.box_type() != "moov").unwrap();
let bbox = bbox.unwrap();
let (_, bbox) = travel_while(bbox.body_data(), |b| b.box_type() != "mvhd").unwrap();
let bbox = bbox.unwrap();
let (_, mvhd) = MvhdBox::parse_box(bbox.data).unwrap();

assert_eq!(mvhd.duration_ms(), milliseconds);
Expand Down
20 changes: 12 additions & 8 deletions src/bbox/tkhd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,19 @@ impl ParseBody<TkhdBox> for TkhdBox {
}

/// Try to find a video track's tkhd in moov body. atom-path: "moov/trak/tkhd".
pub fn parse_video_tkhd_in_moov(input: &[u8]) -> crate::Result<TkhdBox> {
let bbox = find_video_track(input)?;
let (_, bbox) = travel_while(bbox.body_data(), |b| b.box_type() != "tkhd")
.map_err(|e| format!("find tkhd failed: {e:?}"))?;
let (remain, tkhd) = TkhdBox::parse_box(bbox.data).unwrap();
pub fn parse_video_tkhd_in_moov(input: &[u8]) -> crate::Result<Option<TkhdBox>> {
let Some(bbox) = find_video_track(input)? else {
return Ok(None);
};
let (_, Some(bbox)) = find_box(bbox.body_data(), "tkhd")? else {
return Ok(None);
};
let (remain, tkhd) = TkhdBox::parse_box(bbox.data).map_err(|_| "parse tkhd failed")?;
assert_eq!(remain.len(), 0);
Ok(tkhd)
Ok(Some(tkhd))
}

fn find_video_track(input: &[u8]) -> crate::Result<BoxHolder> {
fn find_video_track(input: &[u8]) -> crate::Result<Option<BoxHolder>> {
let (_, bbox) = travel_while(input, |b| {
// find video track
if b.box_type() != "trak" {
Expand Down Expand Up @@ -155,7 +158,8 @@ mod tests {
f.read_to_end(&mut buf).unwrap();

let (_, bbox) = travel_while(&buf, |b| b.box_type() != "moov").unwrap();
let tkhd = parse_video_tkhd_in_moov(bbox.body_data()).unwrap();
let bbox = bbox.unwrap();
let tkhd = parse_video_tkhd_in_moov(bbox.body_data()).unwrap().unwrap();

assert_eq!(tkhd.width, width);
assert_eq!(tkhd.height, height);
Expand Down
2 changes: 1 addition & 1 deletion src/mov.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub fn parse_metadata<R: Read + Seek>(reader: R) -> crate::Result<Vec<(String, E
}
}

if let Ok(tkhd) = parse_video_tkhd_in_moov(&moov_body) {
if let Ok(Some(tkhd)) = parse_video_tkhd_in_moov(&moov_body) {
entries.push(("width".to_owned(), tkhd.width.into()));
entries.push(("height".to_owned(), tkhd.height.into()));
}
Expand Down

0 comments on commit 699f666

Please sign in to comment.