Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  tests.rs

  Sprache: Rust
 

//! Module for parsing ISO Base Media Format aka video/mp4 streams.
//! Internal unit tests.

// 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 https://mozilla.org/MPL/2.0/.

use super::read_mp4;
use super::ParseStrictness;
use super::{Error, Status};
use fallible_collections::TryRead as _;

use std::convert::TryInto as _;
use std::io::Cursor;
use std::io::Read as _;
use test_assembler::*;

use crate::boxes::BoxType;

enum BoxSize {
    Short(u32),
    Long(u64),
    UncheckedShort(u32),
    UncheckedLong(u64),
    Auto,
}

#[allow(clippy::trivially_copy_pass_by_ref)] // TODO: Consider reworking to a copy
fn make_box<F>(size: BoxSize, name: &[u8; 4], func: F) -> Cursor<Vec<u8>>
where
    F: Fn(Section) -> Section,
{
    let mut section = Section::new();
    let box_size = Label::new();
    section = match size {
        BoxSize::Short(size) | BoxSize::UncheckedShort(size) => section.B32(size),
        BoxSize::Long(_) | BoxSize::UncheckedLong(_) => section.B32(1),
        BoxSize::Auto => section.B32(&box_size),
    };
    section = section.append_bytes(name);
    section = match size {
        // The spec allows the 32-bit size to be 0 to indicate unknown
        // length streams.  It's not clear if this is valid when using a
        // 64-bit size, so prohibit it for now.
        BoxSize::Long(size) => {
            assert!(size > 0);
            section.B64(size)
        }
        BoxSize::UncheckedLong(size) => section.B64(size),
        _ => section,
    };
    section = func(section);
    match size {
        BoxSize::Short(size) if size > 0 => {
            assert_eq!(u64::from(size), section.size())
        }
        BoxSize::Long(size) => assert_eq!(size, section.size()),
        BoxSize::Auto => {
            assert!(
                section.size() <= u64::from(u32::MAX),
                "Tried to use a long box with BoxSize::Auto"
            );
            box_size.set_const(section.size());
        }
        // Skip checking BoxSize::Unchecked* cases.
        _ => (),
    }
    Cursor::new(section.get_contents().unwrap())
}

fn make_uuid_box<F>(size: BoxSize, uuid: &[u8; 16], func: F) -> Cursor<Vec<u8>>
where
    F: Fn(Section) -> Section,
{
    make_box(size, b"uuid", |mut s| {
        for b in uuid {
            s = s.B8(*b);
        }
        func(s)
    })
}

#[allow(clippy::trivially_copy_pass_by_ref)] // TODO: Consider reworking to a copy
fn make_fullbox<F>(size: BoxSize, name: &[u8; 4], version: u8, func: F) -> Cursor<Vec<u8>>
where
    F: Fn(Section) -> Section,
{
    make_box(size, name, |s| func(s.B8(version).B8(0).B8(0).B8(0)))
}

#[test]
fn read_box_header_short() {
    let mut stream = make_box(BoxSize::Short(8), b"test", |s| s);
    let header = super::read_box_header(&mut stream).unwrap();
    assert_eq!(header.name, BoxType::UnknownBox(0x7465_7374)); // "test"
    assert_eq!(header.size, 8);
    assert!(header.uuid.is_none());
}

#[test]
fn read_box_header_long() {
    let mut stream = make_box(BoxSize::Long(16), b"test", |s| s);
    let header = super::read_box_header(&mut stream).unwrap();
    assert_eq!(header.name, BoxType::UnknownBox(0x7465_7374)); // "test"
    assert_eq!(header.size, 16);
    assert!(header.uuid.is_none());
}

#[test]
fn read_box_header_short_unknown_size() {
    let mut stream = make_box(BoxSize::Short(0), b"test", |s| s);
    match super::read_box_header(&mut stream) {
        Err(Error::Unsupported(s)) => assert_eq!(s, "unknown sized box"),
        _ => panic!("unexpected result reading box with unknown size"),
    };
}

#[test]
fn read_box_header_short_invalid_size() {
    let mut stream = make_box(BoxSize::UncheckedShort(2), b"test", |s| s);
    match super::read_box_header(&mut stream) {
        Err(Error::InvalidData(s)) => assert_eq!(s, Status::BoxBadSize),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_long_invalid_size() {
    let mut stream = make_box(BoxSize::UncheckedLong(2), b"test", |s| s);
    match super::read_box_header(&mut stream) {
        Err(Error::InvalidData(s)) => assert_eq!(s, Status::BoxBadWideSize),
        _ => panic!("unexpected result reading box with invalid size"),
    };
}

#[test]
fn read_box_header_uuid() {
    const HEADER_UUID: [u8; 16] = [
        0x85, 0xc0, 0xb6, 0x87, 0x82, 0x0f, 0x11, 0xe0, 0x81, 0x11, 0xf4, 0xce, 0x46, 0x2b, 0x6a,
        0x48,
    ];

    let mut stream = make_uuid_box(BoxSize::Short(24), &HEADER_UUID, |s| s);
    let mut iter = super::BoxIter::new(&mut stream);
    let stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::UuidBox);
    assert_eq!(stream.head.size, 24);
    assert!(stream.head.uuid.is_some());
    assert_eq!(stream.head.uuid.unwrap(), HEADER_UUID);
}

#[test]
fn read_box_header_truncated_uuid() {
    const HEADER_UUID: [u8; 16] = [
        0x85, 0xc0, 0xb6, 0x87, 0x82, 0x0f, 0x11, 0xe0, 0x81, 0x11, 0xf4, 0xce, 0x46, 0x2b, 0x6a,
        0x48,
    ];

    let mut stream = make_uuid_box(BoxSize::UncheckedShort(23), &HEADER_UUID, |s| s);
    let mut iter = super::BoxIter::new(&mut stream);
    let stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::UuidBox);
    assert_eq!(stream.head.size, 23);
    assert!(stream.head.uuid.is_none());
}

#[test]
fn read_box_header_uuid_past_eof() {
    const HEADER_UUID: [u8; 20] = [
        0x00, 0x00, 0x00, 0x18, // size = 24
        0x75, 0x75, 0x69, 0x64, // type = uuid
        0x85, 0xc0, 0xb6, 0x87, 0x82, 0x0f, 0x11, 0xe0, 0x81, 0x11, 0xf4, 0xce,
    ];

    let mut cursor = Cursor::new(HEADER_UUID);
    let mut iter = super::BoxIter::new(&mut cursor);
    match iter.next_box() {
        Ok(None) => (),
        Ok(_) => panic!("unexpected box read"),
        _ => panic!("unexpected error"),
    };
}

#[test]
fn read_ftyp() {
    let mut stream = make_box(BoxSize::Short(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0// minor version
            .append_bytes(b"isom")
            .append_bytes(b"mp42")
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    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, b"mp42"); // mp42
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], b"isom"); // isom
    assert_eq!(parsed.compatible_brands[1], b"mp42"); // mp42
}

