First release

This commit is contained in:
Owen Quinlan 2021-07-02 19:29:34 +10:00
commit fa6c85266e
2339 changed files with 761050 additions and 0 deletions

5
node_modules/mux.js/test/.eslintrc.json generated vendored Normal file
View file

@ -0,0 +1,5 @@
{
"env": {
"qunit": true
}
}

289
node_modules/mux.js/test/aac-stream.test.js generated vendored Normal file
View file

@ -0,0 +1,289 @@
'use strict';
var
aacStream,
AacStream = require('../lib/aac'),
QUnit = require('qunit'),
utils = require('./utils'),
createId3Header,
createId3FrameHeader,
createAdtsHeader;
createId3Header = function(tagSize) {
var header = [];
header[0] = 'I'.charCodeAt(0);
header[1] = 'D'.charCodeAt(0);
header[2] = '3'.charCodeAt(0);
// 2 version bytes, ID3v2.4.0 (major 4, revision 0)
header[3] = 4;
header[4] = 0;
// unsynchronization, extended header, experimental indicator, footer present flags
header[5] = 0;
// "The ID3v2 tag size is the sum of the byte length of the extended
// header, the padding and the frames after unsynchronisation. If a
// footer is present this equals to ('total size' - 20) bytes, otherwise
// ('total size' - 10) bytes."
// http://id3.org/id3v2.4.0-structure
header[6] = 0;
header[7] = 0;
header[8] = 0;
header[9] = tagSize;
return header;
};
createId3FrameHeader = function() {
var header = [];
// four byte frame ID, XYZ are experimental
header[0] = 'X'.charCodeAt(0);
header[1] = 'Y'.charCodeAt(0);
header[2] = 'Z'.charCodeAt(0);
header[3] = '0'.charCodeAt(0);
// four byte sync safe integer size (excluding frame header)
header[4] = 0;
header[5] = 0;
header[6] = 0;
header[7] = 10;
// two bytes for flags
header[8] = 0;
header[9] = 0;
return header;
};
createAdtsHeader = function(frameLength) {
// Header consists of 7 or 9 bytes (without or with CRC).
// see: https://wiki.multimedia.cx/index.php/ADTS
return utils.binaryStringToArrayOfBytes(''.concat(
// 12 bits for syncword (0xFFF)
'111111111111',
// 1 bit MPEG version
'0',
// 2 bit layer (always 0)
'00',
// 1 bit protection absent (1 for no CRC)
'1',
// 2 bit profile
'10',
// 4 bit sampling frequency index
'0110',
// 1 bit private bit
'0',
// 3 bit channel config
'100',
// 2 bit (ignore)
'00',
// 2 bit (copright bits)
'00',
// 13 bit frame length (includes header length)
utils.leftPad(frameLength.toString(2), 13),
// 11 bit buffer fullness
'11111111111',
// 2 bit number of AAC frames minus 1
'00'
// 16 bit CRC (if present)
));
};
QUnit.module('AAC Stream', {
beforeEach: function() {
aacStream = new AacStream();
}
});
QUnit.test('parses ID3 tag', function(assert) {
var
id3Count = 0,
adtsCount = 0,
frameHeader = createId3FrameHeader(),
id3Tag = createId3Header(frameHeader.length).concat(frameHeader);
aacStream.on('data', function(frame) {
if (frame.type === 'timed-metadata') {
id3Count += 1;
} else if (frame.type === 'audio') {
adtsCount += 1;
}
});
aacStream.push(new Uint8Array(id3Tag));
assert.equal(adtsCount, 0, 'no adts frames');
assert.equal(id3Count, 1, 'one id3 chunk');
});
QUnit.test('parses two ID3 tags in sequence', function(assert) {
var
id3Count = 0,
adtsCount = 0,
frameHeader = createId3FrameHeader(),
id3Tag = createId3Header(frameHeader.length).concat(frameHeader);
aacStream.on('data', function(frame) {
if (frame.type === 'timed-metadata') {
id3Count += 1;
} else if (frame.type === 'audio') {
adtsCount += 1;
}
});
aacStream.push(new Uint8Array(id3Tag.concat(id3Tag)));
assert.equal(adtsCount, 0, 'no adts frames');
assert.equal(id3Count, 2, 'two id3 chunks');
});
QUnit.test('does not parse second ID3 tag if it\'s incomplete', function(assert) {
var
id3Count = 0,
adtsCount = 0,
frameHeader = createId3FrameHeader(),
id3Tag = createId3Header(frameHeader.length).concat(frameHeader);
aacStream.on('data', function(frame) {
if (frame.type === 'timed-metadata') {
id3Count += 1;
} else if (frame.type === 'audio') {
adtsCount += 1;
}
});
aacStream.push(new Uint8Array(id3Tag.concat(id3Tag.slice(0, id3Tag.length - 1))));
assert.equal(adtsCount, 0, 'no adts frames');
assert.equal(id3Count, 1, 'one id3 chunk');
});
QUnit.test('handles misaligned adts header', function(assert) {
var
id3Count = 0,
adtsCount = 0,
// fake adts frame
adtsFrame = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
packetStream = createAdtsHeader(adtsFrame.length).concat(adtsFrame);
aacStream.on('data', function(frame) {
if (frame.type === 'timed-metadata') {
id3Count += 1;
} else if (frame.type === 'audio') {
adtsCount += 1;
}
});
// misalign by two bytes specific to a bug related to detecting sync bytes
// (where we were only properly checking the second byte)
aacStream.push(new Uint8Array([0x01, 0xf0].concat(packetStream)));
assert.equal(adtsCount, 1, 'one adts frames');
assert.equal(id3Count, 0, 'no id3 chunk');
});
QUnit.test('handles incomplete adts frame after id3 frame', function(assert) {
var
id3Count = 0,
adtsCount = 0,
id3FrameHeader = createId3FrameHeader(),
id3Tag = createId3Header(id3FrameHeader.length).concat(id3FrameHeader),
// in this case:
// id3 tag = 20 bytes
// adts header = 7 bytes
// total = 27 bytes
// report the ADTS frame size as 20 bytes
adtsHeader = createAdtsHeader(20),
// no adts frame, stream was cut off
packetStream = id3Tag.concat(adtsHeader);
aacStream.on('data', function(frame) {
if (frame.type === 'timed-metadata') {
id3Count += 1;
} else if (frame.type === 'audio') {
adtsCount += 1;
}
});
aacStream.push(new Uint8Array(packetStream));
assert.equal(adtsCount, 0, 'no adts frame');
assert.equal(id3Count, 1, 'one id3 chunk');
});
QUnit.test('emits data after receiving push', function(assert) {
var
array = new Uint8Array(109),
count = 0;
array[0] = 255;
array[1] = 241;
array[2] = 92;
array[3] = 128;
array[4] = 13;
array[5] = 191;
array[6] = 252;
array[7] = 33;
array[8] = 32;
array[9] = 3;
array[10] = 64;
array[11] = 104;
array[12] = 27;
array[13] = 212;
aacStream.setTimestamp(90);
aacStream.on('data', function(frame) {
if (frame.pts === 90 && frame.dts === 90) {
count += 1;
}
});
aacStream.push(array);
assert.equal(count, 1);
});
QUnit.test('continues parsing after corrupted stream', function(assert) {
var
array = new Uint8Array(10000),
adtsCount = 0,
id3Count = 0;
// an ID3 frame
array[0] = 73;
array[1] = 68;
array[2] = 51;
array[3] = 4;
array[4] = 0;
array[5] = 0;
array[6] = 0;
array[7] = 0;
array[8] = 0;
array[9] = 63;
array[10] = 80;
array[11] = 82;
array[12] = 73;
array[13] = 86;
// an atds frame
array[1020] = 255;
array[1021] = 241;
array[1022] = 92;
array[1023] = 128;
array[1024] = 13;
array[1025] = 191;
array[1026] = 252;
array[1027] = 33;
array[1028] = 32;
array[1029] = 3;
array[1030] = 64;
array[1031] = 104;
array[1032] = 27;
array[1033] = 212;
aacStream.on('data', function(frame) {
if (frame.type === 'timed-metadata') {
id3Count += 1;
} else if (frame.type === 'audio') {
adtsCount += 1;
}
});
aacStream.push(array);
assert.equal(adtsCount, 1);
assert.equal(id3Count, 1);
});

89
node_modules/mux.js/test/aac-utils.test.js generated vendored Normal file
View file

@ -0,0 +1,89 @@
'use strict';
var segments = require('data-files!segments');
var
QUnit = require('qunit'),
utils = require('../lib/aac/utils.js'),
testSegment = segments['test-aac-segment.aac']();
var id3TagOffset = 0;
var audioFrameOffset = 73;
QUnit.module('AAC Utils');
QUnit.test('correctly determines aac data', function(assert) {
assert.ok(utils.isLikelyAacData(testSegment), 'test segment is aac');
var id3Offset = utils.parseId3TagSize(testSegment, 0);
var id3 = Array.prototype.slice.call(testSegment, 0, id3Offset);
var segmentOnly = testSegment.subarray(id3Offset);
var multipleId3 = new Uint8Array([]
.concat(id3)
.concat(id3)
.concat(id3)
.concat(id3)
.concat(Array.prototype.slice.call(segmentOnly))
);
assert.ok(utils.isLikelyAacData(segmentOnly), 'test segment is aac without id3');
assert.notOk(utils.isLikelyAacData(testSegment.subarray(id3Offset + 25)), 'non aac data not recognized');
assert.notOk(utils.isLikelyAacData(testSegment.subarray(0, 5)), 'not enough aac data is not recognized');
assert.ok(utils.isLikelyAacData(multipleId3), 'test segment with multilpe id3');
});
QUnit.test('correctly parses aac packet type', function(assert) {
assert.equal(utils.parseType(testSegment, id3TagOffset), 'timed-metadata',
'parsed timed-metadata type');
assert.equal(utils.parseType(testSegment, 1), null,
'parsed unknown type');
assert.equal(utils.parseType(testSegment, audioFrameOffset), 'audio',
'parsed audio type');
});
QUnit.test('correctly parses ID3 tag size', function(assert) {
assert.equal(utils.parseId3TagSize(testSegment, id3TagOffset), 73,
'correct id3 tag size');
});
QUnit.test('correctly parses timestamp from ID3 metadata', function(assert) {
var frameSize = utils.parseId3TagSize(testSegment, id3TagOffset);
var frame = testSegment.subarray(id3TagOffset, id3TagOffset + frameSize);
assert.equal(utils.parseAacTimestamp(frame), 895690, 'correct aac timestamp');
});
QUnit.test('correctly parses adts frame size', function(assert) {
assert.equal(utils.parseAdtsSize(testSegment, audioFrameOffset), 13,
'correct adts frame size');
});
QUnit.test('correctly parses packet sample rate', function(assert) {
var frameSize = utils.parseAdtsSize(testSegment, audioFrameOffset);
var frame = testSegment.subarray(audioFrameOffset, audioFrameOffset + frameSize);
assert.equal(utils.parseSampleRate(frame), 44100, 'correct sample rate');
});
QUnit.test('parses correct ID3 tag size', function(assert) {
var packetStream = new Uint8Array(10);
packetStream[9] = 63;
assert.equal(utils.parseId3TagSize(packetStream, 0),
73,
'correctly parsed a header without a footer');
});
QUnit.test('parses correct ADTS Frame size', function(assert) {
var packetStream = new Uint8Array(6);
packetStream[3] = 128;
packetStream[4] = 29;
packetStream[5] = 255;
assert.equal(utils.parseAdtsSize(packetStream, 0), 239, 'correctly parsed framesize');
});

17
node_modules/mux.js/test/base64-to-uint8-array.js generated vendored Normal file
View file

@ -0,0 +1,17 @@
var window = require('global/window');
// TODO: use vhs-utils here
var atob = (s) => window.atob ? window.atob(s) : Buffer.from(s, 'base64').toString('binary');
var base64ToUint8Array = function(base64) {
var decoded = atob(base64);
var uint8Array = new Uint8Array(new ArrayBuffer(decoded.length));
for (var i = 0; i < decoded.length; i++) {
uint8Array[i] = decoded.charCodeAt(i);
}
return uint8Array;
};
module.exports = base64ToUint8Array;

253
node_modules/mux.js/test/caption-parser.test.js generated vendored Normal file
View file

@ -0,0 +1,253 @@
'use strict';
var segments = require('data-files!segments');
var probe = require('../lib/mp4/probe');
var CaptionParser = require('../lib/mp4').CaptionParser;
var captionParser;
var dashInit = segments['dash-608-captions-init.mp4']();
// This file includes 2 segments data to force a flush
// of the first caption. The second caption is at 200s
var dashSegment = segments['dash-608-captions-seg.m4s']();
var mp4Helpers = require('./utils/mp4-helpers');
var box = mp4Helpers.box;
var seiNalUnitGenerator = require('./utils/sei-nal-unit-generator');
var makeMdatFromCaptionPackets = seiNalUnitGenerator.makeMdatFromCaptionPackets;
var characters = seiNalUnitGenerator.characters;
var packets0;
var version0Moof;
var version0Segment;
var packets1;
var version1Moof;
var version1Segment;
QUnit.module('MP4 Caption Parser', {
beforeEach: function() {
captionParser = new CaptionParser();
captionParser.init();
},
afterEach: function() {
captionParser.reset();
}
});
QUnit.test('parse captions from real segment', function(assert) {
var trackIds;
var timescales;
var cc;
trackIds = probe.videoTrackIds(dashInit);
timescales = probe.timescale(dashInit);
cc = captionParser.parse(dashSegment, trackIds, timescales);
assert.equal(cc.captions.length, 1);
assert.equal(cc.captions[0].text, '00:00:00',
'real segment caption has correct text');
assert.equal(cc.captions[0].stream, 'CC1',
'real segment caption has correct stream');
assert.equal(cc.captions[0].startTime, 0,
'real segment caption has correct startTime');
assert.equal(cc.captions[0].endTime, 119,
'real segment caption has correct endTime');
assert.equal(cc.captionStreams.CC1, true,
'real segment caption streams have correct settings');
});
QUnit.test('parse captions when init segment received late', function(assert) {
var trackIds;
var timescales;
var cc;
trackIds = probe.videoTrackIds(dashInit);
timescales = probe.timescale(dashInit);
cc = captionParser.parse(dashSegment, [], {});
assert.ok(!cc, 'there should not be any parsed captions yet');
cc = captionParser.parse(dashSegment, trackIds, timescales);
assert.equal(cc.captions.length, 1);
});
QUnit.test('parseTrackId for version 0 and version 1 boxes', function(assert) {
var v0Captions;
var v1Captions;
v0Captions = captionParser.parse(
new Uint8Array(version0Segment), // segment
[1], // trackIds
{ 1: 90000 }); // timescales);
assert.equal(v0Captions.captions.length, 1, 'got 1 version0 caption');
assert.equal(v0Captions.captions[0].text, 'test string #1',
'got the expected version0 caption text');
assert.equal(v0Captions.captions[0].stream, 'CC1',
'returned the correct caption stream CC1');
assert.equal(v0Captions.captions[0].startTime, 10 / 90000,
'the start time for version0 caption is correct');
assert.equal(v0Captions.captions[0].endTime, 10 / 90000,
'the end time for version0 caption is correct');
assert.equal(v0Captions.captionStreams.CC1, true,
'stream is CC1');
assert.ok(!v0Captions.captionStreams.CC4,
'stream is not CC4');
// Clear parsed captions
captionParser.clearParsedCaptions();
v1Captions = captionParser.parse(
new Uint8Array(version1Segment),
[2], // trackIds
{ 2: 90000 }); // timescales
assert.equal(v1Captions.captions.length, 1, 'got version1 caption');
assert.equal(v1Captions.captions[0].text, 'test string #2',
'got the expected version1 caption text');
assert.equal(v1Captions.captions[0].stream, 'CC4',
'returned the correct caption stream CC4');
assert.equal(v1Captions.captions[0].startTime, 30 / 90000,
'the start time for version1 caption is correct');
assert.equal(v1Captions.captions[0].endTime, 30 / 90000,
'the end time for version1 caption is correct');
assert.equal(v1Captions.captionStreams.CC4, true,
'stream is CC4');
assert.ok(!v1Captions.captionStreams.CC1,
'stream is not CC1');
});
// ---------
// Test Data
// ---------
// "test string #1", channel 1, field 1
packets0 = [
// Send another command so that the second EOC isn't ignored
{ ccData: 0x1420, type: 0 },
// RCL, resume caption loading
{ ccData: 0x1420, type: 0 },
// 'test string #1'
{ ccData: characters('te'), type: 0 },
{ ccData: characters('st'), type: 0 },
{ ccData: characters(' s'), type: 0 },
// 'test string #1' continued
{ ccData: characters('tr'), type: 0 },
{ ccData: characters('in'), type: 0 },
{ ccData: characters('g '), type: 0 },
{ ccData: characters('#1'), type: 0 },
// EOC, End of Caption. End display
{ ccData: 0x142f, type: 0 },
// EOC, End of Caption. Finished transmitting, begin display
{ ccData: 0x142f, type: 0 },
// Send another command so that the second EOC isn't ignored
{ ccData: 0x1420, type: 0 },
// EOC, End of Caption. End display
{ ccData: 0x142f, type: 0 }
];
// "test string #2", channel 2, field 2
packets1 = [
// Send another command so that the second EOC isn't ignored
{ ccData: 0x1d20, type: 1 },
// RCL, resume caption loading
{ ccData: 0x1d20, type: 1 },
// 'test string #2'
{ ccData: characters('te'), type: 1 },
{ ccData: characters('st'), type: 1 },
{ ccData: characters(' s'), type: 1 },
// 'test string #2' continued
{ ccData: characters('tr'), type: 1 },
{ ccData: characters('in'), type: 1 },
{ ccData: characters('g '), type: 1 },
{ ccData: characters('#2'), type: 1 },
// EOC, End of Caption. End display
{ ccData: 0x1d2f, type: 1 },
// EOC, End of Caption. Finished transmitting, begin display
{ ccData: 0x1d2f, type: 1 },
// Send another command so that the second EOC isn't ignored
{ ccData: 0x1d20, type: 1 },
// EOC, End of Caption. End display
{ ccData: 0x1d2f, type: 1 }
];
/**
* version 0:
* Uses version 0 boxes, no first sample flags
* sample size, flags, duration, composition time offset included.
**/
version0Moof =
box('moof',
box('traf',
box('tfhd',
0x00, // version
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x01, // track_ID
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // base_data_offset
0x00, 0x00, 0x00, 0x00, // sample_description_index
0x00, 0x00, 0x00, 0x00, // default_sample_duration
0x00, 0x00, 0x00, 0x00, // default_sample_size
0x00, 0x00, 0x00, 0x00), // default_sample_flags
box('tfdt',
0x00, // version
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x00), // baseMediaDecodeTime,
box('trun',
0x00, // version
0x00, 0x0f, 0x01, // flags: dataOffsetPresent, sampleDurationPresent,
// sampleSizePresent, sampleFlagsPresent,
// sampleCompositionTimeOffsetsPresent
0x00, 0x00, 0x00, 0x02, // sample_count
0x00, 0x00, 0x00, 0x00, // data_offset, no first_sample_flags
// sample 1
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x0a, // signed sample_composition_time_offset = 10
// sample 2
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x14))); // signed sample_composition_time_offset = 20
version0Segment = version0Moof.concat(makeMdatFromCaptionPackets(packets0));
/**
* version 1:
* Uses version 1 boxes, has first sample flags,
* other samples include flags and composition time offset only.
**/
version1Moof =
box('moof',
box('traf',
box('tfhd',
0x01, // version
0x00, 0x00, 0x18, // flags
0x00, 0x00, 0x00, 0x02, // track_ID
// no base_data_offset, sample_description_index
0x00, 0x00, 0x00, 0x0a, // default_sample_duration = 10
0x00, 0x00, 0x00, 0x0a), // default_sample_size = 10
box('tfdt',
0x01, // version
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x14), // baseMediaDecodeTime = 20,
box('trun',
0x01, // version
0x00, 0x0c, 0x05, // flags: dataOffsetPresent, sampleFlagsPresent,
// firstSampleFlagsPresent,
// sampleCompositionTimeOffsetsPresent
0x00, 0x00, 0x00, 0x02, // sample_count
0x00, 0x00, 0x00, 0x00, // data_offset, has first_sample_flags
// sample 1
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x0a, // signed sample_composition_time_offset = 10
// sample 2
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x14))); // signed sample_composition_time_offset = 20
version1Segment = version1Moof.concat(makeMdatFromCaptionPackets(packets1));

3008
node_modules/mux.js/test/caption-stream.test.js generated vendored Normal file

File diff suppressed because it is too large Load diff

1114
node_modules/mux.js/test/captions.dfxp generated vendored Normal file

File diff suppressed because it is too large Load diff

113
node_modules/mux.js/test/exp-golomb.test.js generated vendored Normal file
View file

