123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- /**
- * Helper functions for creating test MP4 data.
- */
- 'use strict';
- // ----------------------
- // Box Generation Helpers
- // ----------------------
- var typeBytes = function(type) {
- return [
- type.charCodeAt(0),
- type.charCodeAt(1),
- type.charCodeAt(2),
- type.charCodeAt(3)
- ];
- };
- var box = function(type) {
- var
- array = Array.prototype.slice.call(arguments, 1),
- result = [],
- size,
- i;
- // "unwrap" any arrays that were passed as arguments
- // e.g. box('etc', 1, [2, 3], 4) -> box('etc', 1, 2, 3, 4)
- for (i = 0; i < array.length; i++) {
- if (array[i] instanceof Array) {
- array.splice.apply(array, [i, 1].concat(array[i]));
- }
- }
- size = 8 + array.length;
- result[0] = (size & 0xFF000000) >> 24;
- result[1] = (size & 0x00FF0000) >> 16;
- result[2] = (size & 0x0000FF00) >> 8;
- result[3] = size & 0xFF;
- result = result.concat(typeBytes(type));
- result = result.concat(array);
- return result;
- };
- var unityMatrix = unityMatrix = [
- 0, 0, 0x10, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0x10, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0x40, 0, 0, 0
- ];
- // ------------
- // Example Data
- // ------------
- var sampleMoov =
- box('moov',
- box('mvhd',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01, // creation_time
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, // modification_time
- 0x00, 0x00, 0x03, 0xe8, // timescale = 1000
- 0x00, 0x00, 0x00, 0x00,
- 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), // next_track_ID
- box('trak',
- box('tkhd',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, // creation_time
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, // modification_time
- 0x00, 0x00, 0x00, 0x01, // track_ID
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00,
- 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, 0x00, 0x00, // 300 in 16.16 fixed-point
- 0x00, 0x96, 0x00, 0x00), // 150 in 16.16 fixed-point
- box('edts',
- box('elst',
- 0x00, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x00, // segment_duration
- 0x00, 0x00, 0x04, 0x00, // media_time
- 0x00, 0x01, 0x80, 0x00)), // media_rate
- box('mdia',
- box('mdhd',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, // creation_time
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, // modification_time
- 0x00, 0x01, 0x5f, 0x90, // timescale = 90000
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
- 0x15, 0xc7, // 'eng' language
- 0x00, 0x00),
- box('hdlr',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00, // pre_defined
- typeBytes('vide'), // handler_type
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00, // reserved
- typeBytes('one'), 0x00), // name
- box('minf',
- box('dinf',
- box('dref',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- box('url ',
- 0x00, // version
- 0x00, 0x00, 0x01))), // flags
- box('stbl',
- box('stsd',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00, // entry_count
- box('avc1',
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, // box content
- typeBytes('avcC'), // codec profile type
- 0x00, 0x4d, 0x40, 0x0d)), // codec parameters
- box('stts',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x01, // sample_count
- 0x00, 0x00, 0x00, 0x01), // sample_delta
- box('stsc',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x02, // first_chunk
- 0x00, 0x00, 0x00, 0x03, // samples_per_chunk
- 0x00, 0x00, 0x00, 0x01), // sample_description_index
- box('stco',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x01), // chunk_offset
- box('stss',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x01), // sync_sample
- box('ctts',
- 0x00, // version 0
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x01, // sample_count
- 0x00, 0x00, 0x00, 0x01))))), // sample_offset
- box('trak',
- box('tkhd',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, // creation_time
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, // modification_time
- 0x00, 0x00, 0x00, 0x02, // track_ID
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00,
- 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, 0x00, 0x00, // 300 in 16.16 fixed-point
- 0x00, 0x96, 0x00, 0x00), // 150 in 16.16 fixed-point
- box('edts',
- box('elst',
- 0x01, // version
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // segment_duration
- 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // media_time
- 0x00, 0x01, 0x80, 0x00)), // media_rate
- box('mdia',
- box('mdhd',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, // creation_time
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x03, // modification_time
- 0x00, 0x01, 0x5f, 0x90, // timescale = 90000
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
- 0x15, 0xc7, // 'eng' language
- 0x00, 0x00),
- box('hdlr',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00, // pre_defined
- typeBytes('soun'), // handler_type
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00, // reserved
- 0x00, 0x00, 0x00, 0x00, // reserved
- typeBytes('one'), 0x00), // name
- box('minf',
- box('dinf',
- box('dref',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- box('url ',
- 0x00, // version
- 0x00, 0x00, 0x01))), // flags
- box('stbl',
- box('stsd',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x00, // entry_count
- box('mp4a',
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- typeBytes('esds'), // codec profile type
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, 0x00, // box content
- 0x00, 0x00, 0x00, // box content
- 0x40, 0x0a, // codec params
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00)), // codec params
- box('stts',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x01, // sample_count
- 0x00, 0x00, 0x00, 0x01), // sample_delta
- box('stsc',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x02, // first_chunk
- 0x00, 0x00, 0x00, 0x03, // samples_per_chunk
- 0x00, 0x00, 0x00, 0x01), // sample_description_index
- box('ctts',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x01, // sample_count
- 0xff, 0xff, 0xff, 0xff), // sample_offset
- box('stco',
- 0x01, // version 1
- 0x00, 0x00, 0x00, // flags
- 0x00, 0x00, 0x00, 0x01, // entry_count
- 0x00, 0x00, 0x00, 0x01)))))); // chunk_offset
- /**
- * Generates generic emsg box data for both v0 and v1 boxes concats the messageData
- * and returns the result as a Uint8Array. Passing any version other than 0 or 1 will
- * return an invalid EMSG box.
- */
- var generateEmsgBoxData = function(version, messageData) {
- var emsgProps;
- if (version === 0) {
- emsgProps = new Uint8Array([
- 0x00, // version
- 0x00, 0x00, 0x00, //flags
- 0x75, 0x72, 0x6E, 0x3A, 0x66, 0x6F, 0x6F, 0x3A, 0x62, 0x61, 0x72, 0x3A, 0x32, 0x30, 0x32, 0x33, 0x00, // urn:foo:bar:2023\0
- 0x66, 0x6F, 0x6F, 0x2E, 0x62, 0x61, 0x72, 0x2E, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x00, // foo.bar.value\0
- 0x00, 0x00, 0x00, 0x64, // timescale = 100
- 0x00, 0x00, 0x03, 0xE8, // presentation_time_delta = 1000
- 0x00, 0x00, 0x00, 0x00, // event_duration = 0
- 0x00, 0x00, 0x00, 0x01 // id = 1
- ]);
- } else if (version === 1) {
- emsgProps = new Uint8Array([
- 0x01, // version
- 0x00, 0x00, 0x00, //flags
- 0x00, 0x00, 0x00, 0x64, // timescale = 100
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x10, // presentation_time = 10000
- 0x00, 0x00, 0x00, 0x01, // event_duration = 1
- 0x00, 0x00, 0x00, 0x02, // id = 2
- 0x75, 0x72, 0x6E, 0x3A, 0x66, 0x6F, 0x6F, 0x3A, 0x62, 0x61, 0x72, 0x3A, 0x32, 0x30, 0x32, 0x33, 0x00, // urn:foo:bar:2023\0
- 0x66, 0x6F, 0x6F, 0x2E, 0x62, 0x61, 0x72, 0x2E, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x00 // foo.bar.value\0
- ]);
- } else if (version === 2) {
- // Invalid version only
- emsgProps = new Uint8Array([
- 0x02, // version
- 0x00, 0x00, 0x00, //flags
- 0x00, 0x00, 0x00, 0x64, // timescale = 100
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x10, // presentation_time = 10000
- 0x00, 0x00, 0x00, 0x01, // event_duration = 1
- 0x00, 0x00, 0x00, 0x02, // id = 2
- 0x75, 0x72, 0x6E, 0x3A, 0x66, 0x6F, 0x6F, 0x3A, 0x62, 0x61, 0x72, 0x3A, 0x32, 0x30, 0x32, 0x33, 0x00, // urn:foo:bar:2023\0
- 0x66, 0x6F, 0x6F, 0x2E, 0x62, 0x61, 0x72, 0x2E, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x00 // foo.bar.value\0
- ]);
- } else {
- emsgProps = new Uint8Array([
- // malformed emsg data
- 0x00, 0x00, 0x00, 0x64, // timescale = 100
- // no presentation_time
- 0x00, 0x00, 0x00, 0x01, // event_duration = 1
- // no id
- 0x75, 0x72, 0x6E, 0x3A, 0x66, 0x6F, 0x6F, 0x3A, 0x62, 0x61, 0x72, 0x3A, 0x32, 0x30, 0x32, 0x33, 0x00, // urn:foo:bar:2023\0
- 0x66, 0x6F, 0x6F, 0x2E, 0x62, 0x61, 0x72, 0x2E, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x00 // foo.bar.value\0
- ]);
- }
- // concat the props and messageData
- var retArr = new Uint8Array(emsgProps.length + messageData.length);
- retArr.set(emsgProps);
- retArr.set(messageData, emsgProps.length);
- return retArr;
- };
- module.exports = {
- typeBytes,
- sampleMoov,
- unityMatrix,
- box,
- generateEmsgBoxData
- };
|