Tracking de l'application VApp (IHM du jeu)

This commit is contained in:
2025-05-11 18:04:12 +02:00
commit 89e9db9b62
17763 changed files with 3718499 additions and 0 deletions

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

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

289
VApp/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
VApp/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
VApp/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;

271
VApp/node_modules/mux.js/test/caption-parser.test.js generated vendored Normal file
View File

@ -0,0 +1,271 @@
'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 malformedSei = segments['malformed-sei.m4s']();
var malformedSeiInit = segments['malformed-sei-init.mp4']();
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].content[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].content[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].content[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');
});
QUnit.test('returns log on invalid sei nal parse', function(assert) {
var trackIds;
var timescales;
var result;
var logs = [];
trackIds = probe.videoTrackIds(malformedSeiInit);
timescales = probe.timescale(malformedSeiInit);
result = captionParser.parse(malformedSei, trackIds, timescales);
assert.deepEqual(result.logs, [
{level: 'warn', message: 'We\'ve encountered a nal unit without data at 189975 for trackId 1. See mux.js#223.'}
], 'logged invalid sei nal');
});
// ---------
// 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));

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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

113
VApp/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
VApp/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);
});

732
VApp/node_modules/mux.js/test/metadata-stream.test.js generated vendored Normal file
View File

@ -0,0 +1,732 @@
'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('triggers log for non-id3/invalid data', function(assert) {
var logs = [];
metadataStream.on('log', function(log) {
logs.push(log);
});
// id3 not long enough
metadataStream.push({type: 'timed-metadata', data: new Uint8Array()});
// invalid data
metadataStream.push({type: 'timed-metadata', data: new Uint8Array([
0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01
])});
const zeroFrames = 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
]));
metadataStream.push({type: 'timed-metadata', data: zeroFrames});
assert.deepEqual(logs, [
{level: 'warn', message: 'Skipping unrecognized metadata packet'},
{level: 'warn', message: 'Skipping unrecognized metadata packet'},
{level: 'warn', message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'}
], 'logs as expected.');
});
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('should skip tag frame parsing on malformed frame, preserving previous frames', function(assert) {
var events = [],
validFrame = id3Frame('TIT2',
0x03, // utf-8
stringToCString('sample title')),
malformedFrame = id3Frame('WOAF'), // frame with size of 0B
tag = id3Tag(validFrame, malformedFrame);
metadataStream.on('data', function(event) {
events.push(event);
});
metadataStream.push({
type: 'timed-metadata',
data: new Uint8Array(tag)
})
assert.equal(events.length, 1, 'parsed 1 tag')
assert.equal(events[0].frames.length, 1, 'parsed 1 frame');
assert.equal(events[0].frames[0].key, 'TIT2');
});
QUnit.test('can parse APIC frame in web worker', function(assert) {
var worker = new MetadataStreamTestWorker(),
done = assert.async();
worker.addEventListener('message', function(e) {
assert.equal(e.data.frames[0].key, 'APIC', 'frame key is APIC');
assert.equal(e.data.frames[0].mimeType, 'image/jpeg', 'parsed MIME type is "image/jpeg"');
assert.equal(e.data.frames[0].pictureType, 0x03, 'parsed picture type is 0x03');
assert.equal(e.data.frames[0].description, 'sample description', 'parsed description');
assert.deepEqual(e.data.frames[0].pictureData, new Uint8Array(stringToInts("picture binary data")), 'parsed picture data');
assert.equal(e.data.frames[1].key, 'APIC', 'frame key is APIC');
assert.equal(e.data.frames[1].mimeType, '-->', 'parsed MIME type is "-->"');
assert.equal(e.data.frames[1].pictureType, 0x04, 'parsed picture type is 0x04');
assert.equal(e.data.frames[1].description, 'sample description 2', 'parsed description');
assert.equal(e.data.frames[1].url, 'http://example.org/cover-back.jpg', 'parsed picture data');
worker.terminate();
done();
});
worker.postMessage({
type: 'timed-metadata',
data: new Uint8Array(id3Tag(id3Frame('APIC',
0x03, // Text encoding: UTF-8
stringToCString('image/jpeg'), // MIME type + \0
0x03, // Picture type: Cover (front) [ID3v2.4.0 section 4.14]
stringToCString('sample description'), // Decription + \0
stringToInts('picture binary data')
),
id3Frame('APIC',
0x03, // Text encoding: UTF-8
stringToCString('-->'), // MIME type: link to the image [ID3v2.4.0 section 4.14] + \0
0x04, // Picture type: Cover (back) [ID3v2.4.0 section 4.14]
stringToCString('sample description 2'), // Decription + \0
stringToInts('http://example.org/cover-back.jpg')
)))
});
});
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('should parse text frames in web worker', function(assert) {
var worker = new MetadataStreamTestWorker(),
done = assert.async();
worker.addEventListener('message', function(e) {
assert.equal(e.data.frames.length, 2, 'got 2 frames');
assert.equal(e.data.frames[0].key, 'TIT2', 'frame key is TIT2');
assert.equal(e.data.frames[0].value, 'sample song title', 'parsed value')
assert.equal(e.data.frames[0].values.length, 1, 'parsed value is an array of size 1')
assert.equal(e.data.frames[0].values[0], 'sample song title', 'parsed a non multiple strings value')
assert.equal(e.data.frames[1].key, 'TIT3', 'frame key is TIT3');
assert.equal(e.data.frames[1].value, 'sample title 1\0sample title 2', 'parsed value')
assert.equal(e.data.frames[1].values.length, 2, 'parsed value is an array of size 2')
assert.equal(e.data.frames[1].values[0], 'sample title 1', 'parsed 1st multiple strings value')
assert.equal(e.data.frames[1].values[1], 'sample title 2', 'parsed 2nd multiple strings value')
worker.terminate();
done();
});
worker.postMessage({
type: 'timed-metadata',
data: new Uint8Array(id3Tag(id3Frame('TIT2',
0x03, // utf-8
// frames that allow different types of encoding contain terminated text [ID3v2.4.0 section 4.]
stringToCString('sample song title')),
id3Frame('TIT3',
0x03, // utf-8
// frames that allow different types of encoding contain terminated text [ID3v2.4.0 section 4.]
// text information frames supports multiple strings, stored as a terminator separated list [ID3v2.4.0 section 4.2.]
stringToCString('sample title 1'), stringToCString('sample title 2'))))
});
});
QUnit.test('should parse URL link frames in web worker', function(assert) {
var worker = new MetadataStreamTestWorker(),
done = assert.async(),
payloadBytes;
// if the payload is followed by a string termination all the following information should be ignored [ID3v2.4.0 section 4.3]
payloadBytes = stringToInts('http://example.org\0 ignored \0 part')
worker.addEventListener('message', function(e) {
assert.equal(e.data.frames[0].key, 'WOAF', 'frame key is WOAF');
assert.equal(e.data.frames[0].url, 'http://example.org', 'parsed URL')
worker.terminate();
done();
});
worker.postMessage({
type: 'timed-metadata',
data: new Uint8Array(id3Tag(id3Frame('WOAF', payloadBytes)))
});
});
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');
});