@ -0,0 +1,113 @@
/*
======== A Handy Little QUnit Reference ========
http://api.qunitjs.com/
Test methods:
module(name, {[setup][ ,teardown]})
test(name, callback)
expect(numberOfAssertions)
stop(increment)
start(decrement)
Test assertions:
assert.ok(value, [message])
assert.equal(actual, expected, [message])
assert.notEqual(actual, expected, [message])
assert.deepEqual(actual, expected, [message])
assert.notDeepEqual(actual, expected, [message])
assert.strictEqual(actual, expected, [message])
assert.notStrictEqual(actual, expected, [message])
assert.throws(block, [expected], [message])
*/
var
buffer,
ExpGolomb = require('../lib/utils/exp-golomb'),
expGolomb;
QUnit.module('Exponential Golomb coding');
QUnit.test('small numbers are coded correctly', function(assert) {
var
expected = [
[0xF8, 0],
[0x5F, 1],
[0x7F, 2],
[0x27, 3],
[0x2F, 4],
[0x37, 5],
[0x3F, 6],
[0x11, 7],
[0x13, 8],
[0x15, 9]
],
i = expected.length,
result;
while (i--) {
buffer = new Uint8Array([expected[i][0]]);
expGolomb = new ExpGolomb(buffer);
result = expGolomb.readUnsignedExpGolomb();
assert.equal(expected[i][1], result, expected[i][0] + ' is decoded to ' + expected[i][1]);
}
});
QUnit.test('drops working data as it is parsed', function(assert) {
var expGolomb = new ExpGolomb(new Uint8Array([0x00, 0xFF]));
expGolomb.skipBits(8);
assert.equal(8, expGolomb.bitsAvailable(), '8 bits remain');
assert.equal(0xFF, expGolomb.readBits(8), 'the second byte is read');
});
QUnit.test('drops working data when skipping leading zeros', function(assert) {
var expGolomb = new ExpGolomb(new Uint8Array([0x00, 0x00, 0x00, 0x00, 0xFF]));
assert.equal(32, expGolomb.skipLeadingZeros(), '32 leading zeros are dropped');
assert.equal(8, expGolomb.bitsAvailable(), '8 bits remain');
assert.equal(0xFF, expGolomb.readBits(8), 'the second byte is read');
});
QUnit.test('drops working data when skipping leading zeros', function(assert) {
var expGolomb = new ExpGolomb(new Uint8Array([0x15, 0xab, 0x40, 0xc8, 0xFF]));
assert.equal(3, expGolomb.skipLeadingZeros(), '3 leading zeros are dropped');
assert.equal((8 * 4) + 5, expGolomb.bitsAvailable(), '37 bits remain');
expGolomb.skipBits(1);
assert.equal(0x5a, expGolomb.readBits(8), 'the next bits are read');
});
QUnit.test('skipBits correctly across word-boundaries', function(assert) {
var expGolomb = new ExpGolomb(new Uint8Array([0x15, 0x00, 0x00, 0x28, 0x00, 0x0a, 0x00, 0x00]));
assert.equal(expGolomb.readUnsignedExpGolomb(), 9, 'the first number is read');
expGolomb.skipBits(17);
assert.equal(expGolomb.readUnsignedExpGolomb(), 4, 'the second number is read');
expGolomb.skipBits(13); // Crosses word boundary
assert.equal(expGolomb.readUnsignedExpGolomb(), 4, 'the third number is read');
});
QUnit.test('parses a sequence parameter set', function(assert) {
var
sps = new Uint8Array([
0x27, 0x42, 0xe0, 0x0b,
0xa9, 0x18, 0x60, 0x9d,
0x80, 0x35, 0x06, 0x01,
0x06, 0xb6, 0xc2, 0xb5,
0xef, 0x7c, 0x04
]),
expGolomb = new ExpGolomb(sps);
assert.strictEqual(expGolomb.readBits(8), 0x27, 'the NAL type specifies an SPS');
assert.strictEqual(expGolomb.readBits(8), 66, 'profile_idc is 66');
assert.strictEqual(expGolomb.readBits(4), 0x0E, 'constraints 0-3 are correct');
expGolomb.skipBits(4);
assert.strictEqual(expGolomb.readBits(8), 11, 'level_idc is 11');
assert.strictEqual(expGolomb.readUnsignedExpGolomb(), 0, 'seq_parameter_set_id is 0');
assert.strictEqual(expGolomb.readUnsignedExpGolomb(), 1, 'log2_max_frame_num_minus4 is 1');
assert.strictEqual(expGolomb.readUnsignedExpGolomb(), 0, 'pic_order_cnt_type is 0');
assert.strictEqual(expGolomb.readUnsignedExpGolomb(), 3, 'log2_max_pic_order_cnt_lsb_minus4 is 3');
assert.strictEqual(expGolomb.readUnsignedExpGolomb(), 2, 'max_num_ref_frames is 2');
assert.strictEqual(expGolomb.readBits(1), 0, 'gaps_in_frame_num_value_allowed_flag is false');
assert.strictEqual(expGolomb.readUnsignedExpGolomb(), 11, 'pic_width_in_mbs_minus1 is 11');
assert.strictEqual(expGolomb.readUnsignedExpGolomb(), 8, 'pic_height_in_map_units_minus1 is 8');
assert.strictEqual(expGolomb.readBits(1), 1, 'frame_mbs_only_flag is true');
assert.strictEqual(expGolomb.readBits(1), 1, 'direct_8x8_inference_flag is true');
assert.strictEqual(expGolomb.readBits(1), 0, 'frame_cropping_flag is false');
});

75
node_modules/mux.js/test/m2ts-probe.test.js generated vendored Normal file
View file

@ -0,0 +1,75 @@
'use strict';
var segments = require('data-files!segments');
var
QUnit = require('qunit'),
probe = require('../lib/m2ts/probe.js'),
testSegment = segments['test-segment.ts'](),
stuffedPesPacket = segments['test-stuffed-pes.ts']();
/**
* All subarray indices verified with the use of thumbcoil.
*/
var patPacket = testSegment.subarray(188, 376);
var pmtPid = 4095;
var programMapTable = {
256: 0x1B,
257: 0x0F
};
var pmtPacket = testSegment.subarray(376, 564);
var pesPacket = testSegment.subarray(564, 752);
var videoPacket = testSegment.subarray(564, 1692);
var videoNoKeyFramePacket = testSegment.subarray(1880, 2820);
var audioPacket = testSegment.subarray(6956, 7144);
var notPusiPacket = testSegment.subarray(1316, 1504);
QUnit.module('M2TS Probe');
QUnit.test('correctly parses packet type', function(assert) {
assert.equal(probe.parseType(patPacket), 'pat', 'parses pat type');
assert.equal(probe.parseType(pmtPacket), null,
'cannot determine type of pmt packet when pmt pid has not been parsed yet');
assert.equal(probe.parseType(pmtPacket, pmtPid), 'pmt', 'parses pmt type');
assert.equal(probe.parseType(pesPacket), null,
'cannot determine type of pes packet when pmt pid has not been parsed yet');
assert.equal(probe.parseType(pesPacket, pmtPid), 'pes', 'parses pes type');
});
QUnit.test('correctly parses pmt pid from pat packet', function(assert) {
assert.equal(probe.parsePat(patPacket), pmtPid, 'parses pmt pid from pat');
});
QUnit.test('correctly parses program map table from pmt packet', function(assert) {
assert.deepEqual(probe.parsePmt(pmtPacket), programMapTable, 'generates correct pmt');
});
QUnit.test('correctly parses payload unit start indicator', function(assert) {
assert.ok(probe.parsePayloadUnitStartIndicator(pesPacket),
'detects payload unit start indicator');
assert.ok(!probe.parsePayloadUnitStartIndicator(notPusiPacket),
'detects no payload unit start indicator');
});
QUnit.test('correctly parses type of pes packet', function(assert) {
assert.equal(probe.parsePesType(videoPacket, programMapTable), 'video',
'parses video pes type');
assert.equal(probe.parsePesType(audioPacket, programMapTable), 'audio',
'parses audio pes type');
});
QUnit.test('correctly parses dts and pts values of pes packet', function(assert) {
var videoPes = probe.parsePesTime(videoPacket);
assert.equal(videoPes.dts, 126000, 'correct dts value');
assert.equal(videoPes.pts, 126000, 'correct pts value');
videoPes = probe.parsePesTime(stuffedPesPacket);
assert.equal(videoPes, null,
'correctly returned null when there is no packet data, only stuffing');
});
QUnit.test('correctly determines if video pes packet contains a key frame', function(assert) {
assert.ok(probe.videoPacketContainsKeyFrame(videoPacket), 'detects key frame in packet');
assert.ok(!probe.videoPacketContainsKeyFrame(videoNoKeyFramePacket),
'detects no key frame in packet');
});

View file

@ -0,0 +1,11 @@
var mp2t, metadataStream;
mp2t = require('../lib/m2ts');
metadataStream = new mp2t.MetadataStream();
self.addEventListener('message', function(e) {
metadataStream.on('data', function(data) {
self.postMessage(data);
});
metadataStream.push(e.data);
});

586
node_modules/mux.js/test/metadata-stream.test.js generated vendored Normal file
View file

@ -0,0 +1,586 @@
'use strict';
/*
======== A Handy Little QUnit Reference ========
http://api.qunitjs.com/
Test methods:
module(name, {[setup][ ,teardown]})
test(name, callback)
expect(numberOfAssertions)
stop(increment)
start(decrement)
Test assertions:
ok(value, [message])
equal(actual, expected, [message])
notEqual(actual, expected, [message])
deepEqual(actual, expected, [message])
notDeepEqual(actual, expected, [message])
strictEqual(actual, expected, [message])
notStrictEqual(actual, expected, [message])
throws(block, [expected], [message])
*/
var metadataStream, stringToInts, stringToCString, id3Tag, id3Frame, id3Generator, mp2t, QUnit,
webworkify, MetadataStreamTestWorker;
mp2t = require('../lib/m2ts');
QUnit = require('qunit');
id3Generator = require('./utils/id3-generator');
MetadataStreamTestWorker = require('worker!./metadata-stream-test-worker.js');
stringToInts = id3Generator.stringToInts;
stringToCString = id3Generator.stringToCString;
id3Tag = id3Generator.id3Tag;
id3Frame = id3Generator.id3Frame;
QUnit.module('MetadataStream', {
beforeEach: function() {
metadataStream = new mp2t.MetadataStream();
}
});
QUnit.test('can construct a MetadataStream', function(assert) {
assert.ok(metadataStream, 'does not return null');
});
QUnit.test('parses simple ID3 metadata out of PES packets', function(assert) {
var
events = [],
wxxxPayload = [
0x00 // text encoding. ISO-8859-1
].concat(stringToCString('ad tag URL'), // description
stringToInts('http://example.com/ad?v=1234&q=7')), // value
id3Bytes,
size;
metadataStream.on('data', function(event) {
events.push(event);
});
id3Bytes = new Uint8Array(stringToInts('ID3').concat([
0x03, 0x00, // version 3.0 of ID3v2 (aka ID3v.2.3.0)
0x40, // flags. include an extended header
0x00, 0x00, 0x00, 0x00, // size. set later
// extended header
0x00, 0x00, 0x00, 0x06, // extended header size. no CRC
0x00, 0x00, // extended flags
0x00, 0x00, 0x00, 0x02 // size of padding
// frame 0
// http://id3.org/id3v2.3.0#User_defined_text_information_frame
], id3Frame('WXXX',
wxxxPayload), // value
// frame 1
// custom tag
id3Frame('XINF',
[
0x04, 0x03, 0x02, 0x01 // arbitrary data
]), [
0x00, 0x00 // padding
]));
// set header size field
size = id3Bytes.byteLength - 10;
id3Bytes[6] = (size >>> 21) & 0x7f;
id3Bytes[7] = (size >>> 14) & 0x7f;
id3Bytes[8] = (size >>> 7) & 0x7f;
id3Bytes[9] = (size) & 0x7f;
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 1000,
// header
data: id3Bytes
});
assert.equal(events.length, 1, 'parsed one tag');
assert.equal(events[0].frames.length, 2, 'parsed two frames');
assert.equal(events[0].frames[0].key, 'WXXX', 'parsed a WXXX frame');
assert.deepEqual(new Uint8Array(events[0].frames[0].data),
new Uint8Array(wxxxPayload),
'attached the frame payload');
assert.equal(events[0].frames[1].key, 'XINF', 'parsed a user-defined frame');
assert.deepEqual(new Uint8Array(events[0].frames[1].data),
new Uint8Array([0x04, 0x03, 0x02, 0x01]),
'attached the frame payload');
assert.equal(events[0].pts, 1000, 'did not modify the PTS');
assert.equal(events[0].dts, 1000, 'did not modify the PTS');
});
QUnit.test('skips non-ID3 metadata events', function(assert) {
var events = [];
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 1000,
// header
data: new Uint8Array([0])
});
assert.equal(events.length, 0, 'did not emit an event');
});
// missing cases:
// unsynchronization
// CRC
// no extended header
// compressed frames
// encrypted frames
// frame groups
// too large/small tag size values
// too large/small frame size values
QUnit.test('parses TXXX frames without null terminators', function(assert) {
var events = [];
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
// header
data: new Uint8Array(id3Tag(id3Frame('TXXX',
0x03, // utf-8
stringToCString('get done'),
stringToInts('{ "key": "value" }')),
[0x00, 0x00]))
});
assert.equal(events.length, 1, 'parsed one tag');
assert.equal(events[0].frames.length, 1, 'parsed one frame');
assert.equal(events[0].frames[0].key, 'TXXX', 'parsed the frame key');
assert.equal(events[0].frames[0].description, 'get done', 'parsed the description');
assert.deepEqual(JSON.parse(events[0].frames[0].data), { key: 'value' }, 'parsed the data');
});
QUnit.test('parses TXXX frames with null terminators', function(assert) {
var events = [];
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
// header
data: new Uint8Array(id3Tag(id3Frame('TXXX',
0x03, // utf-8
stringToCString('get done'),
stringToCString('{ "key": "value" }')),
[0x00, 0x00]))
});
assert.equal(events.length, 1, 'parsed one tag');
assert.equal(events[0].frames.length, 1, 'parsed one frame');
assert.equal(events[0].frames[0].key, 'TXXX', 'parsed the frame key');
assert.equal(events[0].frames[0].description, 'get done', 'parsed the description');
assert.deepEqual(JSON.parse(events[0].frames[0].data), { key: 'value' }, 'parsed the data');
});
QUnit.test('parses WXXX frames', function(assert) {
var events = [], url = 'http://example.com/path/file?abc=7&d=4#ty';
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
// header
data: new Uint8Array(id3Tag(id3Frame('WXXX',
0x03, // utf-8
stringToCString(''),
stringToInts(url)),
[0x00, 0x00]))
});
assert.equal(events.length, 1, 'parsed one tag');
assert.equal(events[0].frames.length, 1, 'parsed one frame');
assert.equal(events[0].frames[0].key, 'WXXX', 'parsed the frame key');
assert.equal(events[0].frames[0].description, '', 'parsed the description');
assert.equal(events[0].frames[0].url, url, 'parsed the value');
});
QUnit.test('parses TXXX frames with characters that have a single-digit hexadecimal representation', function(assert) {
var events = [], value = String.fromCharCode(7);
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
// header
data: new Uint8Array(id3Tag(id3Frame('TXXX',
0x03, // utf-8
stringToCString(''),
stringToCString(value)),
[0x00, 0x00]))
});
assert.equal(events[0].frames[0].data,
value,
'parsed the single-digit character');
});
QUnit.test('parses PRIV frames', function(assert) {
var
events = [],
payload = stringToInts('arbitrary data may be included in the payload ' +
'of a PRIV frame');
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
// header
data: new Uint8Array(id3Tag(id3Frame('PRIV',
stringToCString('priv-owner@example.com'),
payload)))
});
assert.equal(events.length, 1, 'parsed a tag');
assert.equal(events[0].frames.length, 1, 'parsed a frame');
assert.equal(events[0].frames[0].key, 'PRIV', 'frame key is PRIV');
assert.equal(events[0].frames[0].owner, 'priv-owner@example.com', 'parsed the owner');
assert.deepEqual(new Uint8Array(events[0].frames[0].data),
new Uint8Array(payload),
'parsed the frame private data');
});
QUnit.test('parses tags split across pushes', function(assert) {
var
events = [],
owner = stringToCString('owner@example.com'),
payload = stringToInts('A TS packet is 188 bytes in length so that it can' +
' be easily transmitted over ATM networks, an ' +
'important medium at one time. We want to be sure' +
' that ID3 frames larger than a TS packet are ' +
'properly re-assembled.'),
tag = new Uint8Array(id3Tag(id3Frame('PRIV', owner, payload))),
front = tag.subarray(0, 100),
back = tag.subarray(100);
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
data: front,
dataAlignmentIndicator: true
});
assert.equal(events.length, 0, 'parsed zero tags');
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
data: back,
dataAlignmentIndicator: false
});
assert.equal(events.length, 1, 'parsed a tag');
assert.equal(events[0].frames.length, 1, 'parsed a frame');
assert.equal(events[0].frames[0].data.byteLength,
payload.length,
'collected data across pushes');
// parses subsequent fragmented tags
tag = new Uint8Array(id3Tag(id3Frame('PRIV',
owner, payload, payload)));
front = tag.subarray(0, 188);
back = tag.subarray(188);
events = [];
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 2000,
dts: 2000,
data: front,
dataAlignmentIndicator: true
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 2000,
dts: 2000,
data: back,
dataAlignmentIndicator: false
});
assert.equal(events.length, 1, 'parsed a tag');
assert.equal(events[0].frames.length, 1, 'parsed a frame');
assert.equal(events[0].frames[0].data.byteLength,
2 * payload.length,
'collected data across pushes');
});
QUnit.test('id3 frame is malformed first time but gets corrected in the next frame', function(assert) {
var
events = [],
owner = stringToCString('owner@example.com'),
payload = stringToInts('A TS packet is 188 bytes in length so that it can' +
' be easily transmitted over ATM networks, an ' +
'important medium at one time. We want to be sure' +
' that ID3 frames larger than a TS packet are ' +
'properly re-assembled.'),
tag = new Uint8Array(id3Tag(id3Frame('PRIV', owner, payload))),
front = tag.subarray(0, 100);
metadataStream.on('data', function(event) {
events.push(event);
});
// receives incomplete id3
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
data: front,
dataAlignmentIndicator: true
});
assert.equal(events.length, 0, 'parsed zero tags');
// receives complete id3
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
data: tag,
dataAlignmentIndicator: true
});
assert.equal(events.length, 1, 'parsed a tag');
assert.equal(events[0].frames.length, 1, 'parsed a frame');
assert.equal(events[0].frames[0].data.byteLength,
payload.length,
'collected data across pushes');
});
QUnit.test('id3 frame reports more data than its tagsize ', function(assert) {
var
events = [],
owner = stringToCString('owner@example.com'),
payload = stringToInts('A TS packet is 188 bytes in length so that it can' +
' be easily transmitted over ATM networks, an ' +
'important medium at one time. We want to be sure' +
' that ID3 frames larger than a TS packet are ' +
'properly re-assembled.'),
tag = new Uint8Array(id3Tag(id3Frame('PRIV', owner, payload))),
d = new Uint8Array([0x04, 0x05, 0x06]),
data = new Uint8Array(tag.byteLength + d.byteLength);
data.set(tag);
data.set(d, tag.length);
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
data: data,
dataAlignmentIndicator: true
});
assert.equal(events.length, 1, 'parsed a tag');
assert.equal(events[0].frames.length, 1, 'parsed a frame');
assert.equal(events[0].frames[0].data.byteLength,
payload.length,
'collected data across pushes');
});
QUnit.test('ignores tags when the header is fragmented', function(assert) {
var
events = [],
tag = new Uint8Array(id3Tag(id3Frame('PRIV',
stringToCString('owner@example.com'),
stringToInts('payload')))),
// split the 10-byte ID3 tag header in half
front = tag.subarray(0, 5),
back = tag.subarray(5);
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
data: front
});
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
data: back
});
assert.equal(events.length, 0, 'parsed zero tags');
metadataStream.push({
type: 'timed-metadata',
trackId: 7,
pts: 1500,
dts: 1500,
data: new Uint8Array(id3Tag(id3Frame('PRIV',
stringToCString('owner2'),
stringToInts('payload2'))))
});
assert.equal(events.length, 1, 'parsed one tag');
assert.equal(events[0].frames[0].owner, 'owner2', 'dropped the first tag');
});
// https://html.spec.whatwg.org/multipage/embedded-content.html#steps-to-expose-a-media-resource-specific-text-track
QUnit.test('constructs the dispatch type', function(assert) {
metadataStream = new mp2t.MetadataStream({
descriptor: new Uint8Array([0x03, 0x02, 0x01, 0x00])
});
assert.equal(metadataStream.dispatchType, '1503020100', 'built the dispatch type');
});
QUnit.test('can parse PRIV frames in web worker', function(assert) {
var payload = stringToInts('arbitrary'),
worker = new MetadataStreamTestWorker(),
done = assert.async();
worker.addEventListener('message', function(e) {
assert.equal(e.data.frames[0].key, 'PRIV', 'frame key is PRIV');
assert.deepEqual(new Uint8Array(e.data.frames[0].data), new Uint8Array(payload),
'parsed the frame private data');
worker.terminate();
done();
});
worker.postMessage({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
// header
data: new Uint8Array(id3Tag(id3Frame('PRIV',
stringToCString('priv-owner@example.com'),
payload)))
});
});
QUnit.test('can parse TXXX frames in web worker', function(assert) {
var worker = new MetadataStreamTestWorker(),
done = assert.async();
worker.addEventListener('message', function(e) {
assert.equal(e.data.frames[0].key, 'TXXX', 'frame key is TXXX');
assert.equal(e.data.frames[0].description, 'get done', 'parsed the description');
assert.deepEqual(JSON.parse(e.data.frames[0].data), { key: 'value' }, 'parsed the data');
worker.terminate();
done();
});
worker.postMessage({
type: 'timed-metadata',
trackId: 7,
pts: 1000,
dts: 900,
// header
data: new Uint8Array(id3Tag(id3Frame('TXXX',
0x03, // utf-8
stringToCString('get done'),
stringToCString('{ "key": "value" }')),
[0x00, 0x00]))
});
});
QUnit.test('triggers special event after parsing a timestamp ID3 tag', function(assert) {
var
array = new Uint8Array(73),
streamTimestamp = 'com.apple.streaming.transportStreamTimestamp',
priv = 'PRIV',
count = 0,
frame,
tag,
metadataStream,
chunk,
i;
metadataStream = new mp2t.MetadataStream();
metadataStream.on('timestamp', function(f) {
frame = f;
count += 1;
});
metadataStream.on('data', function(t) {
tag = t;
});
array[0] = 73;
array[1] = 68;
array[2] = 51;
array[3] = 4;
array[9] = 63;
array[17] = 53;
array[70] = 13;
array[71] = 187;
array[72] = 160;
for (i = 0; i < priv.length; i++) {
array[i + 10] = priv.charCodeAt(i);
}
for (i = 0; i < streamTimestamp.length; i++) {
array[i + 20] = streamTimestamp.charCodeAt(i);
}
chunk = {
type: 'timed-metadata',
data: array
};
metadataStream.push(chunk);
assert.equal(count, 1, 'timestamp event triggered once');
assert.equal(frame.timeStamp, 900000, 'Initial timestamp fired and calculated correctly');
assert.equal(tag.pts, 10 * 90e3, 'set tag PTS');
assert.equal(tag.dts, 10 * 90e3, 'set tag DTS');
});