#[test]
fn read_truncated_ftyp() {
    // We declare a 24 byte box, but only write 20 bytes.
    let mut stream = make_box(BoxSize::UncheckedShort(24), b"ftyp", |s| {
        s.append_bytes(b"mp42")
            .B32(0// minor version
            .append_bytes(b"isom")
    });
    match read_mp4(&mut stream, ParseStrictness::Normal) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => panic!("expected an error result"),
        _ => panic!("expected a different error result"),
    }
}

#[test]
fn read_ftyp_case() {
    // Brands in BMFF are represented as a u32, so it would seem clear that
    // 0x6d703432 ("mp42") is not equal to 0x4d503432 ("MP42"), but some
    // demuxers treat these as case-insensitive strings, e.g. street.mp4's
    // major brand is "MP42".  I haven't seen case-insensitive
    // compatible_brands (which we also test here), but it doesn't seem
    // unlikely given the major_brand behaviour.
    let mut stream = make_box(BoxSize::Auto, b"ftyp", |s| {
        s.append_bytes(b"MP42")
            .B32(0// minor version
            .append_bytes(b"ISOM")
            .append_bytes(b"MP42")
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    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, b"MP42");
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    assert_eq!(parsed.compatible_brands[0], b"ISOM"); // ISOM
    assert_eq!(parsed.compatible_brands[1], b"MP42"); // MP42
}

#[test]
fn read_elst_v0() {
    let mut stream = make_fullbox(BoxSize::Short(28), b"elst"0, |s| {
        s.B32(1// list count
            // first entry
            .B32(1234// duration
            .B32(5678// time
            .B16(12// rate integer
            .B16(34// rate fraction
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::EditListBox);
    assert_eq!(stream.head.size, 28);
    let parsed = super::read_elst(&mut stream).unwrap();
    assert_eq!(parsed.edits.len(), 1);
    assert_eq!(parsed.edits[0].segment_duration, 1234);
    assert_eq!(parsed.edits[0].media_time, 5678);
    assert_eq!(parsed.edits[0].media_rate_integer, 12);
    assert_eq!(parsed.edits[0].media_rate_fraction, 34);
}

#[test]
fn read_elst_v1() {
    let mut stream = make_fullbox(BoxSize::Short(56), b"elst"1, |s| {
        s.B32(2// list count
            // first entry
            .B64(1234// duration
            .B64(5678// time
            .B16(12// rate integer
            .B16(34// rate fraction
            // second entry
            .B64(1234// duration
            .B64(5678// time
            .B16(12// rate integer
            .B16(34// rate fraction
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::EditListBox);
    assert_eq!(stream.head.size, 56);
    let parsed = super::read_elst(&mut stream).unwrap();
    assert_eq!(parsed.edits.len(), 2);
    assert_eq!(parsed.edits[1].segment_duration, 1234);
    assert_eq!(parsed.edits[1].media_time, 5678);
    assert_eq!(parsed.edits[1].media_rate_integer, 12);
    assert_eq!(parsed.edits[1].media_rate_fraction, 34);
}

#[test]
fn read_mdhd_v0() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd"0, |s| {
        s.B32(0)
            .B32(0)
            .B32(1234// timescale
            .B32(5678// duration
            .B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
    assert_eq!(stream.head.size, 32);
    let parsed = super::read_mdhd(&mut stream).unwrap();
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_v1() {
    let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd"1, |s| {
        s.B64(0)
            .B64(0)
            .B32(1234// timescale
            .B64(5678// duration
            .B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
    assert_eq!(stream.head.size, 44);
    let parsed = super::read_mdhd(&mut stream).unwrap();
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mdhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"mdhd"0, |s| {
        s.B32(0)
            .B32(0)
            .B32(1234// timescale
            .B32(u32::MAX) // duration
            .B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
    assert_eq!(stream.head.size, 32);
    let parsed = super::read_mdhd(&mut stream).unwrap();
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, u64::MAX);
}

#[test]
fn read_mdhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Short(44), b"mdhd"1, |s| {
        s.B64(0)
            .B64(0)
            .B32(0// timescale
            .B64(5678// duration
            .B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MediaHeaderBox);
    assert_eq!(stream.head.size, 44);
    let r = super::parse_mdhd(&mut stream, &super::Track::new(0));
    assert!(r.is_err());
}

#[test]
fn read_mvhd_v0() {
    let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd"0, |s| {
        s.B32(0).B32(0).B32(1234).B32(5678).append_repeated(080)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
    assert_eq!(stream.head.size, 108);
    let parsed = super::read_mvhd(&mut stream).unwrap();
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_v1() {
    let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd"1, |s| {
        s.B64(0).B64(0).B32(1234).B64(5678).append_repeated(080)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
    assert_eq!(stream.head.size, 120);
    let parsed = super::read_mvhd(&mut stream).unwrap();
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_mvhd_invalid_timescale() {
    let mut stream = make_fullbox(BoxSize::Short(120), b"mvhd"1, |s| {
        s.B64(0).B64(0).B32(0).B64(5678).append_repeated(080)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
    assert_eq!(stream.head.size, 120);
    let r = super::parse_mvhd(&mut stream);
    assert!(r.is_err());
}

#[test]
fn read_mvhd_unknown_duration() {
    let mut stream = make_fullbox(BoxSize::Short(108), b"mvhd"0, |s| {
        s.B32(0)
            .B32(0)
            .B32(1234)
            .B32(u32::MAX)
            .append_repeated(080)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
    assert_eq!(stream.head.size, 108);
    let parsed = super::read_mvhd(&mut stream).unwrap();
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, u64::MAX);
}

#[test]
fn read_mvhd_v0_trailing_data() {
    let mut stream = make_fullbox(BoxSize::Short(110), b"mvhd"0, |s| {
        s.B32(0)
            .B32(0)
            .B32(1234)
            .B32(5678)
            .append_repeated(080)
            .B16(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::MovieHeaderBox);
    assert_eq!(stream.head.size, 110);
    let parsed = super::read_mvhd(&mut stream).unwrap();
    assert_eq!(parsed.timescale, 1234);
    assert_eq!(parsed.duration, 5678);
}

#[test]
fn read_vpcc_version_0() {
    let data_length = 12u16;
    let mut stream = make_fullbox(BoxSize::Auto, b"vpcC"0, |s| {
        s.B8(2)
            .B8(0)
            .B8(0x82)
            .B8(0)
            .B16(data_length)
            .append_repeated(42, data_length as usize)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::VPCodecConfigurationBox);
    let r = super::read_vpcc(&mut stream);
    assert!(r.is_ok());
}

// TODO: it'd be better to find a real sample here.
#[test]
#[allow(clippy::unusual_byte_groupings)] // Allow odd grouping for test readability.
fn read_vpcc_version_1() {
    let data_length = 12u16;
    let mut stream = make_fullbox(BoxSize::Auto, b"vpcC"1, |s| {
        s.B8(2// profile
            .B8(0// level
            .B8(0b1000_011_0) // bitdepth (4 bits), chroma (3 bits), video full range (1 bit)
            .B8(1// color primaries
            .B8(1// transfer characteristics
            .B8(1// matrix
            .B16(data_length)
            .append_repeated(42, data_length as usize)
    });

    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::VPCodecConfigurationBox);
    let r = super::read_vpcc(&mut stream);
    match r {
        Ok(vpcc) => {
            assert_eq!(vpcc.bit_depth, 8);
            assert_eq!(vpcc.chroma_subsampling, 3);
            assert!(!vpcc.video_full_range_flag);
            assert_eq!(vpcc.matrix_coefficients.unwrap(), 1);
        }
        _ => panic!("vpcc parsing error"),
    }
}

#[test]
fn read_hdlr() {
    let mut stream = make_fullbox(BoxSize::Short(45), b"hdlr"0, |s| {
        s.B32(0)
            .append_bytes(b"vide")
            .B32(0)
            .B32(0)
            .B32(0)
            .append_bytes(b"VideoHandler")
            .B8(0// null-terminate string
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 45);
    let parsed = super::read_hdlr(&mut stream, ParseStrictness::Normal).unwrap();
    assert_eq!(parsed.handler_type, b"vide");
}

#[test]
fn read_hdlr_multiple_nul_in_name() {
    let mut stream = make_fullbox(BoxSize::Short(45), b"hdlr"0, |s| {
        s.B32(0)
            .append_bytes(b"vide")
            .B32(0)
            .B32(0)
            .B32(0)
            .append_bytes(b"Vide\0Handler")
            .B8(0// null-terminate string
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 45);
    assert_eq!(
        super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Strict)),
        super::Status::Ok,
    );
}

#[test]
fn read_hdlr_short_name() {
    let mut stream = make_fullbox(BoxSize::Short(33), b"hdlr"0, |s| {
        s.B32(0).append_bytes(b"vide").B32(0).B32(0).B32(0).B8(0// null-terminate string
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 33);
    let parsed = super::read_hdlr(&mut stream, ParseStrictness::Normal).unwrap();
    assert_eq!(parsed.handler_type, b"vide");
}

#[test]
fn read_hdlr_unsupported_version() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr"1, |s| {
        s.B32(0).append_bytes(b"vide").B32(0).B32(0).B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 32);
    assert_eq!(
        super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Normal)),
        super::Status::HdlrUnsupportedVersion,
    );
}

#[test]
fn read_hdlr_invalid_pre_defined_field() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr"0, |s| {
        s.B32(1).append_bytes(b"vide").B32(0).B32(0).B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 32);
    assert_eq!(
        super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Strict)),
        super::Status::HdlrPredefinedNonzero,
    );
}

#[test]
fn read_hdlr_invalid_reserved_field() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr"0, |s| {
        s.B32(0).append_bytes(b"vide").B32(0).B32(1).B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 32);
    assert_eq!(
        super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Strict)),
        super::Status::HdlrReservedNonzero,
    );
}

#[test]
fn read_hdlr_zero_length_name() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr"0, |s| {
        s.B32(0).append_bytes(b"vide").B32(0).B32(0).B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 32);
    assert_eq!(
        super::Status::from(super::read_hdlr(&mut stream, ParseStrictness::Normal)),
        super::Status::HdlrNameNoNul,
    );
}

#[test]
fn read_hdlr_zero_length_name_permissive() {
    let mut stream = make_fullbox(BoxSize::Short(32), b"hdlr"0, |s| {
        s.B32(0).append_bytes(b"vide").B32(0).B32(0).B32(0)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::HandlerBox);
    assert_eq!(stream.head.size, 32);
    let parsed = super::read_hdlr(&mut stream, ParseStrictness::Permissive).unwrap();
    assert_eq!(parsed.handler_type, b"vide");
}

fn flac_streaminfo() -> Vec<u8> {
    vec![
        0x10, 0x00, 0x10, 0x00, 0x00, 0x0a, 0x11, 0x00, 0x38, 0x32, 0x0a, 0xc4, 0x42, 0xf0, 0x00,
        0xc9, 0xdf, 0xae, 0xb5, 0x66, 0xfc, 0x02, 0x15, 0xa3, 0xb1, 0x54, 0x61, 0x47, 0x0f, 0xfb,
        0x05, 0x00, 0x33, 0xad,
    ]
}

#[test]
fn read_flac() {
    let mut stream = make_box(BoxSize::Auto, b"fLaC", |s| {
        s.append_repeated(06// reserved
            .B16(1// data reference index
            .B32(0// reserved
            .B32(0// reserved
            .B16(2// channel count
            .B16(16// bits per sample
            .B16(0// pre_defined
            .B16(0// reserved
            .B32(44100 << 16// Sample rate
            .append_bytes(
                &make_dfla(
                    FlacBlockType::StreamInfo,
                    true,
                    &flac_streaminfo(),
                    FlacBlockLength::Correct,
                )
                .into_inner(),
            )
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    let r = super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal);
    assert!(r.is_ok());
}

#[derive(Clone, Copy)]
enum FlacBlockType {
    StreamInfo = 0,
    _Padding = 1,
    _Application = 2,
    _Seektable = 3,
    _Comment = 4,
    _Cuesheet = 5,
    _Picture = 6,
    _Reserved,
    _Invalid = 127,
}

enum FlacBlockLength {
    Correct,
    Incorrect(usize),
}

fn make_dfla(
    block_type: FlacBlockType,
    last: bool,
    data: &[u8],
    data_length: FlacBlockLength,
) -> Cursor<Vec<u8>> {
    assert!(data.len() < 1 << 24);
    make_fullbox(BoxSize::Auto, b"dfLa"0, |s| {
        let flag = u32::from(last);
        let size = match data_length {
            FlacBlockLength::Correct => (data.len() as u32) & 0x00ff_ffff,
            FlacBlockLength::Incorrect(size) => {
                assert!(size < 1 << 24);
                (size as u32) & 0x00ff_ffff
            }
        };
        let block_type = (block_type as u32) & 0x7f;
        s.B32((flag << 31) | (block_type << 24) | size)
            .append_bytes(data)
    })
}

#[test]
fn read_dfla() {
    let mut stream = make_dfla(
        FlacBlockType::StreamInfo,
        true,
        &flac_streaminfo(),
        FlacBlockLength::Correct,
    );
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
    let dfla = super::read_dfla(&mut stream).unwrap();
    assert_eq!(dfla.version, 0);
}

#[test]
fn long_flac_metadata() {
    let streaminfo = flac_streaminfo();
    let mut stream = make_dfla(
        FlacBlockType::StreamInfo,
        true,
        &streaminfo,
        FlacBlockLength::Incorrect(streaminfo.len() + 4),
    );
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::FLACSpecificBox);
    let r = super::read_dfla(&mut stream);
    assert!(r.is_err());
}

#[test]
fn read_opus() {
    let mut stream = make_box(BoxSize::Auto, b"Opus", |s| {
        s.append_repeated(06)
            .B16(1// data reference index
            .B32(0)
            .B32(0)
            .B16(2// channel count
            .B16(16// bits per sample
            .B16(0)
            .B16(0)
            .B32(48000 << 16// Sample rate is always 48 kHz for Opus.
            .append_bytes(&make_dops().into_inner())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    let r = super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal);
    assert!(r.is_ok());
}

fn make_dops() -> Cursor<Vec<u8>> {
    make_box(BoxSize::Auto, b"dOps", |s| {
        s.B8(0// version
            .B8(2// channel count
            .B16(348// pre-skip
            .B32(44100// original sample rate
            .B16(0// gain
            .B8(0// channel mapping
    })
}

#[test]
fn read_dops() {
    let mut stream = make_dops();
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, BoxType::OpusSpecificBox);
    let r = super::read_dops(&mut stream);
    assert!(r.is_ok());
}

#[test]
fn serialize_opus_header() {
    let opus = super::OpusSpecificBox {
        version: 0,
        output_channel_count: 1,
        pre_skip: 342,
        input_sample_rate: 24000,
        output_gain: 0,
        channel_mapping_family: 0,
        channel_mapping_table: None,
    };
    let mut v = Vec::<u8>::new();
    super::serialize_opus_header(&opus, &mut v).unwrap();
    assert_eq!(v.len(), 19);
    assert_eq!(
        v,
        vec![
            0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x01, 0x56, 0x01, 0xc0, 0x5d,
            0x00, 0x00, 0x00, 0x00, 0x00,
        ]
    );
    let opus = super::OpusSpecificBox {
        version: 0,
        output_channel_count: 6,
        pre_skip: 152,
        input_sample_rate: 48000,
        output_gain: 0,
        channel_mapping_family: 1,
        channel_mapping_table: Some(super::ChannelMappingTable {
            stream_count: 4,
            coupled_count: 2,
            channel_mapping: vec![041235].into(),
        }),
    };
    let mut v = Vec::<u8>::new();
    super::serialize_opus_header(&opus, &mut v).unwrap();
    assert_eq!(v.len(), 27);
    assert_eq!(
        v,
        vec![
            0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x01, 0x06, 0x98, 0x00, 0x80, 0xbb,
            0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x02, 0x00, 0x04, 0x01, 0x02, 0x03, 0x05,
        ]
    );
}

#[test]
fn read_alac() {
    let mut stream = make_box(BoxSize::Auto, b"alac", |s| {
        s.append_repeated(06// reserved
            .B16(1// data reference index
            .B32(0// reserved
            .B32(0// reserved
            .B16(2// channel count
            .B16(16// bits per sample
            .B16(0// pre_defined
            .B16(0// reserved
            .B32(44100 << 16// Sample rate
            .append_bytes(
                &make_fullbox(BoxSize::Auto, b"alac"0, |s| s.append_bytes(&[0xfa; 24]))
                    .into_inner(),
            )
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    let r = super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal);
    assert!(r.is_ok());
}

#[test]
fn esds_limit() {
    let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
        s.append_repeated(06)
            .B16(1)
            .B32(0)
            .B32(0)
            .B16(2)
            .B16(16)
            .B16(0)
            .B16(0)
            .B32(48000 << 16)
            .B32(8)
            .append_bytes(b"esds")
            .append_repeated(04)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    match super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal) {
        Err(Error::UnexpectedEOF) => (),
        Ok(_) => panic!("expected an error result"),
        _ => panic!("expected a different error result"),
    }
}

#[test]
fn read_elst_zero_entries() {
    let mut stream = make_fullbox(BoxSize::Auto, b"elst"0, |s| s.B32(0).B16(12).B16(34));
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    match super::read_elst(&mut stream) {
        Ok(elst) => assert_eq!(elst.edits.len(), 0),
        _ => panic!("expected no error"),
    }
}

fn make_elst() -> Cursor<Vec<u8>> {
    make_fullbox(BoxSize::Auto, b"elst"1, |s| {
        s.B32(1)
            // first entry
            .B64(1234// duration
            .B64(0xffff_ffff_ffff_ffff) // time
            .B16(12// rate integer
            .B16(34// rate fraction
    })
}

#[test]
fn read_edts_bogus() {
    // First edit list entry has a media_time of -1, so we expect a second
    // edit list entry to be present to provide a valid media_time.
    // Bogus edts are ignored.
    let mut stream = make_box(BoxSize::Auto, b"edts", |s| {
        s.append_bytes(&make_elst().into_inner())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    let mut track = super::Track::new(0);
    match super::read_edts(&mut stream, &mut track) {
        Ok(_) => {
            assert_eq!(track.media_time, None);
            assert_eq!(track.empty_duration, None);
        }
        _ => panic!("expected no error"),
    }
}

#[test]
fn skip_padding_in_boxes() {
    // Padding data could be added in the end of these boxes. Parser needs to skip
    // them instead of returning error.
    let box_names = vec![b"stts", b"stsc", b"stsz", b"stco", b"co64", b"stss"];

    for name in box_names {
        let mut stream = make_fullbox(BoxSize::Auto, name, 1, |s| {
            s.append_repeated(0100// add padding data
        });
        let mut iter = super::BoxIter::new(&mut stream);
        let mut stream = iter.next_box().unwrap().unwrap();
        match name {
            b"stts" => {
                super::read_stts(&mut stream).expect("fail to skip padding: stts");
            }
            b"stsc" => {
                super::read_stsc(&mut stream).expect("fail to skip padding: stsc");
            }
            b"stsz" => {
                super::read_stsz(&mut stream).expect("fail to skip padding: stsz");
            }
            b"stco" => {
                super::read_stco(&mut stream).expect("fail to skip padding: stco");
            }
            b"co64" => {
                super::read_co64(&mut stream).expect("fail to skip padding: co64");
            }
            b"stss" => {
                super::read_stss(&mut stream).expect("fail to skip padding: stss");
            }
            _ => (),
        }
    }
}

#[test]
fn skip_padding_in_stsd() {
    // Padding data could be added in the end of stsd boxes. Parser needs to skip
    // them instead of returning error.
    let avc = make_box(BoxSize::Auto, b"avc1", |s| {
        s.append_repeated(06)
            .B16(1)
            .append_repeated(016)
            .B16(320)
            .B16(240)
            .append_repeated(014)
            .append_repeated(032)
            .append_repeated(04)
            .B32(0xffff_ffff)
            .append_bytes(b"avcC")
            .append_repeated(0100)
    })
    .into_inner();
    let mut stream = make_fullbox(BoxSize::Auto, b"stsd"0, |s| {
        s.B32(1)
            .append_bytes(avc.as_slice())
            .append_repeated(0100// add padding data
    });

    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    super::read_stsd(&mut stream, &super::Track::new(0), ParseStrictness::Normal)
        .expect("fail to skip padding: stsd");
}

#[test]
fn read_qt_wave_atom() {
    let esds = make_fullbox(BoxSize::Auto, b"esds"0, |s| {
        s.B8(0x03) // elementary stream descriptor tag
            .B8(0x12) // esds length
            .append_repeated(02)
            .B8(0x00) // flags
            .B8(0x04) // decoder config descriptor tag
            .B8(0x0d) // dcds length
            .B8(0x6b) // mp3
            .append_repeated(012)
    })
    .into_inner();
    let chan = make_box(BoxSize::Auto, b"chan", |s| {
        s.append_repeated(010// we don't care its data.
    })
    .into_inner();
    let wave = make_box(BoxSize::Auto, b"wave", |s| s.append_bytes(esds.as_slice())).into_inner();
    let mut stream = make_box(BoxSize::Auto, b"mp4a", |s| {
        s.append_repeated(06)
            .B16(1// data_reference_count
            .B16(1// verion: qt -> 1
            .append_repeated(06)
            .B16(2)
            .B16(16)
            .append_repeated(04)
            .B32(48000 << 16)
            .append_repeated(016)
            .append_bytes(wave.as_slice())
            .append_bytes(chan.as_slice())
    });

    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    let sample_entry = super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal)
        .expect("fail to read qt wave atom");
    match sample_entry {
        super::SampleEntry::Audio(sample_entry) => {
            assert_eq!(sample_entry.codec_type, super::CodecType::MP3)
        }
        _ => panic!("fail to read audio sample enctry"),
    }
}

#[test]
fn read_descriptor_80() {
    let aac_esds = vec![
        0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x02, 0x00, 0x04, 0x80, 0x80, 0x80, 0x17, 0x40, 0x15,
        0x00, 0x00, 0x00, 0x00, 0x03, 0x22, 0xBC, 0x00, 0x01, 0xF5, 0x83, 0x05, 0x80, 0x80, 0x80,
        0x02, 0x11, 0x90, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02,
    ];
    let aac_dc_descriptor = &aac_esds[31..33];
    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, None);
    assert_eq!(es.audio_sample_rate, Some(48000));
    assert_eq!(es.audio_channel_count, Some(2));
    assert_eq!(es.codec_esds, aac_esds);
    assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
}

#[test]
fn read_esds() {
    let aac_esds = vec![
        0x03, 0x24, 0x00, 0x00, 0x00, 0x04, 0x1c, 0x40, 0x15, 0x00, 0x12, 0x00, 0x00, 0x01, 0xf4,
        0x00, 0x00, 0x01, 0xf4, 0x00, 0x05, 0x0d, 0x13, 0x00, 0x05, 0x88, 0x05, 0x00, 0x48, 0x21,
        0x10, 0x00, 0x56, 0xe5, 0x98, 0x06, 0x01, 0x02,
    ];
    let aac_dc_descriptor = &aac_esds[22..35];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, None);
    assert_eq!(es.audio_sample_rate, Some(24000));
    assert_eq!(es.audio_channel_count, Some(6));
    assert_eq!(es.codec_esds, aac_esds);
    assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
}

#[test]
fn read_esds_aac_type5() {
    let aac_esds = vec![
        0x03, 0x80, 0x80, 0x80, 0x2F, 0x00, 0x00, 0x00, 0x04, 0x80, 0x80, 0x80, 0x21, 0x40, 0x15,
        0x00, 0x15, 0x00, 0x00, 0x03, 0xED, 0xAA, 0x00, 0x03, 0x6B, 0x00, 0x05, 0x80, 0x80, 0x80,
        0x0F, 0x2B, 0x01, 0x88, 0x02, 0xC4, 0x04, 0x90, 0x2C, 0x10, 0x8C, 0x80, 0x00, 0x00, 0xED,
        0x40, 0x06, 0x80, 0x80, 0x80, 0x01, 0x02,
    ];

    let aac_dc_descriptor = &aac_esds[31..46];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, Some(5));
    assert_eq!(es.audio_sample_rate, Some(24000));
    assert_eq!(es.audio_channel_count, Some(8));
    assert_eq!(es.codec_esds, aac_esds);
    assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
}

#[test]
fn read_esds_mpeg2_aac_lc() {
    // Recognize MPEG-2 AAC LC (ISO 13818-7) object type as AAC.
    // Extracted from BMO #1722497 sdasdasdasd_001.mp4 using Bento4.
    // "mp4extract --payload-only moov/trak[1]/mdia/minf/stbl/stsd/mp4a/esds sdasdasdasd_001.mp4 /dev/stdout | xxd -i -c 15"
    let aac_esds = vec![
        0x03, 0x19, 0x00, 0x00, 0x00, 0x04, 0x11, 0x67, 0x15, 0x00, 0x02, 0x38, 0x00, 0x01, 0x0f,
        0xd0, 0x00, 0x00, 0xf5, 0x48, 0x05, 0x02, 0x13, 0x90, 0x06, 0x01, 0x02,
    ];
    let aac_dc_descriptor = &aac_esds[22..24];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, None);
    assert_eq!(es.audio_sample_rate, Some(22050));
    assert_eq!(es.audio_channel_count, Some(2));
    assert_eq!(es.codec_esds, aac_esds);
    assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
}

#[test]
fn read_esds_truncated_dsi() {
    // HE-AAC DSI truncated so the GASpecificConfig tail (frameLengthFlag /
    // dependsOnCoreCoder / extensionFlag) runs off the end of the 24-bit
    // payload, causing the bit reader to hit EOF.  Reduced from band-orion.de
    // (Firefox bug 2011644).
    //
    // DSI `2b 92 08` decodes as:
    //   AOT=5 (SBR, explicit signalling)
    //   samplingFrequencyIndex=7 (22050 Hz base)
    //   channelConfiguration=2 (stereo)
    //   extensionSamplingFrequencyIndex=4 (44100 Hz extended)
    //   inner AOT=2 (AAC-LC)
    // which leaves 2 bits remaining, one short of the extensionFlag.
    //
    // Before our fix read_ds_descriptor stored the parsed fields only after
    // the failing reads, so find_descriptor would swallow the BitReaderError
    // in non-strict mode and leave the ES_Descriptor with audio_sample_rate,
    // audio_channel_count and decoder_specific_data all unset — a "playable"
    // AAC track with no config, producing silent audio.
    let aac_esds = vec![
        0x03, 0x1a, // ES_Descriptor tag, len=26
        0x00, 0x00, 0x00, // ES_ID + flags
        0x04, 0x12, // DC_Descriptor tag, len=18
        0x40, 0x15, 0x00, 0x00, 0x00, // objType=AAC, streamType, bufferSize
        0x00, 0x00, 0x00, 0x00, // maxBitrate
        0x00, 0x00, 0x00, 0x00, // avgBitrate
        0x05, 0x03, 0x2b, 0x92, 0x08, // DSI: truncated HE-AAC
        0x06, 0x01, 0x02, // SL_Descriptor
    ];
    let aac_dc_descriptor = &aac_esds[22..25];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, Some(5));
    assert_eq!(es.audio_sample_rate, Some(22050));
    assert_eq!(es.audio_channel_count, Some(2));
    assert_eq!(es.codec_esds, aac_esds);
    assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
}

#[test]
fn read_esds_duplicate_dsi() {
    // Two DecSpecificInfo descriptors with identical AAC-LC 48 kHz stereo
    // payload (`11 90`).  Reduced from Firefox bug 1906838.
    //
    // In non-strict mode the parser must keep the first DSI and ignore the
    // second — matching what Chromium (media/formats/mp4/es_descriptor.cc)
    // and ffmpeg (libavformat/isom.c ff_mp4_read_dec_config_descr) do.
    // Before our fix the parser concatenated both DSI payloads and
    // overwrote audio_object_type / audio_sample_rate / audio_channel_count
    // with the second DSI's parsed values, which left the ES_Descriptor in
    // an inconsistent state when the two DSIs disagreed.
    let aac_esds = vec![
        0x03, 0x1d, // ES_Descriptor tag, len=29
        0x00, 0x00, 0x00, // ES_ID + flags
        0x04, 0x15, // DC_Descriptor tag, len=21
        0x40, 0x15, 0x00, 0x00, 0x00, // objType=AAC, streamType, bufferSize
        0x00, 0x00, 0x01, 0xf4, // maxBitrate
        0x00, 0x00, 0x01, 0xf4, // avgBitrate
        0x05, 0x02, 0x11, 0x90, // DSI #1 (kept)
        0x05, 0x02, 0x11, 0x90, // DSI #2 (ignored in non-strict)
        0x06, 0x01, 0x02, // SL_Descriptor
    ];
    let aac_dc_descriptor = &aac_esds[22..24];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, None);
    assert_eq!(es.audio_sample_rate, Some(48000));
    assert_eq!(es.audio_channel_count, Some(2));
    assert_eq!(es.codec_esds, aac_esds);
    // First DSI's bytes only — not the concatenation of both.
    assert_eq!(es.decoder_specific_data, aac_dc_descriptor);
}

#[test]
fn read_esds_duplicate_dsi_strict() {
    // In strict mode, the duplicate-DSI case is rejected with the
    // corresponding status rather than silently kept as "first wins".
    let aac_esds = vec![
        0x03, 0x1d, 0x00, 0x00, 0x00, 0x04, 0x15, 0x40, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
        0xf4, 0x00, 0x00, 0x01, 0xf4, 0x05, 0x02, 0x11, 0x90, 0x05, 0x02, 0x11, 0x90, 0x06, 0x01,
        0x02,
    ];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    match super::read_esds(&mut stream, ParseStrictness::Strict) {
        Err(Error::InvalidData(Status::EsdsDecSpecificInfoTagQuantity)) => {}
        other => panic!(
            "expected EsdsDecSpecificInfoTagQuantity in strict mode, got {:?}",
            other
        ),
    }
}

#[test]
fn read_esds_duplicate_dsi_disagreeing() {
    // Two DecSpecificInfo descriptors whose payloads disagree on sample rate
    // and channel count.  Locks in "first-wins" rather than "second-wins" or
    // "concatenate":
    //   DSI #1 `11 90` → AOT=2 (AAC-LC), SFI=3 (48 kHz), chCfg=2 (stereo)
    //   DSI #2 `12 88` → AOT=2 (AAC-LC), SFI=5 (32 kHz), chCfg=1 (mono)
    let aac_esds = vec![
        0x03, 0x1d, // ES_Descriptor tag, len=29
        0x00, 0x00, 0x00, // ES_ID + flags
        0x04, 0x15, // DC_Descriptor tag, len=21
        0x40, 0x15, 0x00, 0x00, 0x00, // objType=AAC, streamType, bufferSize
        0x00, 0x00, 0x01, 0xf4, // maxBitrate
        0x00, 0x00, 0x01, 0xf4, // avgBitrate
        0x05, 0x02, 0x11, 0x90, // DSI #1: 48 kHz stereo (kept)
        0x05, 0x02, 0x12, 0x88, // DSI #2: 32 kHz mono (ignored in non-strict)
        0x06, 0x01, 0x02, // SL_Descriptor
    ];
    let dsi1 = &aac_esds[22..24];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, None);
    // First DSI wins — not 32000 / 1 from DSI #2.
    assert_eq!(es.audio_sample_rate, Some(48000));
    assert_eq!(es.audio_channel_count, Some(2));
    assert_eq!(es.decoder_specific_data, dsi1);
}

#[test]
fn read_esds_truncated_dsi_pce() {
    // Truncated DSI with channel_configuration == 0 (program_config_element
    // signalling).  The PCE tail is needed to derive the channel count, so
    // the fix's early-store cannot populate audio_channel_count or the DSI
    // bytes — only AOT / extended_AOT / sample_rate.
    //
    // DSI `11 80` decodes as:
    //   AOT=2 (AAC-LC), SFI=3 (48 kHz), chCfg=0 (PCE)
    //   frameLengthFlag=1, dependsOnCoreCoder=0, extensionFlag=0
    // after which the 4-bit element_instance_tag read runs off the end.
    let aac_esds = vec![
        0x03, 0x19, // ES_Descriptor tag, len=25
        0x00, 0x00, 0x00, // ES_ID + flags
        0x04, 0x11, // DC_Descriptor tag, len=17
        0x40, 0x15, 0x00, 0x00, 0x00, // objType=AAC, streamType, bufferSize
        0x00, 0x00, 0x01, 0xf4, // maxBitrate
        0x00, 0x00, 0x01, 0xf4, // avgBitrate
        0x05, 0x02, 0x11, 0x80, // DSI: AAC-LC 48 kHz PCE, truncated mid-PCE
        0x06, 0x01, 0x02, // SL_Descriptor
    ];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(aac_esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, None);
    assert_eq!(es.audio_sample_rate, Some(48000));
    // PCE parsing hits EOF before deriving the channel count, so these stay
    // unset rather than guessing.
    assert_eq!(es.audio_channel_count, None);
    assert!(es.decoder_specific_data.is_empty());
}

#[test]
fn read_stsd_mp4v() {
    let mp4v = vec![
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xd0, 0x01, 0xe0, 0x00, 0x48,
        0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
        0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x4c, 0x65, 0x73, 0x64, 0x73, 0x00, 0x00, 0x00, 0x00,
        0x03, 0x3e, 0x00, 0x00, 0x1f, 0x04, 0x36, 0x20, 0x11, 0x01, 0x77, 0x00, 0x00, 0x03, 0xe8,
        0x00, 0x00, 0x03, 0xe8, 0x00, 0x05, 0x27, 0x00, 0x00, 0x01, 0xb0, 0x05, 0x00, 0x00, 0x01,
        0xb5, 0x0e, 0xcf, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x86, 0xe0, 0x00,
        0x2e, 0xa6, 0x60, 0x16, 0xf4, 0x01, 0xf4, 0x24, 0xc8, 0x01, 0xe5, 0x16, 0x84, 0x3c, 0x14,
        0x63, 0x06, 0x01, 0x02,
    ];
    #[cfg(not(feature = "mp4v"))]
    let esds_specific_data = &mp4v[90..];
    #[cfg(feature = "mp4v")]
    let esds_specific_data = &mp4v[112..151];
    println!("esds_specific_data {esds_specific_data:?}");

    let mut stream = make_box(BoxSize::Auto, b"mp4v", |s| s.append_bytes(mp4v.as_slice()));
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let sample_entry =
        super::read_video_sample_entry(&mut stream, super::ParseStrictness::Normal).unwrap();

    match sample_entry {
        super::SampleEntry::Video(v) => {
            assert_eq!(v.codec_type, super::CodecType::MP4V);
            assert_eq!(v.width, 720);
            assert_eq!(v.height, 480);
            match v.codec_specific {
                super::VideoCodecSpecific::ESDSConfig(esds_data) => {
                    assert_eq!(esds_data.as_slice(), esds_specific_data);
                }
                _ => panic!("it should be ESDSConfig!"),
            }
        }
        _ => panic!("it should be a video sample entry!"),
    }
}

#[test]
fn read_esds_one_byte_extension_descriptor() {
    let esds = vec![
        0x00, 0x03, 0x80, 0x1b, 0x00, 0x00, 0x00, 0x04, 0x80, 0x12, 0x40, 0x15, 0x00, 0x06, 0x00,
        0x00, 0x01, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x80, 0x02, 0x11, 0x90, 0x06, 0x01,
        0x02,
    ];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let es = super::read_esds(&mut stream, ParseStrictness::Normal).unwrap();

    assert_eq!(es.audio_codec, super::CodecType::AAC);
    assert_eq!(es.audio_object_type, Some(2));
    assert_eq!(es.extended_audio_object_type, None);
    assert_eq!(es.audio_sample_rate, Some(48000));
    assert_eq!(es.audio_channel_count, Some(2));
}

#[test]
fn read_esds_byte_extension_descriptor() {
    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .B16(0x0003)
            .B16(0x8181) // extension byte length 0x81
            .append_repeated(00x81)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    match super::read_esds(&mut stream, ParseStrictness::Normal) {
        Ok(_) => (),
        _ => panic!("fail to parse descriptor extension byte length"),
    }
}

#[test]
fn read_f4v_stsd() {
    let mut stream = make_box(BoxSize::Auto, b".mp3", |s| {
        s.append_repeated(06)
            .B16(1)
            .B16(0)
            .append_repeated(06)
            .B16(2)
            .B16(16)
            .append_repeated(04)
            .B32(48000 << 16)
    });

    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    let sample_entry = super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal)
        .expect("failed to read f4v stsd atom");
    match sample_entry {
        super::SampleEntry::Audio(sample_entry) => {
            assert_eq!(sample_entry.codec_type, super::CodecType::MP3)
        }
        _ => panic!("fail to read audio sample enctry"),
    }
}

#[test]
fn unknown_video_sample_entry() {
    let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| s.append_repeated(016)).into_inner();
    let mut stream = make_box(BoxSize::Auto, b"xxxx", |s| {
        s.append_repeated(06)
            .B16(1)
            .append_repeated(016)
            .B16(0)
            .B16(0)
            .append_repeated(014)
            .append_repeated(032)
            .append_repeated(04)
            .append_bytes(unknown_codec.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    match super::read_video_sample_entry(&mut stream, super::ParseStrictness::Normal) {
        Ok(super::SampleEntry::Unknown) => (),
        _ => panic!("expected a different error result"),
    }
}

#[test]
fn unknown_audio_sample_entry() {
    let unknown_codec = make_box(BoxSize::Auto, b"yyyy", |s| s.append_repeated(016)).into_inner();
    let mut stream = make_box(BoxSize::Auto, b"xxxx", |s| {
        s.append_repeated(06)
            .B16(1)
            .B32(0)
            .B32(0)
            .B16(2)
            .B16(16)
            .B16(0)
            .B16(0)
            .B32(48000 << 16)
            .append_bytes(unknown_codec.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    match super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal) {
        Ok(super::SampleEntry::Unknown) => (),
        _ => panic!("expected a different error result"),
    }
}

#[test]
fn read_esds_invalid_descriptor() {
    // tag 0x06, 0xff, 0x7f is incorrect.
    let esds = vec![
        0x03, 0x80, 0x80, 0x80, 0x22, 0x00, 0x00, 0x00, 0x04, 0x80, 0x80, 0x80, 0x14, 0x40, 0x01,
        0x00, 0x04, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x05, 0x80, 0x80, 0x80,
        0x02, 0xe8, 0x35, 0x06, 0xff, 0x7f, 0x00, 0x00,
    ];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    match super::read_esds(&mut stream, ParseStrictness::Normal) {
        Err(Error::InvalidData(s)) => assert_eq!(s, Status::EsdsBadDescriptor),
        _ => panic!("unexpected result with invalid descriptor"),
    }
}

#[test]
fn read_esds_redundant_descriptor() {
    // the '2' at the end is redundant data.
    let esds = vec![
        32501041964210000000011190521816612,
    ];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    match super::read_esds(&mut stream, ParseStrictness::Normal) {
        Ok(esds) => assert_eq!(esds.audio_codec, super::CodecType::AAC),
        _ => panic!("unexpected result with invalid descriptor"),
    }
}

#[test]
fn read_esds_multiple_descriptors() {
    // Permit multiple descriptors in non-strict mode.
    // Extracted from BMO #1936124 using Bento4.
    // "mp4extract --payload-only moov/trak[0]/mdia/minf/stbl/stsd/mp4a/esds bug1936124.mp4 /dev/stdout | xxd -i -c 15"
    let esds = vec![
        0x03, 0x1d, 0x00, 0x00, 0x00, 0x04, 0x15, 0x40, 0x15, 0x00, 0x06, 0x00, 0x00, 0x01, 0x77,
        0x00, 0x00, 0x01, 0x77, 0x00, 0x05, 0x02, 0x11, 0x90, 0x05, 0x02, 0x11, 0x90, 0x06, 0x01,
        0x02,
    ];

    let mut stream = make_box(BoxSize::Auto, b"esds", |s| {
        s.B32(0// reserved
            .append_bytes(esds.as_slice())
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    match super::read_esds(&mut stream, ParseStrictness::Normal) {
        Ok(esds) => assert_eq!(esds.audio_codec, super::CodecType::AAC),
        _ => panic!("unexpected result with multiple descriptors"),
    }
}

#[test]
fn read_stsd_lpcm() {
    // Extract from sample converted by ffmpeg.
    // "ffmpeg -i ./gizmo-short.mp4 -acodec pcm_s16le -ar 96000 -vcodec copy -f mov gizmo-short.mov"
    let lpcm = vec![
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x03, 0x00, 0x10, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x48, 0x40, 0xf7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x02,
        0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x63, 0x68, 0x61, 0x6e, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ];

    let mut stream = make_box(BoxSize::Auto, b"lpcm", |s| s.append_bytes(lpcm.as_slice()));
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();

    let sample_entry =
        super::read_audio_sample_entry(&mut stream, ParseStrictness::Normal).unwrap();

    match sample_entry {
        #[allow(clippy::float_cmp)] // The float comparison below is valid and intended.
        super::SampleEntry::Audio(a) => {
            assert_eq!(a.codec_type, super::CodecType::LPCM);
            assert_eq!(a.samplerate, 96000.0);
            assert_eq!(a.channelcount, 1);
            match a.codec_specific {
                super::AudioCodecSpecific::LPCM => (),
                _ => panic!("it should be LPCM!"),
            }
        }
        _ => panic!("it should be a audio sample entry!"),
    }
}

#[test]
fn read_to_end_() {
    let mut src = b"1234567890".take(5);
    let buf = src.read_into_try_vec().unwrap();
    assert_eq!(buf.len(), 5);
    assert_eq!(buf, b"12345".as_ref());
}

#[test]
fn read_to_end_oom() {
    let mut src = b"1234567890".take(isize::MAX.try_into().expect("isize < u64"));
    assert!(src.read_into_try_vec().is_err());
}

#[test]
fn read_mdcv() {
    // Synthetic mdcv box. Wire order is G, B, R (x then y for each primary),
    // remapped by read_mdcv to struct indices R[0], G[1], B[2].
    let mut stream = make_box(BoxSize::Auto, b"mdcv", |s| {
        s // Gx, Gy, Bx, By, Rx, Ry (wire order)
            .B16(14600// Gx
            .B16(59210// Gy
            .B16(7500// Bx
            .B16(3000// By
            .B16(35400// Rx
            .B16(14600// Ry
            // white_point_x, white_point_y
            .B16(15635)
            .B16(16450)
            // max_display_mastering_luminance, min_display_mastering_luminance
            .B32(10000000)
            .B32(50)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(
        stream.head.name,
        super::BoxType::MasteringDisplayColourVolumeBox
    );
    let mdcv = super::read_mdcv(&mut stream).unwrap();
    assert_eq!(mdcv.display_primaries_x, [35400146007500]);
    assert_eq!(mdcv.display_primaries_y, [14600592103000]);
    assert_eq!(mdcv.white_point_x, 15635);
    assert_eq!(mdcv.white_point_y, 16450);
    assert_eq!(mdcv.max_display_mastering_luminance, 10000000);
    assert_eq!(mdcv.min_display_mastering_luminance, 50);
}

#[test]
fn read_clli() {
    let mut stream = make_box(BoxSize::Auto, b"clli", |s| s.B16(1000).B16(400));
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, super::BoxType::ContentLightLevelBox);
    let clli = super::read_clli(&mut stream).unwrap();
    assert_eq!(clli.max_content_light_level, 1000);
    assert_eq!(clli.max_pic_average_light_level, 400);
}

#[test]
fn read_colr_nclx() {
    let mut stream = make_box(BoxSize::Auto, b"colr", |s| {
        s.append_bytes(b"nclx").B16(1).B16(1).B16(1).B8(0x80)
    });
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    assert_eq!(stream.head.name, super::BoxType::ColourInformationBox);
    let colour_type = super::be_u32(&mut stream).unwrap().to_be_bytes();
    match super::read_colr(&mut stream, colour_type, ParseStrictness::Strict).unwrap() {
        super::ParsedColourInformation::Supported(super::ColourInformation::Nclx(nclx)) => {
            assert_eq!(nclx.colour_primaries, 1);
            assert_eq!(nclx.transfer_characteristics, 1);
            assert_eq!(nclx.matrix_coefficients, 1);
            assert!(nclx.full_range_flag);
        }
        _ => panic!("expected nclx colour information"),
    }
}

#[test]
fn read_colr_nclx_missing_full_range_flag() {
    // An 18-byte nclx colr box omitting the trailing full_range_flag/reserved
    // byte, as found in the wild (bug 2047239). The layout matches the QTFF
    // 'nclc' colour type.
    let make_stream = || {
        make_box(BoxSize::Auto, b"colr", |s| {
            s.append_bytes(b"nclx").B16(1).B16(1).B16(1)
        })
    };

    for strictness in [ParseStrictness::Permissive, ParseStrictness::Normal] {
        let mut stream = make_stream();
        let mut iter = super::BoxIter::new(&mut stream);
        let mut stream = iter.next_box().unwrap().unwrap();
        let colour_type = super::be_u32(&mut stream).unwrap().to_be_bytes();
        let colr = super::read_colr(&mut stream, colour_type, strictness)
            .expect("nclx missing full_range_flag should parse outside Strict");
        match colr {
            super::ParsedColourInformation::Supported(super::ColourInformation::Nclx(nclx)) => {
                assert!(
                    !nclx.full_range_flag,
                    "missing full_range_flag should default to limited range"
                );
            }
            _ => panic!("expected nclx colour information"),
        }
    }

    let mut stream = make_stream();
    let mut iter = super::BoxIter::new(&mut stream);
    let mut stream = iter.next_box().unwrap().unwrap();
    let colour_type = super::be_u32(&mut stream).unwrap().to_be_bytes();
    match super::read_colr(&mut stream, colour_type, ParseStrictness::Strict) {
        Err(Error::InvalidData(s)) => assert_eq!(s, Status::ColrBadSize),
        Ok(_) => panic!("nclx missing full_range_flag should be rejected under Strict"),
        Err(e) => panic!("unexpected error {:?}", e),
    }
}

Messung V0.5 in Prozent
C=89 H=93 G=90

¤ Dauer der Verarbeitung: 0.26 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002