Bug 1624056 - Properly vendor mp4parse-rust. r=kinetik

This requires --build-peers-said-large-imports-were-ok since
third_party/rust/mp4parse/src/lib.rs is 113KB. This code is just moving from
media/mp4parse-rust to third_party/rust, so it's not really adding to net code
size.

Differential Revision: https://phabricator.services.mozilla.com/D74488
This commit is contained in:
Jon Bauman 2020-05-09 00:36:48 +00:00
Родитель e28d058a27
Коммит ff79fde159
43 изменённых файлов: 1957 добавлений и 1133 удалений

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

@ -17,6 +17,11 @@ git = "https://github.com/mozilla/neqo"
replace-with = "vendored-sources"
tag = "v0.2.4"
[source."https://github.com/mozilla/mp4parse-rust"]
git = "https://github.com/mozilla/mp4parse-rust"
replace-with = "vendored-sources"
rev = "0dc3e6e7c5371fe21f69b847f61c65fe6d6dc317"
[source."https://github.com/mozilla/application-services"]
git = "https://github.com/mozilla/application-services"
replace-with = "vendored-sources"

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

@ -2940,11 +2940,12 @@ dependencies = [
[[package]]
name = "mp4parse"
version = "0.11.4"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=0dc3e6e7c5371fe21f69b847f61c65fe6d6dc317#0dc3e6e7c5371fe21f69b847f61c65fe6d6dc317"
dependencies = [
"bitreader",
"byteorder",
"hashbrown",
"log",
"mp4parse_fallible",
"num-traits",
"static_assertions",
]
@ -2955,7 +2956,8 @@ version = "0.1.0"
[[package]]
name = "mp4parse_capi"
version = "0.11.2"
version = "0.11.4"
source = "git+https://github.com/mozilla/mp4parse-rust?rev=0dc3e6e7c5371fe21f69b847f61c65fe6d6dc317#0dc3e6e7c5371fe21f69b847f61c65fe6d6dc317"
dependencies = [
"byteorder",
"log",
@ -2963,12 +2965,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "mp4parse_fallible"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704f773471ac3e7110427b6bdf93184932b19319c9b7717688da5424e519b10a"
[[package]]
name = "msdos_time"
version = "0.1.6"

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

@ -0,0 +1,74 @@
This directory exists to provide the C++ interface to the mp4parse-rust code.
The code itself is hosted at https://github.com/mozilla/mp4parse-rust and
vendored into the /third_party/rust directory, so the only things here are the
moz.build file which specifies how the dynamically generated bindings header
should be generated and mp4parse.h, the header which consumers should include.
It includes the dynamically-generated bindings header as well as any
additional support code for FFI.
# Updating the version from the github repository
1. In /toolkit/library/rust/shared/Cargo.toml, Set the `rev` attribute of the
`mp4parse_capi` dependency to the revision you want to use.
2. Run `mach vendor rust` (`--build-peers-said-large-imports-were-ok` may be
necessary since the `mp4parse` crate's lib.rs is quite large).
3. Verify the expected changes in /third_party/rust.
4. Build, run try, etc.
NOTE: Git has no concept of checking out a subdirectory, so `cargo` will
search the whole repository to find the crate. Because the `mp4parse_capi`
depends on the `mp4parse` crate in the same repository via a relative path,
both crates will be vendored into /third_party/rust and should be part of the
same revision of mp4parse-rust.
# Developing changes to mp4parse-rust crates
Before committing changes to the github repository, it's a good idea to test
them out in the context of mozilla-central. There are a number of ways to
achieve this with various trade-offs, but here are the two I recommend. Both
start the same way:
1. `git clone https://github.com/mozilla/mp4parse-rust` somewhere outside
mozilla-central. For example: /Users/your_username/src/mp4parse-rust.
## For rapid iteration on local, uncommitted changes
2. In /toolkit/library/rust/shared/Cargo.toml, change the `mp4parse_capi`
dependency to
```
mp4parse_capi = { path = "/Users/your_username/src/mp4parse-rust/mp4parse_capi" }
```
3. Run `mach vendor rust`; the code in third_party/rust/mp4parse_capi and
third_party/rust/mp4parse will be removed, indicating the code in your
local checkout is being used instead.
4. In the moz.build in this directory, in `ffi_generated.inputs`, change
'/third_party/rust/mp4parse_capi' to
'//Users/your_username/src/mp4parse-rust/mp4parse_capi'. Note the
double-slash, it's required to reference paths outside mozilla-central.
5. Build and run the code or tests normally to exercise the code in
/Users/your_username/src/mp4parse-rust.
This is a fast way to try experiment with the rust code, but because it exists
outside the mozilla-central tree, it cannot be used with try.
## For validation of local, committed changes
2. In /toolkit/library/rust/shared/Cargo.toml, change the `mp4parse_capi`
dependency to
```
mp4parse_capi = { git = "file:///Users/your_username/src/mp4parse-rust" }
```
3. Run `mach vendor rust`; the local, committed code will be copied into
third_party/rust/mp4parse_capi and third_party/rust/mp4parse. Confirm the
diff is what you expect.
4. Unlike above, no changes to moz.build are necessary; if locally changed,
make sure to revert.
5. Build and run the code or tests normally to exercise the code in
/Users/your_username/src/mp4parse-rust. This can include try runs, but if
you make any additional changes, you must be sure to commit them in your
local git checkout of mp4parse-rust and re-run `mach vendor rust`.
This is a more thorough way to test local changes to the rust code since try
is available, but it's slower than the `path` dependency approach above
because every change must be committed and copied into the mozilla-central
tree with `mach vendor rust`.

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

@ -21,7 +21,7 @@ if CONFIG['COMPILE_ENVIRONMENT']:
ffi_generated = GENERATED_FILES['mp4parse_ffi_generated.h']
ffi_generated.script = '/build/RunCbindgen.py:generate'
ffi_generated.inputs = [
'/media/mp4parse-rust/mp4parse_capi',
'/third_party/rust/mp4parse_capi',
]
FINAL_LIBRARY = 'xul'

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

@ -1,24 +0,0 @@
diff --git a/media/mp4parse-rust/_upstream/mp4parse/mp4parse_capi/Cargo.toml b/media/mp4parse-rust/mp4parse_capi/Cargo.toml
index 2c606b4..895739f 100644
--- a/media/mp4parse-rust/_upstream/mp4parse/mp4parse_capi/Cargo.toml
+++ b/media/mp4parse-rust/mp4parse_capi/Cargo.toml
@@ -18,8 +18,7 @@ exclude = [
"*.mp4",
]
-[lib]
-crate-type = ["lib", "cdylib"]
+build = false # See bug 1611431 - Generate mp4parse-rust bindings as part of mach build
[badges]
travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
@@ -33,9 +32,6 @@ num-traits = "0.2.0"
[dev-dependencies]
env_logger = "0.7.1"
-[build-dependencies]
-cbindgen = "0.5.2"
-
[features]
# Enable mp4parse_fallible to use fallible memory allocation rather than
# panicking on OOM. Note that this is only safe within Gecko where the system

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

@ -2,10 +2,10 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
#ifndef mozilla_media_mp4parse_rust_mp4parse_h
#define mozilla_media_mp4parse_rust_mp4parse_h
#ifndef mp4parse_rust_mp4parse_h
#define mp4parse_rust_mp4parse_h
#include "mp4parse_ffi_generated.h" // prepend mozilla/media when we namespace this
#include "mp4parse_ffi_generated.h" // prepend mozilla/media when we namespace this
// Add any non-generated support code here

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

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

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

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

Двоичные данные
media/mp4parse-rust/mp4parse/tests/metadata.mp4

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

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

Двоичные данные
media/mp4parse-rust/mp4parse/tests/minimal.mp4

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

Двоичные данные
media/mp4parse-rust/mp4parse/tests/tiny_av1.mp4

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

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

@ -1,51 +0,0 @@
#!/bin/bash
# Script to update mp4parse-rust sources to latest upstream
set -e
# Default version.
VER="63ca8c6bde27b39dea87fb15e2922a23cb38c8df"
# Accept version or commit from the command line.
if test -n "$1"; then
VER=$1
fi
echo "Fetching sources..."
rm -rf _upstream
git clone --recurse-submodules https://github.com/mozilla/mp4parse-rust _upstream/mp4parse
pushd _upstream/mp4parse
git checkout ${VER}
echo "Verifying sources..."
cargo test
popd
rm -rf mp4parse
mkdir -p mp4parse/src
cp _upstream/mp4parse/mp4parse/Cargo.toml mp4parse/
cp _upstream/mp4parse/mp4parse/src/*.rs mp4parse/src/
mkdir -p mp4parse/tests
cp _upstream/mp4parse/mp4parse/tests/*.rs mp4parse/tests/
cp _upstream/mp4parse/mp4parse/tests/*.mp4 mp4parse/tests/
# Remove everything but the cbindgen.toml, since it's needed to configure the
# creation of the bindings as part of moz.build
find mp4parse_capi -not -name cbindgen.toml -delete
mkdir -p mp4parse_capi/src
cp _upstream/mp4parse/mp4parse_capi/Cargo.toml mp4parse_capi/
cp _upstream/mp4parse/mp4parse_capi/src/*.rs mp4parse_capi/src/
echo "Applying patches..."
patch -p3 < mp4parse-cargo.patch
echo "Cleaning up..."
rm -rf _upstream
echo "Updating gecko Cargo.lock..."
pushd ../../toolkit/library/rust/
cargo update --package mp4parse_capi
popd
pushd ../../toolkit/library/gtest/rust/
cargo update --package mp4parse_capi
popd
echo "Updated to ${VER}."

1
third_party/rust/mp4parse/.cargo-checksum.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
{"files":{"Cargo.toml":"107804fbf8f667fbad45e7dea9fa1bb32ce8ef5580b543a54455e678d7769708","src/boxes.rs":"623f948e69244db586d7cc1855e0a1828766cbe2d4998277d170047d0ae0fce0","src/fallible.rs":"836a36c2bc9803aead4bb24621e4fa6176c77b3752e69459a1f36555eb8bf2ec","src/lib.rs":"05d2e8523eab120bbc712adea9cd47979da3e95f54ff5816e6738ebeaf90afb2","src/macros.rs":"76c840f9299797527fe71aa5b378ffb01312767372b45cc62deddb19775400ae","src/tests.rs":"7c7f69051f8b8edcb994d3813bcca7277cc71bcfb0a6eaadbbdbb9a1f777ff88","tests/overflow.rs":"16b591d8def1a155b3b997622f6ea255536870d99c3d8f97c51755b77a50de3c","tests/public.rs":"eb02970aa69c31855936b4ec24dcf09b300fad274b620c879d9b6dfbcd89444c"},"package":null}

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

@ -18,6 +18,7 @@ repository = "https://github.com/mozilla/mp4parse-rust"
# Avoid complaints about trying to package test files.
exclude = [
"*.mp4",
"av1-avif/*"
]
[badges]
@ -26,11 +27,18 @@ travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }
[dependencies]
byteorder = "1.2.1"
bitreader = { version = "0.3.2" }
hashbrown = "0.7.1"
num-traits = "0.2.0"
mp4parse_fallible = { version = "0.0.3", optional = true }
log = "0.4"
static_assertions = "1.1.0"
[dev-dependencies]
test-assembler = "0.1.2"
env_logger = "0.7.1"
walkdir = "2.3.1"
[features]
# Enable mp4parse_fallible to use fallible memory allocation rather than
# panicking on OOM. Note that this is only safe within Gecko where the system
# allocator has been globally overridden (see BMO 1457359).
mp4parse_fallible = []

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

@ -3,6 +3,16 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use std::fmt;
// To ensure we don't use stdlib allocating types by accident
#[allow(dead_code)]
struct Vec;
#[allow(dead_code)]
struct Box;
#[allow(dead_code)]
struct HashMap;
#[allow(dead_code)]
struct String;
macro_rules! box_database {
($($boxenum:ident $boxtype:expr),*,) => {
#[derive(Clone, Copy, PartialEq)]
@ -42,24 +52,14 @@ macro_rules! box_database {
#[derive(Default, PartialEq, Clone)]
pub struct FourCC {
pub value: String,
pub value: [u8; 4],
}
impl From<u32> for FourCC {
fn from(number: u32) -> FourCC {
let mut box_chars = Vec::new();
for x in 0..4 {
let c = (number >> (x * 8) & 0x0000_00FF) as u8;
box_chars.push(c);
FourCC {
value: number.to_be_bytes(),
}
box_chars.reverse();
let box_string = match String::from_utf8(box_chars) {
Ok(t) => t,
_ => String::from("null"), // error to retrieve fourcc
};
FourCC { value: box_string }
}
}
@ -70,23 +70,27 @@ impl From<BoxType> for FourCC {
}
}
impl<'a> From<&'a str> for FourCC {
fn from(v: &'a str) -> FourCC {
FourCC {
value: v.to_owned(),
}
impl From<[u8; 4]> for FourCC {
fn from(v: [u8; 4]) -> FourCC {
FourCC { value: v }
}
}
impl fmt::Debug for FourCC {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
match std::str::from_utf8(&self.value) {
Ok(s) => write!(f, "{}", s),
Err(_) => self.value.fmt(f),
}
}
}
impl fmt::Display for FourCC {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.value)
match std::str::from_utf8(&self.value) {
Ok(s) => write!(f, "{}", s),
Err(_) => write!(f, "null"),
}
}
}

520
third_party/rust/mp4parse/src/fallible.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,520 @@
//! The types in this module are thin wrappers around the stdlib types to add
//! support for fallible allocation. Though the fallible allocator is only
//! enabled with the mp4parse_fallible feature, the API differences from the
//! stdlib types ensure that all operations which allocate return a Result.
//! For the most part, this simply means adding a Result return value to
//! functions which return nothing or a non-Result value. However, these types
//! implement some traits whose API cannot communicate failure, but which do
//! require allocation, so it is important that these wrapper types do not
//! implement these traits.
//!
//! Specifically, do not implement any of the following traits:
//! - Clone
//! - Extend
//! - From
//! - FromIterator
//!
//! This list may not be exhaustive. Exercise caution when implementing
//! any new traits to ensure they won't potentially allocate in a way that
//! can't return a Result to indicate allocation failure.
#[cfg(feature = "mp4parse_fallible")]
extern "C" {
fn malloc(bytes: usize) -> *mut u8;
fn realloc(ptr: *mut u8, bytes: usize) -> *mut u8;
}
use std::convert::TryInto as _;
use std::hash::Hash;
use std::io::Read;
use std::io::Take;
use std::iter::IntoIterator;
use BMFFBox;
type Result<T> = std::result::Result<T, super::Error>;
pub trait TryRead {
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> Result<usize>;
fn read_into_try_vec(&mut self) -> Result<TryVec<u8>> {
let mut buf = TryVec::new();
let _ = self.try_read_to_end(&mut buf)?;
Ok(buf)
}
}
impl<'a, T: Read> TryRead for BMFFBox<'a, T> {
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> Result<usize> {
try_read_up_to(self, self.bytes_left(), buf)
}
}
impl<T: Read> TryRead for Take<T> {
/// With the `mp4parse_fallible` feature enabled, this function reserves the
/// upper limit of what `src` can generate before reading all bytes until EOF
/// in this source, placing them into buf. If the allocation is unsuccessful,
/// or reading from the source generates an error before reaching EOF, this
/// will return an error. Otherwise, it will return the number of bytes read.
///
/// Since `Take::limit()` may return a value greater than the number of bytes
/// which can be read from the source, it's possible this function may fail
/// in the allocation phase even though allocating the number of bytes available
/// to read would have succeeded. In general, it is assumed that the callers
/// have accurate knowledge of the number of bytes of interest and have created
/// `src` accordingly.
///
/// With the `mp4parse_fallible` feature disabled, this is essentially a wrapper
/// around `std::io::Read::read_to_end()`.
fn try_read_to_end(&mut self, buf: &mut TryVec<u8>) -> Result<usize> {
try_read_up_to(self, self.limit(), buf)
}
}
fn try_read_up_to<R: Read>(src: &mut R, limit: u64, buf: &mut TryVec<u8>) -> Result<usize> {
let additional = limit.try_into()?;
buf.reserve(additional)?;
let bytes_read = src.read_to_end(&mut buf.inner)?;
Ok(bytes_read)
}
/// TryBox is a thin wrapper around std::boxed::Box to provide support for
/// fallible allocation.
///
/// See the `fallible` module documentation for more.
pub struct TryBox<T> {
inner: std::boxed::Box<T>,
}
impl<T> TryBox<T> {
pub fn try_new(x: T) -> Result<Self> {
let inner;
#[cfg(feature = "mp4parse_fallible")]
{
let size = std::mem::size_of::<T>();
let new_ptr = unsafe { malloc(size) as *mut T };
if new_ptr.is_null() {
return Err(super::Error::OutOfMemory);
}
// If we did a simple assignment: *new_ptr = x, then the value
// pointed to by new_ptr would immediately be dropped, but
// that would cause an invalid memory access. Instead, we use
// replace() to avoid the immediate drop and forget() to
// ensure that drop never happens.
inner = unsafe {
std::mem::forget(std::mem::replace(&mut *new_ptr, x));
Box::from_raw(new_ptr)
};
}
#[cfg(not(feature = "mp4parse_fallible"))]
{
inner = Box::new(x);
}
Ok(Self { inner })
}
pub fn into_raw(b: TryBox<T>) -> *mut T {
Box::into_raw(b.inner)
}
/// # Safety
///
/// See std::boxed::from_raw
pub unsafe fn from_raw(raw: *mut T) -> Self {
Self {
inner: Box::from_raw(raw),
}
}
}
/// TryHashMap is a thin wrapper around the hashbrown HashMap to provide
/// support for fallible allocation. This is the same library that stdlib
/// currently uses, but we use it directly since it provides try_reserve().
///
/// See the `fallible` module documentation for more.
#[derive(Default)]
pub struct TryHashMap<K, V> {
inner: hashbrown::hash_map::HashMap<K, V>,
}
impl<K, V> TryHashMap<K, V>
where
K: Eq + Hash,
{
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
where
K: std::borrow::Borrow<Q>,
Q: Hash + Eq,
{
self.inner.get(k)
}
pub fn insert(&mut self, k: K, v: V) -> Result<Option<V>> {
self.reserve(if self.inner.capacity() == 0 { 4 } else { 1 })?;
Ok(self.inner.insert(k, v))
}
fn reserve(&mut self, additional: usize) -> Result<()> {
#[cfg(feature = "mp4parse_fallible")]
{
self.inner
.try_reserve(additional)
.map_err(|_| super::Error::OutOfMemory)
}
#[cfg(not(feature = "mp4parse_fallible"))]
{
self.inner.reserve(additional);
Ok(())
}
}
}
#[test]
#[cfg(feature = "mp4parse_fallible")]
fn tryhashmap_oom() {
match TryHashMap::<char, char>::default().reserve(std::usize::MAX) {
Ok(_) => panic!("it should be OOM"),
_ => (),
}
}
#[derive(Default, PartialEq)]
pub struct TryVec<T> {
inner: std::vec::Vec<T>,
}
impl<T: std::fmt::Debug> std::fmt::Debug for TryVec<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.inner)
}
}
/// TryVec is a thin wrapper around std::vec::Vec to provide support for
/// fallible allocation.
///
/// See the `fallible` module documentation for more.
impl<T> TryVec<T> {
pub fn new() -> Self {
Self { inner: Vec::new() }
}
pub fn with_capacity(capacity: usize) -> Result<Self> {
let mut v = Self::new();
v.reserve(capacity)?;
Ok(v)
}
pub fn append(&mut self, other: &mut Self) -> Result<()> {
self.reserve(other.inner.len())?;
self.inner.append(&mut other.inner);
Ok(())
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
self
}
pub fn as_slice(&self) -> &[T] {
self
}
pub fn clear(&mut self) {
self.inner.clear()
}
#[cfg(test)]
pub fn into_inner(self) -> Vec<T> {
self.inner
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut {
inner: self.inner.iter_mut(),
}
}
pub fn iter(&self) -> Iter<T> {
Iter {
inner: self.inner.iter(),
}
}
pub fn pop(&mut self) -> Option<T> {
self.inner.pop()
}
pub fn push(&mut self, value: T) -> Result<()> {
self.reserve(if self.inner.capacity() == 0 { 4 } else { 1 })?;
self.inner.push(value);
Ok(())
}
fn reserve(&mut self, additional: usize) -> Result<()> {
#[cfg(feature = "mp4parse_fallible")]
{
let available = self
.inner
.capacity()
.checked_sub(self.inner.len())
.expect("capacity >= len");
if additional > available {
let increase = additional
.checked_sub(available)
.expect("additional > available");
let new_cap = self
.inner
.capacity()
.checked_add(increase)
.ok_or(super::Error::OutOfMemory)?;
self.try_extend(new_cap)?;
debug_assert!(self.inner.capacity() == new_cap);
}
Ok(())
}
#[cfg(not(feature = "mp4parse_fallible"))]
{
self.inner.reserve(additional);
Ok(())
}
}
pub fn resize_with<F>(&mut self, new_len: usize, f: F) -> Result<()>
where
F: FnMut() -> T,
{
self.reserve(new_len)?;
self.inner.resize_with(new_len, f);
Ok(())
}
#[cfg(feature = "mp4parse_fallible")]
fn try_extend(&mut self, new_cap: usize) -> Result<()> {
let old_ptr = self.as_mut_ptr();
let old_len = self.inner.len();
let old_cap: usize = self.inner.capacity();
if old_cap >= new_cap {
return Ok(());
}
let new_size_bytes = new_cap
.checked_mul(std::mem::size_of::<T>())
.ok_or(super::Error::OutOfMemory)?;
let new_ptr = unsafe {
if old_cap == 0 {
malloc(new_size_bytes)
} else {
realloc(old_ptr as *mut u8, new_size_bytes)
}
};
if new_ptr.is_null() {
return Err(super::Error::OutOfMemory);
}
let new_vec = unsafe { Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap) };
std::mem::forget(std::mem::replace(&mut self.inner, new_vec));
Ok(())
}
}
impl<T: Clone> TryVec<TryVec<T>> {
pub fn concat(&self) -> Result<TryVec<T>> {
let size = self.iter().map(|v| v.inner.len()).sum();
let mut result = TryVec::with_capacity(size)?;
for v in self.iter() {
result.extend_from_slice(&v.inner)?;
}
Ok(result)
}
}
impl<T: Clone> TryVec<T> {
pub fn extend_from_slice(&mut self, other: &[T]) -> Result<()> {
self.reserve(other.len())?;
self.inner.extend_from_slice(other);
Ok(())
}
}
#[test]
#[cfg(feature = "mp4parse_fallible")]
fn oom() {
let mut vec: TryVec<char> = TryVec::new();
match vec.reserve(std::usize::MAX) {
Ok(_) => panic!("it should be OOM"),
_ => (),
}
}
#[test]
fn try_reserve() {
let mut vec: TryVec<_> = vec![1].into();
let old_cap = vec.inner.capacity();
let new_cap = old_cap + 1;
vec.reserve(new_cap).unwrap();
assert!(vec.inner.capacity() >= new_cap);
}
#[test]
fn try_reserve_idempotent() {
let mut vec: TryVec<_> = vec![1].into();
let old_cap = vec.inner.capacity();
let new_cap = old_cap + 1;
vec.reserve(new_cap).unwrap();
let cap_after_reserve = vec.inner.capacity();
vec.reserve(new_cap).unwrap();
assert_eq!(cap_after_reserve, vec.inner.capacity());
}
#[test]
#[cfg(feature = "mp4parse_fallible")]
fn capacity_overflow() {
let mut vec: TryVec<_> = vec![1].into();
match vec.reserve(std::usize::MAX) {
Ok(_) => panic!("capacity calculation should overflow"),
_ => (),
}
}
#[test]
fn extend_from_slice() {
let mut vec: TryVec<u8> = b"foo".as_ref().try_into().unwrap();
vec.extend_from_slice(b"bar").unwrap();
assert_eq!(vec, b"foobar".as_ref());
}
impl<T> IntoIterator for TryVec<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.inner.into_iter()
}
}
impl<'a, T> IntoIterator for &'a TryVec<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
impl std::io::Write for TryVec<u8> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.extend_from_slice(buf)?;
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<T: PartialEq> PartialEq<Vec<T>> for TryVec<T> {
fn eq(&self, other: &Vec<T>) -> bool {
self.inner.eq(other)
}
}
impl<'a, T: PartialEq> PartialEq<&'a [T]> for TryVec<T> {
fn eq(&self, other: &&[T]) -> bool {
self.inner.eq(other)
}
}
impl PartialEq<&str> for TryVec<u8> {
fn eq(&self, other: &&str) -> bool {
self.as_slice() == other.as_bytes()
}
}
impl std::convert::AsRef<[u8]> for TryVec<u8> {
fn as_ref(&self) -> &[u8] {
self.inner.as_ref()
}
}
impl<T> std::convert::From<Vec<T>> for TryVec<T> {
fn from(value: Vec<T>) -> Self {
Self { inner: value }
}
}
impl<T: Clone> std::convert::TryFrom<&[T]> for TryVec<T> {
type Error = super::Error;
fn try_from(value: &[T]) -> Result<Self> {
let mut v = Self::new();
v.extend_from_slice(value)?;
Ok(v)
}
}
impl std::convert::TryFrom<&str> for TryVec<u8> {
type Error = super::Error;
fn try_from(value: &str) -> Result<Self> {
let mut v = Self::new();
v.extend_from_slice(value.as_bytes())?;
Ok(v)
}
}
impl<T> std::ops::Deref for TryVec<T> {
type Target = [T];
fn deref(&self) -> &[T] {
self.inner.deref()
}
}
impl<T> std::ops::DerefMut for TryVec<T> {
fn deref_mut(&mut self) -> &mut [T] {
self.inner.deref_mut()
}
}
pub struct Iter<'a, T> {
inner: std::slice::Iter<'a, T>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
pub struct IterMut<'a, T> {
inner: std::slice::IterMut<'a, T>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

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

@ -5,9 +5,11 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use super::fallible::TryRead as _;
use super::read_mp4;
use super::Error;
use super::MediaContext;
#[cfg(feature = "mp4parse_fallible")]
use std::convert::TryInto as _;
use std::io::Cursor;
@ -179,11 +181,11 @@ fn read_ftyp() {
assert_eq!(stream.head.name, BoxType::FileTypeBox);
assert_eq!(stream.head.size, 24);
let parsed = super::read_ftyp(&mut stream).unwrap();
assert_eq!(parsed.major_brand, FourCC::from("mp42")); // mp42
assert_eq!(parsed.major_brand, FourCC::from(*b"mp42")); // mp42
assert_eq!(parsed.minor_version, 0);
assert_eq!(parsed.compatible_brands.len(), 2);
assert_eq!(parsed.compatible_brands[0], FourCC::from("isom")); // isom
assert_eq!(parsed.compatible_brands[1], FourCC::from("mp42")); // mp42
assert_eq!(parsed.compatible_brands[0], FourCC::from(*b"isom")); // isom
assert_eq!(parsed.compatible_brands[1], FourCC::from(*b"mp42")); // mp42
}
#[test]
@ -221,11 +223,11 @@ fn read_ftyp_case() {
assert_eq!(stream.head.name, BoxType::FileTypeBox);
assert_eq!(stream.head.size, 24);
let parsed = super::read_ftyp(&mut stream).unwrap();
assert_eq!(parsed.major_brand, FourCC::from("MP42"));
assert_eq!(parsed.major_brand, FourCC::from(*b"MP42"));
assert_eq!(parsed.minor_version, 0);
assert_eq!(parsed.compatible_brands.len(), 2);
assert_eq!(parsed.compatible_brands[0], FourCC::from("ISOM")); // ISOM
assert_eq!(parsed.compatible_brands[1], FourCC::from("MP42")); // MP42
assert_eq!(parsed.compatible_brands[0], FourCC::from(*b"ISOM")); // ISOM
assert_eq!(parsed.compatible_brands[1], FourCC::from(*b"MP42")); // MP42
}
#[test]
@ -472,7 +474,7 @@ fn read_hdlr() {
assert_eq!(stream.head.name, BoxType::HandlerBox);
assert_eq!(stream.head.size, 45);
let parsed = super::read_hdlr(&mut stream).unwrap();
assert_eq!(parsed.handler_type, FourCC::from("vide"));
assert_eq!(parsed.handler_type, FourCC::from(*b"vide"));
}
#[test]
@ -485,7 +487,7 @@ fn read_hdlr_short_name() {
assert_eq!(stream.head.name, BoxType::HandlerBox);
assert_eq!(stream.head.size, 33);
let parsed = super::read_hdlr(&mut stream).unwrap();
assert_eq!(parsed.handler_type, FourCC::from("vide"));
assert_eq!(parsed.handler_type, FourCC::from(*b"vide"));
}
#[test]
@ -498,7 +500,7 @@ fn read_hdlr_zero_length_name() {
assert_eq!(stream.head.name, BoxType::HandlerBox);
assert_eq!(stream.head.size, 32);
let parsed = super::read_hdlr(&mut stream).unwrap();
assert_eq!(parsed.handler_type, FourCC::from("vide"));
assert_eq!(parsed.handler_type, FourCC::from(*b"vide"));
}
fn flac_streaminfo() -> Vec<u8> {
@ -680,7 +682,7 @@ fn serialize_opus_header() {
channel_mapping_table: Some(super::ChannelMappingTable {
stream_count: 4,
coupled_count: 2,
channel_mapping: vec![0, 4, 1, 2, 3, 5],
channel_mapping: vec![0, 4, 1, 2, 3, 5].into(),
}),
};
let mut v = Vec::<u8>::new();
@ -1057,7 +1059,7 @@ fn read_stsd_mp4v() {
assert_eq!(v.height, 480);
match v.codec_specific {
super::VideoCodecSpecific::ESDSConfig(esds_data) => {
assert_eq!(esds_data, esds_specific_data.to_vec());
assert_eq!(esds_data.as_slice(), esds_specific_data);
}
_ => panic!("it should be ESDSConfig!"),
}
@ -1293,16 +1295,14 @@ fn read_stsd_lpcm() {
#[test]
fn read_to_end_() {
let mut src = b"1234567890".take(5);
let mut buf = vec![];
let bytes_read = super::read_to_end(&mut src, &mut buf).unwrap();
assert_eq!(bytes_read, 5);
assert_eq!(buf, b"12345");
let buf = src.read_into_try_vec().unwrap();
assert_eq!(buf.len(), 5);
assert_eq!(buf.into_inner(), b"12345");
}
#[test]
#[cfg(feature = "mp4parse_fallible")]
fn read_to_end_oom() {
let mut src = b"1234567890".take(std::usize::MAX.try_into().expect("usize < u64"));
let mut buf = vec![];
assert!(super::read_to_end(&mut src, &mut buf).is_err());
assert!(src.read_into_try_vec().is_err());
}

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

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

@ -4,6 +4,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
extern crate mp4parse as mp4;
use std::convert::TryInto;
use std::fs::File;
use std::io::{Cursor, Read};
use std::path::Path;
@ -28,8 +29,7 @@ static VIDEO_EME_CBCS_MP4: &str = "tests/bipbop_cbcs_video_init.mp4";
static VIDEO_AV1_MP4: &str = "tests/tiny_av1.mp4";
static IMAGE_AVIF: &str = "av1-avif/testFiles/Microsoft/Monochrome.avif";
static IMAGE_AVIF_GRID: &str = "av1-avif/testFiles/Microsoft/Summer_in_Tomsk_720p_5x4_grid.avif";
static MICROSOFT_AVIF_TEST_DIR: &str = "av1-avif/testFiles/Microsoft";
static NETFLIX_AVIF_TEST_DIR: &str = "av1-avif/testFiles/Netflix/avif";
static AVIF_TEST_DIR: &str = "av1-avif/testFiles";
// Adapted from https://github.com/GuillaumeGomez/audio-video-metadata/blob/9dff40f565af71d5502e03a2e78ae63df95cfd40/src/metadata.rs#L53
#[test]
@ -175,7 +175,7 @@ fn public_metadata() {
assert_eq!(meta.year.unwrap(), "2019");
assert_eq!(
meta.genre.unwrap(),
mp4::Genre::CustomGenre("Custom Genre".to_string())
mp4::Genre::CustomGenre("Custom Genre".try_into().unwrap())
);
assert_eq!(meta.encoder.unwrap(), "Lavf56.40.101");
assert_eq!(meta.encoded_by.unwrap(), "Encoded-by");
@ -311,7 +311,7 @@ fn public_audio_tenc() {
Some(ref p) => {
assert_eq!(p.code_name, "mp4a");
if let Some(ref schm) = p.scheme_type {
assert_eq!(schm.scheme_type.value, "cenc");
assert_eq!(schm.scheme_type.value, *b"cenc");
} else {
panic!("Expected scheme type info");
}
@ -370,7 +370,7 @@ fn public_video_cenc() {
Some(ref p) => {
assert_eq!(p.code_name, "avc1");
if let Some(ref schm) = p.scheme_type {
assert_eq!(schm.scheme_type.value, "cenc");
assert_eq!(schm.scheme_type.value, *b"cenc");
} else {
panic!("Expected scheme type info");
}
@ -443,7 +443,7 @@ fn public_audio_cbcs() {
found_encrypted_sample_description = true;
assert_eq!(p.code_name, "mp4a");
if let Some(ref schm) = p.scheme_type {
assert_eq!(schm.scheme_type.value, "cbcs");
assert_eq!(schm.scheme_type.value, *b"cbcs");
} else {
panic!("Expected scheme type info");
}
@ -456,7 +456,7 @@ fn public_audio_cbcs() {
// to indicate full encryption.
assert_eq!(tenc.crypt_byte_block_count, Some(0));
assert_eq!(tenc.skip_byte_block_count, Some(0));
assert_eq!(tenc.constant_iv, Some(default_iv.clone()));
assert_eq!(tenc.constant_iv, Some(default_iv.clone().into()));
} else {
panic!("Invalid test condition");
}
@ -528,7 +528,7 @@ fn public_video_cbcs() {
found_encrypted_sample_description = true;
assert_eq!(p.code_name, "avc1");
if let Some(ref schm) = p.scheme_type {
assert_eq!(schm.scheme_type.value, "cbcs");
assert_eq!(schm.scheme_type.value, *b"cbcs");
} else {
panic!("Expected scheme type info");
}
@ -538,7 +538,7 @@ fn public_video_cbcs() {
assert_eq!(tenc.kid, kid);
assert_eq!(tenc.crypt_byte_block_count, Some(1));
assert_eq!(tenc.skip_byte_block_count, Some(9));
assert_eq!(tenc.constant_iv, Some(default_iv.clone()));
assert_eq!(tenc.constant_iv, Some(default_iv.clone().into()));
} else {
panic!("Invalid test condition");
}
@ -639,22 +639,19 @@ fn public_avif_primary_item_is_grid() {
#[test]
fn public_avif_read_samples() {
env_logger::init();
let microsoft = Path::new(MICROSOFT_AVIF_TEST_DIR)
.read_dir()
.expect("Cannot read AVIF test dir");
let netflix = Path::new(NETFLIX_AVIF_TEST_DIR)
.read_dir()
.expect("Cannot read AVIF test dir");
for entry in microsoft.chain(netflix) {
let path = entry.expect("AVIF entry").path();
if path.extension().expect("no extension") != "avif" {
for entry in walkdir::WalkDir::new(AVIF_TEST_DIR) {
let entry = entry.expect("AVIF entry");
let path = entry.path();
if !path.is_file() || path.extension().unwrap_or_default() != "avif" {
eprintln!("Skipping {:?}", path);
continue; // Skip ReadMe.txt, etc.
continue; // Skip directories, ReadMe.txt, etc.
}
if path == Path::new(IMAGE_AVIF_GRID) {
eprintln!("Skipping {:?}", path);
continue; // Remove when public_avif_primary_item_is_grid passes
}
println!("parsing {:?}", path);
let context = &mut mp4::AvifContext::new();
let input = &mut File::open(path).expect("Unknow file");
mp4::read_avif(input, context).expect("read_avif failed");

1
third_party/rust/mp4parse_capi/.cargo-checksum.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1 @@
{"files":{"Cargo.toml":"13408d7785c5fe40f9db2bac1f93e8cf2aca7c35b5d2ba9acbbb23eb3a71e40a","cbindgen.toml":"5c9429f271d6e914d81b63e6509c04ffe84cab11ed3a53a2ed4715e5d5ace80e","examples/dump.rs":"2db33a7ffbb20880d140e95c93cdeabe7e2ff41e5c09d80aa10dfdda9277942d","src/lib.rs":"deff68e6d20bc20167aa94cc0aaa541d83ca80bd0f18d9524530706a51782f5c","tests/test_chunk_out_of_range.rs":"b5da583218d98027ed973a29c67434a91a1306f2d2fb39ec4d640d4824c308ce","tests/test_encryption.rs":"a26f2fdb40e1fb3619a0625d0afbd677c6bdff1e2e640962197142656499c409","tests/test_fragment.rs":"e90eb5a4418d30002655466c0c4b3125c7fd70a74b6871471eaa172f1def9db8","tests/test_rotation.rs":"fb43c2f2dfa496d151c33bdd46c0fd3252387c23cc71e2cac9ed0234de715a81","tests/test_sample_table.rs":"adc8d264c46aef78c047377fbb792a4400d6db98bc44583b464d7b3dc182c884","tests/test_workaround_stsc.rs":"7dd419f3d55b9a3a039cac57e58a9240a9c8166bcd4356c24f69f731c3ced83b"},"package":null}

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

@ -1,10 +1,11 @@
[package]
name = "mp4parse_capi"
version = "0.11.2"
version = "0.11.4"
authors = [
"Ralph Giles <giles@mozilla.com>",
"Matthew Gregan <kinetik@flim.org>",
"Alfredo Yang <ayang@mozilla.com>",
"Jon Bauman <jbauman@mozilla.com>",
]
description = "Parser for ISO base media file format (mp4)"
@ -18,8 +19,6 @@ exclude = [
"*.mp4",
]
build = false # See bug 1611431 - Generate mp4parse-rust bindings as part of mach build
[badges]
travis-ci = { repository = "https://github.com/mozilla/mp4parse-rust" }

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

@ -1,8 +1,8 @@
header = """/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */"""
autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. See RunCbindgen.py */
#ifndef mozilla_media_mp4parse_rust_mp4parse_h
autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. */
#ifndef mp4parse_rust_mp4parse_h
#error "Don't include this file directly, instead include mp4parse.h"
#endif
"""
@ -11,9 +11,7 @@ braces = "SameLine"
line_length = 100
tab_width = 2
language = "C"
# If we change the language to C++, it would be nice to namespace it
# namespaces = ["mozilla", "media", "ffi"]
cpp_compat = true
[enum]
rename_variants = "QualifiedScreamingSnakeCase"

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

@ -0,0 +1,168 @@
extern crate mp4parse;
extern crate mp4parse_capi;
#[macro_use]
extern crate log;
extern crate env_logger;
use mp4parse_capi::*;
use std::env;
use std::fs::File;
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 mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
fn dump_file(filename: &str) {
let mut file = File::open(filename).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 rv = mp4parse_new(&io, &mut parser);
match rv {
Mp4parseStatus::Ok => (),
_ => {
println!("-- fail to parse, '-v' for more info");
return;
}
}
let mut frag_info = Mp4parseFragmentInfo::default();
match mp4parse_get_fragment_info(parser, &mut frag_info) {
Mp4parseStatus::Ok => {
println!("-- mp4parse_fragment_info {:?}", frag_info);
}
_ => {
println!("-- mp4parse_fragment_info failed");
return;
}
}
let mut counts: u32 = 0;
match mp4parse_get_track_count(parser, &mut counts) {
Mp4parseStatus::Ok => (),
_ => {
println!("-- mp4parse_get_track_count failed");
return;
}
}
for i in 0..counts {
let mut track_info = Mp4parseTrackInfo {
track_type: Mp4parseTrackType::Audio,
track_id: 0,
duration: 0,
media_time: 0,
};
match mp4parse_get_track_info(parser, i, &mut track_info) {
Mp4parseStatus::Ok => {
println!("-- mp4parse_get_track_info {:?}", track_info);
}
_ => {
println!("-- mp4parse_get_track_info failed, track id: {}", i);
return;
}
}
match track_info.track_type {
Mp4parseTrackType::Audio => {
let mut audio_info = Mp4parseTrackAudioInfo::default();
match mp4parse_get_track_audio_info(parser, i, &mut audio_info) {
Mp4parseStatus::Ok => {
println!("-- mp4parse_get_track_audio_info {:?}", audio_info);
for i in 0..audio_info.sample_info_count as isize {
let sample_info = audio_info.sample_info.offset(i);
println!(
" -- mp4parse_get_track_audio_info sample_info[{:?}] {:?}",
i, *sample_info
);
}
}
_ => {
println!("-- mp4parse_get_track_audio_info failed, track id: {}", i);
return;
}
}
}
Mp4parseTrackType::Video => {
let mut video_info = Mp4parseTrackVideoInfo::default();
match mp4parse_get_track_video_info(parser, i, &mut video_info) {
Mp4parseStatus::Ok => {
println!("-- mp4parse_get_track_video_info {:?}", video_info);
for i in 0..video_info.sample_info_count as isize {
let sample_info = video_info.sample_info.offset(i);
println!(
" -- mp4parse_get_track_video_info sample_info[{:?}] {:?}",
i, *sample_info
);
}
}
_ => {
println!("-- mp4parse_get_track_video_info failed, track id: {}", i);
return;
}
}
}
Mp4parseTrackType::Metadata => {
println!("TODO metadata track");
}
}
let mut indices = Mp4parseByteData::default();
match mp4parse_get_indice_table(parser, track_info.track_id, &mut indices) {
Mp4parseStatus::Ok => {
println!(
"-- mp4parse_get_indice_table track_id {} indices {:?}",
track_info.track_id, indices
);
}
_ => {
println!(
"-- mp4parse_get_indice_table failed, track_info.track_id: {}",
track_info.track_id
);
return;
}
}
}
mp4parse_free(parser);
}
}
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
return;
}
// Initialize logging, setting the log level if requested.
let (skip, verbose) = if args[1] == "-v" {
(2, true)
} else {
(1, false)
};
let env = env_logger::Env::default();
let mut logger = env_logger::Builder::from_env(env);
if verbose {
logger.filter(None, log::LevelFilter::Debug);
}
logger.init();
for filename in args.iter().skip(skip) {
info!("-- dump of '{}' --", filename);
dump_file(filename);
info!("-- end of '{}' --", filename);
}
}

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