49
VApp/node_modules/mux.js/test/mp4-emsg.test.js generated vendored Normal file
View File

@ -0,0 +1,49 @@
'use strict';
var QUnit = require('qunit'),
emsg = require('../lib/mp4/emsg'),
generateEmsgBoxData = require('./utils/mp4-helpers').generateEmsgBoxData,
messageData = new Uint8Array([0x64, 0x61, 0x74, 0x61]); // data;
QUnit.module('EMSG Parsing');
QUnit.test('Can parse a v0 emsg box', function(assert) {
var boxData = generateEmsgBoxData(0, messageData);
var parsedBox = emsg.parseEmsgBox(boxData);
assert.equal(parsedBox.scheme_id_uri, 'urn:foo:bar:2023\0', 'v0 box has expected scheme_id_uri');
assert.equal(parsedBox.value, 'foo.bar.value\0', 'v0 box has expected value');
assert.equal(parsedBox.timescale, 100, 'v0 box has expected timescale');
assert.equal(parsedBox.presentation_time, undefined, 'v0 box has expected presentation_time');
assert.equal(parsedBox.presentation_time_delta, 1000, 'v0 box has expected presentation_time_delta');
assert.equal(parsedBox.event_duration, 0, 'v0 box has expected event_duration');
assert.equal(parsedBox.id, 1, 'v0 box has expected id');
assert.deepEqual(parsedBox.message_data, messageData, 'v0 box has expected data');
});
QUnit.test('Can parse a v1 emsg box', function(assert) {
var boxData = generateEmsgBoxData(1, messageData);
var parsedBox = emsg.parseEmsgBox(boxData);
assert.equal(parsedBox.scheme_id_uri, 'urn:foo:bar:2023\0', 'v1 box has expected scheme_id_uri');
assert.equal(parsedBox.value, 'foo.bar.value\0', 'v1 box has expected value');
assert.equal(parsedBox.timescale, 100, 'v1 box has expected timescale');
assert.equal(parsedBox.presentation_time, 10000, 'v1 box has expected presentation_time');
assert.equal(parsedBox.presentation_time_delta, undefined, 'v1 box has expected presentation_time_delta');
assert.equal(parsedBox.event_duration, 1, 'v1 box has expected event_duration');
assert.equal(parsedBox.id, 2, 'v1 box has expected id');
assert.deepEqual(parsedBox.message_data, messageData, 'v1 box has expected data');
});
QUnit.test('Will return undefined if the emsg version is invalid', function(assert) {
var badBoxData = generateEmsgBoxData(2, messageData);
var parsedBox = emsg.parseEmsgBox(badBoxData);
assert.equal(parsedBox, undefined, 'parsed box is undefined');
});
QUnit.test('Will return undefined if the emsg data is malformed', function(assert) {
var badBoxData = generateEmsgBoxData(3, messageData);
var parsedBox = emsg.parseEmsgBox(badBoxData);
assert.equal(parsedBox, undefined, 'malformed box is undefined');
});