581
node_modules/mux.js/test/mp4-generator.test.js generated vendored Normal file
View file

@ -0,0 +1,581 @@
'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'),
QUnit = require('qunit'),
validateMvhd, validateTrak, validateTkhd, validateMdia,
validateMdhd, validateHdlr, validateMinf, validateDinf,
validateStbl, validateStsd, validateMvex,
validateVideoSample, validateAudioSample;
QUnit.module('MP4 Generator');
QUnit.test('generates a BSMFF ftyp', function(assert) {
var data = mp4.generator.ftyp(), boxes;
assert.ok(data, 'box is not null');
boxes = mp4.tools.inspect(data);
assert.equal(1, boxes.length, 'generated a single box');
assert.equal(boxes[0].type, 'ftyp', 'generated ftyp type');
assert.equal(boxes[0].size, data.byteLength, 'generated size');
assert.equal(boxes[0].majorBrand, 'isom', 'major version is "isom"');
assert.equal(boxes[0].minorVersion, 1, 'minor version is one');
});
validateMvhd = function(mvhd) {
QUnit.assert.equal(mvhd.type, 'mvhd', 'generated a mvhd');
QUnit.assert.equal(mvhd.duration, 0xffffffff, 'wrote the maximum movie header duration');
QUnit.assert.equal(mvhd.nextTrackId, 0xffffffff, 'wrote the max next track id');
};
validateTrak = function(trak, expected) {
expected = expected || {};
QUnit.assert.equal(trak.type, 'trak', 'generated a trak');
QUnit.assert.equal(trak.boxes.length, 2, 'generated two track sub boxes');
validateTkhd(trak.boxes[0], expected);
validateMdia(trak.boxes[1], expected);
};
validateTkhd = function(tkhd, expected) {
QUnit.assert.equal(tkhd.type, 'tkhd', 'generated a tkhd');
QUnit.assert.equal(tkhd.trackId, 7, 'wrote the track id');
QUnit.assert.deepEqual(tkhd.flags, new Uint8Array([0, 0, 7]), 'flags should QUnit.equal 7');
QUnit.assert.equal(tkhd.duration,
expected.duration || Math.pow(2, 32) - 1,
'wrote duration into the track header');
QUnit.assert.equal(tkhd.width, expected.width || 0, 'wrote width into the track header');
QUnit.assert.equal(tkhd.height, expected.height || 0, 'wrote height into the track header');
QUnit.assert.equal(tkhd.volume, 1, 'set volume to 1');
};
validateMdia = function(mdia, expected) {
QUnit.assert.equal(mdia.type, 'mdia', 'generated an mdia type');
QUnit.assert.equal(mdia.boxes.length, 3, 'generated three track media sub boxes');
validateMdhd(mdia.boxes[0], expected);
validateHdlr(mdia.boxes[1], expected);
validateMinf(mdia.boxes[2], expected);
};
validateMdhd = function(mdhd, expected) {
QUnit.assert.equal(mdhd.type, 'mdhd', 'generate an mdhd type');
QUnit.assert.equal(mdhd.language, 'und', 'wrote undetermined language');
QUnit.assert.equal(mdhd.timescale, expected.timescale || 90000, 'wrote the timescale');
QUnit.assert.equal(mdhd.duration,
expected.duration || Math.pow(2, 32) - 1,
'wrote duration into the media header');
};
validateHdlr = function(hdlr, expected) {
QUnit.assert.equal(hdlr.type, 'hdlr', 'generate an hdlr type');
if (expected.type !== 'audio') {
QUnit.assert.equal(hdlr.handlerType, 'vide', 'wrote a video handler');
QUnit.assert.equal(hdlr.name, 'VideoHandler', 'wrote the handler name');
} else {
QUnit.assert.equal(hdlr.handlerType, 'soun', 'wrote a sound handler');
QUnit.assert.equal(hdlr.name, 'SoundHandler', 'wrote the sound handler name');
}
};
validateMinf = function(minf, expected) {
QUnit.assert.equal(minf.type, 'minf', 'generate an minf type');
QUnit.assert.equal(minf.boxes.length, 3, 'generates three minf sub boxes');
if (expected.type !== 'audio') {
QUnit.assert.deepEqual({
type: 'vmhd',
size: 20,
version: 0,
flags: new Uint8Array([0, 0, 1]),
graphicsmode: 0,
opcolor: new Uint16Array([0, 0, 0])
}, minf.boxes[0], 'generates a vhmd');
} else {
QUnit.assert.deepEqual({
type: 'smhd',
size: 16,
version: 0,
flags: new Uint8Array([0, 0, 0]),
balance: 0
}, minf.boxes[0], 'generates an smhd');
}
validateDinf(minf.boxes[1]);
validateStbl(minf.boxes[2], expected);
};
validateDinf = function(dinf) {
QUnit.assert.deepEqual({
type: 'dinf',
size: 36,
boxes: [{
type: 'dref',
size: 28,
version: 0,
flags: new Uint8Array([0, 0, 0]),
dataReferences: [{
type: 'url ',
size: 12,
version: 0,
flags: new Uint8Array([0, 0, 1])
}]
}]
}, dinf, 'generates a dinf');
};
validateStbl = function(stbl, expected) {
QUnit.assert.equal(stbl.type, 'stbl', 'generates an stbl type');
QUnit.assert.equal(stbl.boxes.length, 5, 'generated five stbl child boxes');
validateStsd(stbl.boxes[0], expected);
QUnit.assert.deepEqual({
type: 'stts',
size: 16,
version: 0,
flags: new Uint8Array([0, 0, 0]),
timeToSamples: []
}, stbl.boxes[1], 'generated an stts');
QUnit.assert.deepEqual({
type: 'stsc',
size: 16,
version: 0,
flags: new Uint8Array([0, 0, 0]),
sampleToChunks: []
}, stbl.boxes[2], 'generated an stsc');
QUnit.assert.deepEqual({
type: 'stsz',
version: 0,
size: 20,
flags: new Uint8Array([0, 0, 0]),
sampleSize: 0,
entries: []
}, stbl.boxes[3], 'generated an stsz');
QUnit.assert.deepEqual({
type: 'stco',
size: 16,
version: 0,
flags: new Uint8Array([0, 0, 0]),
chunkOffsets: []
}, stbl.boxes[4], 'generated and stco');
};
validateStsd = function(stsd, expected) {
QUnit.assert.equal(stsd.type, 'stsd', 'generated an stsd');
QUnit.assert.equal(stsd.sampleDescriptions.length, 1, 'generated one sample');
if (expected.type !== 'audio') {
validateVideoSample(stsd.sampleDescriptions[0]);
} else {
validateAudioSample(stsd.sampleDescriptions[0]);
}
};
validateVideoSample = function(sample) {
QUnit.assert.deepEqual(sample, {
type: 'avc1',
size: 152,
dataReferenceIndex: 1,
width: 600,
height: 300,
horizresolution: 72,
vertresolution: 72,
frameCount: 1,
depth: 24,
config: [{
type: 'avcC',
size: 30,
configurationVersion: 1,
avcProfileIndication: 3,
avcLevelIndication: 5,
profileCompatibility: 7,
lengthSizeMinusOne: 3,
sps: [new Uint8Array([
0, 1, 2
]), new Uint8Array([
3, 4, 5
])],
pps: [new Uint8Array([
6, 7, 8
])]
}, {
type: 'btrt',
size: 20,
bufferSizeDB: 1875072,
maxBitrate: 3000000,
avgBitrate: 3000000
}, {
type: 'pasp',
size: 16,
data: new Uint8Array([0, 0, 0, 1, 0, 0, 0, 1])
}]
}, 'generated a video sample');
};
validateAudioSample = function(sample) {
QUnit.assert.deepEqual(sample, {
type: 'mp4a',
size: 75,
dataReferenceIndex: 1,
channelcount: 2,
samplesize: 16,
samplerate: 48000,
streamDescriptor: {
type: 'esds',
version: 0,
flags: new Uint8Array([0, 0, 0]),
size: 39,
esId: 0,
streamPriority: 0,
// these values were hard-coded based on a working audio init segment
decoderConfig: {
avgBitrate: 56000,
maxBitrate: 56000,
bufferSize: 1536,
objectProfileIndication: 64,
streamType: 5,
decoderConfigDescriptor: {
audioObjectType: 2,
channelConfiguration: 2,
length: 2,
samplingFrequencyIndex: 3,
tag: 5
}
}
}
}, 'generated an audio sample');
};
validateMvex = function(mvex, options) {
options = options || {
sampleDegradationPriority: 1
};
QUnit.assert.deepEqual({
type: 'mvex',
size: 40,
boxes: [{
type: 'trex',
size: 32,
version: 0,
flags: new Uint8Array([0, 0, 0]),
trackId: 7,
defaultSampleDescriptionIndex: 1,
defaultSampleDuration: 0,
defaultSampleSize: 0,
sampleDependsOn: 0,
sampleIsDependedOn: 0,
sampleHasRedundancy: 0,
samplePaddingValue: 0,
sampleIsDifferenceSample: true,
sampleDegradationPriority: options.sampleDegradationPriority
}]
}, mvex, 'writes a movie extends box');
};
QUnit.test('generates a video moov', function(assert) {
var
boxes,
data = mp4.generator.moov([{
id: 7,
duration: 100,
width: 600,
height: 300,
type: 'video',
profileIdc: 3,
levelIdc: 5,
profileCompatibility: 7,
sarRatio: [1, 1],
sps: [new Uint8Array([0, 1, 2]), new Uint8Array([3, 4, 5])],
pps: [new Uint8Array([6, 7, 8])]
}]);
assert.ok(data, 'box is not null');
boxes = mp4.tools.inspect(data);
assert.equal(boxes.length, 1, 'generated a single box');
assert.equal(boxes[0].type, 'moov', 'generated a moov type');
assert.equal(boxes[0].size, data.byteLength, 'generated size');
assert.equal(boxes[0].boxes.length, 3, 'generated three sub boxes');
validateMvhd(boxes[0].boxes[0]);
validateTrak(boxes[0].boxes[1], {
duration: 100,
width: 600,
height: 300
});
validateMvex(boxes[0].boxes[2]);
});
QUnit.test('generates an audio moov', function(assert) {
var
data = mp4.generator.moov([{
id: 7,
type: 'audio',
audioobjecttype: 2,
channelcount: 2,
samplerate: 48000,
samplingfrequencyindex: 3,
samplesize: 16
}]),
boxes;
assert.ok(data, 'box is not null');
boxes = mp4.tools.inspect(data);
assert.equal(boxes.length, 1, 'generated a single box');
assert.equal(boxes[0].type, 'moov', 'generated a moov type');
assert.equal(boxes[0].size, data.byteLength, 'generated size');
assert.equal(boxes[0].boxes.length, 3, 'generated three sub boxes');
validateMvhd(boxes[0].boxes[0]);
validateTrak(boxes[0].boxes[1], {
type: 'audio',
timescale: 48000
});
validateMvex(boxes[0].boxes[2], {
sampleDegradationPriority: 0
});
});
QUnit.test('generates a sound hdlr', function(assert) {
var boxes, hdlr,
data = mp4.generator.moov([{
duration: 100,
type: 'audio'
}]);
assert.ok(data, 'box is not null');
boxes = mp4.tools.inspect(data);
hdlr = boxes[0].boxes[1].boxes[1].boxes[1];
assert.equal(hdlr.type, 'hdlr', 'generate an hdlr type');
assert.equal(hdlr.handlerType, 'soun', 'wrote a sound handler');
assert.equal(hdlr.name, 'SoundHandler', 'wrote the handler name');
});
QUnit.test('generates a video hdlr', function(assert) {
var boxes, hdlr,
data = mp4.generator.moov([{
duration: 100,
width: 600,
height: 300,
type: 'video',
sps: [],
pps: []
}]);
assert.ok(data, 'box is not null');
boxes = mp4.tools.inspect(data);
hdlr = boxes[0].boxes[1].boxes[1].boxes[1];
assert.equal(hdlr.type, 'hdlr', 'generate an hdlr type');
assert.equal(hdlr.handlerType, 'vide', 'wrote a video handler');
assert.equal(hdlr.name, 'VideoHandler', 'wrote the handler name');
});
QUnit.test('generates an initialization segment', function(assert) {
var
data = mp4.generator.initSegment([{
id: 1,
width: 600,
height: 300,
type: 'video',
sps: [new Uint8Array([0])],
pps: [new Uint8Array([1])]
}, {
id: 2,
type: 'audio'
}]),
init, mvhd, trak1, trak2, mvex;
init = mp4.tools.inspect(data);
assert.equal(init.length, 2, 'generated two boxes');
assert.equal(init[0].type, 'ftyp', 'generated a ftyp box');
assert.equal(init[1].type, 'moov', 'generated a moov box');
assert.equal(init[1].boxes[0].duration, 0xffffffff, 'wrote a maximum duration');
mvhd = init[1].boxes[0];
assert.equal(mvhd.type, 'mvhd', 'wrote an mvhd');
trak1 = init[1].boxes[1];
assert.equal(trak1.type, 'trak', 'wrote a trak');
assert.equal(trak1.boxes[0].trackId, 1, 'wrote the first track id');
assert.equal(trak1.boxes[0].width, 600, 'wrote the first track width');
assert.equal(trak1.boxes[0].height, 300, 'wrote the first track height');
assert.equal(trak1.boxes[1].boxes[1].handlerType, 'vide', 'wrote the first track type');
trak2 = init[1].boxes[2];
assert.equal(trak2.type, 'trak', 'wrote a trak');
assert.equal(trak2.boxes[0].trackId, 2, 'wrote the second track id');
assert.equal(trak2.boxes[1].boxes[1].handlerType, 'soun', 'wrote the second track type');
mvex = init[1].boxes[3];
assert.equal(mvex.type, 'mvex', 'wrote an mvex');
});
QUnit.test('generates a minimal moof', function(assert) {
var
data = mp4.generator.moof(7, [{
id: 17,
samples: [{
duration: 9000,
size: 10,
flags: {
isLeading: 0,
dependsOn: 2,
isDependedOn: 1,
hasRedundancy: 0,
paddingValue: 0,
isNonSyncSample: 0,
degradationPriority: 14
},
compositionTimeOffset: 500
}, {
duration: 10000,
size: 11,
flags: {
isLeading: 0,
dependsOn: 1,
isDependedOn: 0,
hasRedundancy: 0,
paddingValue: 0,
isNonSyncSample: 0,
degradationPriority: 9
},
compositionTimeOffset: 1000
}]
}]),
moof = mp4.tools.inspect(data),
trun,
sdtp;
assert.equal(moof.length, 1, 'generated one box');
assert.equal(moof[0].type, 'moof', 'generated a moof box');
assert.equal(moof[0].boxes.length, 2, 'generated two child boxes');
assert.equal(moof[0].boxes[0].type, 'mfhd', 'generated an mfhd box');
assert.equal(moof[0].boxes[0].sequenceNumber, 7, 'included the sequence_number');
assert.equal(moof[0].boxes[1].type, 'traf', 'generated a traf box');
assert.equal(moof[0].boxes[1].boxes.length, 4, 'generated track fragment info');
assert.equal(moof[0].boxes[1].boxes[0].type, 'tfhd', 'generated a tfhd box');
assert.equal(moof[0].boxes[1].boxes[0].trackId, 17, 'wrote the first track id');
assert.equal(moof[0].boxes[1].boxes[0].baseDataOffset, undefined, 'did not set a base data offset');
assert.equal(moof[0].boxes[1].boxes[1].type, 'tfdt', 'generated a tfdt box');
assert.ok(moof[0].boxes[1].boxes[1].baseMediaDecodeTime >= 0,
'media decode time is non-negative');
trun = moof[0].boxes[1].boxes[2];
assert.equal(trun.type, 'trun', 'generated a trun box');
assert.equal(typeof trun.dataOffset, 'number', 'has a data offset');
assert.ok(trun.dataOffset >= 0, 'has a non-negative data offset');
assert.equal(trun.dataOffset, moof[0].size + 8, 'sets the data offset past the mdat header');
assert.equal(trun.samples.length, 2, 'wrote two samples');
assert.equal(trun.samples[0].duration, 9000, 'wrote a sample duration');
assert.equal(trun.samples[0].size, 10, 'wrote a sample size');
assert.deepEqual(trun.samples[0].flags, {
isLeading: 0,
dependsOn: 2,
isDependedOn: 1,
hasRedundancy: 0,
paddingValue: 0,
isNonSyncSample: 0,
degradationPriority: 14
}, 'wrote the sample flags');
assert.equal(trun.samples[0].compositionTimeOffset, 500, 'wrote the composition time offset');
assert.equal(trun.samples[1].duration, 10000, 'wrote a sample duration');
assert.equal(trun.samples[1].size, 11, 'wrote a sample size');
assert.deepEqual(trun.samples[1].flags, {
isLeading: 0,
dependsOn: 1,
isDependedOn: 0,
hasRedundancy: 0,
paddingValue: 0,
isNonSyncSample: 0,
degradationPriority: 9
}, 'wrote the sample flags');
assert.equal(trun.samples[1].compositionTimeOffset, 1000, 'wrote the composition time offset');
sdtp = moof[0].boxes[1].boxes[3];
assert.equal(sdtp.type, 'sdtp', 'generated an sdtp box');
assert.equal(sdtp.samples.length, 2, 'wrote two samples');
assert.deepEqual(sdtp.samples[0], {
dependsOn: 2,
isDependedOn: 1,
hasRedundancy: 0
}, 'wrote the sample data table');
assert.deepEqual(sdtp.samples[1], {
dependsOn: 1,
isDependedOn: 0,
hasRedundancy: 0
}, 'wrote the sample data table');
});
QUnit.test('generates a moof for audio', function(assert) {
var
data = mp4.generator.moof(7, [{
id: 17,
type: 'audio',
samples: [{
duration: 9000,
size: 10
}, {
duration: 10000,
size: 11
}]
}]),
moof = mp4.tools.inspect(data),
trun;
assert.deepEqual(moof[0].boxes[1].boxes.length, 3, 'generated three traf children');
trun = moof[0].boxes[1].boxes[2];
assert.ok(trun, 'generated a trun');
assert.equal(trun.dataOffset, data.byteLength + 8, 'calculated the data offset');
assert.deepEqual(trun.samples, [{
duration: 9000,
size: 10
}, {
duration: 10000,
size: 11
}], 'wrote simple audio samples');
});
QUnit.test('can generate a traf without samples', function(assert) {
var
data = mp4.generator.moof(8, [{
trackId: 13
}]),
moof = mp4.tools.inspect(data);
assert.equal(moof[0].boxes[1].boxes[2].samples.length, 0, 'generated no samples');
});
QUnit.test('generates an mdat', function(assert) {
var
data = mp4.generator.mdat(new Uint8Array([1, 2, 3, 4])),
mdat = mp4.tools.inspect(data);
assert.equal(mdat.length, 1, 'generated one box');
assert.equal(mdat[0].type, 'mdat', 'generated an mdat box');
assert.deepEqual(mdat[0].byteLength, 4, 'encapsulated the data');
});

1121
node_modules/mux.js/test/mp4-inspector.test.js generated vendored Normal file

File diff suppressed because it is too large Load diff

407
node_modules/mux.js/test/mp4-probe.test.js generated vendored Normal file
View file

