381 lines
16 KiB
JavaScript
381 lines
16 KiB
JavaScript
/**
|
|
* 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
|
|
};
|