582
VApp/node_modules/mux.js/test/mp4-generator.test.js generated vendored Normal file
View File

@ -0,0 +1,582 @@
'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'),
tools = require('../lib/tools/mp4-inspector.js'),
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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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');
});

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

File diff suppressed because it is too large Load Diff

481
VApp/node_modules/mux.js/test/mp4-probe.test.js generated vendored Normal file
View File

@ -0,0 +1,481 @@
'use strict';
var
QUnit = require('qunit'),
probe = require('../lib/mp4/probe'),
mp4Helpers = require('./utils/mp4-helpers'),
box = mp4Helpers.box,
id3 = require('./utils/id3-generator'),
// 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'
);
});
QUnit.test('can get ID3 data from a v0 EMSG box', function(assert) {
var id3Data = new Uint8Array(id3.id3Tag(id3.id3Frame('PRIV',
id3.stringToCString('priv-owner@example.com'),
id3.stringToInts('foo.bar.id3.com')))
);
var v0EmsgId3Data = mp4Helpers.generateEmsgBoxData(0, id3Data);
var emsgId3Box = new Uint8Array(box('emsg', [].slice.call(v0EmsgId3Data)));
var emsgBoxes = probe.getEmsgID3(emsgId3Box, 10);
assert.equal(emsgBoxes[0].cueTime, 20, 'got correct emsg cueTime value from v0 emsg');
assert.equal(emsgBoxes[0].duration, 0, 'got correct emsg duration value from v0 emsg');
assert.equal(emsgBoxes[0].frames[0].id, 'PRIV' , 'got correct ID3 id');
assert.equal(emsgBoxes[0].frames[0].owner, 'priv-owner@example.com', 'got correct ID3 owner');
assert.deepEqual(emsgBoxes[0].frames[0].data, new Uint8Array(id3.stringToInts('foo.bar.id3.com')), 'got correct ID3 data');
});
QUnit.test('can get ID3 data from a v1 EMSG box', function(assert) {
var id3Data = new Uint8Array(id3.id3Tag(id3.id3Frame('TXXX',
0x03, // utf-8
id3.stringToCString('foo bar'),
id3.stringToCString('{ "key": "value" }')),
[0x00, 0x00])
);
var v1EmsgId3Data = mp4Helpers.generateEmsgBoxData(1, id3Data);
var emsgId3Box = new Uint8Array(box('emsg', [].slice.call(v1EmsgId3Data)));
var emsgBoxes = probe.getEmsgID3(emsgId3Box);
assert.equal(emsgBoxes[0].cueTime, 100, 'got correct emsg cueTime value from v1 emsg');
assert.equal(emsgBoxes[0].duration, 0.01, 'got correct emsg duration value from v1 emsg');
assert.equal(emsgBoxes[0].frames[0].id, 'TXXX' , 'got correct ID3 id');
assert.equal(emsgBoxes[0].frames[0].description, 'foo bar', 'got correct ID3 description');
assert.deepEqual(JSON.parse(emsgBoxes[0].frames[0].data), { key: 'value' }, 'got correct ID3 data');
});
QUnit.test('can get ID3 data from multiple EMSG boxes', function(assert) {
var v1id3Data = new Uint8Array(id3.id3Tag(id3.id3Frame('PRIV',
id3.stringToCString('priv-owner@example.com'),
id3.stringToInts('foo.bar.id3.com')))
);
var v0id3Data = new Uint8Array(id3.id3Tag(id3.id3Frame('TXXX',
0x03, // utf-8
id3.stringToCString('foo bar'),
id3.stringToCString('{ "key": "value" }')),
[0x00, 0x00])
);
var v1EmsgId3Data = mp4Helpers.generateEmsgBoxData(1, v1id3Data);
var v1emsgId3Box = new Uint8Array(box('emsg', [].slice.call(v1EmsgId3Data)));
var v0EmsgId3Data = mp4Helpers.generateEmsgBoxData(0, v0id3Data);
var v0emsgId3Box = new Uint8Array(box('emsg', [].slice.call(v0EmsgId3Data)));
var multiBoxData = new Uint8Array(v1emsgId3Box.length + v0emsgId3Box.length);
multiBoxData.set(v1emsgId3Box);
multiBoxData.set(v0emsgId3Box, v1emsgId3Box.length);
var emsgBoxes = probe.getEmsgID3(multiBoxData);
assert.equal(emsgBoxes[0].cueTime, 100, 'got correct emsg cueTime value from v1 emsg');
assert.equal(emsgBoxes[0].duration, 0.01, 'got correct emsg duration value from v1 emsg');
assert.equal(emsgBoxes[0].frames[0].id, 'PRIV' , 'got correct ID3 id');
assert.equal(emsgBoxes[0].frames[0].owner, 'priv-owner@example.com', 'got correct ID3 owner');
assert.deepEqual(emsgBoxes[0].frames[0].data, new Uint8Array(id3.stringToInts('foo.bar.id3.com')), 'got correct ID3 data');
assert.equal(emsgBoxes[1].cueTime, 10, 'got correct emsg cueTime value from v0 emsg');
assert.equal(emsgBoxes[1].duration, 0, 'got correct emsg duration value from v0 emsg');
assert.equal(emsgBoxes[1].frames[0].id, 'TXXX' , 'got correct ID3 id');
assert.equal(emsgBoxes[1].frames[0].description, 'foo bar', 'got correct ID3 description');
assert.deepEqual(JSON.parse(emsgBoxes[1].frames[0].data),{ key: 'value' }, 'got correct ID3 data');
});
// ---------
// 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
VApp/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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
VApp/node_modules/mux.js/test/segments/test-webvtt.m4s generated vendored Normal file