@ -0,0 +1,407 @@
'use strict';
var
QUnit = require('qunit'),
probe = require('../lib/mp4/probe'),
mp4Helpers = require('./utils/mp4-helpers'),
box = mp4Helpers.box,
// defined below
moovWithoutMdhd,
moovWithoutTkhd,
moofWithTfdt,
multiMoof,
multiTraf,
noTrunSamples,
v1boxes;
QUnit.module('MP4 Probe');
QUnit.test('reads the timescale from an mdhd', function(assert) {
// sampleMoov has a base timescale of 1000 with an override to 90kHz
// in the mdhd
assert.deepEqual(probe.timescale(new Uint8Array(mp4Helpers.sampleMoov)), {
1: 90e3,
2: 90e3
}, 'found the timescale');
});
QUnit.test('reads tracks', function(assert) {
var tracks = probe.tracks(new Uint8Array(mp4Helpers.sampleMoov));
assert.equal(tracks.length, 2, 'two tracks');
assert.equal(tracks[0].codec, 'avc1.4d400d', 'codec is correct');
assert.equal(tracks[0].id, 1, 'id is correct');
assert.equal(tracks[0].type, 'video', 'type is correct');
assert.equal(tracks[0].timescale, 90e3, 'timescale is correct');
assert.equal(tracks[1].codec, 'mp4a.40.2', 'codec is correct');
assert.equal(tracks[1].id, 2, 'id is correct');
assert.equal(tracks[1].type, 'audio', 'type is correct');
assert.equal(tracks[1].timescale, 90e3, 'timescale is correct');
});
QUnit.test('returns null if the tkhd is missing', function(assert) {
assert.equal(probe.timescale(new Uint8Array(moovWithoutTkhd)), null, 'indicated missing info');
});
QUnit.test('returns null if the mdhd is missing', function(assert) {
assert.equal(probe.timescale(new Uint8Array(moovWithoutMdhd)), null, 'indicated missing info');
});
QUnit.test('startTime reads the base decode time from a tfdt', function(assert) {
assert.equal(probe.startTime({
4: 2
}, new Uint8Array(moofWithTfdt)),
0x01020304 / 2,
'calculated base decode time');
});
QUnit.test('startTime returns the earliest base decode time', function(assert) {
assert.equal(probe.startTime({
4: 2,
6: 1
}, new Uint8Array(multiMoof)),
0x01020304 / 2,
'returned the earlier time');
});
QUnit.test('startTime parses 64-bit base decode times', function(assert) {
assert.equal(probe.startTime({
4: 3
}, new Uint8Array(v1boxes)),
0x0101020304 / 3,
'parsed a long value');
});
QUnit.test('compositionStartTime calculates composition time using composition time' +
'offset from first trun sample', function(assert) {
assert.equal(probe.compositionStartTime({
1: 6,
4: 3
}, new Uint8Array(moofWithTfdt)),
(0x01020304 + 10) / 3,
'calculated correct composition start time');
});
QUnit.test('compositionStartTime looks at only the first traf', function(assert) {
assert.equal(probe.compositionStartTime({
2: 6,
4: 3
}, new Uint8Array(multiTraf)),
(0x01020304 + 10) / 3,
'calculated composition start time from first traf');
});
QUnit.test('compositionStartTime uses default composition time offset of 0' +
'if no trun samples present', function(assert) {
assert.equal(probe.compositionStartTime({
2: 6,
4: 3
}, new Uint8Array(noTrunSamples)),
(0x01020304 + 0) / 3,
'calculated correct composition start time using default offset');
});
QUnit.test('getTimescaleFromMediaHeader gets timescale for version 0 mdhd', function(assert) {
var mdhd = new Uint8Array([
0x00, // version 0
0x00, 0x00, 0x00, // flags
// version 0 has 32 bit creation_time, modification_time, and duration
0x00, 0x00, 0x00, 0x02, // creation_time
0x00, 0x00, 0x00, 0x03, // modification_time
0x00, 0x00, 0x03, 0xe8, // timescale = 1000
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
0x15, 0xc7 // 'eng' language
]);
assert.equal(
probe.getTimescaleFromMediaHeader(mdhd),
1000,
'got timescale from version 0 mdhd'
);
});
QUnit.test('getTimescaleFromMediaHeader gets timescale for version 0 mdhd', function(assert) {
var mdhd = new Uint8Array([
0x01, // version 1
0x00, 0x00, 0x00, // flags
// version 1 has 64 bit creation_time, modification_time, and duration
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // creation_time
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // modification_time
0x00, 0x00, 0x03, 0xe8, // timescale = 1000
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
0x15, 0xc7 // 'eng' language
]);
assert.equal(
probe.getTimescaleFromMediaHeader(mdhd),
1000,
'got timescale from version 1 mdhd'
);
});
// ---------
// Test Data
// ---------
moovWithoutTkhd =
box('moov',
box('trak',
box('mdia',
box('mdhd',
0x00, // version 0
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x02, // creation_time
0x00, 0x00, 0x00, 0x03, // modification_time
0x00, 0x00, 0x03, 0xe8, // timescale = 1000
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x58, // 600 = 0x258 duration
0x15, 0xc7, // 'eng' language
0x00, 0x00),
box('hdlr',
0x00, // version 1
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x00, // pre_defined
mp4Helpers.typeBytes('vide'), // handler_type
0x00, 0x00, 0x00, 0x00, // reserved
0x00, 0x00, 0x00, 0x00, // reserved
0x00, 0x00, 0x00, 0x00, // reserved
mp4Helpers.typeBytes('one'), 0x00)))); // name
moovWithoutMdhd =
box('moov',
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
mp4Helpers.unityMatrix,
0x01, 0x2c, 0x00, 0x00, // 300 in 16.16 fixed-point
0x00, 0x96, 0x00, 0x00), // 150 in 16.16 fixed-point
box('mdia',
box('hdlr',
0x01, // version 1
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x00, // pre_defined
mp4Helpers.typeBytes('vide'), // handler_type
0x00, 0x00, 0x00, 0x00, // reserved
0x00, 0x00, 0x00, 0x00, // reserved
0x00, 0x00, 0x00, 0x00, // reserved
mp4Helpers.typeBytes('one'), 0x00)))); // name
moofWithTfdt =
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, 0x04, // track_ID = 4
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),
box('tfdt',
0x00, // version
0x00, 0x00, 0x00, // flags
0x01, 0x02, 0x03, 0x04), // baseMediaDecodeTime
box('trun',
0x00, // version
0x00, 0x0f, 0x01, // flags: dataOffsetPresent, sampleDurationPresent,
// sampleSizePresent, sampleFlagsPresent,
// sampleCompositionTimeOffsetsPresent
0x00, 0x00, 0x00, 0x02, // sample_count
0x00, 0x00, 0x00, 0x00, // data_offset, no first_sample_flags
// sample 1
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x0a, // signed sample_composition_time_offset = 10
// sample 2
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x14))); // signed sample_composition_time_offset = 20
noTrunSamples =
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, 0x04, // track_ID = 4
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),
box('tfdt',
0x00, // version
0x00, 0x00, 0x00, // flags
0x01, 0x02, 0x03, 0x04), // baseMediaDecodeTime
box('trun',
0x00, // version
0x00, 0x0f, 0x01, // flags: dataOffsetPresent, sampleDurationPresent,
// sampleSizePresent, sampleFlagsPresent,
// sampleCompositionTimeOffsetsPresent
0x00, 0x00, 0x00, 0x00, // sample_count
0x00, 0x00, 0x00, 0x00))); // data_offset, no first_sample_flags
multiTraf =
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, 0x04, // track_ID = 4
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),
box('tfdt',
0x00, // version
0x00, 0x00, 0x00, // flags
0x01, 0x02, 0x03, 0x04), // baseMediaDecodeTime
box('trun',
0x00, // version
0x00, 0x0f, 0x01, // flags: dataOffsetPresent, sampleDurationPresent,
// sampleSizePresent, sampleFlagsPresent,
// sampleCompositionTimeOffsetsPresent
0x00, 0x00, 0x00, 0x02, // sample_count
0x00, 0x00, 0x00, 0x00, // data_offset, no first_sample_flags
// sample 1
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x0a, // signed sample_composition_time_offset = 10
// sample 2
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x14)), // signed sample_composition_time_offset = 20
box('traf',
box('tfhd',
0x00, // version
0x00, 0x00, 0x3b, // flags
0x00, 0x00, 0x00, 0x02, // track_ID = 2
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),
box('tfdt',
0x00, // version
0x00, 0x00, 0x00, // flags
0x01, 0x02, 0x01, 0x02), // baseMediaDecodeTime
box('trun',
0x00, // version
0x00, 0x0f, 0x01, // flags: dataOffsetPresent, sampleDurationPresent,
// sampleSizePresent, sampleFlagsPresent,
// sampleCompositionTimeOffsetsPresent
0x00, 0x00, 0x00, 0x02, // sample_count
0x00, 0x00, 0x00, 0x00, // data_offset, no first_sample_flags
// sample 1
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x0b, // signed sample_composition_time_offset = 11
// sample 2
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x05))); // signed sample_composition_time_offset = 5
multiMoof = moofWithTfdt
.concat(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, 0x06, // track_ID = 6
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),
box('tfdt',
0x00, // version
0x00, 0x00, 0x00, // flags
0x01, 0x02, 0x03, 0x04), // baseMediaDecodeTime
box('trun',
0x00, // version
0x00, 0x0f, 0x01, // flags: dataOffsetPresent, sampleDurationPresent,
// sampleSizePresent, sampleFlagsPresent,
// sampleCompositionTimeOffsetsPresent
0x00, 0x00, 0x00, 0x02, // sample_count
0x00, 0x00, 0x00, 0x00, // data_offset, no first_sample_flags
// sample 1
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x14, // signed sample_composition_time_offset = 20
// sample 2
0x00, 0x00, 0x00, 0x0a, // sample_duration = 10
0x00, 0x00, 0x00, 0x0a, // sample_size = 10
0x00, 0x00, 0x00, 0x00, // sample_flags
0x00, 0x00, 0x00, 0x0a)))); // signed sample_composition_time_offset = 10
v1boxes =
box('moof',
box('mfhd',
0x01, // version
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x04), // sequence_number
box('traf',
box('tfhd',
0x01, // version
0x00, 0x00, 0x3b, // flags
0x00, 0x00, 0x00, 0x04, // track_ID = 4
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),
box('tfdt',
0x01, // version
0x00, 0x00, 0x00, // flags
0x00, 0x00, 0x00, 0x01,
0x01, 0x02, 0x03, 0x04))); // baseMediaDecodeTime

142
node_modules/mux.js/test/partial.test.js generated vendored Normal file
View file

@ -0,0 +1,142 @@
var Transmuxer = require('../lib/partial/transmuxer.js');
var utils = require('./utils');
var generatePMT = utils.generatePMT;
var videoPes = utils.videoPes;
var audioPes = utils.audioPes;
var packetize = utils.packetize;
var PAT = utils.PAT;
QUnit.module('Partial Transmuxer - Options');
[
{options: {keepOriginalTimestamps: false}},
{options: {keepOriginalTimestamps: true}},
{options: {keepOriginalTimestamps: false, baseMediaDecodeTime: 15000}},
{options: {keepOriginalTimestamps: true, baseMediaDecodeTime: 15000}},
{options: {keepOriginalTimestamps: false}, baseMediaSetter: 15000},
{options: {keepOriginalTimestamps: true}, baseMediaSetter: 15000}
].forEach(function(test) {
var createTransmuxer = function() {
var transmuxer = new Transmuxer(test.options);
if (test.baseMediaSetter) {
transmuxer.setBaseMediaDecodeTime(test.baseMediaSetter);
}
return transmuxer;
};
var name = '';
Object.keys(test.options).forEach(function(optionName) {
name += '' + optionName + ' ' + test.options[optionName] + ' ';
});
if (test.baseMediaSetter) {
name += 'baseMediaDecodeTime setter ' + test.baseMediaSetter;
}
QUnit.test('Audio frames after video not trimmed, ' + name, function(assert) {
var
segments = [],
earliestDts = 15000,
transmuxer = createTransmuxer();
transmuxer.on('data', function(segment) {
segments.push(segment);
});
// the following transmuxer pushes add tiny video and
// audio data to the transmuxer. When we add the data
// we also set the pts/dts time so that audio should
// not be trimmed.
transmuxer.push(packetize(PAT));
transmuxer.push(packetize(generatePMT({
hasVideo: true,
hasAudio: true
})));
transmuxer.push(packetize(audioPes([
0x19, 0x47
], true, earliestDts + 1)));
transmuxer.push(packetize(videoPes([
0x09, 0x01 // access_unit_delimiter_rbsp
], true, earliestDts)));
transmuxer.push(packetize(videoPes([
0x08, 0x01 // pic_parameter_set_rbsp
], true, earliestDts)));
transmuxer.push(packetize(videoPes([
0x07, // seq_parameter_set_rbsp
0x27, 0x42, 0xe0, 0x0b,
0xa9, 0x18, 0x60, 0x9d,
0x80, 0x53, 0x06, 0x01,
0x06, 0xb6, 0xc2, 0xb5,
0xef, 0x7c, 0x04
], false, earliestDts)));
transmuxer.push(packetize(videoPes([
0x05, 0x01 // slice_layer_without_partitioning_rbsp_idr
], true, earliestDts)));
transmuxer.flush();
// the partial transmuxer only generates a video segment
// when all audio frames are trimmed. So we should have an audio and video
// segment
assert.equal(segments.length, 2, 'generated a video and an audio segment');
assert.equal(segments[0].type, 'video', 'video segment exists');
assert.equal(segments[1].type, 'audio', 'audio segment exists');
});
QUnit.test('Audio frames trimmed before video, ' + name, function(assert) {
var
segments = [],
earliestDts = 15000,
baseTime = test.options.baseMediaDecodeTime || test.baseMediaSetter || 0,
transmuxer = createTransmuxer();
transmuxer.on('data', function(segment) {
segments.push(segment);
});
// the following transmuxer pushes add tiny video and
// audio data to the transmuxer. When we add the data
// we also set the pts/dts time so that audio should
// be trimmed.
transmuxer.push(packetize(PAT));
transmuxer.push(packetize(generatePMT({
hasVideo: true,
hasAudio: true
})));
transmuxer.push(packetize(audioPes([
0x19, 0x47
], true, earliestDts - baseTime - 1)));
transmuxer.push(packetize(videoPes([
0x09, 0x01 // access_unit_delimiter_rbsp
], true, earliestDts)));
transmuxer.push(packetize(videoPes([
0x08, 0x01 // pic_parameter_set_rbsp
], true, earliestDts)));
transmuxer.push(packetize(videoPes([
0x07, // seq_parameter_set_rbsp
0x27, 0x42, 0xe0, 0x0b,
0xa9, 0x18, 0x60, 0x9d,
0x80, 0x53, 0x06, 0x01,
0x06, 0xb6, 0xc2, 0xb5,
0xef, 0x7c, 0x04
], false, earliestDts)));
transmuxer.push(packetize(videoPes([
0x05, 0x01 // slice_layer_without_partitioning_rbsp_idr
], true, earliestDts)));
transmuxer.flush();
// the partial transmuxer only generates a video segment
// when all audio frames are trimmed.
if (test.options.keepOriginalTimestamps && !baseTime) {
assert.equal(segments.length, 2, 'generated both a video/audio segment');
assert.equal(segments[0].type, 'video', 'segment is video');
assert.equal(segments[1].type, 'audio', 'segment is audio');
} else {
assert.equal(segments.length, 1, 'generated only a video segment');
assert.equal(segments[0].type, 'video', 'segment is video');
}
});
});

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
node_modules/mux.js/test/segments/sintel-captions.ts generated vendored Normal file

Binary file not shown.

BIN
node_modules/mux.js/test/segments/test-aac-segment.aac generated vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
node_modules/mux.js/test/segments/test-segment.ts generated vendored Normal file

Binary file not shown.

BIN
node_modules/mux.js/test/segments/test-stuffed-pes.ts generated vendored Normal file

Binary file not shown.

48
node_modules/mux.js/test/stream.test.js generated vendored Normal file
View file

@ -0,0 +1,48 @@
'use strict';
var
stream,
Stream = require('../lib/utils/stream'),
QUnit = require('qunit');
QUnit.module('Stream', {
beforeEach: function() {
stream = new Stream();
stream.init();
}
});
QUnit.test('trigger calls listeners', function(assert) {
var args = [];
stream.on('test', function(data) {
args.push(data);
});
stream.trigger('test', 1);
stream.trigger('test', 2);
assert.deepEqual(args, [1, 2]);
});
QUnit.test('callbacks can remove themselves', function(assert) {
var args1 = [], args2 = [], args3 = [];
stream.on('test', function(event) {
args1.push(event);
});
stream.on('test', function t(event) {
args2.push(event);
stream.off('test', t);
});
stream.on('test', function(event) {
args3.push(event);
});
stream.trigger('test', 1);
stream.trigger('test', 2);
assert.deepEqual(args1, [1, 2], 'first callback ran all times');
assert.deepEqual(args2, [1], 'second callback removed after first run');
assert.deepEqual(args3, [1, 2], 'third callback ran all times');
});

4498
node_modules/mux.js/test/transmuxer.test.js generated vendored Normal file

File diff suppressed because it is too large Load diff

205
node_modules/mux.js/test/ts-inspector.test.js generated vendored Normal file
View file

@ -0,0 +1,205 @@
'use strict';
var segments = require('data-files!segments');
var
QUnit = require('qunit'),
tsInspector = require('../lib/tools/ts-inspector.js'),
StreamTypes = require('../lib/m2ts/stream-types.js'),
tsSegment = segments['test-segment.ts'](),
tsNoAudioSegment = segments['test-no-audio-segment.ts'](),
aacSegment = segments['test-aac-segment.aac'](),
utils = require('./utils'),
inspect = tsInspector.inspect,
parseAudioPes_ = tsInspector.parseAudioPes_,
packetize = utils.packetize,
audioPes = utils.audioPes,
PES_TIMESCALE = 90000;
QUnit.module('TS Inspector');
QUnit.test('returns null for empty segment input', function(assert) {
assert.equal(inspect(new Uint8Array([])), null, 'returned null');
});
QUnit.test('can parse a ts segment', function(assert) {
var expected = {
video: [
{
type: 'video',
pts: 126000,
dts: 126000,
ptsTime: 126000 / PES_TIMESCALE,
dtsTime: 126000 / PES_TIMESCALE
},
{
type: 'video',
pts: 924000,
dts: 924000,
ptsTime: 924000 / PES_TIMESCALE,
dtsTime: 924000 / PES_TIMESCALE
}
],
firstKeyFrame: {
type: 'video',
pts: 126000,
dts: 126000,
ptsTime: 126000 / PES_TIMESCALE,
dtsTime: 126000 / PES_TIMESCALE
},
audio: [
{
type: 'audio',
pts: 126000,
dts: 126000,
ptsTime: 126000 / PES_TIMESCALE,
dtsTime: 126000 / PES_TIMESCALE
},
{
type: 'audio',
pts: 859518,
dts: 859518,
ptsTime: 859518 / PES_TIMESCALE,
dtsTime: 859518 / PES_TIMESCALE
}
]
};
assert.deepEqual(inspect(tsSegment), expected, 'parses ts segment timing data');
});
QUnit.test('adjusts timestamp values based on provided reference', function(assert) {
var rollover = Math.pow(2, 33);
var expected = {
video: [
{
type: 'video',
pts: (126000 + rollover),
dts: (126000 + rollover),
ptsTime: (126000 + rollover) / PES_TIMESCALE,
dtsTime: (126000 + rollover) / PES_TIMESCALE
},
{
type: 'video',
pts: (924000 + rollover),
dts: (924000 + rollover),
ptsTime: (924000 + rollover) / PES_TIMESCALE,
dtsTime: (924000 + rollover) / PES_TIMESCALE
}
],
firstKeyFrame: {
type: 'video',
pts: (126000 + rollover),
dts: (126000 + rollover),
ptsTime: (126000 + rollover) / PES_TIMESCALE,
dtsTime: (126000 + rollover) / PES_TIMESCALE
},
audio: [
{
type: 'audio',
pts: (126000 + rollover),
dts: (126000 + rollover),
ptsTime: (126000 + rollover) / PES_TIMESCALE,
dtsTime: (126000 + rollover) / PES_TIMESCALE
},
{
type: 'audio',
pts: (859518 + rollover),
dts: (859518 + rollover),
ptsTime: (859518 + rollover) / PES_TIMESCALE,
dtsTime: (859518 + rollover) / PES_TIMESCALE
}
]
};
assert.deepEqual(inspect(tsSegment, rollover - 1), expected,
'adjusts inspected time data to account for pts rollover');
});
QUnit.test('can parse an aac segment', function(assert) {
var expected = {
audio: [
{
type: 'audio',
pts: 895690,
dts: 895690,
ptsTime: 895690 / PES_TIMESCALE,
dtsTime: 895690 / PES_TIMESCALE
},
{
type: 'audio',
pts: (895690 + (430 * 1024 * PES_TIMESCALE / 44100)),
dts: (895690 + (430 * 1024 * PES_TIMESCALE / 44100)),
ptsTime: (895690 + (430 * 1024 * PES_TIMESCALE / 44100)) / PES_TIMESCALE,
dtsTime: (895690 + (430 * 1024 * PES_TIMESCALE / 44100)) / PES_TIMESCALE
}
]
};
assert.deepEqual(inspect(aacSegment), expected, 'parses aac segment timing data');
});
QUnit.test('can parse ts segment with no audio muxed in', function(assert) {
var expected = {
video: [
{
type: 'video',
pts: 126000,
dts: 126000,
ptsTime: 126000 / PES_TIMESCALE,
dtsTime: 126000 / PES_TIMESCALE
},
{
type: 'video',
pts: 924000,
dts: 924000,
ptsTime: 924000 / PES_TIMESCALE,
dtsTime: 924000 / PES_TIMESCALE
}
],
firstKeyFrame: {
type: 'video',
pts: 126000,
dts: 126000,
ptsTime: 126000 / PES_TIMESCALE,
dtsTime: 126000 / PES_TIMESCALE
}
};
var actual = inspect(tsNoAudioSegment);
assert.equal(typeof actual.audio, 'undefined', 'results do not contain audio info');
assert.deepEqual(actual, expected,
'parses ts segment without audio timing data');
});
QUnit.test('can parse audio PES when it\'s the only packet in a stream', function(assert) {
var
pts = 90000,
pmt = {
// fake pmt pid that doesn't clash with the audio pid
pid: 0x10,
table: {
// pid copied over from default of audioPes function
0x12: StreamTypes.ADTS_STREAM_TYPE
}
},
result = { audio: [] };
parseAudioPes_(packetize(audioPes([0x00], true, pts)), pmt, result);
// note that both the first and last packet timings are the same, as there's only one
// packet to parse
assert.deepEqual(
result.audio,
[{
dts: pts,
pts: pts,
type: 'audio'
}, {
dts: pts,
pts: pts,
type: 'audio'
}],
'parses audio pes for timing info');
});

32
node_modules/mux.js/test/utils.bin.test.js generated vendored Normal file
View file

@ -0,0 +1,32 @@
var
QUnit = require('qunit'),
toUnsigned = require('../lib/utils/bin').toUnsigned;
QUnit.module('Binary Utils');
QUnit.test('converts values to unsigned integers after bitwise operations', function(assert) {
var bytes;
bytes = [0, 0, 124, 129];
assert.equal(toUnsigned(bytes[0] << 24 |
bytes[1] << 16 |
bytes[2] << 8 |
bytes[3]),
31873, 'positive signed result stays positive');
bytes = [150, 234, 221, 192];
// sanity check
assert.equal(bytes[0] << 24 |
bytes[1] << 16 |
bytes[2] << 8 |
bytes[3],
-1762992704, 'bitwise operation produces negative signed result');
assert.equal(toUnsigned(bytes[0] << 24 |
bytes[1] << 16 |
bytes[2] << 8 |
bytes[3]),
2531974592, 'negative signed result becomes unsigned positive');
});

181
node_modules/mux.js/test/utils.clock.test.js generated vendored Normal file
View file

@ -0,0 +1,181 @@
'use strict';
var
QUnit = require('qunit'),
clock = require('../lib/utils/clock');
QUnit.module('Clock Utils');
QUnit.test('converts from seconds to video timestamps', function(assert) {
assert.equal(clock.secondsToVideoTs(0), 0, 'converts seconds to video timestamp');
assert.equal(clock.secondsToVideoTs(1), 90000, 'converts seconds to video timestamp');
assert.equal(clock.secondsToVideoTs(10), 900000, 'converts seconds to video timestamp');
assert.equal(clock.secondsToVideoTs(-1), -90000, 'converts seconds to video timestamp');
assert.equal(clock.secondsToVideoTs(3), 270000, 'converts seconds to video timestamp');
assert.equal(clock.secondsToVideoTs(0.1), 9000, 'converts seconds to video timestamp');
});
QUnit.test('converts from seconds to audio timestamps', function(assert) {
assert.equal(clock.secondsToAudioTs(0, 90000),
0,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(1, 90000),
90000,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(-1, 90000),
-90000,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(3, 90000),
270000,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(0, 44100),
0,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(1, 44100),
44100,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(3, 44100),
132300,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(-1, 44100),
-44100,
'converts seconds to audio timestamp');
assert.equal(clock.secondsToAudioTs(0.1, 44100),
4410,
'converts seconds to audio timestamp');
});
QUnit.test('converts from video timestamp to seconds', function(assert) {
assert.equal(clock.videoTsToSeconds(0), 0, 'converts video timestamp to seconds');
assert.equal(clock.videoTsToSeconds(90000), 1, 'converts video timestamp to seconds');
assert.equal(clock.videoTsToSeconds(900000), 10, 'converts video timestamp to seconds');
assert.equal(clock.videoTsToSeconds(-90000), -1, 'converts video timestamp to seconds');
assert.equal(clock.videoTsToSeconds(270000), 3, 'converts video timestamp to seconds');
assert.equal(clock.videoTsToSeconds(9000), 0.1, 'converts video timestamp to seconds');
});
QUnit.test('converts from audio timestamp to seconds', function(assert) {
assert.equal(clock.audioTsToSeconds(0, 90000),
0,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(90000, 90000),
1,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(-90000, 90000),
-1,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(270000, 90000),
3,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(0, 44100),
0,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(44100, 44100),
1,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(132300, 44100),
3,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(-44100, 44100),
-1,
'converts seconds to audio timestamp');
assert.equal(clock.audioTsToSeconds(4410, 44100),
0.1,
'converts seconds to audio timestamp');
});
QUnit.test('converts from audio timestamp to video timestamp', function(assert) {
assert.equal(clock.audioTsToVideoTs(0, 90000),
0,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(90000, 90000),
90000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(900000, 90000),
900000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(-90000, 90000),
-90000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(270000, 90000),
270000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(9000, 90000),
9000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(0, 44100),
0,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(44100, 44100),
90000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(441000, 44100),
900000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(-44100, 44100),
-90000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(132300, 44100),
270000,
'converts audio timestamp to video timestamp');
assert.equal(clock.audioTsToVideoTs(4410, 44100),
9000,
'converts audio timestamp to video timestamp');
});
QUnit.test('converts from video timestamp to audio timestamp', function(assert) {
assert.equal(clock.videoTsToAudioTs(0, 90000),
0,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(90000, 90000),
90000,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(900000, 90000),
900000,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(-90000, 90000),
-90000,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(270000, 90000),
270000,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(9000, 90000),
9000,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(0, 44100),
0,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(90000, 44100),
44100,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(900000, 44100),
441000,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(-90000, 44100),
-44100,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(270000, 44100),
132300,
'converts video timestamp to audio timestamp');
assert.equal(clock.videoTsToAudioTs(9000, 44100),
4410,
'converts video timestamp to audio timestamp');
});
QUnit.test('converts from metadata timestamp to seconds', function(assert) {
assert.equal(clock.metadataTsToSeconds(90000, 90000, false),
0,
'converts metadata timestamp to seconds and adjusts by timelineStartPts');
assert.equal(clock.metadataTsToSeconds(270000, 90000, false),
2,
'converts metadata timestamp to seconds and adjusts by timelineStartPts');
assert.equal(clock.metadataTsToSeconds(90000, 90000, true),
1,
'converts metadata timestamp to seconds while keeping original timestamps');
assert.equal(clock.metadataTsToSeconds(180000, 0, true),
2,
'converts metadata timestamp to seconds while keeping original timestamps');
});

327
node_modules/mux.js/test/utils.js generated vendored Normal file
View file

@ -0,0 +1,327 @@
var
mp2t = require('../lib/m2ts'),
id3Generator = require('./utils/id3-generator'),
MP2T_PACKET_LENGTH = mp2t.MP2T_PACKET_LENGTH,
PMT,
PAT,
generatePMT,
pesHeader,
packetize,
transportPacket,
videoPes,
adtsFrame,
audioPes,
timedMetadataPes,
binaryStringToArrayOfBytes,
leftPad;
PMT = [
0x47, // sync byte
// tei:0 pusi:1 tp:0 pid:0 0000 0010 0000
0x40, 0x10,
// tsc:01 afc:01 cc:0000 pointer_field:0000 0000
0x50, 0x00,
// tid:0000 0010 ssi:0 0:0 r:00 sl:0000 0001 1100
0x02, 0x00, 0x1c,
// pn:0000 0000 0000 0001
0x00, 0x01,
// r:00 vn:00 000 cni:1 sn:0000 0000 lsn:0000 0000
0x01, 0x00, 0x00,
// r:000 ppid:0 0011 1111 1111
0x03, 0xff,
// r:0000 pil:0000 0000 0000
0x00, 0x00,
// h264
// st:0001 1010 r:000 epid:0 0000 0001 0001
0x1b, 0x00, 0x11,
// r:0000 esil:0000 0000 0000
0x00, 0x00,
// adts
// st:0000 1111 r:000 epid:0 0000 0001 0010
0x0f, 0x00, 0x12,
// r:0000 esil:0000 0000 0000
0x00, 0x00,
// timed metadata
// st:0001 0111 r:000 epid:0 0000 0001 0011
0x15, 0x00, 0x13,
// r:0000 esil:0000 0000 0000
0x00, 0x00,
// crc
0x00, 0x00, 0x00, 0x00
];
/*
Packet Header:
| sb | tei pusi tp pid:5 | pid | tsc afc cc |
with af:
| afl | ... | <data> |
without af:
| <data> |
PAT:
| pf? | ... |
| tid | ssi '0' r sl:4 | sl | tsi:8 |
| tsi | r vn cni | sn | lsn |
with program_number == '0':
| pn | pn | r np:5 | np |
otherwise:
| pn | pn | r pmp:5 | pmp |
*/
PAT = [
0x47, // sync byte
// tei:0 pusi:1 tp:0 pid:0 0000 0000 0000
0x40, 0x00,
// tsc:01 afc:01 cc:0000 pointer_field:0000 0000
0x50, 0x00,
// tid:0000 0000 ssi:0 0:0 r:00 sl:0000 0000 0000
0x00, 0x00, 0x00,
// tsi:0000 0000 0000 0000
0x00, 0x00,
// r:00 vn:00 000 cni:1 sn:0000 0000 lsn:0000 0000
0x01, 0x00, 0x00,
// pn:0000 0000 0000 0001
0x00, 0x01,
// r:000 pmp:0 0000 0010 0000
0x00, 0x10,
// crc32:0000 0000 0000 0000 0000 0000 0000 0000
0x00, 0x00, 0x00, 0x00
];
generatePMT = function(options) {
var PMT = [
0x47, // sync byte
// tei:0 pusi:1 tp:0 pid:0 0000 0010 0000
0x40, 0x10,
// tsc:01 afc:01 cc:0000 pointer_field:0000 0000
0x50, 0x00,
// tid:0000 0010 ssi:0 0:0 r:00 sl:0000 0001 1100
0x02, 0x00, 0x1c,
// pn:0000 0000 0000 0001
0x00, 0x01,
// r:00 vn:00 000 cni:1 sn:0000 0000 lsn:0000 0000
0x01, 0x00, 0x00,
// r:000 ppid:0 0011 1111 1111
0x03, 0xff,
// r:0000 pil:0000 0000 0000
0x00, 0x00];
if (options.hasVideo) {
// h264
PMT = PMT.concat([
// st:0001 1010 r:000 epid:0 0000 0001 0001
0x1b, 0x00, 0x11,
// r:0000 esil:0000 0000 0000
0x00, 0x00
]);
}
if (options.hasAudio) {
// adts
PMT = PMT.concat([
// st:0000 1111 r:000 epid:0 0000 0001 0010
0x0f, 0x00, 0x12,
// r:0000 esil:0000 0000 0000
0x00, 0x00
]);
}
if (options.hasMetadata) {
// timed metadata
PMT = PMT.concat([
// st:0001 0111 r:000 epid:0 0000 0001 0011
0x15, 0x00, 0x13,
// r:0000 esil:0000 0000 0000
0x00, 0x00
]);
}
// crc
return PMT.concat([0x00, 0x00, 0x00, 0x00]);
};
pesHeader = function(first, pts, dataLength) {
if (!dataLength) {
dataLength = 0;
} else {
// Add the pes header length (only the portion after the
// pes_packet_length field)
dataLength += 3;
}
// PES_packet(), Rec. ITU-T H.222.0, Table 2-21
var result = [
// pscp:0000 0000 0000 0000 0000 0001
0x00, 0x00, 0x01,
// sid:0000 0000 ppl:0000 0000 0000 0000
0x00, 0x00, 0x00,
// 10 psc:00 pp:0 dai:1 c:0 ooc:0
0x84,
// pdf:?0 ef:1 erf:0 dtmf:0 acif:0 pcf:0 pef:0
0x20 | (pts ? 0x80 : 0x00),
// phdl:0000 0000
(first ? 0x01 : 0x00) + (pts ? 0x05 : 0x00)
];
// Only store 15 bits of the PTS for QUnit.testing purposes
if (pts) {
var
pts32 = Math.floor(pts / 2), // right shift by 1
leftMostBit = ((pts32 & 0x80000000) >>> 31) & 0x01,
firstThree;
pts = pts & 0xffffffff; // remove left most bit
firstThree = (leftMostBit << 3) | (((pts & 0xc0000000) >>> 29) & 0x06) | 0x01;
result.push((0x2 << 4) | firstThree);
result.push((pts >>> 22) & 0xff);
result.push(((pts >>> 14) | 0x01) & 0xff);
result.push((pts >>> 7) & 0xff);
result.push(((pts << 1) | 0x01) & 0xff);
// Add the bytes spent on the pts info
dataLength += 5;
}
if (first) {
result.push(0x00);
dataLength += 1;
}
// Finally set the pes_packet_length field
result[4] = (dataLength & 0x0000FF00) >> 8;
result[5] = dataLength & 0x000000FF;
return result;
};
packetize = function(data) {
var packet = new Uint8Array(MP2T_PACKET_LENGTH);
packet.set(data);
return packet;
};
/**
* Helper function to create transport stream PES packets
* @param pid {uint8} - the program identifier (PID)
* @param data {arraylike} - the payload bytes
* @payload first {boolean} - true if this PES should be a payload
* unit start
*/
transportPacket = function(pid, data, first, pts, isVideoData) {
var
adaptationFieldLength = 188 - data.length - 14 - (first ? 1 : 0) - (pts ? 5 : 0),
// transport_packet(), Rec. ITU-T H.222.0, Table 2-2
result = [
// sync byte
0x47,
// tei:0 pusi:1 tp:0 pid:0 0000 0001 0001
0x40, pid,
// tsc:01 afc:11 cc:0000
0x70
].concat([
// afl
adaptationFieldLength & 0xff,
// di:0 rai:0 espi:0 pf:0 of:0 spf:0 tpdf:0 afef:0
0x00
]),
i;
i = adaptationFieldLength - 1;
while (i--) {
// stuffing_bytes
result.push(0xff);
}
// PES_packet(), Rec. ITU-T H.222.0, Table 2-21
result = result.concat(pesHeader(first, pts, isVideoData ? 0 : data.length));
return result.concat(data);
};
/**
* Helper function to create video PES packets
* @param data {arraylike} - the payload bytes
* @payload first {boolean} - true if this PES should be a payload
* unit start
*/
videoPes = function(data, first, pts) {
return transportPacket(0x11, [
// NAL unit start code
0x00, 0x00, 0x01
].concat(data), first, pts, true);
};
/**
* Helper function to create audio ADTS frame header
* @param dataLength {number} - the payload byte count
*/
adtsFrame = function(dataLength) {
var frameLength = dataLength + 7;
return [
0xff, 0xf1, // no CRC
0x10, // AAC Main, 44.1KHz
0xb0 | ((frameLength & 0x1800) >> 11), // 2 channels
(frameLength & 0x7f8) >> 3,
((frameLength & 0x07) << 5) + 7, // frame length in bytes
0x00 // one AAC per ADTS frame
];
};
/**
* Helper function to create audio PES packets
* @param data {arraylike} - the payload bytes
* @payload first {boolean} - true if this PES should be a payload
* unit start
*/
audioPes = function(data, first, pts) {
return transportPacket(0x12,
adtsFrame(data.length).concat(data),
first, pts);
};
timedMetadataPes = function(data) {
var id3 = id3Generator;
return transportPacket(0x13, id3.id3Tag(id3.id3Frame('PRIV', 0x00, 0x01)));
};
binaryStringToArrayOfBytes = function(string) {
var
array = [],
arrayIndex = 0,
stringIndex = 0;
while (stringIndex < string.length) {
array[arrayIndex] = parseInt(string.slice(stringIndex, stringIndex + 8), 2);
arrayIndex++;
// next byte
stringIndex += 8;
}
return array;
};
leftPad = function(string, targetLength) {
if (string.length >= targetLength) {
return string;
}
return new Array(targetLength - string.length + 1).join('0') + string;
};
module.exports = {
PMT: PMT,
PAT: PAT,
generatePMT: generatePMT,
pesHeader: pesHeader,
packetize: packetize,
transportPacket: transportPacket,
videoPes: videoPes,
adtsFrame: adtsFrame,
audioPes: audioPes,
timedMetadataPes: timedMetadataPes,
binaryStringToArrayOfBytes: binaryStringToArrayOfBytes,
leftPad: leftPad
};

10816
node_modules/mux.js/test/utils/cc708-pink-underscore.js generated vendored Normal file

File diff suppressed because it is too large Load diff

74
node_modules/mux.js/test/utils/id3-generator.js generated vendored Normal file
View file

@ -0,0 +1,74 @@
/**
* Helper functions for creating ID3 metadata.
*/
'use strict';
var stringToInts, stringToCString, id3Tag, id3Frame;
stringToInts = function(string) {
var result = [], i;
for (i = 0; i < string.length; i++) {
result[i] = string.charCodeAt(i);
}
return result;
};
stringToCString = function(string) {
return stringToInts(string).concat([0x00]);
};
id3Tag = function() {
var
frames = Array.prototype.concat.apply([], Array.prototype.slice.call(arguments)),
result = stringToInts('ID3').concat([
0x03, 0x00, // version 3.0 of ID3v2 (aka ID3v.2.3.0)
0x40, // flags. include an extended header
0x00, 0x00, 0x00, 0x00, // size. set later
// extended header
0x00, 0x00, 0x00, 0x06, // extended header size. no CRC
0x00, 0x00, // extended flags
0x00, 0x00, 0x00, 0x02 // size of padding
], frames),
size;
// size is stored as a sequence of four 7-bit integers with the
// high bit of each byte set to zero
size = result.length - 10;
result[6] = (size >>> 21) & 0x7f;
result[7] = (size >>> 14) & 0x7f;
result[8] = (size >>> 7) & 0x7f;
result[9] = size & 0x7f;
return result;
};
id3Frame = function(type) {
var result = stringToInts(type).concat([
0x00, 0x00, 0x00, 0x00, // size
0xe0, 0x00 // flags. tag/file alter preservation, read-only
]),
size = result.length - 10;
// append the fields of the ID3 frame
result = result.concat.apply(result, Array.prototype.slice.call(arguments, 1));
// set the size
size = result.length - 10;
result[4] = (size >>> 21) & 0x7f;
result[5] = (size >>> 14) & 0x7f;
result[6] = (size >>> 7) & 0x7f;
result[7] = size & 0x7f;
return result;
};
module.exports = {
stringToInts: stringToInts,
stringToCString: stringToCString,
id3Tag: id3Tag,
id3Frame: id3Frame
};

View file

@ -0,0 +1,996 @@
module.exports = [
{ type: 1, pts: 7192231956, ccData: 36782 },
{ type: 0, pts: 7192231956, ccData: 38062 },
{ type: 3, pts: 7192231956, ccData: 17186 },
{ type: 2, pts: 7192234926, ccData: 0 },
{ type: 1, pts: 7192234926, ccData: 387 },
{ type: 2, pts: 7192234926, ccData: 36094 },
{ type: 0, pts: 7192234926, ccData: 38062 },
{ type: 2, pts: 7192240866, ccData: 16640 },
{ type: 2, pts: 7192240866, ccData: 39195 },
{ type: 2, pts: 7192240866, ccData: 1283 },
{ type: 2, pts: 7192240866, ccData: 37162 },
{ type: 2, pts: 7192240866, ccData: 42 },
{ type: 2, pts: 7192240866, ccData: 37376 },
{ type: 2, pts: 7192240866, ccData: 1024 },
{ type: 2, pts: 7192240866, ccData: 31 },
{ type: 0, pts: 7192240866, ccData: 37970 },
{ type: 1, pts: 7192240866, ccData: 62196 },
{ type: 2, pts: 7192240866, ccData: 5264 },
{ type: 1, pts: 7192243926, ccData: 26656 },
{ type: 3, pts: 7192243926, ccData: 49955 },
{ type: 0, pts: 7192243926, ccData: 38817 },
{ type: 1, pts: 7192246896, ccData: 22511 },
{ type: 0, pts: 7192246896, ccData: 38817 },
{ type: 2, pts: 7192246896, ccData: 37376 },
{ type: 2, pts: 7192246896, ccData: 1280 },
{ type: 1, pts: 7192249956, ccData: 61284 },
{ type: 0, pts: 7192249956, ccData: 49877 },
{ type: 3, pts: 7192249956, ccData: 802 },
{ type: 1, pts: 7192253016, ccData: 29472 },
{ type: 2, pts: 7192253016, ccData: 0 },
{ type: 0, pts: 7192253016, ccData: 21536 },
{ type: 2, pts: 7192253016, ccData: 16981 },
{ type: 3, pts: 7192253016, ccData: 17186 },
{ type: 3, pts: 7192255986, ccData: 33570 },
{ type: 1, pts: 7192255986, ccData: 19553 },
{ type: 0, pts: 7192255986, ccData: 18772 },
{ type: 2, pts: 7192255986, ccData: 21536 },
{ type: 2, pts: 7192255986, ccData: 0 },
{ type: 0, pts: 7192258956, ccData: 42963 },
{ type: 2, pts: 7192258956, ccData: 18772 },
{ type: 2, pts: 7192258956, ccData: 0 },
{ type: 3, pts: 7192258956, ccData: 49954 },
{ type: 1, pts: 7192258956, ccData: 63418 },
{ type: 0, pts: 7192261926, ccData: 8398 },
{ type: 1, pts: 7192261926, ccData: 8271 },
{ type: 2, pts: 7192261926, ccData: 10067 },
{ type: 2, pts: 7192261926, ccData: 0 },
{ type: 3, pts: 7192261926, ccData: 802 },
{ type: 3, pts: 7192264896, ccData: 17186 },
{ type: 2, pts: 7192264896, ccData: 0 },
{ type: 2, pts: 7192264896, ccData: 8270 },
{ type: 1, pts: 7192264896, ccData: 28192 },
{ type: 0, pts: 7192264896, ccData: 20308 },
{ type: 2, pts: 7192267956, ccData: 0 },
{ type: 2, pts: 7192267956, ccData: 20308 },
{ type: 1, pts: 7192267956, ccData: 62568 },
{ type: 0, pts: 7192267956, ccData: 8403 },
{ type: 3, pts: 7192267956, ccData: 33570 },
{ type: 3, pts: 7192270926, ccData: 49954 },
{ type: 0, pts: 7192270926, ccData: 54598 },
{ type: 2, pts: 7192270926, ccData: 8275 },
{ type: 2, pts: 7192270926, ccData: 0 },
{ type: 1, pts: 7192270926, ccData: 58656 },
{ type: 1, pts: 7192273986, ccData: 51317 },
{ type: 0, pts: 7192273986, ccData: 17989 },
{ type: 2, pts: 7192273986, ccData: 21830 },
{ type: 2, pts: 7192273986, ccData: 0 },
{ type: 3, pts: 7192273986, ccData: 802 },
{ type: 3, pts: 7192277046, ccData: 17186 },
{ type: 2, pts: 7192277046, ccData: 17989 },
{ type: 1, pts: 7192277046, ccData: 28404 },
{ type: 0, pts: 7192277046, ccData: 21065 },
{ type: 2, pts: 7192277046, ccData: 0 },
{ type: 1, pts: 7192279926, ccData: 8360 },
{ type: 2, pts: 7192279926, ccData: 21065 },
{ type: 2, pts: 7192279926, ccData: 0 },
{ type: 3, pts: 7192279926, ccData: 33570 },
{ type: 0, pts: 7192279926, ccData: 52935 },
{ type: 1, pts: 7192282986, ccData: 54245 },
{ type: 0, pts: 7192282986, ccData: 38132 },
{ type: 2, pts: 7192282986, ccData: 20039 },
{ type: 2, pts: 7192282986, ccData: 0 },
{ type: 3, pts: 7192282986, ccData: 51761 },
{ type: 1, pts: 7192285956, ccData: 36667 },
{ type: 2, pts: 7192285956, ccData: 2048 },
{ type: 2, pts: 7192285956, ccData: 39195 },
{ type: 2, pts: 7192285956, ccData: 16640 },
{ type: 2, pts: 7192285956, ccData: 287 },
{ type: 2, pts: 7192285956, ccData: 4240 },
{ type: 2, pts: 7192285956, ccData: 1283 },
{ type: 2, pts: 7192285956, ccData: 37162 },
{ type: 2, pts: 7192285956, ccData: 0 },
{ type: 0, pts: 7192285956, ccData: 38132 },
{ type: 2, pts: 7192285956, ccData: 37377 },
{ type: 3, pts: 7192288926, ccData: 803 },
{ type: 1, pts: 7192288926, ccData: 258 },
{ type: 0, pts: 7192288926, ccData: 38691 },
{ type: 1, pts: 7192291986, ccData: 16448 },
{ type: 2, pts: 7192291986, ccData: 37377 },
{ type: 2, pts: 7192291986, ccData: 2816 },
{ type: 0, pts: 7192291986, ccData: 38691 },
{ type: 1, pts: 7192294956, ccData: 16448 },
{ type: 0, pts: 7192294956, ccData: 21065 },
{ type: 3, pts: 7192294956, ccData: 17186 },
{ type: 0, pts: 7192298016, ccData: 51144 },
{ type: 2, pts: 7192298016, ccData: 21065 },
{ type: 2, pts: 7192298016, ccData: 0 },
{ type: 3, pts: 7192298016, ccData: 33570 },
{ type: 1, pts: 7192298016, ccData: 16512 },
{ type: 1, pts: 7192300986, ccData: 36782 },
{ type: 2, pts: 7192300986, ccData: 0 },
{ type: 2, pts: 7192300986, ccData: 18248 },
{ type: 3, pts: 7192309986, ccData: 33828 },
{ type: 2, pts: 7192309986, ccData: 0 },
{ type: 2, pts: 7192309986, ccData: 22318 },
{ type: 0, pts: 7192309986, ccData: 22446 },
{ type: 1, pts: 7192309986, ccData: 62196 },
{ type: 0, pts: 7192309986, ccData: 37935 },
{ type: 3, pts: 7192309986, ccData: 17186 },
{ type: 2, pts: 7192313046, ccData: 0 },
{ type: 0, pts: 7192313046, ccData: 37935 },
{ type: 1, pts: 7192313046, ccData: 26656 },
{ type: 2, pts: 7192313046, ccData: 35074 },
{ type: 2, pts: 7192313046, ccData: 35841 },
{ type: 0, pts: 7192316016, ccData: 32896 },
{ type: 1, pts: 7192316016, ccData: 22511 },
{ type: 1, pts: 7192318986, ccData: 61284 },
{ type: 0, pts: 7192318986, ccData: 32896 },
{ type: 1, pts: 7192322046, ccData: 29472 },
{ type: 0, pts: 7192322046, ccData: 32896 },
{ type: 1, pts: 7192324926, ccData: 389 },
{ type: 0, pts: 7192324926, ccData: 32896 },
{ type: 0, pts: 7192327986, ccData: 32896 },
{ type: 1, pts: 7192327986, ccData: 51396 },
{ type: 1, pts: 7192331046, ccData: 36831 },
{ type: 0, pts: 7192331046, ccData: 32896 },
{ type: 0, pts: 7192334016, ccData: 32896 },
{ type: 1, pts: 7192334016, ccData: 258 },
{ type: 0, pts: 7192337076, ccData: 32896 },
{ type: 1, pts: 7192337076, ccData: 16448 },
{ type: 1, pts: 7192340046, ccData: 16448 },
{ type: 0, pts: 7192340046, ccData: 32896 },
{ type: 0, pts: 7192343016, ccData: 32896 },
{ type: 1, pts: 7192343016, ccData: 16512 },
{ type: 1, pts: 7192346076, ccData: 36782 },
{ type: 0, pts: 7192346076, ccData: 32896 },
{ type: 0, pts: 7192348956, ccData: 32896 },
{ type: 1, pts: 7192348956, ccData: 387 },
{ type: 1, pts: 7192352016, ccData: 52975 },
{ type: 0, pts: 7192352016, ccData: 32896 },
{ type: 1, pts: 7192355076, ccData: 62196 },
{ type: 0, pts: 7192355076, ccData: 32896 },
{ type: 0, pts: 7192358046, ccData: 32896 },
{ type: 1, pts: 7192358046, ccData: 26656 },
{ type: 1, pts: 7192361106, ccData: 22511 },
{ type: 0, pts: 7192361106, ccData: 32896 },
{ type: 1, pts: 7192364076, ccData: 61284 },
{ type: 0, pts: 7192364076, ccData: 32896 },
{ type: 1, pts: 7192367046, ccData: 29472 },
{ type: 0, pts: 7192367046, ccData: 32896 },
{ type: 1, pts: 7192370016, ccData: 19553 },
{ type: 0, pts: 7192370016, ccData: 32896 },
{ type: 0, pts: 7192372986, ccData: 32896 },
{ type: 1, pts: 7192372986, ccData: 63418 },
{ type: 0, pts: 7192376046, ccData: 32896 },
{ type: 1, pts: 7192376046, ccData: 8271 },
{ type: 0, pts: 7192379106, ccData: 32896 },
{ type: 1, pts: 7192379106, ccData: 28192 },
{ type: 1, pts: 7192382076, ccData: 62568 },
{ type: 0, pts: 7192382076, ccData: 32896 },
{ type: 1, pts: 7192385136, ccData: 58656 },
{ type: 0, pts: 7192385136, ccData: 32896 },
{ type: 0, pts: 7192388106, ccData: 32896 },
{ type: 1, pts: 7192388106, ccData: 51317 },
{ type: 1, pts: 7192391076, ccData: 28404 },
{ type: 0, pts: 7192391076, ccData: 32896 },
{ type: 0, pts: 7192394046, ccData: 32896 },
{ type: 1, pts: 7192394046, ccData: 8360 },
{ type: 1, pts: 7192397016, ccData: 54245 },
{ type: 0, pts: 7192397016, ccData: 32896 },
{ type: 1, pts: 7192400076, ccData: 36667 },
{ type: 0, pts: 7192400076, ccData: 32896 },
{ type: 1, pts: 7192403046, ccData: 258 },
{ type: 0, pts: 7192403046, ccData: 32896 },
{ type: 1, pts: 7192406106, ccData: 16448 },
{ type: 0, pts: 7192406106, ccData: 32896 },
{ type: 1, pts: 7192409166, ccData: 16448 },
{ type: 0, pts: 7192409166, ccData: 32896 },
{ type: 1, pts: 7192412136, ccData: 16512 },
{ type: 0, pts: 7192412136, ccData: 32896 },
{ type: 0, pts: 7192415106, ccData: 32896 },
{ type: 1, pts: 7192415106, ccData: 36782 },
{ type: 1, pts: 7192418076, ccData: 387 },
{ type: 0, pts: 7192418076, ccData: 32896 },
{ type: 1, pts: 7192421046, ccData: 52975 },
{ type: 0, pts: 7192421046, ccData: 32896 },
{ type: 1, pts: 7192424106, ccData: 62196 },
{ type: 0, pts: 7192424106, ccData: 32896 },
{ type: 0, pts: 7192427076, ccData: 32896 },
{ type: 1, pts: 7192427076, ccData: 26656 },
{ type: 1, pts: 7192430136, ccData: 22511 },
{ type: 0, pts: 7192430136, ccData: 32896 },
{ type: 1, pts: 7192433196, ccData: 61284 },
{ type: 0, pts: 7192433196, ccData: 32896 },
{ type: 1, pts: 7192436166, ccData: 29472 },
{ type: 0, pts: 7192436166, ccData: 32896 },
{ type: 0, pts: 7192439136, ccData: 32896 },
{ type: 1, pts: 7192439136, ccData: 19553 },
{ type: 1, pts: 7192442106, ccData: 63418 },
{ type: 0, pts: 7192442106, ccData: 37920 },
{ type: 0, pts: 7192445076, ccData: 37920 },
{ type: 1, pts: 7192445076, ccData: 8271 },
{ type: 1, pts: 7192448136, ccData: 28192 },
{ type: 3, pts: 7192448136, ccData: 49954 },
{ type: 0, pts: 7192448136, ccData: 38062 },
{ type: 2, pts: 7192451106, ccData: 36093 },
{ type: 1, pts: 7192451106, ccData: 62568 },
{ type: 0, pts: 7192451106, ccData: 38062 },
{ type: 2, pts: 7192451106, ccData: 0 },
{ type: 0, pts: 7192454166, ccData: 38000 },
{ type: 3, pts: 7192454166, ccData: 2609 },
{ type: 1, pts: 7192454166, ccData: 58656 },
{ type: 0, pts: 7192457226, ccData: 38000 },
{ type: 2, pts: 7192457226, ccData: 38939 },
{ type: 2, pts: 7192457226, ccData: 17920 },
{ type: 2, pts: 7192457226, ccData: 31 },
{ type: 2, pts: 7192457226, ccData: 5264 },
{ type: 2, pts: 7192457226, ccData: 1283 },
{ type: 2, pts: 7192457226, ccData: 37162 },
{ type: 2, pts: 7192457226, ccData: 42 },
{ type: 2, pts: 7192457226, ccData: 37376 },
{ type: 2, pts: 7192457226, ccData: 0 },
{ type: 1, pts: 7192457226, ccData: 51317 },
{ type: 1, pts: 7192460106, ccData: 28404 },
{ type: 0, pts: 7192460106, ccData: 38818 },
{ type: 3, pts: 7192460106, ccData: 17187 },
{ type: 2, pts: 7192463166, ccData: 512 },
{ type: 1, pts: 7192463166, ccData: 8360 },
{ type: 0, pts: 7192463166, ccData: 38818 },
{ type: 2, pts: 7192463166, ccData: 37376 },
{ type: 0, pts: 7192466136, ccData: 18772 },
{ type: 1, pts: 7192466136, ccData: 54245 },
{ type: 3, pts: 7192466136, ccData: 33570 },
{ type: 3, pts: 7192469106, ccData: 49954 },
{ type: 2, pts: 7192469106, ccData: 0 },
{ type: 0, pts: 7192469106, ccData: 42963 },
{ type: 1, pts: 7192469106, ccData: 36667 },
{ type: 2, pts: 7192469106, ccData: 18772 },
{ type: 2, pts: 7192472166, ccData: 10067 },
{ type: 2, pts: 7192472166, ccData: 0 },
{ type: 3, pts: 7192472166, ccData: 802 },
{ type: 0, pts: 7192472166, ccData: 8398 },
{ type: 1, pts: 7192472166, ccData: 258 },
{ type: 2, pts: 7192475136, ccData: 8270 },
{ type: 0, pts: 7192475136, ccData: 20308 },
{ type: 3, pts: 7192475136, ccData: 17186 },
{ type: 2, pts: 7192475136, ccData: 0 },
{ type: 1, pts: 7192475136, ccData: 16448 },
{ type: 1, pts: 7192478196, ccData: 16448 },
{ type: 0, pts: 7192478196, ccData: 8385 },
{ type: 2, pts: 7192478196, ccData: 20308 },
{ type: 2, pts: 7192478196, ccData: 0 },
{ type: 3, pts: 7192478196, ccData: 33570 },
{ type: 2, pts: 7192481166, ccData: 8257 },
{ type: 0, pts: 7192481166, ccData: 8276 },
{ type: 2, pts: 7192481166, ccData: 0 },
{ type: 1, pts: 7192481166, ccData: 16512 },
{ type: 3, pts: 7192481166, ccData: 49954 },
{ type: 3, pts: 7192484136, ccData: 802 },
{ type: 2, pts: 7192484136, ccData: 0 },
{ type: 1, pts: 7192484136, ccData: 36782 },
{ type: 0, pts: 7192484136, ccData: 51282 },
{ type: 2, pts: 7192484136, ccData: 8276 },
{ type: 3, pts: 7192487196, ccData: 17186 },
{ type: 0, pts: 7192487196, ccData: 17857 },
{ type: 2, pts: 7192487196, ccData: 18514 },
{ type: 2, pts: 7192487196, ccData: 0 },
{ type: 1, pts: 7192487196, ccData: 387 },
{ type: 3, pts: 7192490166, ccData: 33570 },
{ type: 1, pts: 7192490166, ccData: 52975 },
{ type: 0, pts: 7192490166, ccData: 21536 },
{ type: 2, pts: 7192490166, ccData: 17729 },
{ type: 2, pts: 7192490166, ccData: 0 },
{ type: 2, pts: 7192493226, ccData: 21536 },
{ type: 3, pts: 7192493226, ccData: 49954 },
{ type: 2, pts: 7192493226, ccData: 0 },
{ type: 0, pts: 7192493226, ccData: 21583 },
{ type: 1, pts: 7192493226, ccData: 62196 },
{ type: 1, pts: 7192496196, ccData: 26656 },
{ type: 0, pts: 7192496196, ccData: 8385 },
{ type: 2, pts: 7192496196, ccData: 21583 },
{ type: 2, pts: 7192496196, ccData: 0 },
{ type: 3, pts: 7192496196, ccData: 802 },
{ type: 1, pts: 7192499166, ccData: 22511 },
{ type: 0, pts: 7192499166, ccData: 52953 },
{ type: 2, pts: 7192499166, ccData: 8257 },
{ type: 2, pts: 7192499166, ccData: 0 },
{ type: 3, pts: 7192499166, ccData: 17186 },
{ type: 2, pts: 7192502226, ccData: 0 },
{ type: 2, pts: 7192502226, ccData: 20057 },
{ type: 3, pts: 7192502226, ccData: 33570 },
{ type: 1, pts: 7192502226, ccData: 61284 },
{ type: 0, pts: 7192502226, ccData: 49743 },
{ type: 3, pts: 7192505106, ccData: 49954 },
{ type: 2, pts: 7192505106, ccData: 0 },
{ type: 0, pts: 7192505106, ccData: 50393 },
{ type: 1, pts: 7192505106, ccData: 29472 },
{ type: 2, pts: 7192505106, ccData: 16975 },
{ type: 2, pts: 7192508166, ccData: 17497 },
{ type: 3, pts: 7192508166, ccData: 802 },
{ type: 0, pts: 7192508166, ccData: 44672 },
{ type: 2, pts: 7192508166, ccData: 0 },
{ type: 1, pts: 7192508166, ccData: 389 },
{ type: 2, pts: 7192511226, ccData: 11776 },
{ type: 2, pts: 7192511226, ccData: 0 },
{ type: 1, pts: 7192511226, ccData: 51396 },
{ type: 0, pts: 7192511226, ccData: 37935 },
{ type: 3, pts: 7192511226, ccData: 17444 },
{ type: 0, pts: 7192514196, ccData: 37935 },
{ type: 2, pts: 7192514196, ccData: 35842 },
{ type: 2, pts: 7192514196, ccData: 35073 },
{ type: 2, pts: 7192514196, ccData: 0 },
{ type: 1, pts: 7192514196, ccData: 36831 },
{ type: 0, pts: 7192517256, ccData: 32896 },
{ type: 1, pts: 7192517256, ccData: 258 },
{ type: 1, pts: 7192520226, ccData: 16448 },
{ type: 0, pts: 7192520226, ccData: 32896 },
{ type: 1, pts: 7192523196, ccData: 16448 },
{ type: 0, pts: 7192523196, ccData: 32896 },
{ type: 1, pts: 7192526256, ccData: 16512 },
{ type: 0, pts: 7192526256, ccData: 32896 },
{ type: 1, pts: 7192529136, ccData: 36782 },
{ type: 0, pts: 7192529136, ccData: 32896 },
{ type: 1, pts: 7192532196, ccData: 387 },
{ type: 0, pts: 7192532196, ccData: 32896 },
{ type: 1, pts: 7192535256, ccData: 52975 },
{ type: 0, pts: 7192535256, ccData: 32896 },
{ type: 1, pts: 7192538226, ccData: 62196 },
{ type: 0, pts: 7192538226, ccData: 32896 },
{ type: 1, pts: 7192541286, ccData: 26656 },
{ type: 0, pts: 7192541286, ccData: 32896 },
{ type: 1, pts: 7192544256, ccData: 22511 },
{ type: 0, pts: 7192544256, ccData: 32896 },
{ type: 1, pts: 7192547226, ccData: 61284 },
{ type: 0, pts: 7192547226, ccData: 32896 },
{ type: 1, pts: 7192550196, ccData: 29472 },
{ type: 0, pts: 7192550196, ccData: 32896 },
{ type: 0, pts: 7192553166, ccData: 32896 },
{ type: 1, pts: 7192553166, ccData: 19553 },
{ type: 0, pts: 7192556226, ccData: 32896 },
{ type: 1, pts: 7192556226, ccData: 63418 },
{ type: 1, pts: 7192559286, ccData: 8271 },
{ type: 0, pts: 7192559286, ccData: 32896 },
{ type: 1, pts: 7192562256, ccData: 28192 },
{ type: 0, pts: 7192562256, ccData: 32896 },
{ type: 1, pts: 7192565316, ccData: 62568 },
{ type: 0, pts: 7192565316, ccData: 32896 },
{ type: 1, pts: 7192568286, ccData: 58656 },
{ type: 0, pts: 7192568286, ccData: 32896 },
{ type: 1, pts: 7192571256, ccData: 51317 },
{ type: 0, pts: 7192571256, ccData: 32896 },
{ type: 1, pts: 7192574226, ccData: 28404 },
{ type: 0, pts: 7192574226, ccData: 32896 },
{ type: 1, pts: 7192577196, ccData: 8360 },
{ type: 0, pts: 7192577196, ccData: 32896 },
{ type: 0, pts: 7192580256, ccData: 32896 },
{ type: 1, pts: 7192580256, ccData: 54245 },
{ type: 1, pts: 7192583226, ccData: 36667 },
{ type: 0, pts: 7192583226, ccData: 32896 },
{ type: 1, pts: 7192586286, ccData: 258 },
{ type: 0, pts: 7192586286, ccData: 32896 },
{ type: 0, pts: 7192589346, ccData: 32896 },
{ type: 1, pts: 7192589346, ccData: 16448 },
{ type: 1, pts: 7192592316, ccData: 16448 },
{ type: 0, pts: 7192592316, ccData: 32896 },
{ type: 0, pts: 7192595286, ccData: 32896 },
{ type: 1, pts: 7192595286, ccData: 16512 },
{ type: 0, pts: 7192598256, ccData: 32896 },
{ type: 1, pts: 7192598256, ccData: 36782 },
{ type: 1, pts: 7192601226, ccData: 387 },
{ type: 0, pts: 7192601226, ccData: 32896 },
{ type: 0, pts: 7192604286, ccData: 32896 },
{ type: 1, pts: 7192604286, ccData: 52975 },
{ type: 1, pts: 7192607256, ccData: 62196 },
{ type: 0, pts: 7192607256, ccData: 32896 },
{ type: 1, pts: 7192610316, ccData: 26656 },
{ type: 0, pts: 7192610316, ccData: 32896 },
{ type: 0, pts: 7192613376, ccData: 32896 },
{ type: 1, pts: 7192613376, ccData: 22511 },
{ type: 0, pts: 7192616346, ccData: 32896 },
{ type: 1, pts: 7192616346, ccData: 61284 },
{ type: 0, pts: 7192619316, ccData: 32896 },
{ type: 1, pts: 7192619316, ccData: 29472 },
{ type: 0, pts: 7192622286, ccData: 32896 },
{ type: 1, pts: 7192622286, ccData: 19553 },
{ type: 1, pts: 7192625256, ccData: 63418 },
{ type: 0, pts: 7192625256, ccData: 32896 },
{ type: 1, pts: 7192628316, ccData: 8271 },
{ type: 0, pts: 7192628316, ccData: 32896 },
{ type: 0, pts: 7192631286, ccData: 37920 },
{ type: 1, pts: 7192631286, ccData: 28192 },
{ type: 1, pts: 7192634346, ccData: 62568 },
{ type: 0, pts: 7192634346, ccData: 37920 },
{ type: 1, pts: 7192637406, ccData: 58656 },
{ type: 3, pts: 7192637406, ccData: 33570 },
{ type: 0, pts: 7192637406, ccData: 38062 },
{ type: 2, pts: 7192640286, ccData: 0 },
{ type: 1, pts: 7192640286, ccData: 51317 },
{ type: 0, pts: 7192640286, ccData: 38062 },
{ type: 2, pts: 7192640286, ccData: 36094 },
{ type: 1, pts: 7192643346, ccData: 28404 },
{ type: 3, pts: 7192643346, ccData: 51761 },
{ type: 0, pts: 7192643346, ccData: 38096 },
{ type: 1, pts: 7192646316, ccData: 8360 },
{ type: 0, pts: 7192646316, ccData: 38096 },
{ type: 2, pts: 7192646316, ccData: 39195 },
{ type: 2, pts: 7192646316, ccData: 16640 },
{ type: 2, pts: 7192646316, ccData: 31 },
{ type: 2, pts: 7192646316, ccData: 5264 },
{ type: 2, pts: 7192646316, ccData: 1283 },
{ type: 2, pts: 7192646316, ccData: 37162 },
{ type: 2, pts: 7192646316, ccData: 42 },
{ type: 2, pts: 7192646316, ccData: 37376 },
{ type: 2, pts: 7192646316, ccData: 0 },
{ type: 3, pts: 7192649286, ccData: 802 },
{ type: 0, pts: 7192649286, ccData: 22341 },
{ type: 1, pts: 7192649286, ccData: 54245 },
{ type: 0, pts: 7192652346, ccData: 8276 },
{ type: 1, pts: 7192652346, ccData: 36667 },
{ type: 2, pts: 7192652346, ccData: 0 },
{ type: 3, pts: 7192652346, ccData: 17186 },
{ type: 2, pts: 7192652346, ccData: 22341 },
{ type: 0, pts: 7192655316, ccData: 21209 },
{ type: 2, pts: 7192655316, ccData: 8276 },
{ type: 1, pts: 7192655316, ccData: 258 },
{ type: 3, pts: 7192655316, ccData: 33570 },
{ type: 2, pts: 7192655316, ccData: 0 },
{ type: 1, pts: 7192658376, ccData: 16448 },
{ type: 0, pts: 7192658376, ccData: 8398 },
{ type: 2, pts: 7192658376, ccData: 21081 },
{ type: 2, pts: 7192658376, ccData: 0 },
{ type: 3, pts: 7192658376, ccData: 49954 },
{ type: 0, pts: 7192661346, ccData: 20308 },
{ type: 2, pts: 7192661346, ccData: 8270 },
{ type: 2, pts: 7192661346, ccData: 0 },
{ type: 3, pts: 7192661346, ccData: 802 },
{ type: 1, pts: 7192661346, ccData: 16448 },
{ type: 0, pts: 7192664316, ccData: 8276 },
{ type: 2, pts: 7192664316, ccData: 20308 },
{ type: 2, pts: 7192664316, ccData: 0 },
{ type: 3, pts: 7192664316, ccData: 17186 },
{ type: 1, pts: 7192664316, ccData: 16512 },
{ type: 0, pts: 7192667376, ccData: 20256 },
{ type: 1, pts: 7192667376, ccData: 36782 },
{ type: 2, pts: 7192667376, ccData: 8276 },
{ type: 2, pts: 7192667376, ccData: 0 },
{ type: 3, pts: 7192667376, ccData: 33570 },
{ type: 3, pts: 7192670346, ccData: 49954 },
{ type: 1, pts: 7192670346, ccData: 387 },
{ type: 0, pts: 7192670346, ccData: 53461 },
{ type: 2, pts: 7192670346, ccData: 20256 },
{ type: 2, pts: 7192670346, ccData: 0 },
{ type: 0, pts: 7192673406, ccData: 21536 },
{ type: 3, pts: 7192673406, ccData: 802 },
{ type: 2, pts: 7192673406, ccData: 0 },
{ type: 2, pts: 7192673406, ccData: 20565 },
{ type: 1, pts: 7192673406, ccData: 52975 },
{ type: 1, pts: 7192676376, ccData: 62196 },
{ type: 2, pts: 7192676376, ccData: 21536 },
{ type: 2, pts: 7192676376, ccData: 0 },
{ type: 3, pts: 7192676376, ccData: 17186 },
{ type: 0, pts: 7192676376, ccData: 49614 },
{ type: 0, pts: 7192679346, ccData: 8385 },
{ type: 2, pts: 7192679346, ccData: 16718 },
{ type: 1, pts: 7192679346, ccData: 26656 },
{ type: 3, pts: 7192679346, ccData: 33570 },
{ type: 2, pts: 7192679346, ccData: 0 },
{ type: 1, pts: 7192682406, ccData: 22511 },
{ type: 0, pts: 7192682406, ccData: 52809 },
{ type: 2, pts: 7192682406, ccData: 8257 },
{ type: 2, pts: 7192682406, ccData: 0 },
{ type: 3, pts: 7192682406, ccData: 49954 },
{ type: 0, pts: 7192685286, ccData: 52673 },
{ type: 2, pts: 7192685286, ccData: 20041 },
{ type: 2, pts: 7192685286, ccData: 0 },
{ type: 3, pts: 7192685286, ccData: 802 },
{ type: 1, pts: 7192685286, ccData: 61284 },
{ type: 1, pts: 7192688346, ccData: 389 },
{ type: 0, pts: 7192688346, ccData: 19488 },
{ type: 2, pts: 7192688346, ccData: 19777 },
{ type: 2, pts: 7192688346, ccData: 0 },
{ type: 3, pts: 7192688346, ccData: 17186 },
{ type: 3, pts: 7192691406, ccData: 33570 },
{ type: 2, pts: 7192691406, ccData: 0 },
{ type: 2, pts: 7192691406, ccData: 19488 },
{ type: 0, pts: 7192691406, ccData: 50255 },
{ type: 1, pts: 7192691406, ccData: 51396 },
{ type: 1, pts: 7192694376, ccData: 36831 },
{ type: 0, pts: 7192694376, ccData: 22478 },
{ type: 2, pts: 7192694376, ccData: 17487 },
{ type: 2, pts: 7192694376, ccData: 0 },
{ type: 3, pts: 7192694376, ccData: 49954 },
{ type: 3, pts: 7192697436, ccData: 2609 },
{ type: 1, pts: 7192697436, ccData: 258 },
{ type: 2, pts: 7192697436, ccData: 22350 },
{ type: 2, pts: 7192697436, ccData: 0 },
{ type: 0, pts: 7192697436, ccData: 38130 },
{ type: 2, pts: 7192700406, ccData: 1024 },
{ type: 0, pts: 7192700406, ccData: 38130 },
{ type: 2, pts: 7192700406, ccData: 16640 },
{ type: 2, pts: 7192700406, ccData: 287 },
{ type: 2, pts: 7192700406, ccData: 4240 },
{ type: 2, pts: 7192700406, ccData: 1283 },
{ type: 2, pts: 7192700406, ccData: 37162 },
{ type: 2, pts: 7192700406, ccData: 0 },
{ type: 2, pts: 7192700406, ccData: 37377 },
{ type: 2, pts: 7192700406, ccData: 39195 },
{ type: 1, pts: 7192700406, ccData: 16448 },
{ type: 0, pts: 7192703376, ccData: 38818 },
{ type: 3, pts: 7192703376, ccData: 17187 },
{ type: 1, pts: 7192703376, ccData: 16448 },
{ type: 1, pts: 7192706436, ccData: 16512 },
{ type: 0, pts: 7192706436, ccData: 38818 },
{ type: 2, pts: 7192706436, ccData: 37377 },
{ type: 2, pts: 7192706436, ccData: 1536 },
{ type: 3, pts: 7192709316, ccData: 33570 },
{ type: 1, pts: 7192709316, ccData: 36782 },
{ type: 0, pts: 7192709316, ccData: 18758 },
{ type: 1, pts: 7192712376, ccData: 387 },
{ type: 0, pts: 7192712376, ccData: 8279 },
{ type: 2, pts: 7192712376, ccData: 18758 },
{ type: 2, pts: 7192712376, ccData: 0 },
{ type: 3, pts: 7192712376, ccData: 49954 },
{ type: 1, pts: 7192715436, ccData: 52975 },
{ type: 0, pts: 7192715436, ccData: 17696 },
{ type: 2, pts: 7192715436, ccData: 8279 },
{ type: 2, pts: 7192715436, ccData: 0 },
{ type: 3, pts: 7192715436, ccData: 802 },
{ type: 3, pts: 7192718406, ccData: 17186 },
{ type: 1, pts: 7192718406, ccData: 62196 },
{ type: 2, pts: 7192718406, ccData: 0 },
{ type: 0, pts: 7192718406, ccData: 50255 },
{ type: 2, pts: 7192718406, ccData: 17696 },
{ type: 3, pts: 7192721466, ccData: 33570 },
{ type: 2, pts: 7192721466, ccData: 17487 },
{ type: 0, pts: 7192721466, ccData: 52903 },
{ type: 1, pts: 7192721466, ccData: 26656 },
{ type: 2, pts: 7192721466, ccData: 0 },
{ type: 1, pts: 7192724436, ccData: 22511 },
{ type: 0, pts: 7192724436, ccData: 21536 },
{ type: 2, pts: 7192724436, ccData: 20007 },
{ type: 2, pts: 7192724436, ccData: 0 },
{ type: 3, pts: 7192724436, ccData: 49954 },
{ type: 2, pts: 7192727406, ccData: 0 },
{ type: 2, pts: 7192727406, ccData: 21536 },
{ type: 0, pts: 7192727406, ccData: 51393 },
{ type: 1, pts: 7192727406, ccData: 61284 },
{ type: 3, pts: 7192727406, ccData: 802 },
{ type: 0, pts: 7192730376, ccData: 54853 },
{ type: 1, pts: 7192730376, ccData: 29472 },
{ type: 2, pts: 7192730376, ccData: 18497 },
{ type: 2, pts: 7192730376, ccData: 0 },
{ type: 3, pts: 7192730376, ccData: 17186 },
{ type: 2, pts: 7192733346, ccData: 22085 },
{ type: 3, pts: 7192733346, ccData: 33570 },
{ type: 0, pts: 7192733346, ccData: 8276 },
{ type: 1, pts: 7192733346, ccData: 19553 },
{ type: 2, pts: 7192733346, ccData: 0 },
{ type: 1, pts: 7192736406, ccData: 63418 },
{ type: 2, pts: 7192736406, ccData: 0 },
{ type: 3, pts: 7192736406, ccData: 49954 },
{ type: 2, pts: 7192736406, ccData: 8276 },
{ type: 0, pts: 7192736406, ccData: 20398 },
{ type: 1, pts: 7192739466, ccData: 8271 },
{ type: 0, pts: 7192739466, ccData: 37935 },
{ type: 2, pts: 7192739466, ccData: 20270 },
{ type: 2, pts: 7192739466, ccData: 0 },
{ type: 3, pts: 7192739466, ccData: 1060 },
{ type: 0, pts: 7192742436, ccData: 37935 },
{ type: 2, pts: 7192742436, ccData: 35841 },
{ type: 2, pts: 7192742436, ccData: 35074 },
{ type: 2, pts: 7192742436, ccData: 0 },
{ type: 1, pts: 7192742436, ccData: 28192 },
{ type: 1, pts: 7192745496, ccData: 62568 },
{ type: 0, pts: 7192745496, ccData: 32896 },
{ type: 1, pts: 7192748466, ccData: 58656 },
{ type: 0, pts: 7192748466, ccData: 32896 },
{ type: 1, pts: 7192751436, ccData: 51317 },
{ type: 0, pts: 7192751436, ccData: 32896 },
{ type: 1, pts: 7192754406, ccData: 28404 },
{ type: 0, pts: 7192754406, ccData: 32896 },
{ type: 0, pts: 7192757376, ccData: 32896 },
{ type: 1, pts: 7192757376, ccData: 8360 },
{ type: 1, pts: 7192760436, ccData: 54245 },
{ type: 0, pts: 7192760436, ccData: 32896 },
{ type: 1, pts: 7192763406, ccData: 36667 },
{ type: 0, pts: 7192763406, ccData: 32896 },
{ type: 1, pts: 7192766466, ccData: 258 },
{ type: 0, pts: 7192766466, ccData: 32896 },
{ type: 1, pts: 7192769526, ccData: 16448 },
{ type: 0, pts: 7192769526, ccData: 32896 },
{ type: 1, pts: 7192772496, ccData: 16448 },
{ type: 0, pts: 7192772496, ccData: 32896 },
{ type: 1, pts: 7192775466, ccData: 16512 },
{ type: 0, pts: 7192775466, ccData: 32896 },
{ type: 1, pts: 7192778436, ccData: 36782 },
{ type: 0, pts: 7192778436, ccData: 32896 },
{ type: 1, pts: 7192781406, ccData: 387 },
{ type: 0, pts: 7192781406, ccData: 32896 },
{ type: 1, pts: 7192784466, ccData: 52975 },
{ type: 0, pts: 7192784466, ccData: 32896 },
{ type: 0, pts: 7192787436, ccData: 32896 },
{ type: 1, pts: 7192787436, ccData: 62196 },
{ type: 1, pts: 7192790496, ccData: 26656 },
{ type: 0, pts: 7192790496, ccData: 32896 },
{ type: 0, pts: 7192793556, ccData: 32896 },
{ type: 1, pts: 7192793556, ccData: 22511 },
{ type: 0, pts: 7192796526, ccData: 32896 },
{ type: 1, pts: 7192796526, ccData: 61284 },
{ type: 1, pts: 7192799496, ccData: 29472 },
{ type: 0, pts: 7192799496, ccData: 32896 },
{ type: 1, pts: 7192802466, ccData: 19553 },
{ type: 0, pts: 7192802466, ccData: 32896 },
{ type: 1, pts: 7192805436, ccData: 63418 },
{ type: 0, pts: 7192805436, ccData: 32896 },
{ type: 1, pts: 7192808496, ccData: 8271 },
{ type: 0, pts: 7192808496, ccData: 32896 },
{ type: 0, pts: 7192811466, ccData: 32896 },
{ type: 1, pts: 7192811466, ccData: 28192 },
{ type: 1, pts: 7192814526, ccData: 62568 },
{ type: 0, pts: 7192814526, ccData: 32896 },
{ type: 1, pts: 7192817586, ccData: 58656 },
{ type: 0, pts: 7192817586, ccData: 32896 },
{ type: 0, pts: 7192820466, ccData: 32896 },
{ type: 1, pts: 7192820466, ccData: 51317 },
{ type: 0, pts: 7192823526, ccData: 32896 },
{ type: 1, pts: 7192823526, ccData: 28404 },
{ type: 1, pts: 7192826496, ccData: 8360 },
{ type: 0, pts: 7192826496, ccData: 32896 },
{ type: 0, pts: 7192829466, ccData: 32896 },
{ type: 1, pts: 7192829466, ccData: 54245 },
{ type: 1, pts: 7192832526, ccData: 36667 },
{ type: 0, pts: 7192832526, ccData: 32896 },
{ type: 1, pts: 7192835496, ccData: 258 },
{ type: 0, pts: 7192835496, ccData: 32896 },
{ type: 1, pts: 7192838556, ccData: 16448 },
{ type: 0, pts: 7192838556, ccData: 32896 },
{ type: 0, pts: 7192841526, ccData: 32896 },
{ type: 1, pts: 7192841526, ccData: 16448 },
{ type: 1, pts: 7192844496, ccData: 16512 },
{ type: 0, pts: 7192844496, ccData: 32896 },
{ type: 1, pts: 7192847556, ccData: 36782 },
{ type: 0, pts: 7192847556, ccData: 32896 },
{ type: 1, pts: 7192850526, ccData: 387 },
{ type: 0, pts: 7192850526, ccData: 32896 },
{ type: 1, pts: 7192853586, ccData: 52975 },
{ type: 0, pts: 7192853586, ccData: 37920 },
{ type: 0, pts: 7192856556, ccData: 37920 },
{ type: 1, pts: 7192856556, ccData: 62196 },
{ type: 1, pts: 7192859526, ccData: 26656 },
{ type: 0, pts: 7192859526, ccData: 38062 },
{ type: 3, pts: 7192859526, ccData: 17186 },
{ type: 1, pts: 7192862586, ccData: 22511 },
{ type: 0, pts: 7192862586, ccData: 38062 },
{ type: 2, pts: 7192862586, ccData: 36093 },
{ type: 2, pts: 7192862586, ccData: 0 },
{ type: 0, pts: 7192865466, ccData: 4982 },
{ type: 1, pts: 7192865466, ccData: 61284 },
{ type: 3, pts: 7192865466, ccData: 35377 },
{ type: 2, pts: 7192868526, ccData: 3072 },
{ type: 2, pts: 7192868526, ccData: 37376 },
{ type: 2, pts: 7192868526, ccData: 42 },
{ type: 2, pts: 7192868526, ccData: 37162 },
{ type: 1, pts: 7192868526, ccData: 29472 },
{ type: 0, pts: 7192868526, ccData: 4982 },
{ type: 2, pts: 7192868526, ccData: 38939 },
{ type: 2, pts: 7192868526, ccData: 15360 },
{ type: 2, pts: 7192868526, ccData: 31 },
{ type: 2, pts: 7192868526, ccData: 5264 },
{ type: 2, pts: 7192868526, ccData: 1283 },
{ type: 1, pts: 7192871586, ccData: 389 },
{ type: 0, pts: 7192871586, ccData: 52833 },
{ type: 3, pts: 7192871586, ccData: 49954 },
{ type: 2, pts: 7192874556, ccData: 0 },
{ type: 1, pts: 7192874556, ccData: 51396 },
{ type: 0, pts: 7192874556, ccData: 62194 },
{ type: 2, pts: 7192874556, ccData: 20065 },
{ type: 3, pts: 7192874556, ccData: 802 },
{ type: 0, pts: 7192877616, ccData: 25076 },
{ type: 2, pts: 7192877616, ccData: 29298 },
{ type: 3, pts: 7192877616, ccData: 17186 },
{ type: 1, pts: 7192877616, ccData: 36831 },
{ type: 2, pts: 7192877616, ccData: 0 },
{ type: 3, pts: 7192880586, ccData: 33570 },
{ type: 2, pts: 7192880586, ccData: 0 },
{ type: 2, pts: 7192880586, ccData: 24948 },
{ type: 0, pts: 7192880586, ccData: 61426 },
{ type: 1, pts: 7192880586, ccData: 258 },
{ type: 3, pts: 7192883556, ccData: 49954 },
{ type: 2, pts: 7192883556, ccData: 0 },
{ type: 2, pts: 7192883556, ccData: 28530 },
{ type: 0, pts: 7192883556, ccData: 47744 },
{ type: 1, pts: 7192883556, ccData: 16448 },
{ type: 3, pts: 7192886616, ccData: 2609 },
{ type: 1, pts: 7192886616, ccData: 16448 },
{ type: 0, pts: 7192886616, ccData: 38096 },
{ type: 2, pts: 7192886616, ccData: 14848 },
{ type: 2, pts: 7192886616, ccData: 0 },
{ type: 2, pts: 7192889496, ccData: 287 },
{ type: 2, pts: 7192889496, ccData: 15360 },
{ type: 2, pts: 7192889496, ccData: 38939 },
{ type: 0, pts: 7192889496, ccData: 38096 },
{ type: 2, pts: 7192889496, ccData: 0 },
{ type: 2, pts: 7192889496, ccData: 37162 },
{ type: 2, pts: 7192889496, ccData: 1283 },
{ type: 2, pts: 7192889496, ccData: 4240 },
{ type: 2, pts: 7192889496, ccData: 0 },
{ type: 2, pts: 7192889496, ccData: 37377 },
{ type: 1, pts: 7192889496, ccData: 16512 },
{ type: 1, pts: 7192892556, ccData: 36782 },
{ type: 3, pts: 7192892556, ccData: 17187 },
{ type: 0, pts: 7192892556, ccData: 38817 },
{ type: 0, pts: 7192895616, ccData: 38817 },
{ type: 1, pts: 7192895616, ccData: 387 },
{ type: 2, pts: 7192895616, ccData: 256 },
{ type: 2, pts: 7192895616, ccData: 37377 },
{ type: 1, pts: 7192898586, ccData: 52975 },
{ type: 0, pts: 7192898586, ccData: 18758 },
{ type: 3, pts: 7192898586, ccData: 33570 },
{ type: 0, pts: 7192901646, ccData: 8276 },
{ type: 2, pts: 7192901646, ccData: 18758 },
{ type: 2, pts: 7192901646, ccData: 0 },
{ type: 3, pts: 7192901646, ccData: 49954 },
{ type: 1, pts: 7192901646, ccData: 62196 },
{ type: 1, pts: 7192904616, ccData: 26656 },
{ type: 0, pts: 7192904616, ccData: 51269 },
{ type: 2, pts: 7192904616, ccData: 8276 },
{ type: 2, pts: 7192904616, ccData: 0 },
{ type: 3, pts: 7192904616, ccData: 802 },
{ type: 3, pts: 7192907586, ccData: 17186 },
{ type: 2, pts: 7192907586, ccData: 0 },
{ type: 2, pts: 7192907586, ccData: 18501 },
{ type: 0, pts: 7192907586, ccData: 8403 },
{ type: 1, pts: 7192907586, ccData: 22511 },
{ type: 1, pts: 7192910556, ccData: 61284 },
{ type: 0, pts: 7192910556, ccData: 18755 },
{ type: 2, pts: 7192910556, ccData: 8275 },
{ type: 2, pts: 7192910556, ccData: 0 },
{ type: 3, pts: 7192910556, ccData: 33570 },
{ type: 3, pts: 7192913526, ccData: 49954 },
{ type: 1, pts: 7192913526, ccData: 29472 },
{ type: 2, pts: 7192913526, ccData: 18755 },
{ type: 2, pts: 7192913526, ccData: 0 },
{ type: 0, pts: 7192913526, ccData: 52000 },
{ type: 0, pts: 7192916586, ccData: 49614 },
{ type: 2, pts: 7192916586, ccData: 19232 },
{ type: 2, pts: 7192916586, ccData: 0 },
{ type: 3, pts: 7192916586, ccData: 802 },
{ type: 1, pts: 7192916586, ccData: 19553 },
{ type: 0, pts: 7192919646, ccData: 50208 },
{ type: 1, pts: 7192919646, ccData: 63418 },
{ type: 2, pts: 7192919646, ccData: 16718 },
{ type: 2, pts: 7192919646, ccData: 0 },
{ type: 3, pts: 7192919646, ccData: 17186 },
{ type: 3, pts: 7192922616, ccData: 33570 },
{ type: 1, pts: 7192922616, ccData: 8271 },
{ type: 0, pts: 7192922616, ccData: 17989 },
{ type: 2, pts: 7192922616, ccData: 17440 },
{ type: 2, pts: 7192922616, ccData: 0 },
{ type: 2, pts: 7192925676, ccData: 17989 },
{ type: 3, pts: 7192925676, ccData: 49954 },
{ type: 0, pts: 7192925676, ccData: 49490 },
{ type: 1, pts: 7192925676, ccData: 28192 },
{ type: 2, pts: 7192925676, ccData: 0 },
{ type: 0, pts: 7192928646, ccData: 19525 },
{ type: 2, pts: 7192928646, ccData: 16722 },
{ type: 2, pts: 7192928646, ccData: 0 },
{ type: 3, pts: 7192928646, ccData: 802 },
{ type: 1, pts: 7192928646, ccData: 62568 },
{ type: 0, pts: 7192931616, ccData: 54227 },
{ type: 1, pts: 7192931616, ccData: 58656 },
{ type: 3, pts: 7192931616, ccData: 17186 },
{ type: 2, pts: 7192931616, ccData: 19525 },
{ type: 2, pts: 7192931616, ccData: 0 },
{ type: 1, pts: 7192934586, ccData: 51317 },
{ type: 0, pts: 7192934586, ccData: 8397 },
{ type: 2, pts: 7192934586, ccData: 21331 },
{ type: 2, pts: 7192934586, ccData: 0 },
{ type: 3, pts: 7192934586, ccData: 33570 },
{ type: 2, pts: 7192937556, ccData: 0 },
{ type: 0, pts: 7192937556, ccData: 20303 },
{ type: 2, pts: 7192937556, ccData: 8269 },
{ type: 1, pts: 7192937556, ccData: 28404 },
{ type: 3, pts: 7192937556, ccData: 49954 },
{ type: 1, pts: 7192940616, ccData: 8360 },
{ type: 0, pts: 7192940616, ccData: 54085 },
{ type: 2, pts: 7192940616, ccData: 20303 },
{ type: 2, pts: 7192940616, ccData: 0 },
{ type: 3, pts: 7192940616, ccData: 802 },
{ type: 0, pts: 7192943586, ccData: 38000 },
{ type: 3, pts: 7192943586, ccData: 18993 },
{ type: 1, pts: 7192943586, ccData: 54245 },
{ type: 2, pts: 7192943586, ccData: 0 },
{ type: 2, pts: 7192943586, ccData: 21317 },
{ type: 2, pts: 7192946646, ccData: 1283 },
{ type: 1, pts: 7192946646, ccData: 36667 },
{ type: 2, pts: 7192946646, ccData: 38939 },
{ type: 2, pts: 7192946646, ccData: 15360 },
{ type: 2, pts: 7192946646, ccData: 543 },
{ type: 2, pts: 7192946646, ccData: 4240 },
{ type: 0, pts: 7192946646, ccData: 38000 },
{ type: 2, pts: 7192946646, ccData: 37162 },
{ type: 2, pts: 7192946646, ccData: 0 },
{ type: 2, pts: 7192946646, ccData: 37378 },
{ type: 2, pts: 7192946646, ccData: 0 },
{ type: 3, pts: 7192949706, ccData: 33571 },
{ type: 0, pts: 7192949706, ccData: 38817 },
{ type: 1, pts: 7192949706, ccData: 258 },
{ type: 2, pts: 7192952676, ccData: 256 },
{ type: 1, pts: 7192952676, ccData: 16448 },
{ type: 0, pts: 7192952676, ccData: 38817 },
{ type: 2, pts: 7192952676, ccData: 37378 },
{ type: 1, pts: 7192955646, ccData: 16448 },
{ type: 0, pts: 7192955646, ccData: 22465 },
{ type: 3, pts: 7192955646, ccData: 49954 },
{ type: 3, pts: 7192958616, ccData: 802 },
{ type: 2, pts: 7192958616, ccData: 22337 },
{ type: 2, pts: 7192958616, ccData: 0 },
{ type: 1, pts: 7192958616, ccData: 16512 },
{ type: 0, pts: 7192958616, ccData: 54048 },
{ type: 0, pts: 7192961586, ccData: 17228 },
{ type: 2, pts: 7192961586, ccData: 21280 },
{ type: 2, pts: 7192961586, ccData: 0 },
{ type: 3, pts: 7192961586, ccData: 17186 },
{ type: 1, pts: 7192961586, ccData: 36782 },
{ type: 0, pts: 7192964646, ccData: 20435 },
{ type: 2, pts: 7192964646, ccData: 17228 },
{ type: 2, pts: 7192964646, ccData: 0 },
{ type: 3, pts: 7192964646, ccData: 33570 },
{ type: 1, pts: 7192964646, ccData: 387 },
{ type: 0, pts: 7192967616, ccData: 17746 },
{ type: 1, pts: 7192967616, ccData: 52975 },
{ type: 2, pts: 7192967616, ccData: 0 },
{ type: 2, pts: 7192967616, ccData: 20307 },
{ type: 3, pts: 7192967616, ccData: 49954 },
{ type: 1, pts: 7192970676, ccData: 62196 },
{ type: 0, pts: 7192970676, ccData: 8276 },
{ type: 2, pts: 7192970676, ccData: 17746 },
{ type: 2, pts: 7192970676, ccData: 0 },
{ type: 3, pts: 7192970676, ccData: 802 },
{ type: 2, pts: 7192973736, ccData: 0 },
{ type: 2, pts: 7192973736, ccData: 8276 },
{ type: 3, pts: 7192973736, ccData: 17186 },
{ type: 0, pts: 7192973736, ccData: 20256 },
{ type: 1, pts: 7192973736, ccData: 26656 },
{ type: 1, pts: 7192976706, ccData: 22511 },
{ type: 0, pts: 7192976706, ccData: 49440 },
{ type: 2, pts: 7192976706, ccData: 20256 },
{ type: 2, pts: 7192976706, ccData: 0 },
{ type: 3, pts: 7192976706, ccData: 33570 },
{ type: 3, pts: 7192979676, ccData: 49954 },
{ type: 2, pts: 7192979676, ccData: 0 },
{ type: 2, pts: 7192979676, ccData: 16672 },
{ type: 0, pts: 7192979676, ccData: 53327 },
{ type: 1, pts: 7192979676, ccData: 61284 },
{ type: 1, pts: 7192982646, ccData: 29472 },
{ type: 0, pts: 7192982646, ccData: 53461 },
{ type: 2, pts: 7192982646, ccData: 20559 },
{ type: 2, pts: 7192982646, ccData: 0 },
{ type: 3, pts: 7192982646, ccData: 802 },
{ type: 3, pts: 7192985616, ccData: 17186 },
{ type: 1, pts: 7192985616, ccData: 19553 },
{ type: 2, pts: 7192985616, ccData: 20565 },
{ type: 2, pts: 7192985616, ccData: 0 },
{ type: 0, pts: 7192985616, ccData: 19649 },
{ type: 2, pts: 7192988676, ccData: 19521 },
{ type: 1, pts: 7192988676, ccData: 63418 },
{ type: 0, pts: 7192988676, ccData: 21573 },
{ type: 2, pts: 7192988676, ccData: 0 },
{ type: 3, pts: 7192988676, ccData: 33570 },
{ type: 2, pts: 7192991646, ccData: 0 },
{ type: 2, pts: 7192991646, ccData: 21573 },
{ type: 3, pts: 7192991646, ccData: 49954 },
{ type: 1, pts: 7192991646, ccData: 8271 },
{ type: 0, pts: 7192991646, ccData: 50208 },
{ type: 1, pts: 7192994706, ccData: 28192 },
{ type: 0, pts: 7192994706, ccData: 49490 },
{ type: 2, pts: 7192994706, ccData: 17440 },
{ type: 2, pts: 7192994706, ccData: 0 },
{ type: 3, pts: 7192994706, ccData: 802 },
{ type: 2, pts: 7192997766, ccData: 0 },
{ type: 0, pts: 7192997766, ccData: 17857 },
{ type: 3, pts: 7192997766, ccData: 17186 },
{ type: 1, pts: 7192997766, ccData: 62568 },
{ type: 2, pts: 7192997766, ccData: 16722 },
{ type: 3, pts: 7193000646, ccData: 33570 },
{ type: 1, pts: 7193000646, ccData: 58656 },
{ type: 0, pts: 7193000646, ccData: 11392 },
{ type: 2, pts: 7193000646, ccData: 17729 },
{ type: 2, pts: 7193000646, ccData: 0 },
{ type: 1, pts: 7193003706, ccData: 51317 },
{ type: 2, pts: 7193003706, ccData: 11264 },
{ type: 2, pts: 7193003706, ccData: 0 },
{ type: 3, pts: 7193003706, ccData: 50212 },
{ type: 0, pts: 7193003706, ccData: 37935 },
{ type: 1, pts: 7193006676, ccData: 28404 },
{ type: 0, pts: 7193006676, ccData: 37935 },
{ type: 2, pts: 7193006676, ccData: 35842 },
{ type: 2, pts: 7193006676, ccData: 35073 },
{ type: 2, pts: 7193006676, ccData: 0 },
{ type: 1, pts: 7193009646, ccData: 8360 },
{ type: 0, pts: 7193009646, ccData: 32896 },
{ type: 1, pts: 7193012706, ccData: 54245 },
{ type: 0, pts: 7193012706, ccData: 32896 },
{ type: 1, pts: 7193015676, ccData: 36667 },
{ type: 0, pts: 7193015676, ccData: 32896 },
{ type: 0, pts: 7193018736, ccData: 32896 },
{ type: 1, pts: 7193018736, ccData: 258 },
{ type: 0, pts: 7193021706, ccData: 32896 },
{ type: 1, pts: 7193021706, ccData: 16448 },
{ type: 1, pts: 7193024676, ccData: 16448 },
{ type: 0, pts: 7193024676, ccData: 32896 },
{ type: 1, pts: 7193027736, ccData: 16512 },
{ type: 0, pts: 7193027736, ccData: 32896 },
{ type: 0, pts: 7193030706, ccData: 32896 },
{ type: 1, pts: 7193030706, ccData: 36782 },
{ type: 1, pts: 7193033766, ccData: 387 },
{ type: 0, pts: 7193033766, ccData: 32896 },
{ type: 1, pts: 7193036736, ccData: 52975 },
{ type: 0, pts: 7193036736, ccData: 32896 },
{ type: 1, pts: 7193039706, ccData: 62196 },
{ type: 0, pts: 7193039706, ccData: 32896 },
{ type: 1, pts: 7193042766, ccData: 26656 },
{ type: 0, pts: 7193042766, ccData: 32896 },
{ type: 1, pts: 7193045646, ccData: 22511 },
{ type: 0, pts: 7193045646, ccData: 32896 },
{ type: 1, pts: 7193048706, ccData: 61284 },
{ type: 0, pts: 7193048706, ccData: 32896 },
{ type: 1, pts: 7193051766, ccData: 29472 },
{ type: 0, pts: 7193051766, ccData: 32896 },
{ type: 1, pts: 7193054736, ccData: 389 },
{ type: 0, pts: 7193054736, ccData: 32896 },
{ type: 1, pts: 7193057796, ccData: 51396 },
{ type: 0, pts: 7193057796, ccData: 32896 },
{ type: 1, pts: 7193060766, ccData: 36831 },
{ type: 0, pts: 7193060766, ccData: 32896 },
{ type: 1, pts: 7193063736, ccData: 258 },
{ type: 0, pts: 7193063736, ccData: 32896 },
{ type: 0, pts: 7193066796, ccData: 32896 },
{ type: 1, pts: 7193066796, ccData: 16448 },
{ type: 0, pts: 7193069676, ccData: 32896 },
{ type: 1, pts: 7193069676, ccData: 16448 },
{ type: 1, pts: 7193072736, ccData: 16512 },
{ type: 0, pts: 7193072736, ccData: 32896 },
{ type: 0, pts: 7193075796, ccData: 32896 },
{ type: 1, pts: 7193075796, ccData: 36782 },
{ type: 1, pts: 7193078766, ccData: 387 },
{ type: 0, pts: 7193078766, ccData: 32896 },
{ type: 1, pts: 7193081826, ccData: 52975 },
{ type: 0, pts: 7193081826, ccData: 32896 },
{ type: 1, pts: 7193084796, ccData: 62196 },
{ type: 0, pts: 7193084796, ccData: 32896 },
{ type: 0, pts: 7193087766, ccData: 32896 },
{ type: 1, pts: 7193087766, ccData: 26656 },
{ type: 0, pts: 7193090736, ccData: 32896 },
{ type: 1, pts: 7193090736, ccData: 22511 },
{ type: 0, pts: 7193093706, ccData: 32896 },
{ type: 1, pts: 7193093706, ccData: 61284 },
{ type: 1, pts: 7193096766, ccData: 29472 },
{ type: 0, pts: 7193096766, ccData: 32896 },
{ type: 1, pts: 7193099826, ccData: 19553 },
{ type: 0, pts: 7193099826, ccData: 32896 },
{ type: 1, pts: 7193102796, ccData: 63418 },
{ type: 0, pts: 7193102796, ccData: 32896 },
{ type: 0, pts: 7193105856, ccData: 32896 },
{ type: 1, pts: 7193105856, ccData: 8271 },
{ type: 0, pts: 7193108826, ccData: 32896 },
{ type: 1, pts: 7193108826, ccData: 28192 },
{ type: 1, pts: 7193111796, ccData: 62568 },
{ type: 0, pts: 7193111796, ccData: 32896 },
{ type: 1, pts: 7193114766, ccData: 58656 },
{ type: 0, pts: 7193114766, ccData: 32896 },
{ type: 0, pts: 7193117736, ccData: 32896 },
{ type: 1, pts: 7193117736, ccData: 51317 },
{ type: 0, pts: 7193120796, ccData: 32896 },
{ type: 1, pts: 7193120796, ccData: 28404 },
{ type: 1, pts: 7193123766, ccData: 8360 },
{ type: 0, pts: 7193123766, ccData: 32896 },
{ type: 1, pts: 7193126826, ccData: 54245 },
{ type: 0, pts: 7193126826, ccData: 32896 },
{ type: 0, pts: 7193129886, ccData: 32896 },
{ type: 1, pts: 7193129886, ccData: 36667 },
{ type: 1, pts: 7193138796, ccData: 16448 },
{ type: 0, pts: 7193138796, ccData: 32896 }
];

