123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173 |
- 'use strict';
- /*
- ======== A Handy Little QUnit Reference ========
- http://api.qunitjs.com/
- Test methods:
- module(name, {[setup][ ,teardown]})
- QUnit.test(name, callback)
- expect(numberOfAssertions)
- stop(increment)
- start(decrement)
- Test assertions:
- assert.ok(value, [message])
- assert.equal(actual, expected, [message])
- notEqual(actual, expected, [message])
- assert.deepEqual(actual, expected, [message])
- notDeepEqual(actual, expected, [message])
- assert.strictEqual(actual, expected, [message])
- notStrictEqual(actual, expected, [message])
- throws(block, [expected], [message])
- */
- var
- mp4 = require('../lib/mp4'),
- mp4Helpers = require('./utils/mp4-helpers'),
- QUnit = require('qunit'),
- window = require('global/window'),
- typeBytes = mp4Helpers.typeBytes,
- box = mp4Helpers.box,
- unityMatrix = mp4Helpers.unityMatrix,
- BigInt = window.BigInt || Number,
- mvhd0 = box('mvhd',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // creation_time
- 0x00, 0x00, 0x00, 0x02, // modification_time
- 0x00, 0x00, 0x00, 0x3c, // timescale
- 0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
- 0x00, 0x01, 0x00, 0x00, // 1.0 rate
- 0x01, 0x00, // 1.0 volume
- 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00, // reserved
- unityMatrix,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, // pre_defined
- 0x00, 0x00, 0x00, 0x02),
- tkhd0 = box('tkhd',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x02, // creation_time
- 0x00, 0x00, 0x00, 0x03, // modification_time
- 0x00, 0x00, 0x00, 0x01, // track_ID
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, // layer
- 0x00, 0x00, // alternate_group
- 0x00, 0x00, // non-audio track volume
- 0x00, 0x00, // reserved
- unityMatrix,
- 0x01, 0x2c, 0x80, 0x00, // 300.5 in 16.16 fixed point
- 0x00, 0x96, 0x80, 0x00), // 150.5 in 16.16 fixed point
- mdhd0 = box('mdhd',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x02, // creation_time
- 0x00, 0x00, 0x00, 0x03, // modification_time
- 0x00, 0x00, 0x00, 0x3c, // timescale
- 0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
- 0x15, 0xc7, // 'eng' language
- 0x00, 0x00);
- QUnit.module('MP4 Inspector');
- QUnit.test('produces an empty array for empty input', function(assert) {
- assert.strictEqual(mp4.tools.inspect(new Uint8Array([])).length, 0, 'returned an empty array');
- });
- QUnit.test('can parse a Box', function(assert) {
- var box = new Uint8Array([
- 0x00, 0x00, 0x00, 0x00, // size 0
- 0x00, 0x00, 0x00, 0x00 // boxtype 0
- ]);
- assert.deepEqual(mp4.tools.inspect(box), [{
- type: '\u0000\u0000\u0000\u0000',
- size: 0,
- data: box.subarray(box.byteLength)
- }], 'parsed a Box');
- });
- QUnit.test('can parse an ftyp', function(assert) {
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(box('ftyp',
- 0x61, 0x76, 0x63, 0x31, // major brand
- 0x00, 0x00, 0x00, 0x02, // minor version
- 98, 111, 111, 112, // compatible brands
- 98, 101, 101, 112 // compatible brands
- ))), [{
- type: 'ftyp',
- size: 4 * 6,
- majorBrand: 'avc1',
- minorVersion: 2,
- compatibleBrands: ['boop', 'beep']
- }], 'parsed an ftyp');
- });
- QUnit.test('can parse a pdin', function(assert) {
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(box('pdin',
- 0x01, // version 1
- 0x01, 0x02, 0x03, // flags
- 0x00, 0x00, 0x04, 0x00, // 1024 = 0x400 bytes/second rate
- 0x00, 0x00, 0x00, 0x01 // initial delay
- ))), [{
- size: 20,
- type: 'pdin',
- version: 1,
- flags: new Uint8Array([1, 2, 3]),
- rate: 1024,
- initialDelay: 1
- }], 'parsed a pdin');
- });
- QUnit.test('can parse an mdat', function(assert) {
- var mdat = new Uint8Array(box('mdat',
- 0, 0, 0, 4, // length
- 0x01, 0x02, 0x03, 0x04 // data
- ));
- assert.deepEqual(mp4.tools.inspect(mdat), [{
- size: 16,
- type: 'mdat',
- nals: [
- 'slice_layer_without_partitioning_rbsp'
- ],
- byteLength: 8
- }], 'parsed an mdat');
- });
- QUnit.test('can parse a free or skip', function(assert) {
- var
- free = new Uint8Array(box('free',
- 0x01, 0x02, 0x03, 0x04)), // data
- skip = new Uint8Array(box('skip',
- 0x01, 0x02, 0x03, 0x04)); // data
- assert.deepEqual(mp4.tools.inspect(free), [{
- size: 12,
- type: 'free',
- data: free.subarray(free.byteLength - 4)
- }], 'parsed a free');
- assert.deepEqual(mp4.tools.inspect(skip), [{
- size: 12,
- type: 'skip',
- data: skip.subarray(skip.byteLength - 4)
- }], 'parsed a skip');
- });
- QUnit.test('can parse a version 0 mvhd', function(assert) {
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(mvhd0)), [{
- type: 'mvhd',
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- creationTime: new Date(1000 - 2082844800000),
- modificationTime: new Date(2000 - 2082844800000),
- timescale: 60,
- duration: 600,
- rate: 1,
- volume: 1,
- matrix: new Uint32Array(unityMatrix),
- size: 108,
- nextTrackId: 2
- }]);
- });
- QUnit.test('can parse a version 0 tkhd', function(assert) {
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(tkhd0)), [{
- type: 'tkhd',
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- creationTime: new Date(2000 - 2082844800000),
- modificationTime: new Date(3000 - 2082844800000),
- size: 92,
- trackId: 1,
- duration: 600,
- layer: 0,
- alternateGroup: 0,
- volume: 0,
- matrix: new Uint32Array(unityMatrix),
- width: 300.5,
- height: 150.5
- }]);
- });
- QUnit.test('can parse a version 0 mdhd', function(assert) {
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(mdhd0)), [{
- type: 'mdhd',
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- creationTime: new Date(2000 - 2082844800000),
- modificationTime: new Date(3000 - 2082844800000),
- size: 32,
- timescale: 60,
- duration: 600,
- language: 'eng'
- }]);
- });
- QUnit.test('can parse a moov', function(assert) {
- var data = mp4Helpers.sampleMoov;
- QUnit.dump.maxDepth = 100;
- var result = QUnit.dump.parse(mp4.tools.inspect(new Uint8Array(data)));
- var expected = QUnit.dump.parse([{
- type: 'moov',
- size: 1129,
- boxes: [{
- type: 'mvhd',
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- creationTime: new Date(1000 - 2082844800000),
- modificationTime: new Date(2000 - 2082844800000),
- timescale: 1000,
- duration: 600,
- rate: 1,
- size: 120,
- volume: 1,
- matrix: new Uint32Array(unityMatrix),
- nextTrackId: 2
- }, {
- type: 'trak',
- size: 519,
- boxes: [{
- type: 'tkhd',
- flags: new Uint8Array([0, 0, 0]),
- version: 1,
- creationTime: new Date(2000 - 2082844800000),
- modificationTime: new Date(3000 - 2082844800000),
- size: 104,
- trackId: 1,
- duration: 600,
- layer: 0,
- alternateGroup: 0,
- volume: 0,
- matrix: new Uint32Array(unityMatrix),
- width: 300,
- height: 150
- }, {
- type: 'edts',
- size: 36,
- boxes: [{
- type: 'elst',
- size: 28,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- edits: [{
- segmentDuration: 0,
- mediaTime: 1024,
- mediaRate: 1.5
- }]
- }]
- }, {
- type: 'mdia',
- size: 371,
- boxes: [{
- type: 'mdhd',
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- creationTime: new Date(2000 - 2082844800000),
- modificationTime: new Date(3000 - 2082844800000),
- timescale: 90e3,
- duration: 600,
- language: 'eng',
- size: 44
- }, {
- type: 'hdlr',
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- handlerType: 'vide',
- name: 'one',
- size: 37
- }, {
- type: 'minf',
- size: 282,
- boxes: [{
- type: 'dinf',
- size: 36,
- boxes: [{
- type: 'dref',
- size: 28,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- dataReferences: [{
- type: 'url ',
- size: 12,
- version: 0,
- flags: new Uint8Array([0, 0, 1])
- }]
- }]
- }, {
- type: 'stbl',
- size: 238,
- boxes: [{
- type: 'stsd',
- size: 114,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- sampleDescriptions: [{
- config: [
- {
- avcLevelIndication: 13,
- avcProfileIndication: 77,
- configurationVersion: 0,
- lengthSizeMinusOne: 0,
- pps: [],
- profileCompatibility: 64,
- size: 0,
- sps: [],
- type: 'avcC'
- }
- ],
- dataReferenceIndex: 0,
- depth: 0,
- frameCount: 0,
- height: 0,
- horizresolution: 0,
- size: 98,
- type: 'avc1',
- vertresolution: 0,
- width: 0
- }
- ]
- }, {
- type: 'stts',
- size: 24,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- timeToSamples: [{
- sampleCount: 1,
- sampleDelta: 1
- }]
- }, {
- type: 'stsc',
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- sampleToChunks: [{
- firstChunk: 2,
- samplesPerChunk: 3,
- sampleDescriptionIndex: 1
- }],
- size: 28
- }, {
- type: 'stco',
- size: 20,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- chunkOffsets: [1]
- }, {
- type: 'stss',
- size: 20,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- syncSamples: [1]
- }, {
- type: 'ctts',
- size: 24,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- compositionOffsets: [
- { sampleCount: 1, sampleOffset: 1 }
- ]
- }]
- }]
- }]
- }]
- }, {
- type: 'trak',
- size: 482,
- boxes: [{
- type: 'tkhd',
- flags: new Uint8Array([0, 0, 0]),
- version: 1,
- creationTime: new Date(2000 - 2082844800000),
- modificationTime: new Date(3000 - 2082844800000),
- size: 104,
- trackId: 2,
- duration: 600,
- layer: 0,
- alternateGroup: 0,
- volume: 0,
- matrix: new Uint32Array(unityMatrix),
- width: 300,
- height: 150
- }, {
- type: 'edts',
- size: 44,
- boxes: [{
- type: 'elst',
- size: 36,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- edits: [{
- segmentDuration: 0,
- mediaTime: BigInt('0x1000000000000000'),
- mediaRate: 1.5
- }]
- }]
- }, {
- type: 'mdia',
- size: 326,
- boxes: [{
- type: 'mdhd',
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- creationTime: new Date(2000 - 2082844800000),
- modificationTime: new Date(3000 - 2082844800000),
- timescale: 90e3,
- duration: 600,
- language: 'eng',
- size: 44
- }, {
- type: 'hdlr',
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- handlerType: 'soun',
- name: 'one',
- size: 37
- }, {
- type: 'minf',
- size: 237,
- boxes: [{
- type: 'dinf',
- size: 36,
- boxes: [{
- type: 'dref',
- size: 28,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- dataReferences: [{
- type: 'url ',
- size: 12,
- version: 0,
- flags: new Uint8Array([0, 0, 1])
- }]
- }]
- }, {
- type: 'stbl',
- size: 193,
- boxes: [{
- type: 'stsd',
- size: 89,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- sampleDescriptions: [{
- channelcount: 0,
- dataReferenceIndex: 0,
- samplerate: 0,
- samplesize: 0,
- size: 73,
- streamDescriptor: {
- decoderConfig: {
- avgBitrate: 0,
- bufferSize: 0,
- decoderConfigDescriptor: {
- audioObjectType: 0,
- channelConfiguration: 0,
- length: 0,
- samplingFrequencyIndex: 0,
- tag: 0
- },
- maxBitrate: 0,
- objectProfileIndication: 64,
- streamType: 2
- },
- esId: 0,
- flags: {
- 0: 0,
- 1: 0,
- 2: 0
- },
- size: 0,
- streamPriority: 0,
- type: 'esds',
- version: 0
- },
- type: 'mp4a'
- }]
- }, {
- type: 'stts',
- size: 24,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- timeToSamples: [{
- sampleCount: 1,
- sampleDelta: 1
- }]
- }, {
- type: 'stsc',
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- sampleToChunks: [{
- firstChunk: 2,
- samplesPerChunk: 3,
- sampleDescriptionIndex: 1
- }],
- size: 28
- }, {
- type: 'ctts',
- size: 24,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- compositionOffsets: [
- { sampleCount: 1, sampleOffset: -1 }
- ]
- }, {
- type: 'stco',
- size: 20,
- version: 1,
- flags: new Uint8Array([0, 0, 0]),
- chunkOffsets: [1]
- }]
- }]
- }]
- }]
- }]
- }]);
- assert.equal(result, expected, 'can parse moov');
- });
- QUnit.test('can parse an mvex', function(assert) {
- var mvex =
- box('mvex',
- box('trex',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // track_ID
- 0x00, 0x00, 0x00, 0x01, // default_sample_description_index
- 0x00, 0x00, 0x00, 0x02, // default_sample_duration
- 0x00, 0x00, 0x00, 0x03, // default_sample_size
- 0x00, 0x61, 0x00, 0x01)); // default_sample_flags
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(mvex)), [{
- type: 'mvex',
- size: 40,
- boxes: [{
- type: 'trex',
- size: 32,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- trackId: 1,
- defaultSampleDescriptionIndex: 1,
- defaultSampleDuration: 2,
- defaultSampleSize: 3,
- sampleDependsOn: 0,
- sampleIsDependedOn: 1,
- sampleHasRedundancy: 2,
- samplePaddingValue: 0,
- sampleIsDifferenceSample: true,
- sampleDegradationPriority: 1
- }]
- }], 'parsed an mvex');
- });
- QUnit.test('can parse a video stsd', function(assert) {
- var data = box('stsd',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01,
- box('avc1',
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, // reserved
- 0x00, 0x01, // data_reference_index
- 0x00, 0x00, // pre_defined
- 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, // pre_defined
- 0x01, 0x2c, // width = 300
- 0x00, 0x96, // height = 150
- 0x00, 0x48, 0x00, 0x00, // horizresolution
- 0x00, 0x48, 0x00, 0x00, // vertresolution
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x01, // frame_count
- 0x04,
- typeBytes('avc1'),
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, // compressorname
- 0x00, 0x18, // depth = 24
- 0x11, 0x11, // pre_defined
- box('avcC',
- 0x01, // configurationVersion
- 0x00, // AVCProfileIndication??
- 0x00, // profile_compatibility
- 0x00, // AVCLevelIndication
- 0x1c, // lengthSizeMinusOne
- 0xe1, // numOfSequenceParameterSets
- 0x00, 0x01, // sequenceParameterSetLength
- 0x00, // "SPS"
- 0x02, // numOfPictureParameterSets
- 0x00, 0x02, // pictureParameterSetLength
- 0x01, 0x02, // "PPS"
- 0x00, 0x01, // pictureParameterSetLength
- 0xff), // "PPS"
- box('btrt',
- 0x00, 0x00, 0x00, 0x00, // bufferSizeDB
- 0x00, 0x00, 0x00, 0x01, // maxBitrate
- 0x00, 0x00, 0x00, 0x01), // avgBitrate
- box('pasp',
- 0x00, 0x00, 0x00, 0x01, // hSpacing
- 0x00, 0x00, 0x00, 0x01))); // vSpacing
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)), [{
- type: 'stsd',
- size: 163,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- sampleDescriptions: [{
- type: 'avc1',
- size: 147,
- dataReferenceIndex: 1,
- width: 300,
- height: 150,
- horizresolution: 72,
- vertresolution: 72,
- frameCount: 1,
- depth: 24,
- config: [{
- type: 'avcC',
- size: 25,
- configurationVersion: 1,
- avcProfileIndication: 0,
- profileCompatibility: 0,
- avcLevelIndication: 0,
- lengthSizeMinusOne: 0,
- sps: [new Uint8Array(1)],
- pps: [new Uint8Array([1, 2]),
- new Uint8Array([0xff])]
- }, {
- type: 'btrt',
- size: 20,
- bufferSizeDB: 0,
- maxBitrate: 1,
- avgBitrate: 1
- }, {
- type: 'pasp',
- size: 16,
- data: new Uint8Array([0, 0, 0, 1, 0, 0, 0, 1])
- }]
- }]
- }]);
- });
- QUnit.test('can parse an audio stsd', function(assert) {
- var data = box('stsd',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- box('mp4a',
- 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, // reserved
- 0x00, 0x01, // data_reference_index
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x02, // channelcount
- 0x00, 0x10, // samplesize
- 0x00, 0x00, // pre_defined
- 0x00, 0x00, // reserved
- 0xbb, 0x80, 0x00, 0x00, // samplerate, fixed-point 16.16
- box('esds',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x03, // tag, ES_DescrTag
- 0x00, // length
- 0x00, 0x01, // ES_ID
- 0x00, // streamDependenceFlag, URL_Flag, reserved, streamPriority
- // DecoderConfigDescriptor
- 0x04, // tag, DecoderConfigDescrTag
- 0x0d, // length
- 0x40, // objectProfileIndication, AAC Main
- 0x15, // streamType, AudioStream. upstream, reserved
- 0x00, 0x00, 0xff, // bufferSizeDB
- 0x00, 0x00, 0x00, 0xff, // maxBitrate
- 0x00, 0x00, 0x00, 0xaa, // avgBitrate
- // DecoderSpecificInfo
- 0x05, // tag, DecoderSpecificInfoTag
- 0x02, // length
- // audioObjectType, samplingFrequencyIndex, channelConfiguration
- 0x11, 0x90,
- // GASpecificConfig
- 0x06, 0x01, 0x02)));
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)), [{
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- type: 'stsd',
- size: 91,
- sampleDescriptions: [{
- type: 'mp4a',
- dataReferenceIndex: 1,
- channelcount: 2,
- samplesize: 16,
- samplerate: 48000,
- size: 75,
- streamDescriptor: {
- type: 'esds',
- version: 0,
- size: 39,
- flags: new Uint8Array([0, 0, 0]),
- esId: 1,
- streamPriority: 0,
- decoderConfig: {
- objectProfileIndication: 0x40,
- streamType: 0x05,
- bufferSize: 0xff,
- maxBitrate: 0xff,
- avgBitrate: 0xaa,
- decoderConfigDescriptor: {
- tag: 5,
- length: 2,
- audioObjectType: 2,
- samplingFrequencyIndex: 3,
- channelConfiguration: 2
- }
- }
- }
- }]
- }], 'parsed an audio stsd');
- });
- QUnit.test('can parse an styp', function(assert) {
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(box('styp',
- 0x61, 0x76, 0x63, 0x31, // major brand
- 0x00, 0x00, 0x00, 0x02, // minor version
- 98, 111, 111, 112 // compatible brands
- ))), [{
- type: 'styp',
- size: 4 * 5,
- majorBrand: 'avc1',
- minorVersion: 2,
- compatibleBrands: ['boop']
- }], 'parsed an styp');
- });
- QUnit.test('can parse a vmhd', function(assert) {
- var data = box('vmhd',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, // graphicsmode
- 0x00, 0x00,
- 0x00, 0x00,
- 0x00, 0x00); // opcolor
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'vmhd',
- size: 20,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- graphicsmode: 0,
- opcolor: new Uint16Array([0, 0, 0])
- }]);
- });
- QUnit.test('can parse an stsz', function(assert) {
- var data = box('stsz',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00, // sample_size
- 0x00, 0x00, 0x00, 0x03, // sample_count
- 0x00, 0x00, 0x00, 0x01, // entry_size
- 0x00, 0x00, 0x00, 0x02, // entry_size
- 0x00, 0x00, 0x00, 0x03); // entry_size
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'stsz',
- size: 32,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- sampleSize: 0,
- entries: [1, 2, 3]
- }]);
- });
- QUnit.test('can parse a moof', function(assert) {
- var data = box('moof',
- box('mfhd',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x04), // sequence_number
- box('traf',
- box('tfhd',
- 0x00, // version
- 0x00, 0x00, 0x3b, // flags
- 0x00, 0x00, 0x00, 0x01, // track_ID
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, // base_data_offset
- 0x00, 0x00, 0x00, 0x02, // sample_description_index
- 0x00, 0x00, 0x00, 0x03, // default_sample_duration,
- 0x00, 0x00, 0x00, 0x04, // default_sample_size
- 0x00, 0x00, 0x00, 0x05))); // default_sample_flags
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'moof',
- size: 72,
- boxes: [{
- type: 'mfhd',
- size: 16,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- sequenceNumber: 4
- },
- {
- type: 'traf',
- size: 48,
- boxes: [{
- type: 'tfhd',
- version: 0,
- size: 40,
- flags: new Uint8Array([0x00, 0, 0x3b]),
- trackId: 1,
- baseDataOffset: 1,
- sampleDescriptionIndex: 2,
- defaultSampleDuration: 3,
- defaultSampleSize: 4,
- defaultSampleFlags: 5
- }]
- }]
- }]);
- });
- QUnit.test('can parse a trun', function(assert) {
- var data = box('trun',
- 0x00, // version
- 0x00, 0x0b, 0x05, // flags
- 0x00, 0x00, 0x00, 0x02, // sample_count
- 0x00, 0x00, 0x00, 0x01, // data_offset
- // first_sample_flags
- // r:0000 il:10 sdo:01 sido:10 shr:01 spv:111 snss:1
- // dp:1111 1110 1101 1100
- 0x09, 0x9f, 0xfe, 0xdc,
- 0x00, 0x00, 0x00, 0x09, // sample_duration
- 0x00, 0x00, 0x00, 0xff, // sample_size
- 0x00, 0x00, 0x00, 0x00, // sample_composition_time_offset
- 0x00, 0x00, 0x00, 0x08, // sample_duration
- 0x00, 0x00, 0x00, 0xfe, // sample_size
- 0x00, 0x00, 0x00, 0x00); // sample_composition_time_offset
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'trun',
- version: 0,
- size: 48,
- flags: new Uint8Array([0, 0x0b, 0x05]),
- dataOffset: 1,
- samples: [{
- duration: 9,
- size: 0xff,
- flags: {
- isLeading: 2,
- dependsOn: 1,
- isDependedOn: 2,
- hasRedundancy: 1,
- paddingValue: 7,
- isNonSyncSample: 1,
- degradationPriority: 0xfedc
- },
- compositionTimeOffset: 0
- }, {
- duration: 8,
- size: 0xfe,
- compositionTimeOffset: 0
- }]
- }]);
- });
- QUnit.test('can parse a trun with per-sample flags', function(assert) {
- var data = box('trun',
- 0x00, // version
- 0x00, 0x0f, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // sample_count
- 0x00, 0x00, 0x00, 0x09, // sample_duration
- 0x00, 0x00, 0x00, 0xff, // sample_size
- // sample_flags
- // r:0000 il:00 sdo:01, sido:11 shr:00 spv:010 snss:0
- // dp: 0001 0010 0011 0100
- 0x01, 0xc4, 0x12, 0x34,
- 0x00, 0x00, 0x00, 0x00); // sample_composition_time_offset
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'trun',
- version: 0,
- size: 32,
- flags: new Uint8Array([0, 0x0f, 0x00]),
- samples: [{
- duration: 9,
- size: 0xff,
- flags: {
- isLeading: 0,
- dependsOn: 1,
- isDependedOn: 3,
- hasRedundancy: 0,
- paddingValue: 2,
- isNonSyncSample: 0,
- degradationPriority: 0x1234
- },
- compositionTimeOffset: 0
- }]
- }]);
- });
- QUnit.test('can parse an sdtp', function(assert) {
- var data = box('sdtp',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- // reserved + sample_depends_on +
- // sample_is_dependend_on + sample_has_redundancy
- 0x15,
- // reserved + sample_depends_on +
- // sample_is_dependend_on + sample_has_redundancy
- 0x27);
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)), [{
- type: 'sdtp',
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- size: 14,
- samples: [{
- dependsOn: 1,
- isDependedOn: 1,
- hasRedundancy: 1
- }, {
- dependsOn: 2,
- isDependedOn: 1,
- hasRedundancy: 3
- }]
- }]);
- });
- QUnit.test('can parse a sidx', function(assert) {
- var data = box('sidx',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x02, // reference_ID
- 0x00, 0x00, 0x00, 0x01, // timescale
- 0x01, 0x02, 0x03, 0x04, // earliest_presentation_time
- 0x00, 0x00, 0x00, 0x00, // first_offset
- 0x00, 0x00, // reserved
- 0x00, 0x02, // reference_count
- // first reference
- 0x80, 0x00, 0x00, 0x07, // reference_type(1) + referenced_size(31)
- 0x00, 0x00, 0x00, 0x08, // subsegment_duration
- 0x80, 0x00, 0x00, 0x09, // starts_with_SAP(1) + SAP_type(3) + SAP_delta_time(28)
- // second reference
- 0x00, 0x00, 0x00, 0x03, // reference_type(1) + referenced_size(31)
- 0x00, 0x00, 0x00, 0x04, // subsegment_duration
- 0x10, 0x00, 0x00, 0x05 // starts_with_SAP(1) + SAP_type(3) + SAP_delta_time(28)
- );
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'sidx',
- version: 0,
- flags: new Uint8Array([0, 0x00, 0x00]),
- timescale: 1,
- earliestPresentationTime: 0x01020304,
- firstOffset: 0,
- referenceId: 2,
- size: 56,
- references: [{
- referenceType: 1,
- referencedSize: 7,
- subsegmentDuration: 8,
- startsWithSap: true,
- sapType: 0,
- sapDeltaTime: 9
- }, {
- referenceType: 0,
- referencedSize: 3,
- subsegmentDuration: 4,
- startsWithSap: false,
- sapType: 1,
- sapDeltaTime: 5
- }]
- }]);
- });
- QUnit.test('can parse a version 1 sidx', function(assert) {
- var data = box('sidx',
- 0x01, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x02, // reference_ID
- 0x00, 0x00, 0x00, 0x01, // timescale
- 0x00, 0x00, 0x00, 0x00, // earliest_presentation_time
- 0x01, 0x02, 0x03, 0x04,
- 0x00, 0x00, 0x00, 0x00, // first_offset
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, // reserved
- 0x00, 0x02, // reference_count
- // first reference
- 0x80, 0x00, 0x00, 0x07, // reference_type(1) + referenced_size(31)
- 0x00, 0x00, 0x00, 0x08, // subsegment_duration
- 0x80, 0x00, 0x00, 0x09, // starts_with_SAP(1) + SAP_type(3) + SAP_delta_time(28)
- // second reference
- 0x00, 0x00, 0x00, 0x03, // reference_type(1) + referenced_size(31)
- 0x00, 0x00, 0x00, 0x04, // subsegment_duration
- 0x10, 0x00, 0x00, 0x05 // starts_with_SAP(1) + SAP_type(3) + SAP_delta_time(28)
- );
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'sidx',
- version: 1,
- flags: new Uint8Array([0, 0x00, 0x00]),
- timescale: 1,
- earliestPresentationTime: 0x01020304,
- firstOffset: 0,
- referenceId: 2,
- size: 64,
- references: [{
- referenceType: 1,
- referencedSize: 7,
- subsegmentDuration: 8,
- startsWithSap: true,
- sapType: 0,
- sapDeltaTime: 9
- }, {
- referenceType: 0,
- referencedSize: 3,
- subsegmentDuration: 4,
- startsWithSap: false,
- sapType: 1,
- sapDeltaTime: 5
- }]
- }]);
- });
- QUnit.test('can parse a big version 1 sidx', function(assert) {
- var data = box('sidx',
- 0x01, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x02, // reference_ID
- 0x00, 0x00, 0x00, 0x01, // timescale
- 0x01, 0x02, 0x03, 0x04, // earliest_presentation_time
- 0x05, 0x06, 0x07, 0x08,
- 0x08, 0x07, 0x06, 0x05, // first_offset
- 0x04, 0x03, 0x02, 0x01,
- 0x00, 0x00, // reserved
- 0x00, 0x02, // reference_count
- // first reference
- 0x80, 0x00, 0x00, 0x07, // reference_type(1) + referenced_size(31)
- 0x00, 0x00, 0x00, 0x08, // subsegment_duration
- 0x80, 0x00, 0x00, 0x09, // starts_with_SAP(1) + SAP_type(3) + SAP_delta_time(28)
- // second reference
- 0x00, 0x00, 0x00, 0x03, // reference_type(1) + referenced_size(31)
- 0x00, 0x00, 0x00, 0x04, // subsegment_duration
- 0x10, 0x00, 0x00, 0x05 // starts_with_SAP(1) + SAP_type(3) + SAP_delta_time(28)
- );
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'sidx',
- version: 1,
- flags: new Uint8Array([0, 0x00, 0x00]),
- timescale: 1,
- earliestPresentationTime: BigInt('0x0102030405060708'),
- firstOffset: BigInt('0x0807060504030201'),
- referenceId: 2,
- size: 64,
- references: [{
- referenceType: 1,
- referencedSize: 7,
- subsegmentDuration: 8,
- startsWithSap: true,
- sapType: 0,
- sapDeltaTime: 9
- }, {
- referenceType: 0,
- referencedSize: 3,
- subsegmentDuration: 4,
- startsWithSap: false,
- sapType: 1,
- sapDeltaTime: 5
- }]
- }]);
- });
- QUnit.test('can parse an smhd', function(assert) {
- var data = box('smhd',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0xff, // balance, fixed-point 8.8
- 0x00, 0x00); // reserved
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'smhd',
- size: 16,
- version: 0,
- flags: new Uint8Array([0, 0, 0]),
- balance: 0xff / Math.pow(2, 8)
- }],
- 'parsed an smhd');
- });
- QUnit.test('can parse a version 0 tfdt', function(assert) {
- var data = box('tfdt',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x01, 0x02, 0x03, 0x04); // baseMediaDecodeTime
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'tfdt',
- version: 0,
- size: 16,
- flags: new Uint8Array([0, 0, 0]),
- baseMediaDecodeTime: 0x01020304
- }]);
- });
- QUnit.test('can parse a version 1 tfdt and return an unsigned integer value', function(assert) {
- var data = box('tfdt',
- 0x01, // version
- 0x00, 0x00, 0x00, // flags
- 0x81, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07, 0x08); // baseMediaDecodeTime
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(data)),
- [{
- type: 'tfdt',
- version: 1,
- size: 20,
- flags: new Uint8Array([0, 0, 0]),
- baseMediaDecodeTime: BigInt('0x8102030405060708')
- }]);
- });
- QUnit.test('can parse a series of boxes', function(assert) {
- var ftyp = [
- 0x00, 0x00, 0x00, 0x18 // size 4 * 6 = 24
- ].concat(typeBytes('ftyp')).concat([
- 0x69, 0x73, 0x6f, 0x6d, // major brand
- 0x00, 0x00, 0x00, 0x02, // minor version
- 98, 101, 101, 112, // compatible brands
- 98, 111, 111, 112 // compatible brands
- ]);
- assert.deepEqual(mp4.tools.inspect(new Uint8Array(ftyp.concat(ftyp))),
- [{
- type: 'ftyp',
- size: 4 * 6,
- majorBrand: 'isom',
- minorVersion: 2,
- compatibleBrands: ['beep', 'boop']
- }, {
- type: 'ftyp',
- size: 4 * 6,
- majorBrand: 'isom',
- minorVersion: 2,
- compatibleBrands: ['beep', 'boop']
- }],
- 'parsed two boxes in series');
- });
|