mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-09-02 01:33:47 +00:00
mux/mp4: migrate to mp4-atom to check muxing
This avoids implementing parsing logic for tests. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2258>
This commit is contained in:
parent
bd7cc01377
commit
34f16e0567
3 changed files with 131 additions and 87 deletions
50
Cargo.lock
generated
50
Cargo.lock
generated
|
@ -1721,6 +1721,26 @@ dependencies = [
|
|||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
|
@ -2958,6 +2978,7 @@ dependencies = [
|
|||
"gstreamer-pbutils",
|
||||
"gstreamer-tag",
|
||||
"gstreamer-video",
|
||||
"mp4-atom",
|
||||
"num-integer",
|
||||
"tempfile",
|
||||
"url",
|
||||
|
@ -5292,6 +5313,19 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e"
|
||||
|
||||
[[package]]
|
||||
name = "mp4-atom"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40a59fd1da0f5d0864ba19bd9d45cefc3dc19835f6f3bbf9016a86e4b4480042"
|
||||
dependencies = [
|
||||
"derive_more",
|
||||
"num",
|
||||
"paste",
|
||||
"thiserror 1.0.69",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "muldiv"
|
||||
version = "1.0.1"
|
||||
|
@ -5441,6 +5475,20 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.6"
|
||||
|
@ -6123,7 +6171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"heck 0.4.1",
|
||||
"heck 0.5.0",
|
||||
"itertools 0.12.1",
|
||||
"log",
|
||||
"multimap",
|
||||
|
|
|
@ -25,6 +25,7 @@ crate-type = ["cdylib", "rlib"]
|
|||
path = "src/lib.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
mp4-atom = "0.8.1"
|
||||
tempfile = "3"
|
||||
url = "2"
|
||||
|
||||
|
|
|
@ -7,13 +7,10 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
//
|
||||
|
||||
use std::{
|
||||
fs::{self},
|
||||
io::{Cursor, Read},
|
||||
path::Path,
|
||||
};
|
||||
use std::{fs::File, path::Path};
|
||||
|
||||
use gst_pbutils::prelude::*;
|
||||
use mp4_atom::{Atom as _, ReadAtom as _, ReadFrom as _};
|
||||
use tempfile::tempdir;
|
||||
|
||||
fn init() {
|
||||
|
@ -67,40 +64,6 @@ impl Pipeline {
|
|||
}
|
||||
}
|
||||
|
||||
struct FileTypeBox {
|
||||
major_brand: [u8; 4],
|
||||
minor_version: u32,
|
||||
compatible_brands: Vec<[u8; 4]>,
|
||||
}
|
||||
|
||||
impl FileTypeBox {
|
||||
fn read(mut reader: Cursor<&[u8]>) -> std::io::Result<FileTypeBox> {
|
||||
let mut box_size_buf = [0u8; 4];
|
||||
reader.read_exact(&mut box_size_buf)?;
|
||||
let box_size = u32::from_be_bytes(box_size_buf);
|
||||
let mut four_cc = [0u8; 4];
|
||||
reader.read_exact(&mut four_cc)?;
|
||||
assert_eq!(four_cc, *b"ftyp");
|
||||
let mut major_brand = [0u8; 4];
|
||||
reader.read_exact(&mut major_brand)?;
|
||||
let mut minor_version_buf = [0u8; 4];
|
||||
reader.read_exact(&mut minor_version_buf)?;
|
||||
let minor_version = u32::from_be_bytes(minor_version_buf);
|
||||
let num_brands = (box_size - 16) / 4;
|
||||
let mut compatible_brands = Vec::with_capacity(num_brands.try_into().unwrap());
|
||||
for _ in 0..num_brands {
|
||||
let mut compatible_brand = [0u8; 4];
|
||||
reader.read_exact(&mut compatible_brand)?;
|
||||
compatible_brands.push(compatible_brand);
|
||||
}
|
||||
Ok(FileTypeBox {
|
||||
major_brand,
|
||||
minor_version,
|
||||
compatible_brands,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn test_basic_with(video_enc: &str, audio_enc: &str, cb: impl FnOnce(&Path)) {
|
||||
let Ok(pipeline) = gst::parse::launch(&format!(
|
||||
"videotestsrc num-buffers=99 ! {video_enc} ! mux. \
|
||||
|
@ -302,26 +265,20 @@ fn test_encode_uncompressed(video_format: &str, width: u32, height: u32) {
|
|||
}
|
||||
|
||||
fn test_expected_uncompressed_output(location: &Path) {
|
||||
let check_data: Vec<u8> = fs::read(location).unwrap();
|
||||
let cursor = Cursor::new(check_data.as_ref());
|
||||
test_default_mpeg_file_type_box(cursor);
|
||||
}
|
||||
let required_top_level_boxes: Vec<mp4_atom::FourCC> = vec![
|
||||
b"ftyp".into(),
|
||||
b"free".into(),
|
||||
b"mdat".into(),
|
||||
b"moov".into(),
|
||||
];
|
||||
|
||||
fn test_expected_file_type_box(
|
||||
expected_major_brand: &[u8; 4],
|
||||
expected_minor_version: u32,
|
||||
expected_compatible_brands: Vec<[u8; 4]>,
|
||||
cursor: Cursor<&[u8]>,
|
||||
) {
|
||||
let ftyp = FileTypeBox::read(cursor).unwrap();
|
||||
|
||||
assert_eq!(ftyp.major_brand, *expected_major_brand);
|
||||
assert_eq!(ftyp.minor_version, expected_minor_version);
|
||||
let mut sorted_compatible_brands = ftyp.compatible_brands.clone();
|
||||
sorted_compatible_brands.sort();
|
||||
let mut sorted_expected_compatible_brands = expected_compatible_brands.clone();
|
||||
sorted_expected_compatible_brands.sort();
|
||||
assert_eq!(sorted_compatible_brands, sorted_expected_compatible_brands);
|
||||
check_file_boxes(
|
||||
location,
|
||||
required_top_level_boxes,
|
||||
b"iso4".into(),
|
||||
0,
|
||||
vec![b"isom".into(), b"mp41".into(), b"mp42".into()],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -582,21 +539,20 @@ fn test_encode_uncompressed_image_sequence(video_format: &str, width: u32, heigh
|
|||
test_expected_image_sequence_output(location);
|
||||
}
|
||||
|
||||
fn test_expected_image_sequence_output(filename: &Path) {
|
||||
let check_data: Vec<u8> = fs::read(filename).unwrap();
|
||||
let cursor = Cursor::new(check_data.as_ref());
|
||||
test_expected_image_sequence_file_type_box_content(cursor);
|
||||
}
|
||||
fn test_expected_image_sequence_output(location: &Path) {
|
||||
let required_top_level_boxes: Vec<mp4_atom::FourCC> = vec![
|
||||
b"ftyp".into(),
|
||||
b"free".into(),
|
||||
b"mdat".into(),
|
||||
b"moov".into(),
|
||||
];
|
||||
|
||||
fn test_expected_image_sequence_file_type_box_content(cursor: Cursor<&[u8]>) {
|
||||
let expected_major_brand = b"msf1";
|
||||
let expected_minor_version = 0;
|
||||
let expected_compatible_brands: Vec<[u8; 4]> = vec![*b"iso8", *b"msf1", *b"unif"];
|
||||
test_expected_file_type_box(
|
||||
expected_major_brand,
|
||||
expected_minor_version,
|
||||
expected_compatible_brands,
|
||||
cursor,
|
||||
check_file_boxes(
|
||||
location,
|
||||
required_top_level_boxes,
|
||||
b"msf1".into(),
|
||||
0,
|
||||
vec![b"iso8".into(), b"msf1".into(), b"unif".into()],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -650,20 +606,59 @@ fn test_encode_audio_trak() {
|
|||
test_audio_only_output(location);
|
||||
}
|
||||
|
||||
fn test_audio_only_output(filename: &Path) {
|
||||
let check_data: Vec<u8> = fs::read(filename).unwrap();
|
||||
let cursor = Cursor::new(check_data.as_ref());
|
||||
test_default_mpeg_file_type_box(cursor);
|
||||
}
|
||||
fn test_audio_only_output(location: &Path) {
|
||||
let required_top_level_boxes: Vec<mp4_atom::FourCC> = vec![
|
||||
b"ftyp".into(),
|
||||
b"free".into(),
|
||||
b"mdat".into(),
|
||||
b"moov".into(),
|
||||
];
|
||||
|
||||
fn test_default_mpeg_file_type_box(cursor: Cursor<&[u8]>) {
|
||||
let expected_major_brand = b"iso4";
|
||||
let expected_minor_version = 0;
|
||||
let expected_compatible_brands: Vec<[u8; 4]> = vec![*b"isom", *b"mp41", *b"mp42"];
|
||||
test_expected_file_type_box(
|
||||
expected_major_brand,
|
||||
expected_minor_version,
|
||||
expected_compatible_brands,
|
||||
cursor,
|
||||
check_file_boxes(
|
||||
location,
|
||||
required_top_level_boxes,
|
||||
b"iso4".into(),
|
||||
0,
|
||||
vec![b"isom".into(), b"mp41".into(), b"mp42".into()],
|
||||
);
|
||||
}
|
||||
|
||||
fn check_file_boxes(
|
||||
location: &Path,
|
||||
mut required_top_level_boxes: Vec<mp4_atom::FourCC>,
|
||||
expected_major_brand: mp4_atom::FourCC,
|
||||
expected_minor_version: u32,
|
||||
expected_compatible_brands: Vec<mp4_atom::FourCC>,
|
||||
) {
|
||||
let mut input = File::open(location).unwrap();
|
||||
while let Ok(header) = mp4_atom::Header::read_from(&mut input) {
|
||||
assert!(required_top_level_boxes.contains(&header.kind));
|
||||
let pos = required_top_level_boxes
|
||||
.iter()
|
||||
.position(|&fourcc| fourcc == header.kind)
|
||||
.unwrap_or_else(|| panic!("expected to find a matching fourcc {:?}", header.kind));
|
||||
required_top_level_boxes.remove(pos);
|
||||
match header.kind {
|
||||
mp4_atom::Ftyp::KIND => {
|
||||
let ftyp = mp4_atom::Ftyp::read_atom(&header, &mut input).unwrap();
|
||||
assert_eq!(ftyp.major_brand, expected_major_brand);
|
||||
assert_eq!(ftyp.minor_version, expected_minor_version);
|
||||
assert_eq!(
|
||||
ftyp.compatible_brands.len(),
|
||||
expected_compatible_brands.len()
|
||||
);
|
||||
for fourcc in &expected_compatible_brands {
|
||||
assert!(ftyp.compatible_brands.contains(fourcc));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let _ = mp4_atom::Any::read_atom(&header, &mut input).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
required_top_level_boxes.is_empty(),
|
||||
"expected all top level boxes to be found, but these were missed: {:?}",
|
||||
required_top_level_boxes
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue