Bug 1817997 - Update mp4parse to 888ce901bb604d9e385. r=kinetik,glandium

Differential Revision: https://phabricator.services.mozilla.com/D176046
This commit is contained in:
Paul Adenot 2023-05-24 13:18:44 +00:00
Родитель 5852e70c3f
Коммит ae2988ec95
19 изменённых файлов: 314 добавлений и 230 удалений

Просмотреть файл

@ -90,9 +90,9 @@ git = "https://github.com/mozilla/midir.git"
rev = "519e651241e867af3391db08f9ae6400bc023e18"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/mp4parse-rust?rev=2b572e83608a3d0867b935e076f45d9fe248069d"]
[source."git+https://github.com/mozilla/mp4parse-rust?rev=1825cee59139d53669a5b8c563e4ea3e440d6a6c"]
git = "https://github.com/mozilla/mp4parse-rust"
rev = "2b572e83608a3d0867b935e076f45d9fe248069d"
rev = "1825cee59139d53669a5b8c563e4ea3e440d6a6c"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/neqo?tag=v0.6.4"]

8
Cargo.lock сгенерированный
Просмотреть файл

@ -3469,8 +3469,8 @@ dependencies = [
[[package]]
name = "mp4parse"
version = "0.16.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=2b572e83608a3d0867b935e076f45d9fe248069d#2b572e83608a3d0867b935e076f45d9fe248069d"
version = "0.17.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=1825cee59139d53669a5b8c563e4ea3e440d6a6c#1825cee59139d53669a5b8c563e4ea3e440d6a6c"
dependencies = [
"bitreader",
"byteorder",
@ -3486,8 +3486,8 @@ version = "0.1.0"
[[package]]
name = "mp4parse_capi"
version = "0.16.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=2b572e83608a3d0867b935e076f45d9fe248069d#2b572e83608a3d0867b935e076f45d9fe248069d"
version = "0.17.0"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=1825cee59139d53669a5b8c563e4ea3e440d6a6c#1825cee59139d53669a5b8c563e4ea3e440d6a6c"
dependencies = [
"byteorder",
"fallible_collections",

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

2
third_party/rust/mp4parse/Cargo.toml поставляемый
Просмотреть файл

@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "mp4parse"
version = "0.16.0"
version = "0.17.0"
authors = [
"Ralph Giles <giles@mozilla.com>",
"Matthew Gregan <kinetik@flim.org>",

66
third_party/rust/mp4parse/src/lib.rs поставляемый
Просмотреть файл

@ -2273,11 +2273,11 @@ impl<'a, T: Read> BoxIter<'a, T> {
fn next_box(&mut self) -> Result<Option<BMFFBox<T>>> {
let r = read_box_header(self.src);
match r {
Ok(h) => Ok(Some(BMFFBox {
Ok(Some(h)) => Ok(Some(BMFFBox {
head: h,
content: self.src.take(h.size.saturating_sub(h.offset)),
})),
Err(Error::UnexpectedEOF) => Ok(None),
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
@ -2332,8 +2332,12 @@ impl<'a, T> Drop for BMFFBox<'a, T> {
/// skip unknown or uninteresting boxes.
///
/// See ISOBMFF (ISO 14496-12:2020) § 4.2
fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
let size32 = be_u32(src)?;
fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<Option<BoxHeader>> {
let size32 = match be_u32(src) {
Ok(v) => v,
Err(Error::UnexpectedEOF) => return Ok(None),
Err(error) => return Err(error),
};
let name = BoxType::from(be_u32(src)?);
let size = match size32 {
// valid only for top-level box and indicates it's the last box in the file. usually mdat.
@ -2344,19 +2348,8 @@ fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
return Err(Error::Unsupported("unknown sized box"));
}
}
1 => {
let size64 = be_u64(src)?;
if size64 < BoxHeader::MIN_LARGE_SIZE {
return Status::BoxBadWideSize.into();
}
size64
}
_ => {
if u64::from(size32) < BoxHeader::MIN_SIZE {
return Status::BoxBadSize.into();
}
u64::from(size32)
}
1 => be_u64(src)?,
_ => u64::from(size32),
};
trace!("read_box_header: name: {:?}, size: {}", name, size);
let mut offset = match size32 {
@ -2371,23 +2364,27 @@ fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
if count == 16 {
Some(buffer)
} else {
debug!("malformed uuid (short read), skipping");
None
debug!("malformed uuid (short read)");
return Err(Error::UnexpectedEOF);
}
} else {
debug!("malformed uuid, skipping");
None
}
} else {
None
};
assert!(offset <= size || size == 0);
Ok(BoxHeader {
match size32 {
0 => (),
1 if offset > size => return Err(Error::from(Status::BoxBadWideSize)),
_ if offset > size => return Err(Error::from(Status::BoxBadSize)),
_ => (),
}
Ok(Some(BoxHeader {
name,
size,
offset,
uuid,
})
}))
}
/// Parse the extra header fields for a full box.
@ -2521,7 +2518,19 @@ pub fn read_avif<T: Read>(f: &mut T, strictness: ParseStrictness) -> Result<Avif
let mut image_sequence = None;
let mut media_storage = TryVec::new();
while let Some(mut b) = iter.next_box()? {
loop {
let mut b = match iter.next_box() {
Ok(Some(b)) => b,
Ok(_) => break,
Err(Error::UnexpectedEOF) => {
if strictness == ParseStrictness::Strict {
return Err(Error::UnexpectedEOF);
}
break;
}
Err(error) => return Err(error),
};
trace!("read_avif parsing {:?} box", b.head.name);
match b.head.name {
BoxType::MetadataBox => {
@ -2564,7 +2573,14 @@ pub fn read_avif<T: Read>(f: &mut T, strictness: ParseStrictness) -> Result<Avif
};
media_storage.push(DataBox::from_mdat(file_offset, data))?;
}
_ => skip_box_content(&mut b)?,
_ => {
let result = skip_box_content(&mut b);
// Allow garbage at EOF if we aren't in strict mode.
if b.bytes_left() > 0 && strictness != ParseStrictness::Strict {
break;
}
result?;
}
}
check_parser_state!(b.content);

21
third_party/rust/mp4parse/src/tests.rs поставляемый
Просмотреть файл

@ -93,7 +93,7 @@ where
#[test]
fn read_box_header_short() {
let mut stream = make_box(BoxSize::Short(8), b"test", |s| s);
let header = super::read_box_header(&mut stream).unwrap();
let header = super::read_box_header(&mut stream).unwrap().unwrap();
assert_eq!(header.name, BoxType::UnknownBox(0x7465_7374)); // "test"
assert_eq!(header.size, 8);
assert!(header.uuid.is_none());
@ -102,7 +102,7 @@ fn read_box_header_short() {
#[test]
fn read_box_header_long() {
let mut stream = make_box(BoxSize::Long(16), b"test", |s| s);
let header = super::read_box_header(&mut stream).unwrap();
let header = super::read_box_header(&mut stream).unwrap().unwrap();
assert_eq!(header.name, BoxType::UnknownBox(0x7465_7374)); // "test"
assert_eq!(header.size, 16);
assert!(header.uuid.is_none());
@ -166,6 +166,23 @@ fn read_box_header_truncated_uuid() {
assert!(stream.head.uuid.is_none());
}
#[test]
fn read_box_header_uuid_past_eof() {
const HEADER_UUID: [u8; 20] = [
0x00, 0x00, 0x00, 0x18, // size = 24
0x75, 0x75, 0x69, 0x64, // type = uuid
0x85, 0xc0, 0xb6, 0x87, 0x82, 0x0f, 0x11, 0xe0, 0x81, 0x11, 0xf4, 0xce,
];
let mut cursor = Cursor::new(HEADER_UUID);
let mut iter = super::BoxIter::new(&mut cursor);
match iter.next_box() {
Err(Error::UnexpectedEOF) => (),
Ok(_) => panic!("expected an error result"),
_ => panic!("expected a different error result"),
};
}
#[test]
fn read_ftyp() {
let mut stream = make_box(BoxSize::Short(24), b"ftyp", |s| {

23
third_party/rust/mp4parse/src/unstable.rs поставляемый
Просмотреть файл

@ -115,14 +115,14 @@ pub struct Indice {
/// sample. Typically this will be the `start_offset` of the next sample
/// in the file.
pub end_offset: CheckedInteger<u64>,
/// The time in microseconds when the indexed sample should be displayed.
/// The time in ticks when the indexed sample should be displayed.
/// Analogous to the concept of presentation time stamp (pts).
pub start_composition: CheckedInteger<i64>,
/// The time in microseconds when the indexed sample should stop being
/// The time in ticks when the indexed sample should stop being
/// displayed. Typically this would be the `start_composition` time of the
/// next sample if samples were ordered by composition time.
pub end_composition: CheckedInteger<i64>,
/// The time in microseconds that the indexed sample should be decoded at.
/// The time in ticks that the indexed sample should be decoded at.
/// Analogous to the concept of decode time stamp (dts).
pub start_decode: CheckedInteger<i64>,
/// Set if the indexed sample is a sync sample. The meaning of sync is
@ -140,11 +140,6 @@ pub fn create_sample_table(
track: &Track,
track_offset_time: CheckedInteger<i64>,
) -> Option<TryVec<Indice>> {
let timescale = match track.timescale {
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
_ => return None,
};
let (stsc, stco, stsz, stts) = match (&track.stsc, &track.stco, &track.stsz, &track.stts) {
(Some(a), Some(b), Some(c), Some(d)) => (a, b, c, d),
_ => return None,
@ -238,15 +233,15 @@ pub fn create_sample_table(
// ctts_offset is the current sample offset time.
let ctts_offset = ctts_offset_iter.next_offset_time();
let start_composition = track_time_to_us((decode_time + ctts_offset)?, timescale)?.0;
let start_composition = decode_time + ctts_offset;
let end_composition = track_time_to_us((sum_delta + ctts_offset)?, timescale)?.0;
let end_composition = sum_delta + ctts_offset;
let start_decode = track_time_to_us(decode_time, timescale)?.0;
let start_decode = decode_time;
sample.start_composition = (track_offset_time + start_composition)?;
sample.end_composition = (track_offset_time + end_composition)?;
sample.start_decode = start_decode.into();
sample.start_composition = CheckedInteger(track_offset_time.0 + start_composition?.0);
sample.end_composition = CheckedInteger(track_offset_time.0 + end_composition?.0);
sample.start_decode = CheckedInteger(start_decode.0);
}
// Correct composition end time due to 'ctts' causes composition time re-ordering.

27
third_party/rust/mp4parse/tests/public.rs поставляемый
Просмотреть файл

@ -68,6 +68,10 @@ static IMAGE_AVIF_CLAP_MISSING_ESSENTIAL: &str = "tests/clap-missing-essential.a
static IMAGE_AVIF_UNKNOWN_MDAT_SIZE: &str = "tests/unknown_mdat.avif";
static IMAGE_AVIF_UNKNOWN_MDAT_SIZE_IN_OVERSIZED_META: &str =
"tests/unknown_mdat_in_oversized_meta.avif";
static IMAGE_AVIF_VALID_WITH_GARBAGE_OVERREAD_AT_END: &str =
"tests/valid_with_garbage_overread.avif";
static IMAGE_AVIF_VALID_WITH_GARBAGE_BYTE_AT_END: &str = "tests/valid_with_garbage_byte.avif";
static IMAGE_AVIF_WIDE_BOX_SIZE_0: &str = "tests/wide_box_size_0.avif";
static AVIF_TEST_DIRS: &[&str] = &["tests", "av1-avif/testFiles", "link-u-avif-sample-images"];
// These files are
@ -127,6 +131,7 @@ static AVIF_UNSUPPORTED_IMAGES: &[&str] = &[
// TODO: make this into a map of expected errors?
static AV1_AVIF_CORRUPT_IMAGES: &[&str] = &[
IMAGE_AVIF_UNKNOWN_MDAT_SIZE_IN_OVERSIZED_META,
IMAGE_AVIF_WIDE_BOX_SIZE_0,
"av1-avif/testFiles/Link-U/kimono.crop.avif",
"av1-avif/testFiles/Link-U/kimono.mirror-horizontal.avif",
"av1-avif/testFiles/Link-U/kimono.mirror-vertical.avif",
@ -1279,6 +1284,28 @@ fn public_avif_avis_with_pitm_no_iloc() {
assert_avif_should(AVIF_AVIS_WITH_PITM_NO_ILOC, Status::PitmNotFound);
}
#[test]
fn public_avif_valid_with_garbage_overread_at_end() {
assert_avif_should(
IMAGE_AVIF_VALID_WITH_GARBAGE_OVERREAD_AT_END,
Status::CheckParserStateErr,
);
}
#[test]
fn public_avif_valid_with_garbage_byte_at_end() {
assert_avif_should(IMAGE_AVIF_VALID_WITH_GARBAGE_BYTE_AT_END, Status::Eof);
}
#[test]
fn public_avif_bad_video_sample_entry() {
let input = &mut File::open(IMAGE_AVIF_WIDE_BOX_SIZE_0).expect("Unknown file");
assert_eq!(
Status::from(mp4::read_avif(input, ParseStrictness::Normal)),
Status::BoxBadWideSize
);
}
fn public_avis_loop_impl(path: &str, looped: bool) {
let input = &mut File::open(path).expect("Unknown file");
match mp4::read_avif(input, ParseStrictness::Normal) {

Двоичные данные
third_party/rust/mp4parse/tests/valid_with_garbage_byte.avif поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rust/mp4parse/tests/valid_with_garbage_overread.avif поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
third_party/rust/mp4parse/tests/wide_box_size_0.avif поставляемый Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"0e0f8d369a370833da96719c0e56439063f136e9f8e3caf520b9db11f86f0ef1","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"f776ed4bbb7b58a5684402a9c5c28dfe1fa02b6b184139b2c2c49384cc1e3723","cbindgen.toml":"62066cd34285ab9e7f1cc5db8950a51e9e080f5a85bd55ad43d7022e4eae2758","examples/dump.rs":"2a3cdebc5ed6f0f6b640e6722cd13fc7f4534774eb057b369a791c2eddb8132d","src/lib.rs":"e3cdb813622bc4c2894e5a72ba70994dd06e6d43a3d43ecdec87b912708967db","tests/loop_1.avif":"bf8777d103e023a0da94f16dbe89b7081d13fe8b50e6418c69381a23561a5a84","tests/loop_2.avif":"be5f53417f8432342c0e0cbace60e33a791f2e98a03a44c4a9f5af3ec0bf6906","tests/loop_ceiled_4.avif":"136c36b7d2f5839c9107e56b6e3ce327d8b97bea291756f0ce377e6011716712","tests/loop_forever.avif":"aa425b4da99646d3b71d63f6b1741b60a2331ee2c9ab3bcf2fbc05b0cc832565","tests/no_edts.avif":"8940e97673d7d67c283a0f8f52fdbc45a9b74d5fb6c430507d406b70e4bbfe5f","tests/test_avis_loop_count.rs":"bcf67821a9ca91a13e5a4abf0fe6f766320f5654ebbd69c1d69cea771ed6159c","tests/test_chunk_out_of_range.rs":"4039d0db0ee5973787e4ca14cea510fd958ae5d21856a79240a5e7b826caa18d","tests/test_encryption.rs":"f62131a36b0516caf9e2c48f8aea060d300b0f5c8a32bc54d31cbc97aa25b4e6","tests/test_fragment.rs":"b87fe0a967c5a3184f9264955b08209e64769e6358ff670665fc719380f22157","tests/test_rotation.rs":"23fa4898eca2e17255bc1ba2f538707a6554fb4644bb75f80548ae56a7cd2d44","tests/test_sample_table.rs":"6e2f5eaadede1e37a5ced722bc071506fd0eecf3cd17310479d3c9692632a2cd","tests/test_workaround_stsc.rs":"1d17a394f55e1524c30888bfe1e57e2b0457444b79c23eb91b02d2edf859c9ad"},"package":null}
{"files":{"Cargo.toml":"6b2b4576bf1bca3cf6b019f297a84189a3dd595353c451a4af38246ec14bcbef","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README.md":"f776ed4bbb7b58a5684402a9c5c28dfe1fa02b6b184139b2c2c49384cc1e3723","cbindgen.toml":"62066cd34285ab9e7f1cc5db8950a51e9e080f5a85bd55ad43d7022e4eae2758","examples/dump.rs":"2a3cdebc5ed6f0f6b640e6722cd13fc7f4534774eb057b369a791c2eddb8132d","src/lib.rs":"554b96bb3a9a5d0c311004d040404f8da17a74e04ab48b044930a49909d0343a","tests/loop_1.avif":"bf8777d103e023a0da94f16dbe89b7081d13fe8b50e6418c69381a23561a5a84","tests/loop_2.avif":"be5f53417f8432342c0e0cbace60e33a791f2e98a03a44c4a9f5af3ec0bf6906","tests/loop_ceiled_4.avif":"136c36b7d2f5839c9107e56b6e3ce327d8b97bea291756f0ce377e6011716712","tests/loop_forever.avif":"aa425b4da99646d3b71d63f6b1741b60a2331ee2c9ab3bcf2fbc05b0cc832565","tests/no_edts.avif":"8940e97673d7d67c283a0f8f52fdbc45a9b74d5fb6c430507d406b70e4bbfe5f","tests/test_avis.rs":"d480b104ab2dfde7a25afd6705532caf7988aea21fc955dcf2f86fc8a5e85151","tests/test_chunk_out_of_range.rs":"4039d0db0ee5973787e4ca14cea510fd958ae5d21856a79240a5e7b826caa18d","tests/test_encryption.rs":"f62131a36b0516caf9e2c48f8aea060d300b0f5c8a32bc54d31cbc97aa25b4e6","tests/test_fragment.rs":"6614df84bf0184acc33eccf86a8cd62e8192f8d93ab4593f5e54dd6b2a6d5724","tests/test_rotation.rs":"23fa4898eca2e17255bc1ba2f538707a6554fb4644bb75f80548ae56a7cd2d44","tests/test_sample_table.rs":"53ed6a5e8db463ad8dc0300116f470c2aadd39896e6ba4cabcd01c6b9a7b5c59","tests/test_workaround_stsc.rs":"1d17a394f55e1524c30888bfe1e57e2b0457444b79c23eb91b02d2edf859c9ad"},"package":null}

4
third_party/rust/mp4parse_capi/Cargo.toml поставляемый
Просмотреть файл

@ -12,7 +12,7 @@
[package]
edition = "2018"
name = "mp4parse_capi"
version = "0.16.0"
version = "0.17.0"
authors = [
"Ralph Giles <giles@mozilla.com>",
"Matthew Gregan <kinetik@flim.org>",
@ -37,7 +37,7 @@ version = "0.4"
features = ["std_io"]
[dependencies.mp4parse]
version = "0.16.0"
version = "0.17.0"
path = "../mp4parse"
features = ["unstable-api"]

111
third_party/rust/mp4parse_capi/src/lib.rs поставляемый
Просмотреть файл

@ -42,9 +42,7 @@ use std::io::Read;
// Symbols we need from our rust api.
use mp4parse::serialize_opus_header;
use mp4parse::unstable::{
create_sample_table, media_time_to_us, track_time_to_us, CheckedInteger, Indice, Microseconds,
};
use mp4parse::unstable::{create_sample_table, CheckedInteger, Indice};
use mp4parse::AV1ConfigBox;
use mp4parse::AudioCodecSpecific;
use mp4parse::AvifContext;
@ -127,10 +125,8 @@ pub struct Mp4parseTrackInfo {
pub track_type: Mp4parseTrackType,
pub track_id: u32,
pub duration: u64,
pub media_time: CheckedInteger<i64>, // wants to be u64? understand how elst adjustment works
// TODO(kinetik): include crypto guff
// If this changes to u64, we can get rid of the strange
// impl Sub for CheckedInteger<u64>
pub media_time: CheckedInteger<i64>,
pub time_scale: u32,
}
#[repr(C)]
@ -278,9 +274,9 @@ impl Default for Mp4parseTrackVideoInfo {
#[repr(C)]
#[derive(Default, Debug)]
pub struct Mp4parseFragmentInfo {
pub fragment_duration: u64,
// TODO:
// info in trex box.
pub fragment_duration: u64, // in ticks
// TODO:
// info in trex box.
}
#[derive(Default)]
@ -631,46 +627,34 @@ pub unsafe extern "C" fn mp4parse_get_track_info(
let track = &context.tracks[track_index];
if let (Some(track_timescale), Some(context_timescale)) = (track.timescale, context.timescale) {
let media_time: CheckedInteger<_> = match track
if let (Some(timescale), Some(_)) = (track.timescale, context.timescale) {
info.time_scale = timescale.0 as u32;
let media_time: CheckedInteger<u64> = track
.media_time
.map_or(Some(Microseconds(0)), |media_time| {
track_time_to_us(media_time, track_timescale)
}) {
Some(time) => time.0.into(),
None => return Mp4parseStatus::Invalid,
};
let empty_duration: CheckedInteger<_> = match track
.map_or(0.into(), |media_time| media_time.0.into());
let empty_duration: CheckedInteger<u64> = track
.empty_duration
.map_or(Some(Microseconds(0)), |empty_duration| {
media_time_to_us(empty_duration, context_timescale)
}) {
Some(time) => time.0.into(),
None => return Mp4parseStatus::Invalid,
};
.map_or(0.into(), |empty_duration| empty_duration.0.into());
info.media_time = match media_time - empty_duration {
Some(difference) => difference,
None => return Mp4parseStatus::Invalid,
};
if let Some(track_duration) = track.duration {
match track_time_to_us(track_duration, track_timescale) {
Some(duration) => info.duration = duration.0,
None => return Mp4parseStatus::Invalid,
match track.duration {
Some(duration) => info.duration = duration.0,
None => {
// Duration unknown; stagefright returns 0 for this.
info.duration = 0
}
} else {
// Duration unknown; stagefright returns 0 for this.
info.duration = 0
}
} else {
return Mp4parseStatus::Invalid;
}
};
info.track_id = match track.track_id {
Some(track_id) => track_id,
None => return Mp4parseStatus::Invalid,
};
Mp4parseStatus::Ok
}
@ -1313,6 +1297,7 @@ pub unsafe extern "C" fn mp4parse_avif_get_indice_table(
parser: *mut Mp4parseAvifParser,
track_id: u32,
indices: *mut Mp4parseByteData,
timescale: *mut u64,
) -> Mp4parseStatus {
if parser.is_null() {
return Mp4parseStatus::BadArg;
@ -1326,6 +1311,27 @@ pub unsafe extern "C" fn mp4parse_avif_get_indice_table(
*indices = Default::default();
if let Some(sequence) = &(*parser).context.sequence {
// Use the top level timescale, and the track timescale if present.
let mut found_timescale = false;
if let Some(context_timescale) = sequence.timescale {
*timescale = context_timescale.0;
found_timescale = true;
}
let maybe_track_timescale = match sequence
.tracks
.iter()
.find(|track| track.track_id == Some(track_id))
{
Some(track) => track.timescale,
_ => None,
};
if let Some(track_timescale) = maybe_track_timescale {
found_timescale = true;
*timescale = track_timescale.0;
}
if !found_timescale {
return Mp4parseStatus::Invalid;
}
return get_indice_table(
sequence,
&mut (*parser).sample_table,
@ -1355,20 +1361,15 @@ fn get_indice_table(
return Ok(());
}
let media_time = match (&track.media_time, &track.timescale) {
(&Some(t), &Some(s)) => track_time_to_us(t, s)
.and_then(|v| i64::try_from(v.0).ok())
.map(Into::into),
let media_time = match &track.media_time {
&Some(t) => i64::try_from(t.0).ok().map(Into::into),
_ => None,
};
let empty_duration: Option<CheckedInteger<_>> =
match (&track.empty_duration, &context.timescale) {
(&Some(e), &Some(s)) => media_time_to_us(e, s)
.and_then(|v| i64::try_from(v.0).ok())
.map(Into::into),
_ => None,
};
let empty_duration: Option<CheckedInteger<_>> = match &track.empty_duration {
&Some(e) => i64::try_from(e.0).ok().map(Into::into),
_ => None,
};
// Find the track start offset time from 'elst'.
// 'media_time' maps start time onward, 'empty_duration' adds time offset
@ -1420,12 +1421,12 @@ pub unsafe extern "C" fn mp4parse_get_fragment_info(
None => return Mp4parseStatus::Invalid,
};
if let (Some(time), Some(scale)) = (duration, context.timescale) {
info.fragment_duration = match media_time_to_us(time, scale) {
Some(time_us) => time_us.0,
None => return Mp4parseStatus::Invalid,
match duration {
Some(duration_ticks) => {
info.fragment_duration = duration_ticks.0;
}
}
None => return Mp4parseStatus::Invalid,
};
Mp4parseStatus::Ok
}
@ -1741,7 +1742,7 @@ fn minimal_mp4_get_track_info() {
});
assert_eq!(info.track_type, Mp4parseTrackType::Video);
assert_eq!(info.track_id, 1);
assert_eq!(info.duration, 40000);
assert_eq!(info.duration, 512);
assert_eq!(info.media_time, 0);
assert_eq!(Mp4parseStatus::Ok, unsafe {
@ -1749,8 +1750,8 @@ fn minimal_mp4_get_track_info() {
});
assert_eq!(info.track_type, Mp4parseTrackType::Audio);
assert_eq!(info.track_id, 2);
assert_eq!(info.duration, 61333);
assert_eq!(info.media_time, 21333);
assert_eq!(info.duration, 2944);
assert_eq!(info.media_time, 1024);
unsafe {
mp4parse_free(parser);

113
third_party/rust/mp4parse_capi/tests/test_avis.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,113 @@
use mp4parse_capi::*;
use num_traits::ToPrimitive;
use std::io::Read;
extern "C" fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
let input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
let buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
unsafe fn parse_file_and_get_info(path: &str) -> (*mut Mp4parseAvifParser, Mp4parseAvifInfo) {
let mut file = std::fs::File::open(path).expect("Unknown file");
let io = Mp4parseIo {
read: Some(buf_read),
userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
};
let mut parser = std::ptr::null_mut();
let mut rv = mp4parse_avif_new(&io, ParseStrictness::Normal, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut info = Mp4parseAvifInfo {
premultiplied_alpha: Default::default(),
major_brand: Default::default(),
unsupported_features_bitfield: Default::default(),
spatial_extents: std::ptr::null(),
nclx_colour_information: std::ptr::null(),
icc_colour_information: Default::default(),
image_rotation: mp4parse::ImageRotation::D0,
image_mirror: std::ptr::null(),
pixel_aspect_ratio: std::ptr::null(),
has_primary_item: Default::default(),
primary_item_bit_depth: Default::default(),
has_alpha_item: Default::default(),
alpha_item_bit_depth: Default::default(),
has_sequence: Default::default(),
loop_mode: Default::default(),
loop_count: Default::default(),
color_track_id: Default::default(),
color_track_bit_depth: Default::default(),
alpha_track_id: Default::default(),
alpha_track_bit_depth: Default::default(),
};
rv = mp4parse_avif_get_info(parser, &mut info);
assert_eq!(rv, Mp4parseStatus::Ok);
(parser, info)
}
fn check_loop_count(path: &str, expected_loop_count: i64) {
let (parser, info) = unsafe { parse_file_and_get_info(path) };
match info.loop_mode {
Mp4parseAvifLoopMode::NoEdits => assert_eq!(expected_loop_count, -1),
Mp4parseAvifLoopMode::LoopByCount => {
assert_eq!(info.loop_count.to_i64(), Some(expected_loop_count))
}
Mp4parseAvifLoopMode::LoopInfinitely => assert_eq!(expected_loop_count, std::i64::MIN),
}
unsafe { mp4parse_avif_free(parser) };
}
fn check_timescale(path: &str, expected_timescale: u64) {
let (parser, info) = unsafe { parse_file_and_get_info(path) };
let mut indices: Mp4parseByteData = Mp4parseByteData::default();
let mut timescale: u64 = 0;
let rv = unsafe {
mp4parse_avif_get_indice_table(parser, info.color_track_id, &mut indices, &mut timescale)
};
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(timescale, expected_timescale);
unsafe { mp4parse_avif_free(parser) };
}
#[test]
fn loop_once() {
check_loop_count("tests/loop_1.avif", 1);
}
#[test]
fn loop_twice() {
check_loop_count("tests/loop_2.avif", 2);
}
#[test]
fn loop_four_times_due_to_ceiling() {
check_loop_count("tests/loop_ceiled_4.avif", 4);
}
#[test]
fn loop_forever() {
check_loop_count("tests/loop_forever.avif", std::i64::MIN);
}
#[test]
fn no_edts() {
check_loop_count("tests/no_edts.avif", -1);
}
#[test]
fn check_timescales() {
check_timescale("tests/loop_1.avif", 2);
check_timescale("tests/loop_2.avif", 2);
check_timescale("tests/loop_ceiled_4.avif", 2);
check_timescale("tests/loop_forever.avif", 2);
check_timescale("tests/no_edts.avif", 16384);
}

Просмотреть файл

@ -1,87 +0,0 @@
use mp4parse_capi::*;
use num_traits::ToPrimitive;
use std::io::Read;
extern "C" fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c_void) -> isize {
let input: &mut std::fs::File = unsafe { &mut *(userdata as *mut _) };
let buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
fn check_loop_count(path: &str, expected_loop_count: i64) {
let mut file = std::fs::File::open(path).expect("Unknown file");
let io = Mp4parseIo {
read: Some(buf_read),
userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
};
unsafe {
let mut parser = std::ptr::null_mut();
let mut rv = mp4parse_avif_new(&io, ParseStrictness::Normal, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut info = Mp4parseAvifInfo {
premultiplied_alpha: Default::default(),
major_brand: Default::default(),
unsupported_features_bitfield: Default::default(),
spatial_extents: std::ptr::null(),
nclx_colour_information: std::ptr::null(),
icc_colour_information: Default::default(),
image_rotation: mp4parse::ImageRotation::D0,
image_mirror: std::ptr::null(),
pixel_aspect_ratio: std::ptr::null(),
has_primary_item: Default::default(),
primary_item_bit_depth: Default::default(),
has_alpha_item: Default::default(),
alpha_item_bit_depth: Default::default(),
has_sequence: Default::default(),
loop_mode: Default::default(),
loop_count: Default::default(),
color_track_id: Default::default(),
color_track_bit_depth: Default::default(),
alpha_track_id: Default::default(),
alpha_track_bit_depth: Default::default(),
};
rv = mp4parse_avif_get_info(parser, &mut info);
assert_eq!(rv, Mp4parseStatus::Ok);
match info.loop_mode {
Mp4parseAvifLoopMode::NoEdits => assert_eq!(expected_loop_count, -1),
Mp4parseAvifLoopMode::LoopByCount => {
assert_eq!(info.loop_count.to_i64(), Some(expected_loop_count))
}
Mp4parseAvifLoopMode::LoopInfinitely => assert_eq!(expected_loop_count, std::i64::MIN),
}
mp4parse_avif_free(parser);
}
}
#[test]
fn loop_once() {
check_loop_count("tests/loop_1.avif", 1);
}
#[test]
fn loop_twice() {
check_loop_count("tests/loop_2.avif", 2);
}
#[test]
fn loop_four_times_due_to_ceiling() {
check_loop_count("tests/loop_ceiled_4.avif", 4);
}
#[test]
fn loop_forever() {
check_loop_count("tests/loop_forever.avif", std::i64::MIN);
}
#[test]
fn no_edts() {
check_loop_count("tests/no_edts.avif", -1);
}

Просмотреть файл

@ -36,6 +36,7 @@ fn parse_fragment() {
assert_eq!(track_info.track_id, 1);
assert_eq!(track_info.duration, 0);
assert_eq!(track_info.media_time, 0);
assert_eq!(track_info.time_scale, 22050);
let mut audio = Default::default();
rv = mp4parse_get_track_audio_info(parser, 0, &mut audio);
@ -57,7 +58,7 @@ fn parse_fragment() {
let mut fragment_info = Mp4parseFragmentInfo::default();
rv = mp4parse_get_fragment_info(parser, &mut fragment_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(fragment_info.fragment_duration, 10_032_000);
assert_eq!(fragment_info.fragment_duration, 10_032);
mp4parse_free(parser);
}
@ -89,6 +90,7 @@ fn parse_opus_fragment() {
assert_eq!(track_info.track_id, 1);
assert_eq!(track_info.duration, 0);
assert_eq!(track_info.media_time, 0);
assert_eq!(track_info.time_scale, 48000);
let mut audio = Default::default();
rv = mp4parse_get_track_audio_info(parser, 0, &mut audio);

Просмотреть файл

@ -51,16 +51,16 @@ fn parse_sample_table() {
start_offset: 27_046.into(),
end_offset: 27_052.into(),
start_composition: 0.into(),
end_composition: 46_439.into(),
end_composition: 1024.into(),
start_decode: 0.into(),
sync: true,
};
let audio_indice_215 = Indice {
start_offset: 283_550.into(),
end_offset: 283_556.into(),
start_composition: 9_984_580.into(),
end_composition: 10_031_020.into(),
start_decode: 9_984_580.into(),
start_composition: 220160.into(),
end_composition: 221184.into(),
start_decode: 220160.into(),
sync: true,
};
assert_eq!(indice.length, 216);
@ -85,17 +85,17 @@ fn parse_sample_table() {
let video_indice_291 = Indice {
start_offset: 280_226.into(),
end_offset: 280_855.into(),
start_composition: 9_838_333.into(),
end_composition: 9_871_677.into(),
start_decode: 9_710_000.into(),
start_composition: 876995.into(),
end_composition: 879996.into(),
start_decode: 873900.into(),
sync: false,
};
let video_indice_292 = Indice {
start_offset: 280_855.into(),
end_offset: 281_297.into(),
start_composition: 9_805_011.into(),
end_composition: 9_838_333.into(),
start_decode: 9_710_011.into(),
start_composition: 873996.into(),
end_composition: 876995.into(),
start_decode: 873901.into(),
sync: false,
};
// TODO: start_composition time in stagefright is 9905000, but it is 9904999 in parser, it
@ -105,17 +105,17 @@ fn parse_sample_table() {
let video_indice_295 = Indice {
start_offset: 282_391.into(),
end_offset: 283_032.into(),
start_composition: 9_971_666.into(),
end_composition: 9_971_677.into(),
start_decode: 9_843_333.into(),
start_composition: 888995.into(),
end_composition: 888996.into(),
start_decode: 885900.into(),
sync: false,
};
let video_indice_296 = Indice {
start_offset: 283_092.into(),
end_offset: 283_526.into(),
start_composition: 9_938_344.into(),
end_composition: 9_971_666.into(),
start_decode: 9_843_344.into(),
start_composition: 885996.into(),
end_composition: 888995.into(),
start_decode: 885901.into(),
sync: false,
};
@ -171,25 +171,25 @@ fn parse_sample_table_with_elst() {
let audio_indice_0 = Indice {
start_offset: 6992.into(),
end_offset: 7363.into(),
start_composition: (-36281).into(),
end_composition: (-13062).into(),
start_composition: (-1600).into(),
end_composition: (-576).into(),
start_decode: 0.into(),
sync: true,
};
let audio_indice_1 = Indice {
start_offset: 7363.into(),
end_offset: 7735.into(),
start_composition: (-13062).into(),
end_composition: 10158.into(),
start_decode: 23219.into(),
start_composition: (-576).into(),
end_composition: 448.into(),
start_decode: 1024.into(),
sync: true,
};
let audio_indice_2 = Indice {
start_offset: 7735.into(),
end_offset: 8106.into(),
start_composition: 10158.into(),
end_composition: 33378.into(),
start_decode: 46439.into(),
start_composition: 448.into(),
end_composition: 1472.into(),
start_decode: 2048.into(),
sync: true,
};
assert_eq!(indice.length, 21);
@ -239,32 +239,32 @@ fn parse_sample_table_with_negative_ctts() {
start_offset: 48.into(),
end_offset: 890.into(),
start_composition: 0.into(),
end_composition: 33_333.into(),
end_composition: 100.into(),
start_decode: 0.into(),
sync: true,
};
let video_indice_1 = Indice {
start_offset: 890.into(),
end_offset: 913.into(),
start_composition: 133_333.into(),
end_composition: 166_666.into(),
start_decode: 33_333.into(),
start_composition: 400.into(),
end_composition: 500.into(),
start_decode: 100.into(),
sync: false,
};
let video_indice_2 = Indice {
start_offset: 913.into(),
end_offset: 934.into(),
start_composition: 66_666.into(),
end_composition: 100_000.into(),
start_decode: 66_666.into(),
start_composition: 200.into(),
end_composition: 300.into(),
start_decode: 200.into(),
sync: false,
};
let video_indice_3 = Indice {
start_offset: 934.into(),
end_offset: 955.into(),
start_composition: 33_333.into(),
end_composition: 66_666.into(),
start_decode: 100_000.into(),
start_composition: 100.into(),
end_composition: 200.into(),
start_decode: 300.into(),
sync: false,
};
assert_eq!(indice.length, 300);

Просмотреть файл

@ -12,7 +12,7 @@ mozglue-static = { path = "../../../../mozglue/static/rust" }
geckoservo = { path = "../../../../servo/ports/geckolib" }
kvstore = { path = "../../../components/kvstore" }
lmdb-rkv-sys = { version = "0.11", features = ["mdb_idl_logn_9"] }
mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "2b572e83608a3d0867b935e076f45d9fe248069d", features = ["missing-pixi-permitted"] }
mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "1825cee59139d53669a5b8c563e4ea3e440d6a6c", features = ["missing-pixi-permitted"] }
nserror = { path = "../../../../xpcom/rust/nserror" }
nsstring = { path = "../../../../xpcom/rust/nsstring" }
netwerk_helper = { path = "../../../../netwerk/base/rust-helper" }