@ -41,15 +41,12 @@ extern crate num_traits;
use byteorder::WriteBytesExt;
use num_traits::{PrimInt, Zero};
use std::collections::HashMap;
use std::io::Read;
// Symbols we need from our rust api.
use mp4parse::extend_from_slice;
use mp4parse::read_avif;
use mp4parse::read_mp4;
use mp4parse::serialize_opus_header;
use mp4parse::vec_push;
use mp4parse::AudioCodecSpecific;
use mp4parse::AvifContext;
use mp4parse::CodecType;
@ -62,8 +59,21 @@ use mp4parse::Track;
use mp4parse::TrackScaledTime;
use mp4parse::TrackTimeScale;
use mp4parse::TrackType;
use mp4parse::TryBox;
use mp4parse::TryHashMap;
use mp4parse::TryVec;
use mp4parse::VideoCodecSpecific;
// To ensure we don't use stdlib allocating types by accident
#[allow(dead_code)]
struct Vec;
#[allow(dead_code)]
struct Box;
#[allow(dead_code)]
struct HashMap;
#[allow(dead_code)]
struct String;
#[repr(C)]
#[derive(PartialEq, Debug)]
pub enum Mp4parseStatus {
@ -295,15 +305,15 @@ pub struct Mp4parseFragmentInfo {
#[derive(Default)]
pub struct Mp4parseParser {
context: MediaContext,
opus_header: HashMap<u32, Vec<u8>>,
pssh_data: Vec<u8>,
sample_table: HashMap<u32, Vec<Mp4parseIndice>>,
opus_header: TryHashMap<u32, TryVec<u8>>,
pssh_data: TryVec<u8>,
sample_table: TryHashMap<u32, TryVec<Mp4parseIndice>>,
// Store a mapping from track index (not id) to associated sample
// descriptions. Because each track has a variable number of sample
// descriptions, and because we need the data to live long enough to be
// copied out by callers, we store these on the parser struct.
audio_track_sample_descriptions: HashMap<u32, Vec<Mp4parseTrackAudioSampleInfo>>,
video_track_sample_descriptions: HashMap<u32, Vec<Mp4parseTrackVideoSampleInfo>>,
audio_track_sample_descriptions: TryHashMap<u32, TryVec<Mp4parseTrackAudioSampleInfo>>,
video_track_sample_descriptions: TryHashMap<u32, TryVec<Mp4parseTrackVideoSampleInfo>>,
}
/// A unified interface for the parsers which have different contexts, but
@ -328,18 +338,6 @@ impl Mp4parseParser {
fn context_mut(&mut self) -> &mut MediaContext {
&mut self.context
}
fn opus_header_mut(&mut self) -> &mut HashMap<u32, Vec<u8>> {
&mut self.opus_header
}
fn pssh_data_mut(&mut self) -> &mut Vec<u8> {
&mut self.pssh_data
}
fn sample_table_mut(&mut self) -> &mut HashMap<u32, Vec<Mp4parseIndice>> {
&mut self.sample_table
}
}
impl ContextParser for Mp4parseParser {
@ -483,8 +481,8 @@ fn mp4parse_new_common_safe<T: Read, P: ContextParser>(
P::read(io, &mut context)
.map(|_| P::with_context(context))
.map(Box::new)
.map(Box::into_raw)
.and_then(TryBox::try_new)
.map(TryBox::into_raw)
.map_err(Mp4parseStatus::from)
}
@ -505,6 +503,16 @@ impl From<mp4parse::Error> for Mp4parseStatus {
}
}
impl From<Result<(), Mp4parseStatus>> for Mp4parseStatus {
fn from(result: Result<(), Mp4parseStatus>) -> Self {
match result {
Ok(()) => Mp4parseStatus::Ok,
Err(Mp4parseStatus::Ok) => unreachable!(),
Err(e) => e,
}
}
}
/// Free an `Mp4parseParser*` allocated by `mp4parse_new()`.
///
/// # Safety
@ -515,7 +523,7 @@ impl From<mp4parse::Error> for Mp4parseStatus {
#[no_mangle]
pub unsafe extern "C" fn mp4parse_free(parser: *mut Mp4parseParser) {
assert!(!parser.is_null());
let _ = Box::from_raw(parser);
let _ = TryBox::from_raw(parser);
}
/// Free an `Mp4parseAvifParser*` allocated by `mp4parse_avif_new()`.
@ -528,7 +536,7 @@ pub unsafe extern "C" fn mp4parse_free(parser: *mut Mp4parseParser) {
#[no_mangle]
pub unsafe extern "C" fn mp4parse_avif_free(parser: *mut Mp4parseAvifParser) {
assert!(!parser.is_null());
let _ = Box::from_raw(parser);
let _ = TryBox::from_raw(parser);
}
/// Return the number of tracks parsed by previous `mp4parse_read()` call.
@ -694,34 +702,46 @@ pub unsafe extern "C" fn mp4parse_get_track_audio_info(
// Initialize fields to default values to ensure all fields are always valid.
*info = Default::default();
let context = (*parser).context();
get_track_audio_info(&mut *parser, track_index, &mut *info).into()
}
fn get_track_audio_info(
parser: &mut Mp4parseParser,
track_index: u32,
info: &mut Mp4parseTrackAudioInfo,
) -> Result<(), Mp4parseStatus> {
let Mp4parseParser {
context,
opus_header,
..
} = parser;
if track_index as usize >= context.tracks.len() {
return Mp4parseStatus::BadArg;
return Err(Mp4parseStatus::BadArg);
}
let track = &context.tracks[track_index as usize];
if track.track_type != TrackType::Audio {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
// Handle track.stsd
let stsd = match track.stsd {
Some(ref stsd) => stsd,
None => return Mp4parseStatus::Invalid, // Stsd should be present
None => return Err(Mp4parseStatus::Invalid), // Stsd should be present
};
if stsd.descriptions.is_empty() {
return Mp4parseStatus::Invalid; // Should have at least 1 description
return Err(Mp4parseStatus::Invalid); // Should have at least 1 description
}
let mut audio_sample_infos = Vec::with_capacity(stsd.descriptions.len());
let mut audio_sample_infos = TryVec::with_capacity(stsd.descriptions.len())?;
for description in stsd.descriptions.iter() {
let mut sample_info = Mp4parseTrackAudioSampleInfo::default();
let audio = match description {
SampleEntry::Audio(a) => a,
_ => return Mp4parseStatus::Invalid,
_ => return Err(Mp4parseStatus::Invalid),
};
// UNKNOWN for unsupported format.
@ -748,7 +768,7 @@ pub unsafe extern "C" fn mp4parse_get_track_audio_info(
match audio.codec_specific {
AudioCodecSpecific::ES_Descriptor(ref esds) => {
if esds.codec_esds.len() > std::u32::MAX as usize {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
sample_info.extra_data.length = esds.codec_esds.len() as u32;
sample_info.extra_data.data = esds.codec_esds.as_ptr();
@ -772,23 +792,22 @@ pub unsafe extern "C" fn mp4parse_get_track_audio_info(
// Return the STREAMINFO metadata block in the codec_specific.
let streaminfo = &flac.blocks[0];
if streaminfo.block_type != 0 || streaminfo.data.len() != 34 {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
sample_info.codec_specific_config.length = streaminfo.data.len() as u32;
sample_info.codec_specific_config.data = streaminfo.data.as_ptr();
}
AudioCodecSpecific::OpusSpecificBox(ref opus) => {
let mut v = Vec::new();
let mut v = TryVec::new();
match serialize_opus_header(opus, &mut v) {
Err(_) => {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
Ok(_) => {
let header = (*parser).opus_header_mut();
header.insert(track_index, v);
if let Some(v) = header.get(&track_index) {
opus_header.insert(track_index, v)?;
if let Some(v) = opus_header.get(&track_index) {
if v.len() > std::u32::MAX as usize {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
sample_info.codec_specific_config.length = v.len() as u32;
sample_info.codec_specific_config.data = v.as_ptr();
@ -811,8 +830,8 @@ pub unsafe extern "C" fn mp4parse_get_track_audio_info(
sample_info.protected_data.scheme_type = match p.scheme_type {
Some(ref scheme_type_box) => {
match scheme_type_box.scheme_type.value.as_ref() {
"cenc" => Mp4ParseEncryptionSchemeType::Cenc,
"cbcs" => Mp4ParseEncryptionSchemeType::Cbcs,
b"cenc" => Mp4ParseEncryptionSchemeType::Cenc,
b"cbcs" => Mp4ParseEncryptionSchemeType::Cbcs,
// We don't support other schemes, and shouldn't reach
// this case. Try to gracefully handle by treating as
// no encryption case.
@ -835,35 +854,32 @@ pub unsafe extern "C" fn mp4parse_get_track_audio_info(
};
if let Some(ref iv_vec) = tenc.constant_iv {
if iv_vec.len() > std::u32::MAX as usize {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
sample_info.protected_data.constant_iv.set_data(iv_vec);
};
}
}
let res = vec_push(&mut audio_sample_infos, sample_info);
if res.is_err() {
return Mp4parseStatus::Oom;
}
audio_sample_infos.push(sample_info)?;
}
(*parser)
parser
.audio_track_sample_descriptions
.insert(track_index, audio_sample_infos);
match (*parser).audio_track_sample_descriptions.get(&track_index) {
.insert(track_index, audio_sample_infos)?;
match parser.audio_track_sample_descriptions.get(&track_index) {
Some(sample_info) => {
if sample_info.len() > std::u32::MAX as usize {
// Should never happen due to upper limits on number of sample
// descriptions a track can have, but lets be safe.
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
(*info).sample_info_count = sample_info.len() as u32;
(*info).sample_info = sample_info.as_ptr();
info.sample_info_count = sample_info.len() as u32;
info.sample_info = sample_info.as_ptr();
}
None => return Mp4parseStatus::Invalid, // Shouldn't happen, we just inserted the info!
None => return Err(Mp4parseStatus::Invalid), // Shouldn't happen, we just inserted the info!
}
Mp4parseStatus::Ok
Ok(())
}
/// Fill the supplied `Mp4parseTrackVideoInfo` with metadata for `track`.
@ -887,54 +903,62 @@ pub unsafe extern "C" fn mp4parse_get_track_video_info(
// Initialize fields to default values to ensure all fields are always valid.
*info = Default::default();
let context = (*parser).context();
mp4parse_get_track_video_info_safe(&mut *parser, track_index, &mut *info).into()
}
fn mp4parse_get_track_video_info_safe(
parser: &mut Mp4parseParser,
track_index: u32,
info: &mut Mp4parseTrackVideoInfo,
) -> Result<(), Mp4parseStatus> {
let context = parser.context();
if track_index as usize >= context.tracks.len() {
return Mp4parseStatus::BadArg;
return Err(Mp4parseStatus::BadArg);
}
let track = &context.tracks[track_index as usize];
if track.track_type != TrackType::Video {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
// Handle track.tkhd
if let Some(ref tkhd) = track.tkhd {
(*info).display_width = tkhd.width >> 16; // 16.16 fixed point
(*info).display_height = tkhd.height >> 16; // 16.16 fixed point
info.display_width = tkhd.width >> 16; // 16.16 fixed point
info.display_height = tkhd.height >> 16; // 16.16 fixed point
let matrix = (
tkhd.matrix.a >> 16,
tkhd.matrix.b >> 16,
tkhd.matrix.c >> 16,
tkhd.matrix.d >> 16,
);
(*info).rotation = match matrix {
info.rotation = match matrix {
(0, 1, -1, 0) => 90, // rotate 90 degrees
(-1, 0, 0, -1) => 180, // rotate 180 degrees
(0, -1, 1, 0) => 270, // rotate 270 degrees
_ => 0,
};
} else {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
// Handle track.stsd
let stsd = match track.stsd {
Some(ref stsd) => stsd,
None => return Mp4parseStatus::Invalid, // Stsd should be present
None => return Err(Mp4parseStatus::Invalid), // Stsd should be present
};
if stsd.descriptions.is_empty() {
return Mp4parseStatus::Invalid; // Should have at least 1 description
return Err(Mp4parseStatus::Invalid); // Should have at least 1 description
}
let mut video_sample_infos = Vec::with_capacity(stsd.descriptions.len());
let mut video_sample_infos = TryVec::with_capacity(stsd.descriptions.len())?;
for description in stsd.descriptions.iter() {
let mut sample_info = Mp4parseTrackVideoSampleInfo::default();
let video = match description {
SampleEntry::Video(v) => v,
_ => return Mp4parseStatus::Invalid,
_ => return Err(Mp4parseStatus::Invalid),
};
// UNKNOWN for unsupported format.
@ -966,8 +990,8 @@ pub unsafe extern "C" fn mp4parse_get_track_video_info(
sample_info.protected_data.scheme_type = match p.scheme_type {
Some(ref scheme_type_box) => {
match scheme_type_box.scheme_type.value.as_ref() {
"cenc" => Mp4ParseEncryptionSchemeType::Cenc,
"cbcs" => Mp4ParseEncryptionSchemeType::Cbcs,
b"cenc" => Mp4ParseEncryptionSchemeType::Cenc,
b"cbcs" => Mp4ParseEncryptionSchemeType::Cbcs,
// We don't support other schemes, and shouldn't reach
// this case. Try to gracefully handle by treating as
// no encryption case.
@ -990,34 +1014,31 @@ pub unsafe extern "C" fn mp4parse_get_track_video_info(
};
if let Some(ref iv_vec) = tenc.constant_iv {
if iv_vec.len() > std::u32::MAX as usize {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
sample_info.protected_data.constant_iv.set_data(iv_vec);
};
}
}
let res = vec_push(&mut video_sample_infos, sample_info);
if res.is_err() {
return Mp4parseStatus::Oom;
}
video_sample_infos.push(sample_info)?;
}
(*parser)
parser
.video_track_sample_descriptions
.insert(track_index, video_sample_infos);
match (*parser).video_track_sample_descriptions.get(&track_index) {
.insert(track_index, video_sample_infos)?;
match parser.video_track_sample_descriptions.get(&track_index) {
Some(sample_info) => {
if sample_info.len() > std::u32::MAX as usize {
// Should never happen due to upper limits on number of sample
// descriptions a track can have, but lets be safe.
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
(*info).sample_info_count = sample_info.len() as u32;
(*info).sample_info = sample_info.as_ptr();
info.sample_info_count = sample_info.len() as u32;
info.sample_info = sample_info.as_ptr();
}
None => return Mp4parseStatus::Invalid, // Shouldn't happen, we just inserted the info!
None => return Err(Mp4parseStatus::Invalid), // Shouldn't happen, we just inserted the info!
}
Mp4parseStatus::Ok
Ok(())
}
/// Return a pointer to the primary item parsed by previous `mp4parse_avif_new()` call.
@ -1071,17 +1092,28 @@ pub unsafe extern "C" fn mp4parse_get_indice_table(
// Initialize fields to default values to ensure all fields are always valid.
*indices = Default::default();
let context = (*parser).context();
get_indice_table(&mut *parser, track_id, &mut *indices).into()
}
fn get_indice_table(
parser: &mut Mp4parseParser,
track_id: u32,
indices: &mut Mp4parseByteData,
) -> Result<(), Mp4parseStatus> {
let Mp4parseParser {
context,
sample_table: index_table,
..
} = parser;
let tracks = &context.tracks;
let track = match tracks.iter().find(|track| track.track_id == Some(track_id)) {
Some(t) => t,
_ => return Mp4parseStatus::Invalid,
_ => return Err(Mp4parseStatus::Invalid),
};
let index_table = (*parser).sample_table_mut();
if let Some(v) = index_table.get(&track_id) {
(*indices).set_indices(v);
return Mp4parseStatus::Ok;
indices.set_indices(v);
return Ok(());
}
let media_time = match (&track.media_time, &track.timescale) {
@ -1105,12 +1137,12 @@ pub unsafe extern "C" fn mp4parse_get_indice_table(
};
if let Some(v) = create_sample_table(track, offset_time) {
(*indices).set_indices(&v);
index_table.insert(track_id, v);
return Mp4parseStatus::Ok;
indices.set_indices(&v);
index_table.insert(track_id, v)?;
return Ok(());
}
Mp4parseStatus::Invalid
Err(Mp4parseStatus::Invalid)
}
// Convert a 'ctts' compact table to full table by iterator,
@ -1274,7 +1306,7 @@ impl<'a> SampleToChunkIterator<'a> {
}
}
fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<Mp4parseIndice>> {
fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<TryVec<Mp4parseIndice>> {
let timescale = match track.timescale {
Some(ref t) => TrackTimeScale::<i64>(t.0 as i64, t.1),
_ => return None,
@ -1291,7 +1323,7 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<Mp4p
_ => false,
};
let mut sample_table = Vec::new();
let mut sample_table = TryVec::new();
let mut sample_size_iter = stsz.sample_sizes.iter();
// Get 'stsc' iterator for (chunk_id, chunk_sample_count) and calculate the sample
@ -1322,20 +1354,16 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<Mp4p
}
cur_position = end_offset;
let res = vec_push(
&mut sample_table,
Mp4parseIndice {
sample_table
.push(Mp4parseIndice {
start_offset,
end_offset,
start_composition: 0,
end_composition: 0,
start_decode: 0,
sync: !has_sync_table,
},
);
if res.is_err() {
return None;
}
})
.ok()?;
}
}
@ -1407,11 +1435,9 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<Mp4p
// calculate to correct the composition end time.
if !sample_table.is_empty() {
// Create an index table refers to sample_table and sorted by start_composisiton time.
let mut sort_table = Vec::new();
let mut sort_table = TryVec::new();
for i in 0..sample_table.len() {
if vec_push(&mut sort_table, i).is_err() {
return None;
}
sort_table.push(i).ok()?;
}
sort_table.sort_by_key(|i| match sample_table.get(*i) {
@ -1419,13 +1445,12 @@ fn create_sample_table(track: &Track, track_offset_time: i64) -> Option<Vec<Mp4p
_ => 0,
});
let iter = sort_table.iter();
for i in 0..(iter.len() - 1) {
let current_index = sort_table[i];
let peek_index = sort_table[i + 1];
let next_start_composition_time = sample_table[peek_index].start_composition;
let sample = &mut sample_table[current_index];
sample.end_composition = next_start_composition_time;
for indices in sort_table.windows(2) {
if let [current_index, peek_index] = *indices {
let next_start_composition_time = sample_table[peek_index].start_composition;
let sample = &mut sample_table[current_index];
sample.end_composition = next_start_composition_time;
}
}
}
@ -1544,37 +1569,38 @@ pub unsafe extern "C" fn mp4parse_get_pssh_info(
// Initialize fields to default values to ensure all fields are always valid.
*info = Default::default();
let context = (*parser).context_mut();
let pssh_data = (*parser).pssh_data_mut();
let info: &mut Mp4parsePsshInfo = &mut *info;
get_pssh_info(&mut *parser, &mut *info).into()
}
fn get_pssh_info(
parser: &mut Mp4parseParser,
info: &mut Mp4parsePsshInfo,
) -> Result<(), Mp4parseStatus> {
let Mp4parseParser {
context, pssh_data, ..
} = parser;
pssh_data.clear();
for pssh in &context.psshs {
let content_len = pssh.box_content.len();
if content_len > std::u32::MAX as usize {
return Mp4parseStatus::Invalid;
return Err(Mp4parseStatus::Invalid);
}
let mut data_len = Vec::new();
let mut data_len = TryVec::new();
if data_len
.write_u32::<byteorder::NativeEndian>(content_len as u32)
.is_err()
{
return Mp4parseStatus::Io;
}
pssh_data.extend_from_slice(pssh.system_id.as_slice());
pssh_data.extend_from_slice(data_len.as_slice());
// The previous two calls have known, small sizes, but pssh_data has
// arbitrary size based on untrusted input, so use fallible allocation
let res = extend_from_slice(pssh_data, pssh.box_content.as_slice());
if res.is_err() {
return Mp4parseStatus::Oom;
return Err(Mp4parseStatus::Io);
}
pssh_data.extend_from_slice(pssh.system_id.as_slice())?;
pssh_data.extend_from_slice(data_len.as_slice())?;
pssh_data.extend_from_slice(pssh.box_content.as_slice())?;
}
info.data.set_data(pssh_data);
Mp4parseStatus::Ok
Ok(())
}
#[cfg(test)]
@ -1676,7 +1702,7 @@ fn parser_input_must_be_null() {
read: Some(error_read),
userdata: &mut dummy_value as *mut _ as *mut std::os::raw::c_void,
};
let mut parser = 0xDEADBEEF as *mut _;
let mut parser = 0xDEAD_BEEF as *mut _;
let rv = unsafe { mp4parse_new(&io, &mut parser) };
assert_eq!(rv, Mp4parseStatus::BadArg);
}

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

@ -0,0 +1,45 @@
extern crate mp4parse_capi;
use mp4parse_capi::*;
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 mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
#[test]
fn parse_out_of_chunk_range() {
let mut file = std::fs::File::open("tests/chunk_out_of_range.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 1);
// its first chunk is out of range.
// <SampleToChunkBox EntryCount="1">
// <BoxInfo Size="28" Type="stsc"/>
// <FullBoxInfo Version="0" Flags="0x0"/>
// <SampleToChunkEntry FirstChunk="16777217" SamplesPerChunk="17" SampleDescriptionIndex="1"/>
//
let mut indice = Mp4parseByteData::default();
let rv = mp4parse_get_indice_table(parser, 1, &mut indice);
assert_eq!(rv, Mp4parseStatus::Invalid);
mp4parse_free(parser);
}
}

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

@ -0,0 +1,200 @@
extern crate mp4parse_capi;
use mp4parse_capi::*;
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 mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
#[test]
#[allow(clippy::cognitive_complexity)] // TODO: Consider simplifying this
fn parse_cenc() {
let mut file = std::fs::File::open("tests/short-cenc.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 2);
// Make sure we have a video track and it's at index 0
let mut video_track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 0, &mut video_track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(video_track_info.track_type, Mp4parseTrackType::Video);
// Make sure we have a audio track and it's at index 1
let mut audio_track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 1, &mut audio_track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(audio_track_info.track_type, Mp4parseTrackType::Audio);
// Verify video track and crypto information
let mut video = Mp4parseTrackVideoInfo::default();
rv = mp4parse_get_track_video_info(parser, 0, &mut video);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(video.sample_info_count, 1);
assert_eq!((*video.sample_info).codec_type, Mp4parseCodec::Avc);
assert_eq!((*video.sample_info).image_width, 320);
assert_eq!((*video.sample_info).image_height, 240);
let protected_data = &(*video.sample_info).protected_data;
assert_eq!(
protected_data.scheme_type,
Mp4ParseEncryptionSchemeType::Cenc
);
assert_eq!(protected_data.is_encrypted, 0x01);
assert_eq!(protected_data.iv_size, 16);
assert_eq!(protected_data.kid.length, 16);
let expected_kid = [
0x7e, 0x57, 0x1d, 0x01, 0x7e, 0x57, 0x1d, 0x01, 0x7e, 0x57, 0x1d, 0x01, 0x7e, 0x57,
0x1d, 0x01,
];
for (i, expected_byte) in expected_kid.iter().enumerate() {
assert_eq!(&(*protected_data.kid.data.add(i)), expected_byte);
}
assert_eq!(protected_data.crypt_byte_block, 0);
assert_eq!(protected_data.skip_byte_block, 0);
assert_eq!(protected_data.constant_iv.length, 0);
// Verify audio track and crypto information
let mut audio = Mp4parseTrackAudioInfo::default();
rv = mp4parse_get_track_audio_info(parser, 1, &mut audio);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(audio.sample_info_count, 1);
assert_eq!((*audio.sample_info).codec_type, Mp4parseCodec::Aac);
assert_eq!((*audio.sample_info).channels, 2);
assert_eq!((*audio.sample_info).bit_depth, 16);
assert_eq!((*audio.sample_info).sample_rate, 44100);
let protected_data = &(*audio.sample_info).protected_data;
assert_eq!(protected_data.is_encrypted, 0x01);
assert_eq!(protected_data.iv_size, 16);
assert_eq!(protected_data.kid.length, 16);
let expected_kid = [
0x7e, 0x57, 0x1d, 0x02, 0x7e, 0x57, 0x1d, 0x02, 0x7e, 0x57, 0x1d, 0x02, 0x7e, 0x57,
0x1d, 0x02,
];
for (i, expected_byte) in expected_kid.iter().enumerate() {
assert_eq!(&(*protected_data.kid.data.add(i)), expected_byte);
}
assert_eq!(protected_data.crypt_byte_block, 0);
assert_eq!(protected_data.skip_byte_block, 0);
assert_eq!(protected_data.constant_iv.length, 0);
}
}
#[test]
fn parse_cbcs() {
let mut file = std::fs::File::open("tests/bipbop_cbcs_video_init.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 1);
// Make sure we have a video track
let mut video_track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 0, &mut video_track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(video_track_info.track_type, Mp4parseTrackType::Video);
// Verify video track and crypto information
let mut video = Mp4parseTrackVideoInfo::default();
rv = mp4parse_get_track_video_info(parser, 0, &mut video);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(video.sample_info_count, 2);
assert_eq!((*video.sample_info).codec_type, Mp4parseCodec::Avc);
assert_eq!((*video.sample_info).image_width, 400);
assert_eq!((*video.sample_info).image_height, 300);
let protected_data = &(*video.sample_info).protected_data;
assert_eq!(
protected_data.scheme_type,
Mp4ParseEncryptionSchemeType::Cbcs
);
assert_eq!(protected_data.is_encrypted, 0x01);
assert_eq!(protected_data.iv_size, 0);
assert_eq!(protected_data.kid.length, 16);
let expected_kid = [
0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57, 0x1d, 0x04, 0x7e, 0x57,
0x1d, 0x21,
];
for (i, expected_byte) in expected_kid.iter().enumerate() {
assert_eq!(&(*protected_data.kid.data.add(i)), expected_byte);
}
assert_eq!(protected_data.crypt_byte_block, 1);
assert_eq!(protected_data.skip_byte_block, 9);
assert_eq!(protected_data.constant_iv.length, 16);
let expected_iv = [
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44,
0x55, 0x66,
];
for (i, expected_byte) in expected_iv.iter().enumerate() {
assert_eq!(&(*protected_data.constant_iv.data.add(i)), expected_byte);
}
}
}
#[test]
fn parse_unencrypted() {
// Ensure the encryption related data is not populated for files without
// encryption metadata.
let mut file = std::fs::File::open("tests/opus_audioinit.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 1);
let mut track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 0, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Audio);
let mut audio = Mp4parseTrackAudioInfo::default();
rv = mp4parse_get_track_audio_info(parser, 0, &mut audio);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(audio.sample_info_count, 1);
let protected_data = &(*audio.sample_info).protected_data;
assert_eq!(
protected_data.scheme_type,
Mp4ParseEncryptionSchemeType::None
);
assert_eq!(protected_data.is_encrypted, 0x00);
assert_eq!(protected_data.iv_size, 0);
assert_eq!(protected_data.kid.length, 0);
assert_eq!(protected_data.crypt_byte_block, 0);
assert_eq!(protected_data.skip_byte_block, 0);
assert_eq!(protected_data.constant_iv.length, 0);
}
}

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

@ -0,0 +1,117 @@
extern crate mp4parse_capi;
use mp4parse_capi::*;
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 mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
#[test]
fn parse_fragment() {
let mut file = std::fs::File::open("tests/bipbop_audioinit.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 1);
let mut track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 0, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Audio);
assert_eq!(track_info.track_id, 1);
assert_eq!(track_info.duration, 0);
assert_eq!(track_info.media_time, 0);
let mut audio = Default::default();
rv = mp4parse_get_track_audio_info(parser, 0, &mut audio);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(audio.sample_info_count, 1);
assert_eq!((*audio.sample_info).codec_type, Mp4parseCodec::Aac);
assert_eq!((*audio.sample_info).channels, 2);
assert_eq!((*audio.sample_info).bit_depth, 16);
assert_eq!((*audio.sample_info).sample_rate, 22050);
assert_eq!((*audio.sample_info).extra_data.length, 27);
assert_eq!((*audio.sample_info).codec_specific_config.length, 2);
let mut is_fragmented_file: u8 = 0;
rv = mp4parse_is_fragmented(parser, track_info.track_id, &mut is_fragmented_file);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(is_fragmented_file, 1);
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);
mp4parse_free(parser);
}
}
#[test]
fn parse_opus_fragment() {
let mut file = std::fs::File::open("tests/opus_audioinit.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 1);
let mut track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 0, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Audio);
assert_eq!(track_info.track_id, 1);
assert_eq!(track_info.duration, 0);
assert_eq!(track_info.media_time, 0);
let mut audio = Default::default();
rv = mp4parse_get_track_audio_info(parser, 0, &mut audio);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(audio.sample_info_count, 1);
assert_eq!((*audio.sample_info).codec_type, Mp4parseCodec::Opus);
assert_eq!((*audio.sample_info).channels, 1);
assert_eq!((*audio.sample_info).bit_depth, 16);
assert_eq!((*audio.sample_info).sample_rate, 48000);
assert_eq!((*audio.sample_info).extra_data.length, 0);
assert_eq!((*audio.sample_info).codec_specific_config.length, 19);
let mut is_fragmented_file: u8 = 0;
rv = mp4parse_is_fragmented(parser, track_info.track_id, &mut is_fragmented_file);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(is_fragmented_file, 1);
let mut fragment_info = Mp4parseFragmentInfo::default();
rv = mp4parse_get_fragment_info(parser, &mut fragment_info);
assert_eq!(rv, Mp4parseStatus::Ok);
mp4parse_free(parser);
}
}

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

@ -0,0 +1,41 @@
extern crate mp4parse_capi;
use mp4parse_capi::*;
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 mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
#[test]
fn parse_rotation() {
let mut file = std::fs::File::open("tests/video_rotation_90.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 1);
let mut video = Mp4parseTrackVideoInfo::default();
let rv = mp4parse_get_track_video_info(parser, 0, &mut video);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(video.rotation, 90);
mp4parse_free(parser);
}
}

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

@ -0,0 +1,278 @@
extern crate mp4parse_capi;
use mp4parse_capi::*;
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 mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
#[test]
fn parse_sample_table() {
let mut file =
std::fs::File::open("tests/bipbop_nonfragment_header.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 2);
let mut track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 1, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Audio);
// Check audio smaple table
let mut is_fragmented_file: u8 = 0;
rv = mp4parse_is_fragmented(parser, track_info.track_id, &mut is_fragmented_file);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(is_fragmented_file, 0);
let mut indice = Mp4parseByteData::default();
rv = mp4parse_get_indice_table(parser, track_info.track_id, &mut indice);
assert_eq!(rv, Mp4parseStatus::Ok);
// Compare the value from stagefright.
let audio_indice_0 = Mp4parseIndice {
start_offset: 27_046,
end_offset: 27_052,
start_composition: 0,
end_composition: 46_439,
start_decode: 0,
sync: true,
};
let audio_indice_215 = Mp4parseIndice {
start_offset: 283_550,
end_offset: 283_556,
start_composition: 9_984_580,
end_composition: 10_031_020,
start_decode: 9_984_580,
sync: true,
};
assert_eq!(indice.length, 216);
assert_eq!(*indice.indices.offset(0), audio_indice_0);
assert_eq!(*indice.indices.offset(215), audio_indice_215);
// Check video smaple table
rv = mp4parse_get_track_info(parser, 0, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Video);
let mut is_fragmented_file: u8 = 0;
rv = mp4parse_is_fragmented(parser, track_info.track_id, &mut is_fragmented_file);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(is_fragmented_file, 0);
let mut indice = Mp4parseByteData::default();
rv = mp4parse_get_indice_table(parser, track_info.track_id, &mut indice);
assert_eq!(rv, Mp4parseStatus::Ok);
// Compare the last few data from stagefright.
let video_indice_291 = Mp4parseIndice {
start_offset: 280_226,
end_offset: 280_855,
start_composition: 9_838_333,
end_composition: 9_871_677,
start_decode: 9_710_000,
sync: false,
};
let video_indice_292 = Mp4parseIndice {
start_offset: 280_855,
end_offset: 281_297,
start_composition: 9_805_011,
end_composition: 9_838_333,
start_decode: 9_710_011,
sync: false,
};
// TODO: start_composition time in stagefright is 9905000, but it is 9904999 in parser, it
// could be rounding error.
//let video_indice_293 = Mp4parseIndice { start_offset: 281_297, end_offset: 281_919, start_composition: 9_905_000, end_composition: 9_938_344, start_decode: 9_776_666, sync: false };
//let video_indice_294 = Mp4parseIndice { start_offset: 281_919, end_offset: 282_391, start_composition: 9_871_677, end_composition: 9_905_000, start_decode: 9_776_677, sync: false };
let video_indice_295 = Mp4parseIndice {
start_offset: 282_391,
end_offset: 283_032,
start_composition: 9_971_666,
end_composition: 9_971_677,
start_decode: 9_843_333,
sync: false,
};
let video_indice_296 = Mp4parseIndice {
start_offset: 283_092,
end_offset: 283_526,
start_composition: 9_938_344,
end_composition: 9_971_666,
start_decode: 9_843_344,
sync: false,
};
assert_eq!(indice.length, 297);
assert_eq!(*indice.indices.offset(291), video_indice_291);
assert_eq!(*indice.indices.offset(292), video_indice_292);
//assert_eq!(*indice.indices.offset(293), video_indice_293);
//assert_eq!(*indice.indices.offset(294), video_indice_294);
assert_eq!(*indice.indices.offset(295), video_indice_295);
assert_eq!(*indice.indices.offset(296), video_indice_296);
mp4parse_free(parser);
}
}
#[test]
fn parse_sample_table_with_elst() {
let mut file = std::fs::File::open("tests/short-cenc.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 2);
let mut track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 1, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Audio);
// Check audio sample table
let mut is_fragmented_file: u8 = std::u8::MAX;
rv = mp4parse_is_fragmented(parser, track_info.track_id, &mut is_fragmented_file);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(is_fragmented_file, 0);
let mut indice = Mp4parseByteData::default();
rv = mp4parse_get_indice_table(parser, track_info.track_id, &mut indice);
assert_eq!(rv, Mp4parseStatus::Ok);
// Compare the value from stagefright.
// Due to 'elst', the start_composition and end_composition are negative
// at first two samples.
let audio_indice_0 = Mp4parseIndice {
start_offset: 6992,
end_offset: 7363,
start_composition: -36281,
end_composition: -13062,
start_decode: 0,
sync: true,
};
let audio_indice_1 = Mp4parseIndice {
start_offset: 7363,
end_offset: 7735,
start_composition: -13062,
end_composition: 10158,
start_decode: 23219,
sync: true,
};
let audio_indice_2 = Mp4parseIndice {
start_offset: 7735,
end_offset: 8106,
start_composition: 10158,
end_composition: 33378,
start_decode: 46439,
sync: true,
};
assert_eq!(indice.length, 21);
assert_eq!(*indice.indices.offset(0), audio_indice_0);
assert_eq!(*indice.indices.offset(1), audio_indice_1);
assert_eq!(*indice.indices.offset(2), audio_indice_2);
mp4parse_free(parser);
}
}
#[test]
fn parse_sample_table_with_negative_ctts() {
let mut file = std::fs::File::open("tests/white.mp4").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_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 1);
let mut track_info = Mp4parseTrackInfo::default();
rv = mp4parse_get_track_info(parser, 0, &mut track_info);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(track_info.track_type, Mp4parseTrackType::Video);
let mut is_fragmented_file: u8 = std::u8::MAX;
rv = mp4parse_is_fragmented(parser, track_info.track_id, &mut is_fragmented_file);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(is_fragmented_file, 0);
let mut indice = Mp4parseByteData::default();
rv = mp4parse_get_indice_table(parser, track_info.track_id, &mut indice);
assert_eq!(rv, Mp4parseStatus::Ok);
// There are negative value in 'ctts' table.
let video_indice_0 = Mp4parseIndice {
start_offset: 48,
end_offset: 890,
start_composition: 0,
end_composition: 33_333,
start_decode: 0,
sync: true,
};
let video_indice_1 = Mp4parseIndice {
start_offset: 890,
end_offset: 913,
start_composition: 133_333,
end_composition: 166_666,
start_decode: 33_333,
sync: false,
};
let video_indice_2 = Mp4parseIndice {
start_offset: 913,
end_offset: 934,
start_composition: 66_666,
end_composition: 100_000,
start_decode: 66_666,
sync: false,
};
let video_indice_3 = Mp4parseIndice {
start_offset: 934,
end_offset: 955,
start_composition: 33_333,
end_composition: 66_666,
start_decode: 100_000,
sync: false,
};
assert_eq!(indice.length, 300);
assert_eq!(*indice.indices.offset(0), video_indice_0);
assert_eq!(*indice.indices.offset(1), video_indice_1);
assert_eq!(*indice.indices.offset(2), video_indice_2);
assert_eq!(*indice.indices.offset(3), video_indice_3);
mp4parse_free(parser);
}
}

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

@ -0,0 +1,46 @@
extern crate mp4parse_capi;
use mp4parse_capi::*;
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 mut buf = unsafe { std::slice::from_raw_parts_mut(buf, size) };
match input.read(&mut buf) {
Ok(n) => n as isize,
Err(_) => -1,
}
}
#[test]
fn parse_invalid_stsc_table() {
let mut file = std::fs::File::open("tests/zero_empty_stsc.mp4").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 rv = mp4parse_new(&io, &mut parser);
assert_eq!(rv, Mp4parseStatus::Ok);
assert!(!parser.is_null());
let mut counts: u32 = 0;
let rv = mp4parse_get_track_count(parser, &mut counts);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(counts, 2);
let mut indice_video = Mp4parseByteData::default();
let rv = mp4parse_get_indice_table(parser, 1, &mut indice_video);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(indice_video.length, 1040);
let mut indice_audio = Mp4parseByteData::default();
let rv = mp4parse_get_indice_table(parser, 2, &mut indice_audio);
assert_eq!(rv, Mp4parseStatus::Ok);
assert_eq!(indice_audio.length, 1952);
mp4parse_free(parser);
}
}

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

@ -1 +0,0 @@
{"files":{"CODE_OF_CONDUCT.md":"902d5357af363426631d907e641e220b3ec89039164743f8442b3f120479b7cf","Cargo.toml":"2edecc4249f6ff011255fe3c92892050e466246b23ee6d002243b0df760625c7","LICENSE":"fab3dd6bdab226f1c08630b1dd917e11fcb4ec5e1e020e2c16f83a0a13863e85","README":"6f28a5c89ff7c018760402038a991a581771b8f66869268a7288f64915f192a6","lib.rs":"70f5bec52c586809882a1edce407552e8a5c3d0f126eaa92abd676484395cfc8"},"package":"704f773471ac3e7110427b6bdf93184932b19319c9b7717688da5424e519b10a"}

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

@ -1,15 +0,0 @@
# Community Participation Guidelines
This repository is governed by Mozilla's code of conduct and etiquette guidelines.
For more details, please read the
[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/).
## How to Report
For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.
<!--
## Project Specific Etiquette
In some cases, there will be additional project etiquette i.e.: (https://bugzilla.mozilla.org/page.cgi?id=etiquette.html).
Please update for your project.
-->

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

@ -1,26 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "mp4parse_fallible"
version = "0.0.3"
authors = ["The Servo Project Developers"]
description = "Fallible replacement for Vec"
documentation = "https://docs.rs/mp4parse_fallible/"
license = "MPL-2.0"
repository = "https://github.com/mozilla/mp4parse_fallible"
[lib]
name = "mp4parse_fallible"
path = "lib.rs"
[badges.travis-ci]
repository = "https://github.com/mozilla/mp4parse_fallible"

373
third_party/rust/mp4parse_fallible/LICENSE поставляемый
Просмотреть файл

@ -1,373 +0,0 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

7
third_party/rust/mp4parse_fallible/README поставляемый
Просмотреть файл

@ -1,7 +0,0 @@
This is from https://github.com/servo/servo/tree/master/components/fallible
with modification for mp4 demuxer.
The purpose of this crate is to solve infallible memory allocation problem
which causes OOM easily on win32. This is more like a temporary solution.
Once rust supports fallible memory allocation in its stdlib, this can be
retired.

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

@ -1,147 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::mem;
use std::vec::Vec;
extern "C" {
fn realloc(ptr: *mut u8, bytes: usize) -> *mut u8;
fn malloc(bytes: usize) -> *mut u8;
}
pub trait FallibleVec<T> {
/// Append |val| to the end of |vec|. Returns Ok(()) on success,
/// Err(()) if it fails, which can only be due to lack of memory.
fn try_push(&mut self, value: T) -> Result<(), ()>;
/// Reserves capacity for at least `additional` more elements to
/// be inserted in the vector. Does nothing if capacity is already
/// sufficient. Return Ok(()) on success, Err(()) if it fails either
/// due to lack of memory, or overflowing the `usize` used to store
/// the capacity.
fn try_reserve(&mut self, additional: usize) -> Result<(), ()>;
/// Clones and appends all elements in a slice to the Vec.
/// Returns Ok(()) on success, Err(()) if it fails, which can
/// only be due to lack of memory.
fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> where T: Clone;
}
/////////////////////////////////////////////////////////////////
// Vec
impl<T> FallibleVec<T> for Vec<T> {
#[inline]
fn try_push(&mut self, val: T) -> Result<(), ()> {
if self.capacity() == self.len() {
let old_cap: usize = self.capacity();
let new_cap: usize
= if old_cap == 0 { 4 } else { old_cap.checked_mul(2).ok_or(()) ? };
try_extend_vec(self, new_cap)?;
debug_assert!(self.capacity() > self.len());
}
self.push(val);
Ok(())
}
#[inline]
fn try_reserve(&mut self, additional: usize) -> Result<(), ()> {
let available = self.capacity().checked_sub(self.len()).expect("capacity >= len");
if additional > available {
let increase = additional.checked_sub(available).expect("additional > available");
let new_cap = self.capacity().checked_add(increase).ok_or(())?;
try_extend_vec(self, new_cap)?;
debug_assert!(self.capacity() == new_cap);
}
Ok(())
}
#[inline]
fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), ()> where T: Clone {
FallibleVec::try_reserve(self, other.len())?;
self.extend_from_slice(other);
Ok(())
}
}
#[inline(never)]
#[cold]
fn try_extend_vec<T>(vec: &mut Vec<T>, new_cap: usize) -> Result<(), ()> {
let old_ptr = vec.as_mut_ptr();
let old_len = vec.len();
let old_cap: usize = vec.capacity();
if old_cap >= new_cap {
return Ok(());
}
let new_size_bytes
= new_cap.checked_mul(mem::size_of::<T>()).ok_or(()) ? ;
let new_ptr = unsafe {
if old_cap == 0 {
malloc(new_size_bytes)
} else {
realloc(old_ptr as *mut u8, new_size_bytes)
}
};
if new_ptr.is_null() {
return Err(());
}
let new_vec = unsafe {
Vec::from_raw_parts(new_ptr as *mut T, old_len, new_cap)
};
mem::forget(mem::replace(vec, new_vec));
Ok(())
}
#[test]
fn oom() {
let mut vec: Vec<char> = Vec::new();
match FallibleVec::try_reserve(&mut vec, std::usize::MAX) {
Ok(_) => panic!("it should be OOM"),
_ => (),
}
}
#[test]
fn try_reserve() {
let mut vec = vec![1];
let old_cap = vec.capacity();
let new_cap = old_cap + 1;
FallibleVec::try_reserve(&mut vec, new_cap).unwrap();
assert!(vec.capacity() >= new_cap);
}
#[test]
fn try_reserve_idempotent() {
let mut vec = vec![1];
let old_cap = vec.capacity();
let new_cap = old_cap + 1;
FallibleVec::try_reserve(&mut vec, new_cap).unwrap();
let cap_after_reserve = vec.capacity();
FallibleVec::try_reserve(&mut vec, new_cap).unwrap();
assert_eq!(cap_after_reserve, vec.capacity());
}
#[test]
fn capacity_overflow() {
let mut vec = vec![1];
match FallibleVec::try_reserve(&mut vec, std::usize::MAX) {
Ok(_) => panic!("capacity calculation should overflow"),
_ => (),
}
}
#[test]
fn extend_from_slice() {
let mut vec = b"foo".to_vec();
FallibleVec::try_extend_from_slice(&mut vec, b"bar").unwrap();
assert_eq!(&vec, b"foobar");
}

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

@ -9,7 +9,7 @@ description = "Shared Rust code for libxul"
geckoservo = { path = "../../../../servo/ports/geckolib" }
kvstore = { path = "../../../components/kvstore" }
lmdb-rkv-sys = { version = "0.11", features = ["mdb_idl_logn_9"] }
mp4parse_capi = { path = "../../../../media/mp4parse-rust/mp4parse_capi" }
mp4parse_capi = { git = "https://github.com/mozilla/mp4parse-rust", rev = "0dc3e6e7c5371fe21f69b847f61c65fe6d6dc317" }
nserror = { path = "../../../../xpcom/rust/nserror" }
nsstring = { path = "../../../../xpcom/rust/nsstring" }
netwerk_helper = { path = "../../../../netwerk/base/rust-helper" }

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

@ -17,8 +17,6 @@ clippy:
- js/src/rust/shared/
- js/src/wasm/cranelift/
- media/audioipc/
- media/mp4parse-rust/mp4parse/
- media/mp4parse-rust/mp4parse_capi/
- modules/libpref/init/static_prefs/
- mozglue/static/rust/
- netwerk/base/mozurl/
@ -39,6 +37,8 @@ clippy:
- testing/mozbase/rust/mozrunner/
- testing/mozbase/rust/mozversion/
- testing/webdriver/
- third_party/rust/mp4parse/
- third_party/rust/mp4parse_capi/
- toolkit/components/kvstore/
- toolkit/components/glean/
- toolkit/components/xulstore/tests/gtest/