315
node_modules/mux.js/test/utils/mp4-helpers.js generated vendored Normal file
View file

@ -0,0 +1,315 @@
/**
* Helper functions for creating test MP4 data.
*/
'use strict';
var box, typeBytes, unityMatrix;
module.exports = {};
// ----------------------
// Box Generation Helpers
// ----------------------
module.exports.typeBytes = typeBytes = function(type) {
return [
type.charCodeAt(0),
type.charCodeAt(1),
type.charCodeAt(2),
type.charCodeAt(3)
];
};
module.exports.box = 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;
};
module.exports.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
// ------------
module.exports.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

View file

@ -0,0 +1,137 @@
/**
* Helper functions for creating 608/708 SEI NAL units
*/
'use strict';
var box = require('./mp4-helpers').box;
// Create SEI nal-units from Caption packets
var makeSeiFromCaptionPacket = function(caption) {
return {
pts: caption.pts,
dts: caption.dts,
nalUnitType: 'sei_rbsp',
escapedRBSP: new Uint8Array([
0x04, // payload_type === user_data_registered_itu_t_t35
0x0e, // payload_size
181, // itu_t_t35_country_code
0x00, 0x31, // itu_t_t35_provider_code
0x47, 0x41, 0x39, 0x34, // user_identifier, "GA94"
0x03, // user_data_type_code, 0x03 is cc_data
// 110 00001
0xc1, // process_cc_data, cc_count
0xff, // reserved
// 1111 1100
(0xfc | caption.type), // cc_valid, cc_type (608, field 1)
(caption.ccData & 0xff00) >> 8, // cc_data_1
caption.ccData & 0xff, // cc_data_2 without parity bit set
0xff // marker_bits
])
};
};
// Create SEI nal-units from Caption packets
var makeSeiFromMultipleCaptionPackets = function(captionHash) {
var pts = captionHash.pts,
dts = captionHash.dts,
captions = captionHash.captions;
var data = [];
captions.forEach(function(caption) {
data.push(0xfc | caption.type);
data.push((caption.ccData & 0xff00) >> 8);
data.push(caption.ccData & 0xff);
});
return {
pts: pts,
dts: dts,
nalUnitType: 'sei_rbsp',
escapedRBSP: new Uint8Array([
0x04, // payload_type === user_data_registered_itu_t_t35
(0x0b + (captions.length * 3)), // payload_size
181, // itu_t_t35_country_code
0x00, 0x31, // itu_t_t35_provider_code
0x47, 0x41, 0x39, 0x34, // user_identifier, "GA94"
0x03, // user_data_type_code, 0x03 is cc_data
// 110 00001
(0x6 << 5) | captions.length, // process_cc_data, cc_count
0xff // reserved
].concat(data).concat([0xff /* marker bits */])
)
};
};
var makeMdatFromCaptionPackets = function(packets) {
var mdat = ['mdat'];
var seis = packets.map(makeSeiFromCaptionPacket);
seis.forEach(function(sei) {
mdat.push(0x00);
mdat.push(0x00);
mdat.push(0x00);
mdat.push(sei.escapedRBSP.length + 1); // nal length
mdat.push(0x06); // declare nal type as SEI
// SEI message
for (var i = 0; i < sei.escapedRBSP.length; i++) {
var byte = sei.escapedRBSP[i];
mdat.push(byte);
}
});
return box.apply(null, mdat);
};
// Returns a ccData byte-pair for a two character string. That is,
// it converts a string like 'hi' into the two-byte number that
// would be parsed back as 'hi' when provided as ccData.
var characters = function(text) {
if (text.length !== 2) {
throw new Error('ccdata must be specified two characters at a time');
}
return (text.charCodeAt(0) << 8) | text.charCodeAt(1);
};
// Returns a ccData byte-pair including
// Header for 708 packet
// Header for the first service block
// seq should increment by 1 for each byte pair mod 3 (0,1,2,0,1,2,...)
// sizeCode is the number of byte pairs in the packet (including header)
// serviceNum is the service number of the first service block
// blockSize is the size of the first service block in bytes (no header)
// If there's only one service block, the blockSize should be (sizeCode-1)*2
var packetHeader708 = function(seq, sizeCode, serviceNum, blockSize) {
var b1 = (seq << 6) | sizeCode;
var b2 = (serviceNum << 5) | blockSize;
return (b1 << 8) | b2;
};
// Returns a ccData byte-pair to execute a 708 DSW command
// Takes an array of window indicies to display
var displayWindows708 = function(windows) {
var cmd = 0x8900;
windows.forEach(function(winIdx) {
cmd |= (0x01 << winIdx);
});
return cmd;
};
module.exports = {
makeSeiFromCaptionPacket: makeSeiFromCaptionPacket,
makeSeiFromMultipleCaptionPackets: makeSeiFromMultipleCaptionPackets,
makeMdatFromCaptionPackets: makeMdatFromCaptionPackets,
characters: characters,
packetHeader708: packetHeader708,
displayWindows708: displayWindows708
};