Binary file not shown.

48
VApp/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');
});

4664
VApp/node_modules/mux.js/test/transmuxer.test.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

205
VApp/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
VApp/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
VApp/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
VApp/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
};

32
VApp/node_modules/mux.js/test/utils.string.test.js generated vendored Normal file
View File

@ -0,0 +1,32 @@
'use strict';
var
QUnit = require('qunit'),
string = require('../lib/utils/string');
QUnit.module('String Utils');
QUnit.test('Converts a uint8 array into a C string from start of array until first null char', function(assert) {
var uint8String = new Uint8Array([0x66, 0x6F, 0x6F, 0x2E, 0x62, 0x61, 0x72, 0x2E, 0x76, 0x61, 0x6C, 0x75, 0x65, 0x00,
0x76, 0x61, 0x6C, 0x75, 0x65, 0x2E, 0x62, 0x61, 0x72, 0x00]); // foo.bar.value\0value.bar\0
var firstString = string.uint8ToCString(uint8String);
assert.equal(firstString, 'foo.bar.value\0', 'converts uint8 data to a c string');
assert.equal(firstString.length, 14, 'string has the correct length');
var secondString = string.uint8ToCString(uint8String.subarray(14));
assert.equal(secondString, 'value.bar\0', 'converts uint8 data to a c string');
assert.equal(secondString.length, 10, 'string has the correct length');
});
QUnit.test('Converts a uint8 array with no null char into a C string', function(assert) {
var uint8String = new Uint8Array([0x66, 0x6F, 0x6F, 0x2E, 0x62, 0x61, 0x72]); // foo.bar
var firstString = string.uint8ToCString(uint8String);
assert.equal(firstString, 'foo.bar\0', 'converts uint8 data to a c string');
assert.equal(firstString.length, 8, 'string has the correct length');
});
QUnit.test('Returns a null char from a uint8 array starting with a null char', function(assert) {
var uint8String = new Uint8Array([0x00, 0x66, 0x6F, 0x6F, 0x2E, 0x62, 0x61, 0x72]); // \0foo.bar
var firstString = string.uint8ToCString(uint8String);
assert.equal(firstString, '\0', 'converts uint8 data to a c string');
assert.equal(firstString.length, 1, 'string has the correct length');
});

View File

@ -0,0 +1,28 @@
'use strict';
var
QUnit = require('qunit'),
typedArrayIndexOf = require('../lib/utils/typed-array').typedArrayIndexOf;
QUnit.module('typedArrayIndexOf');
QUnit.test('returns -1 when no typed array', function(assert) {
assert.equal(typedArrayIndexOf(null, 5, 0), -1, 'returned -1');
});
QUnit.test('returns -1 when element not found', function(assert) {
assert.equal(typedArrayIndexOf(new Uint8Array([2, 3]), 5, 0), -1, 'returned -1');
});
QUnit.test('returns -1 when element not found starting from index', function(assert) {
assert.equal(typedArrayIndexOf(new Uint8Array([3, 5, 6, 7]), 5, 2), -1, 'returned -1');
});
QUnit.test('returns index when element found', function(assert) {
assert.equal(typedArrayIndexOf(new Uint8Array([2, 3, 5]), 5, 0), 2, 'returned 2');
});
QUnit.test('returns index when element found starting from index', function(assert) {
assert.equal(typedArrayIndexOf(new Uint8Array([2, 3, 5]), 5, 2), 2, 'returned 2');
});

134
VApp/node_modules/mux.js/test/utils/cc708-korean.js generated vendored Normal file
View File

@ -0,0 +1,134 @@
module.exports = [
{
type: 3,
pts: 4720415602,
ccData: 545,
presortIndex: 292
},
{
type: 3,
pts: 4721117602,
ccData: 53308,
presortIndex: 381
},
{
type: 2,
pts: 4721117602,
ccData: 39200,
presortIndex: 382
},
{
type: 2,
pts: 4721117602,
ccData: 58162,
presortIndex: 383
},
{
type: 2,
pts: 4721117602,
ccData: 29229,
presortIndex: 384
},
{
type: 2,
pts: 4721117602,
ccData: 4503,
presortIndex: 385
},
{
type: 2,
pts: 4721117602,
ccData: 49152,
presortIndex: 386
},
{
type: 2,
pts: 4721117602,
ccData: 3072,
presortIndex: 387
},
{
type: 2,
pts: 4721117602,
ccData: 37183,
presortIndex: 388
},
{
type: 2,
pts: 4721117602,
ccData: 0,
presortIndex: 389
},
{
type: 2,
pts: 4721117602,
ccData: 37378,
presortIndex: 390
},
{
type: 2,
pts: 4721117602,
ccData: 1304,
presortIndex: 391
},
{
type: 2,
pts: 4721117602,
ccData: 46287,
presortIndex: 392
},
{
type: 2,
pts: 4721117602,
ccData: 6320,
presortIndex: 393
},
{
type: 2,
pts: 4721117602,
ccData: 41240,
presortIndex: 394
},
{
type: 2,
pts: 4721117602,
ccData: 32,
presortIndex: 395
},
{
type: 2,
pts: 4721117602,
ccData: 0,
presortIndex: 396
},
{
type: 3,
pts: 4721138662,
ccData: 1318,
presortIndex: 411
},
{
type: 2,
pts: 4721138662,
ccData: 6323,
presortIndex: 412
},
{
type: 2,
pts: 4721138662,
ccData: 47896,
presortIndex: 413
},
{
type: 2,
pts: 4721138662,
ccData: 32,
presortIndex: 414
},
{
type: 2,
pts: 4721138662,
ccData: 0,
presortIndex: 415
}
]

File diff suppressed because it is too large Load Diff

74
VApp/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 }
];

380
VApp/node_modules/mux.js/test/utils/mp4-helpers.js generated vendored Normal file
View File

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

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
};

39
VApp/node_modules/mux.js/test/webvtt-parser.test.js generated vendored Normal file
View File

@ -0,0 +1,39 @@
var segments = require('data-files!segments');
var vttContentSegment = segments['test-webvtt.m4s']();
var vttInitSegment = segments['test-webvtt-init.mp4']();
var WebVttParser = require('../lib/mp4').WebVttParser;
var window = require('global/window');
var webVttParser;
QUnit.module('MP4 WebVtt Segment Parser', {
beforeEach: function() {
webVttParser = new WebVttParser();
}
});
QUnit.test('parse webvtt init and content segments', function(assert) {
// Init segment sets the timescale.
webVttParser.init(vttInitSegment);
assert.ok(webVttParser, 'WebVtt parser created');
// we need a TextDecoder to test the WebVTT segment parser.
if (window.TextDecoder) {
const parsedWebVttCues = webVttParser.parseSegment(vttContentSegment);
const expectedCueValues = [
{
cueText: "2024-09-19T20:13:06Z\nen # 863388393",
start: 1726776786,
end: 1726776786.9,
settings: undefined
},
{
cueText: "2024-09-19T20:13:07Z\nen # 863388393",
start: 1726776787,
end: 1726776787.9,
settings: undefined
}
];
assert.ok(parsedWebVttCues, 'parsed WebVtt Cues are created');
assert.equal(parsedWebVttCues.length, 2, '2 WebVtt Cues are created');
assert.deepEqual(parsedWebVttCues, expectedCueValues, 'WebVtt cues are expected values');
}
});