1
0
Fork 0
mirror of https://github.com/DanielnetoDotCom/YouPHPTube synced 2025-10-03 09:49:28 +02:00
Daniel Neto 2023-06-30 08:55:17 -03:00
parent 746e163d01
commit 1c7ea28b46
808 changed files with 316395 additions and 381162 deletions

29
node_modules/mux.js/CHANGELOG.md generated vendored
View file

@ -1,3 +1,32 @@
<a name="6.3.0"></a>
# [6.3.0](https://github.com/videojs/mux.js/compare/v6.2.0...v6.3.0) (2023-02-22)
### Features
* support emsg box parsing ([2e77285](https://github.com/videojs/mux.js/commit/2e77285))
### Bug Fixes
* emsg ie11 test failures ([528e9ed](https://github.com/videojs/mux.js/commit/528e9ed))
<a name="6.2.0"></a>
# [6.2.0](https://github.com/videojs/mux.js/compare/v6.1.0...v6.2.0) (2022-07-08)
### Features
* add ID3 parsing for text, link, and APIC frames ([#412](https://github.com/videojs/mux.js/issues/412)) ([5454bdd](https://github.com/videojs/mux.js/commit/5454bdd))
### Bug Fixes
* replace indexOf with typedArrayIndexOf for IE11 support ([#417](https://github.com/videojs/mux.js/issues/417)) ([4e1b195](https://github.com/videojs/mux.js/commit/4e1b195))
<a name="6.1.0"></a>
# [6.1.0](https://github.com/videojs/mux.js/compare/v6.0.1...v6.1.0) (2022-05-26)
### Features
* send ID3 tag even when a frame has malformed content ([#408](https://github.com/videojs/mux.js/issues/408)) ([1da5d23](https://github.com/videojs/mux.js/commit/1da5d23))
<a name="6.0.1"></a>
## [6.0.1](https://github.com/videojs/mux.js/compare/v6.0.0...v6.0.1) (2021-12-20)

View file

@ -12,84 +12,7 @@
var Stream = require('../utils/stream'),
StreamTypes = require('./stream-types'),
// return a percent-encoded representation of the specified byte range
// @see http://en.wikipedia.org/wiki/Percent-encoding
percentEncode = function percentEncode(bytes, start, end) {
var i,
result = '';
for (i = start; i < end; i++) {
result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
}
return result;
},
// return the string representation of the specified byte range,
// interpreted as UTf-8.
parseUtf8 = function parseUtf8(bytes, start, end) {
return decodeURIComponent(percentEncode(bytes, start, end));
},
// return the string representation of the specified byte range,
// interpreted as ISO-8859-1.
parseIso88591 = function parseIso88591(bytes, start, end) {
return unescape(percentEncode(bytes, start, end)); // jshint ignore:line
},
parseSyncSafeInteger = function parseSyncSafeInteger(data) {
return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
},
tagParsers = {
TXXX: function TXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the text fields
tag.description = parseUtf8(tag.data, 1, i); // do not include the null terminator in the tag value
tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, '');
break;
}
}
tag.data = tag.value;
},
WXXX: function WXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.description = parseUtf8(tag.data, 1, i);
tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
break;
}
}
},
PRIV: function PRIV(tag) {
var i;
for (i = 0; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.owner = parseIso88591(tag.data, 0, i);
break;
}
}
tag.privateData = tag.data.subarray(i + 1);
tag.data = tag.privateData;
}
},
id3 = require('../tools/parse-id3'),
_MetadataStream;
_MetadataStream = function MetadataStream(options) {
@ -152,7 +75,7 @@ _MetadataStream = function MetadataStream(options) {
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
tagSize = id3.parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10;
@ -185,23 +108,25 @@ _MetadataStream = function MetadataStream(options) {
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
frameStart += id3.parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20));
tagSize -= id3.parseSyncSafeInteger(tag.data.subarray(16, 20));
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
frameSize = id3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
this.trigger('log', {
level: 'warn',
message: 'Malformed ID3 frame encountered. Skipping metadata parsing.'
});
return;
message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'
}); // If the frame is malformed, don't parse any further frames but allow previous valid parsed frames
// to be sent along.
break;
}
frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]);
@ -209,29 +134,37 @@ _MetadataStream = function MetadataStream(options) {
id: frameHeader,
data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id;
frame.key = frame.id; // parse frame values
if (tagParsers[frame.id]) {
tagParsers[frame.id](frame); // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (id3.frameParsers[frame.id]) {
// use frame specific parser
id3.frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
id3.frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
id3.frameParsers['W*'](frame);
} // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
this.trigger('timestamp', frame);
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
this.trigger('timestamp', frame);
}
tag.frames.push(frame);

37
node_modules/mux.js/cjs/mp4/probe.js generated vendored
View file

@ -16,6 +16,8 @@ var findBox = require('../mp4/find-box.js');
var parseType = require('../mp4/parse-type.js');
var emsg = require('../mp4/emsg.js');
var parseTfhd = require('../tools/parse-tfhd.js');
var parseTrun = require('../tools/parse-trun.js');
@ -24,9 +26,11 @@ var parseTfdt = require('../tools/parse-tfdt.js');
var getUint64 = require('../utils/numbers.js').getUint64;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader, getEmsgID3;
var window = require('global/window');
var parseId3Frames = require('../tools/parse-id3.js').parseId3Frames;
/**
* Parses an MP4 initialization segment and extracts the timescale
* values for any declared tracks. Timescale values indicate the
@ -346,6 +350,34 @@ getTracks = function getTracks(init) {
});
return tracks;
};
/**
* Returns an array of emsg ID3 data from the provided segmentData.
* An offset can also be provided as the Latest Arrival Time to calculate
* the Event Start Time of v0 EMSG boxes.
* See: https://dashif-documents.azurewebsites.net/Events/master/event.html#Inband-event-timing
*
* @param {Uint8Array} segmentData the segment byte array.
* @param {number} offset the segment start time or Latest Arrival Time,
* @return {Object[]} an array of ID3 parsed from EMSG boxes
*/
getEmsgID3 = function getEmsgID3(segmentData, offset) {
if (offset === void 0) {
offset = 0;
}
var emsgBoxes = findBox(segmentData, ['emsg']);
return emsgBoxes.map(function (data) {
var parsedBox = emsg.parseEmsgBox(new Uint8Array(data));
var parsedId3Frames = parseId3Frames(parsedBox.message_data);
return {
cueTime: emsg.scaleTime(parsedBox.presentation_time, parsedBox.timescale, parsedBox.presentation_time_delta, offset),
duration: emsg.scaleTime(parsedBox.event_duration, parsedBox.timescale),
frames: parsedId3Frames
};
});
};
module.exports = {
// export mp4 inspector's findBox and parseType for backwards compatibility
@ -356,5 +388,6 @@ module.exports = {
compositionStartTime: compositionStartTime,
videoTrackIds: getVideoTrackIds,
tracks: getTracks,
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader,
getEmsgID3: getEmsgID3
};

307
node_modules/mux.js/dist/mux-flv.js generated vendored
View file

@ -1,4 +1,4 @@
/*! @name mux.js @version 6.0.1 @license Apache-2.0 */
/*! @name mux.js @version 6.3.0 @license Apache-2.0 */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
@ -2677,7 +2677,44 @@
handleRollover: handleRollover
};
var percentEncode = function percentEncode(bytes, start, end) {
// IE11 doesn't support indexOf for TypedArrays.
// Once IE11 support is dropped, this function should be removed.
var typedArrayIndexOf$1 = function typedArrayIndexOf(typedArray, element, fromIndex) {
if (!typedArray) {
return -1;
}
var currentIndex = fromIndex;
for (; currentIndex < typedArray.length; currentIndex++) {
if (typedArray[currentIndex] === element) {
return currentIndex;
}
}
return -1;
};
var typedArray = {
typedArrayIndexOf: typedArrayIndexOf$1
};
var typedArrayIndexOf = typedArray.typedArrayIndexOf,
// Frames that allow different types of text encoding contain a text
// encoding description byte [ID3v2.4.0 section 4.]
textEncodingDescriptionByte = {
Iso88591: 0x00,
// ISO-8859-1, terminated with \0.
Utf16: 0x01,
// UTF-16 encoded Unicode BOM, terminated with \0\0
Utf16be: 0x02,
// UTF-16BE encoded Unicode, without BOM, terminated with \0\0
Utf8: 0x03 // UTF-8 encoded Unicode, terminated with \0
},
// return a percent-encoded representation of the specified byte range
// @see http://en.wikipedia.org/wiki/Percent-encoding
percentEncode = function percentEncode(bytes, start, end) {
var i,
result = '';
@ -2700,60 +2737,202 @@
parseSyncSafeInteger = function parseSyncSafeInteger(data) {
return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
},
tagParsers = {
TXXX: function TXXX(tag) {
var i;
frameParsers = {
'APIC': function APIC(frame) {
var i = 1,
mimeTypeEndIndex,
descriptionEndIndex,
LINK_MIME_TYPE = '-->';
if (tag.data[0] !== 3) {
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
} // parsing fields [ID3v2.4.0 section 4.14.]
mimeTypeEndIndex = typedArrayIndexOf(frame.data, 0, i);
if (mimeTypeEndIndex < 0) {
// malformed frame
return;
} // parsing Mime type field (terminated with \0)
frame.mimeType = parseIso88591(frame.data, i, mimeTypeEndIndex);
i = mimeTypeEndIndex + 1; // parsing 1-byte Picture Type field
frame.pictureType = frame.data[i];
i++;
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, i);
if (descriptionEndIndex < 0) {
// malformed frame
return;
} // parsing Description field (terminated with \0)
frame.description = parseUtf8(frame.data, i, descriptionEndIndex);
i = descriptionEndIndex + 1;
if (frame.mimeType === LINK_MIME_TYPE) {
// parsing Picture Data field as URL (always represented as ISO-8859-1 [ID3v2.4.0 section 4.])
frame.url = parseIso88591(frame.data, i, frame.data.length);
} else {
// parsing Picture Data field as binary data
frame.pictureData = frame.data.subarray(i, frame.data.length);
}
},
'T*': function T(frame) {
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
} // parse text field, do not include null terminator in the frame value
// frames that allow different types of encoding contain terminated text [ID3v2.4.0 section 4.]
frame.value = parseUtf8(frame.data, 1, frame.data.length).replace(/\0*$/, ''); // text information frames supports multiple strings, stored as a terminator separated list [ID3v2.4.0 section 4.2.]
frame.values = frame.value.split('\0');
},
'TXXX': function TXXX(frame) {
var descriptionEndIndex;
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the text fields
tag.description = parseUtf8(tag.data, 1, i); // do not include the null terminator in the tag value
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, '');
break;
}
}
if (descriptionEndIndex === -1) {
return;
} // parse the text fields
tag.data = tag.value;
frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // do not include the null terminator in the tag value
// frames that allow different types of encoding contain terminated text
// [ID3v2.4.0 section 4.]
frame.value = parseUtf8(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\0*$/, '');
frame.data = frame.value;
},
WXXX: function WXXX(tag) {
var i;
'W*': function W(frame) {
// parse URL field; URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]
// if the value is followed by a string termination all the following information should be ignored [ID3v2.4.0 section 4.3]
frame.url = parseIso88591(frame.data, 0, frame.data.length).replace(/\0.*$/, '');
},
'WXXX': function WXXX(frame) {
var descriptionEndIndex;
if (tag.data[0] !== 3) {
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.description = parseUtf8(tag.data, 1, i);
tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
break;
}
}
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
if (descriptionEndIndex === -1) {
return;
} // parse the description and URL fields
frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]
// if the value is followed by a string termination all the following information
// should be ignored [ID3v2.4.0 section 4.3]
frame.url = parseIso88591(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\0.*$/, '');
},
PRIV: function PRIV(tag) {
'PRIV': function PRIV(frame) {
var i;
for (i = 0; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
for (i = 0; i < frame.data.length; i++) {
if (frame.data[i] === 0) {
// parse the description and URL fields
tag.owner = parseIso88591(tag.data, 0, i);
frame.owner = parseIso88591(frame.data, 0, i);
break;
}
}
tag.privateData = tag.data.subarray(i + 1);
tag.data = tag.privateData;
frame.privateData = frame.data.subarray(i + 1);
frame.data = frame.privateData;
}
},
_MetadataStream;
};
var parseId3Frames = function parseId3Frames(data) {
var frameSize,
frameHeader,
frameStart = 10,
tagSize = 0,
frames = []; // If we don't have enough data for a header, 10 bytes,
// or 'ID3' in the first 3 bytes this is not a valid ID3 tag.
if (data.length < 10 || data[0] !== 'I'.charCodeAt(0) || data[1] !== 'D'.charCodeAt(0) || data[2] !== '3'.charCodeAt(0)) {
return;
} // the frame size is transmitted as a 28-bit integer in the
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger(data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10; // check bit 6 of byte 5 for the extended header flag.
var hasExtendedHeader = data[5] & 0x40;
if (hasExtendedHeader) {
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger(data.subarray(10, 14));
tagSize -= parseSyncSafeInteger(data.subarray(16, 20)); // clip any padding off the end
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger(data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
break;
}
frameHeader = String.fromCharCode(data[frameStart], data[frameStart + 1], data[frameStart + 2], data[frameStart + 3]);
var frame = {
id: frameHeader,
data: data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id; // parse frame values
if (frameParsers[frame.id]) {
// use frame specific parser
frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
frameParsers['W*'](frame);
}
frames.push(frame);
frameStart += 10; // advance past the frame header
frameStart += frameSize; // advance past the frame body
} while (frameStart < tagSize);
return frames;
};
var parseId3 = {
parseId3Frames: parseId3Frames,
parseSyncSafeInteger: parseSyncSafeInteger,
frameParsers: frameParsers
};
var _MetadataStream;
_MetadataStream = function MetadataStream(options) {
var settings = {
@ -2815,7 +2994,7 @@
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
tagSize = parseId3.parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10;
@ -2848,23 +3027,25 @@
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
frameStart += parseId3.parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20));
tagSize -= parseId3.parseSyncSafeInteger(tag.data.subarray(16, 20));
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
frameSize = parseId3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
this.trigger('log', {
level: 'warn',
message: 'Malformed ID3 frame encountered. Skipping metadata parsing.'
});
return;
message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'
}); // If the frame is malformed, don't parse any further frames but allow previous valid parsed frames
// to be sent along.
break;
}
frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]);
@ -2872,29 +3053,37 @@
id: frameHeader,
data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id;
frame.key = frame.id; // parse frame values
if (tagParsers[frame.id]) {
tagParsers[frame.id](frame); // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (parseId3.frameParsers[frame.id]) {
// use frame specific parser
parseId3.frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
parseId3.frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
parseId3.frameParsers['W*'](frame);
} // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
this.trigger('timestamp', frame);
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
this.trigger('timestamp', frame);
}
tag.frames.push(frame);

File diff suppressed because one or more lines are too long

560
node_modules/mux.js/dist/mux-mp4.js generated vendored
View file

@ -1,4 +1,4 @@
/*! @name mux.js @version 6.0.1 @license Apache-2.0 */
/*! @name mux.js @version 6.3.0 @license Apache-2.0 */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('global/window')) :
typeof define === 'function' && define.amd ? define(['global/window'], factory) :
@ -11,7 +11,7 @@
var MAX_UINT32$1 = Math.pow(2, 32);
var getUint64$2 = function getUint64(uint8) {
var getUint64$3 = function getUint64(uint8) {
var dv = new DataView(uint8.buffer, uint8.byteOffset, uint8.byteLength);
var value;
@ -29,7 +29,7 @@
};
var numbers = {
getUint64: getUint64$2,
getUint64: getUint64$3,
MAX_UINT32: MAX_UINT32$1
};
@ -707,6 +707,133 @@
var findBox_1 = findBox;
/**
* Returns the first string in the data array ending with a null char '\0'
* @param {UInt8} data
* @returns the string with the null char
*/
var uint8ToCString$1 = function uint8ToCString(data) {
var index = 0;
var curChar = String.fromCharCode(data[index]);
var retString = '';
while (curChar !== '\0') {
retString += curChar;
index++;
curChar = String.fromCharCode(data[index]);
} // Add nullChar
retString += curChar;
return retString;
};
var string = {
uint8ToCString: uint8ToCString$1
};
var uint8ToCString = string.uint8ToCString;
var getUint64$2 = numbers.getUint64;
/**
* Based on: ISO/IEC 23009 Section: 5.10.3.3
* References:
* https://dashif-documents.azurewebsites.net/Events/master/event.html#emsg-format
* https://aomediacodec.github.io/id3-emsg/
*
* Takes emsg box data as a uint8 array and returns a emsg box object
* @param {UInt8Array} boxData data from emsg box
* @returns A parsed emsg box object
*/
var parseEmsgBox = function parseEmsgBox(boxData) {
// version + flags
var offset = 4;
var version = boxData[0];
var scheme_id_uri, value, timescale, presentation_time, presentation_time_delta, event_duration, id, message_data;
if (version === 0) {
scheme_id_uri = uint8ToCString(boxData.subarray(offset));
offset += scheme_id_uri.length;
value = uint8ToCString(boxData.subarray(offset));
offset += value.length;
var dv = new DataView(boxData.buffer);
timescale = dv.getUint32(offset);
offset += 4;
presentation_time_delta = dv.getUint32(offset);
offset += 4;
event_duration = dv.getUint32(offset);
offset += 4;
id = dv.getUint32(offset);
offset += 4;
} else if (version === 1) {
var dv = new DataView(boxData.buffer);
timescale = dv.getUint32(offset);
offset += 4;
presentation_time = getUint64$2(boxData.subarray(offset));
offset += 8;
event_duration = dv.getUint32(offset);
offset += 4;
id = dv.getUint32(offset);
offset += 4;
scheme_id_uri = uint8ToCString(boxData.subarray(offset));
offset += scheme_id_uri.length;
value = uint8ToCString(boxData.subarray(offset));
offset += value.length;
}
message_data = new Uint8Array(boxData.subarray(offset, boxData.byteLength));
var emsgBox = {
scheme_id_uri: scheme_id_uri,
value: value,
// if timescale is undefined or 0 set to 1
timescale: timescale ? timescale : 1,
presentation_time: presentation_time,
presentation_time_delta: presentation_time_delta,
event_duration: event_duration,
id: id,
message_data: message_data
};
return isValidEmsgBox(version, emsgBox) ? emsgBox : undefined;
};
/**
* Scales a presentation time or time delta with an offset with a provided timescale
* @param {number} presentationTime
* @param {number} timescale
* @param {number} timeDelta
* @param {number} offset
* @returns the scaled time as a number
*/
var scaleTime = function scaleTime(presentationTime, timescale, timeDelta, offset) {
return presentationTime || presentationTime === 0 ? presentationTime / timescale : offset + timeDelta / timescale;
};
/**
* Checks the emsg box data for validity based on the version
* @param {number} version of the emsg box to validate
* @param {Object} emsg the emsg data to validate
* @returns if the box is valid as a boolean
*/
var isValidEmsgBox = function isValidEmsgBox(version, emsg) {
var hasScheme = emsg.scheme_id_uri !== '\0';
var isValidV0Box = version === 0 && isDefined(emsg.presentation_time_delta) && hasScheme;
var isValidV1Box = version === 1 && isDefined(emsg.presentation_time) && hasScheme; // Only valid versions of emsg are 0 and 1
return !(version > 1) && isValidV0Box || isValidV1Box;
}; // Utility function to check if an object is defined
var isDefined = function isDefined(data) {
return data !== undefined || data !== null;
};
var emsg = {
parseEmsgBox: parseEmsgBox,
scaleTime: scaleTime
};
var tfhd = function tfhd(data) {
var view = new DataView(data.buffer, data.byteOffset, data.byteLength),
result = {
@ -896,10 +1023,266 @@
var parseTfdt = tfdt;
// IE11 doesn't support indexOf for TypedArrays.
// Once IE11 support is dropped, this function should be removed.
var typedArrayIndexOf$1 = function typedArrayIndexOf(typedArray, element, fromIndex) {
if (!typedArray) {
return -1;
}
var currentIndex = fromIndex;
for (; currentIndex < typedArray.length; currentIndex++) {
if (typedArray[currentIndex] === element) {
return currentIndex;
}
}
return -1;
};
var typedArray = {
typedArrayIndexOf: typedArrayIndexOf$1
};
var typedArrayIndexOf = typedArray.typedArrayIndexOf,
// Frames that allow different types of text encoding contain a text
// encoding description byte [ID3v2.4.0 section 4.]
textEncodingDescriptionByte = {
Iso88591: 0x00,
// ISO-8859-1, terminated with \0.
Utf16: 0x01,
// UTF-16 encoded Unicode BOM, terminated with \0\0
Utf16be: 0x02,
// UTF-16BE encoded Unicode, without BOM, terminated with \0\0
Utf8: 0x03 // UTF-8 encoded Unicode, terminated with \0
},
// return a percent-encoded representation of the specified byte range
// @see http://en.wikipedia.org/wiki/Percent-encoding
percentEncode$1 = function percentEncode(bytes, start, end) {
var i,
result = '';
for (i = start; i < end; i++) {
result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
}
return result;
},
// return the string representation of the specified byte range,
// interpreted as UTf-8.
parseUtf8 = function parseUtf8(bytes, start, end) {
return decodeURIComponent(percentEncode$1(bytes, start, end));
},
// return the string representation of the specified byte range,
// interpreted as ISO-8859-1.
parseIso88591$1 = function parseIso88591(bytes, start, end) {
return unescape(percentEncode$1(bytes, start, end)); // jshint ignore:line
},
parseSyncSafeInteger$1 = function parseSyncSafeInteger(data) {
return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
},
frameParsers = {
'APIC': function APIC(frame) {
var i = 1,
mimeTypeEndIndex,
descriptionEndIndex,
LINK_MIME_TYPE = '-->';
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
} // parsing fields [ID3v2.4.0 section 4.14.]
mimeTypeEndIndex = typedArrayIndexOf(frame.data, 0, i);
if (mimeTypeEndIndex < 0) {
// malformed frame
return;
} // parsing Mime type field (terminated with \0)
frame.mimeType = parseIso88591$1(frame.data, i, mimeTypeEndIndex);
i = mimeTypeEndIndex + 1; // parsing 1-byte Picture Type field
frame.pictureType = frame.data[i];
i++;
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, i);
if (descriptionEndIndex < 0) {
// malformed frame
return;
} // parsing Description field (terminated with \0)
frame.description = parseUtf8(frame.data, i, descriptionEndIndex);
i = descriptionEndIndex + 1;
if (frame.mimeType === LINK_MIME_TYPE) {
// parsing Picture Data field as URL (always represented as ISO-8859-1 [ID3v2.4.0 section 4.])
frame.url = parseIso88591$1(frame.data, i, frame.data.length);
} else {
// parsing Picture Data field as binary data
frame.pictureData = frame.data.subarray(i, frame.data.length);
}
},
'T*': function T(frame) {
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
} // parse text field, do not include null terminator in the frame value
// frames that allow different types of encoding contain terminated text [ID3v2.4.0 section 4.]
frame.value = parseUtf8(frame.data, 1, frame.data.length).replace(/\0*$/, ''); // text information frames supports multiple strings, stored as a terminator separated list [ID3v2.4.0 section 4.2.]
frame.values = frame.value.split('\0');
},
'TXXX': function TXXX(frame) {
var descriptionEndIndex;
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
}
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
if (descriptionEndIndex === -1) {
return;
} // parse the text fields
frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // do not include the null terminator in the tag value
// frames that allow different types of encoding contain terminated text
// [ID3v2.4.0 section 4.]
frame.value = parseUtf8(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\0*$/, '');
frame.data = frame.value;
},
'W*': function W(frame) {
// parse URL field; URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]
// if the value is followed by a string termination all the following information should be ignored [ID3v2.4.0 section 4.3]
frame.url = parseIso88591$1(frame.data, 0, frame.data.length).replace(/\0.*$/, '');
},
'WXXX': function WXXX(frame) {
var descriptionEndIndex;
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
}
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
if (descriptionEndIndex === -1) {
return;
} // parse the description and URL fields
frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]
// if the value is followed by a string termination all the following information
// should be ignored [ID3v2.4.0 section 4.3]
frame.url = parseIso88591$1(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\0.*$/, '');
},
'PRIV': function PRIV(frame) {
var i;
for (i = 0; i < frame.data.length; i++) {
if (frame.data[i] === 0) {
// parse the description and URL fields
frame.owner = parseIso88591$1(frame.data, 0, i);
break;
}
}
frame.privateData = frame.data.subarray(i + 1);
frame.data = frame.privateData;
}
};
var parseId3Frames$1 = function parseId3Frames(data) {
var frameSize,
frameHeader,
frameStart = 10,
tagSize = 0,
frames = []; // If we don't have enough data for a header, 10 bytes,
// or 'ID3' in the first 3 bytes this is not a valid ID3 tag.
if (data.length < 10 || data[0] !== 'I'.charCodeAt(0) || data[1] !== 'D'.charCodeAt(0) || data[2] !== '3'.charCodeAt(0)) {
return;
} // the frame size is transmitted as a 28-bit integer in the
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger$1(data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10; // check bit 6 of byte 5 for the extended header flag.
var hasExtendedHeader = data[5] & 0x40;
if (hasExtendedHeader) {
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger$1(data.subarray(10, 14));
tagSize -= parseSyncSafeInteger$1(data.subarray(16, 20)); // clip any padding off the end
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger$1(data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
break;
}
frameHeader = String.fromCharCode(data[frameStart], data[frameStart + 1], data[frameStart + 2], data[frameStart + 3]);
var frame = {
id: frameHeader,
data: data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id; // parse frame values
if (frameParsers[frame.id]) {
// use frame specific parser
frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
frameParsers['W*'](frame);
}
frames.push(frame);
frameStart += 10; // advance past the frame header
frameStart += frameSize; // advance past the frame body
} while (frameStart < tagSize);
return frames;
};
var parseId3 = {
parseId3Frames: parseId3Frames$1,
parseSyncSafeInteger: parseSyncSafeInteger$1,
frameParsers: frameParsers
};
var toUnsigned = bin.toUnsigned;
var toHexString = bin.toHexString;
var getUint64 = numbers.getUint64;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader, getEmsgID3;
var parseId3Frames = parseId3.parseId3Frames;
/**
* Parses an MP4 initialization segment and extracts the timescale
* values for any declared tracks. Timescale values indicate the
@ -1218,6 +1601,34 @@
});
return tracks;
};
/**
* Returns an array of emsg ID3 data from the provided segmentData.
* An offset can also be provided as the Latest Arrival Time to calculate
* the Event Start Time of v0 EMSG boxes.
* See: https://dashif-documents.azurewebsites.net/Events/master/event.html#Inband-event-timing
*
* @param {Uint8Array} segmentData the segment byte array.
* @param {number} offset the segment start time or Latest Arrival Time,
* @return {Object[]} an array of ID3 parsed from EMSG boxes
*/
getEmsgID3 = function getEmsgID3(segmentData, offset) {
if (offset === void 0) {
offset = 0;
}
var emsgBoxes = findBox_1(segmentData, ['emsg']);
return emsgBoxes.map(function (data) {
var parsedBox = emsg.parseEmsgBox(new Uint8Array(data));
var parsedId3Frames = parseId3Frames(parsedBox.message_data);
return {
cueTime: emsg.scaleTime(parsedBox.presentation_time, parsedBox.timescale, parsedBox.presentation_time_delta, offset),
duration: emsg.scaleTime(parsedBox.event_duration, parsedBox.timescale),
frames: parsedId3Frames
};
});
};
var probe = {
// export mp4 inspector's findBox and parseType for backwards compatibility
@ -1228,7 +1639,8 @@
compositionStartTime: compositionStartTime,
videoTrackIds: getVideoTrackIds,
tracks: getTracks,
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader,
getEmsgID3: getEmsgID3
};
/**
@ -4197,83 +4609,7 @@
handleRollover: handleRollover
};
var percentEncode$1 = function percentEncode(bytes, start, end) {
var i,
result = '';
for (i = start; i < end; i++) {
result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
}
return result;
},
// return the string representation of the specified byte range,
// interpreted as UTf-8.
parseUtf8 = function parseUtf8(bytes, start, end) {
return decodeURIComponent(percentEncode$1(bytes, start, end));
},
// return the string representation of the specified byte range,
// interpreted as ISO-8859-1.
parseIso88591$1 = function parseIso88591(bytes, start, end) {
return unescape(percentEncode$1(bytes, start, end)); // jshint ignore:line
},
parseSyncSafeInteger$1 = function parseSyncSafeInteger(data) {
return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
},
tagParsers = {
TXXX: function TXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the text fields
tag.description = parseUtf8(tag.data, 1, i); // do not include the null terminator in the tag value
tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, '');
break;
}
}
tag.data = tag.value;
},
WXXX: function WXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.description = parseUtf8(tag.data, 1, i);
tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
break;
}
}
},
PRIV: function PRIV(tag) {
var i;
for (i = 0; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.owner = parseIso88591$1(tag.data, 0, i);
break;
}
}
tag.privateData = tag.data.subarray(i + 1);
tag.data = tag.privateData;
}
},
_MetadataStream;
var _MetadataStream;
_MetadataStream = function MetadataStream(options) {
var settings = {
@ -4335,7 +4671,7 @@
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger$1(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
tagSize = parseId3.parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10;
@ -4368,23 +4704,25 @@
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger$1(tag.data.subarray(10, 14)); // clip any padding off the end
frameStart += parseId3.parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
tagSize -= parseSyncSafeInteger$1(tag.data.subarray(16, 20));
tagSize -= parseId3.parseSyncSafeInteger(tag.data.subarray(16, 20));
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger$1(tag.data.subarray(frameStart + 4, frameStart + 8));
frameSize = parseId3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
this.trigger('log', {
level: 'warn',
message: 'Malformed ID3 frame encountered. Skipping metadata parsing.'
});
return;
message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'
}); // If the frame is malformed, don't parse any further frames but allow previous valid parsed frames
// to be sent along.
break;
}
frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]);
@ -4392,29 +4730,37 @@
id: frameHeader,
data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id;
frame.key = frame.id; // parse frame values
if (tagParsers[frame.id]) {
tagParsers[frame.id](frame); // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (parseId3.frameParsers[frame.id]) {
// use frame specific parser
parseId3.frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
parseId3.frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
parseId3.frameParsers['W*'](frame);
} // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
this.trigger('timestamp', frame);
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
this.trigger('timestamp', frame);
}
tag.frames.push(frame);

File diff suppressed because one or more lines are too long

560
node_modules/mux.js/dist/mux.js generated vendored
View file

@ -1,4 +1,4 @@
/*! @name mux.js @version 6.0.1 @license Apache-2.0 */
/*! @name mux.js @version 6.3.0 @license Apache-2.0 */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('global/window')) :
typeof define === 'function' && define.amd ? define(['global/window'], factory) :
@ -1085,7 +1085,7 @@
var MAX_UINT32$1 = Math.pow(2, 32);
var getUint64$4 = function getUint64(uint8) {
var getUint64$5 = function getUint64(uint8) {
var dv = new DataView(uint8.buffer, uint8.byteOffset, uint8.byteLength);
var value;
@ -1103,7 +1103,7 @@
};
var numbers = {
getUint64: getUint64$4,
getUint64: getUint64$5,
MAX_UINT32: MAX_UINT32$1
};
@ -1781,6 +1781,133 @@
var findBox_1 = findBox;
/**
* Returns the first string in the data array ending with a null char '\0'
* @param {UInt8} data
* @returns the string with the null char
*/
var uint8ToCString$1 = function uint8ToCString(data) {
var index = 0;
var curChar = String.fromCharCode(data[index]);
var retString = '';
while (curChar !== '\0') {
retString += curChar;
index++;
curChar = String.fromCharCode(data[index]);
} // Add nullChar
retString += curChar;
return retString;
};
var string = {
uint8ToCString: uint8ToCString$1
};
var uint8ToCString = string.uint8ToCString;
var getUint64$4 = numbers.getUint64;
/**
* Based on: ISO/IEC 23009 Section: 5.10.3.3
* References:
* https://dashif-documents.azurewebsites.net/Events/master/event.html#emsg-format
* https://aomediacodec.github.io/id3-emsg/
*
* Takes emsg box data as a uint8 array and returns a emsg box object
* @param {UInt8Array} boxData data from emsg box
* @returns A parsed emsg box object
*/
var parseEmsgBox = function parseEmsgBox(boxData) {
// version + flags
var offset = 4;
var version = boxData[0];
var scheme_id_uri, value, timescale, presentation_time, presentation_time_delta, event_duration, id, message_data;
if (version === 0) {
scheme_id_uri = uint8ToCString(boxData.subarray(offset));
offset += scheme_id_uri.length;
value = uint8ToCString(boxData.subarray(offset));
offset += value.length;
var dv = new DataView(boxData.buffer);
timescale = dv.getUint32(offset);
offset += 4;
presentation_time_delta = dv.getUint32(offset);
offset += 4;
event_duration = dv.getUint32(offset);
offset += 4;
id = dv.getUint32(offset);
offset += 4;
} else if (version === 1) {
var dv = new DataView(boxData.buffer);
timescale = dv.getUint32(offset);
offset += 4;
presentation_time = getUint64$4(boxData.subarray(offset));
offset += 8;
event_duration = dv.getUint32(offset);
offset += 4;
id = dv.getUint32(offset);
offset += 4;
scheme_id_uri = uint8ToCString(boxData.subarray(offset));
offset += scheme_id_uri.length;
value = uint8ToCString(boxData.subarray(offset));
offset += value.length;
}
message_data = new Uint8Array(boxData.subarray(offset, boxData.byteLength));
var emsgBox = {
scheme_id_uri: scheme_id_uri,
value: value,
// if timescale is undefined or 0 set to 1
timescale: timescale ? timescale : 1,
presentation_time: presentation_time,
presentation_time_delta: presentation_time_delta,
event_duration: event_duration,
id: id,
message_data: message_data
};
return isValidEmsgBox(version, emsgBox) ? emsgBox : undefined;
};
/**
* Scales a presentation time or time delta with an offset with a provided timescale
* @param {number} presentationTime
* @param {number} timescale
* @param {number} timeDelta
* @param {number} offset
* @returns the scaled time as a number
*/
var scaleTime = function scaleTime(presentationTime, timescale, timeDelta, offset) {
return presentationTime || presentationTime === 0 ? presentationTime / timescale : offset + timeDelta / timescale;
};
/**
* Checks the emsg box data for validity based on the version
* @param {number} version of the emsg box to validate
* @param {Object} emsg the emsg data to validate
* @returns if the box is valid as a boolean
*/
var isValidEmsgBox = function isValidEmsgBox(version, emsg) {
var hasScheme = emsg.scheme_id_uri !== '\0';
var isValidV0Box = version === 0 && isDefined(emsg.presentation_time_delta) && hasScheme;
var isValidV1Box = version === 1 && isDefined(emsg.presentation_time) && hasScheme; // Only valid versions of emsg are 0 and 1
return !(version > 1) && isValidV0Box || isValidV1Box;
}; // Utility function to check if an object is defined
var isDefined = function isDefined(data) {
return data !== undefined || data !== null;
};
var emsg = {
parseEmsgBox: parseEmsgBox,
scaleTime: scaleTime
};
var tfhd = function tfhd(data) {
var view = new DataView(data.buffer, data.byteOffset, data.byteLength),
result = {
@ -1970,10 +2097,266 @@
var parseTfdt = tfdt;
// IE11 doesn't support indexOf for TypedArrays.
// Once IE11 support is dropped, this function should be removed.
var typedArrayIndexOf$1 = function typedArrayIndexOf(typedArray, element, fromIndex) {
if (!typedArray) {
return -1;
}
var currentIndex = fromIndex;
for (; currentIndex < typedArray.length; currentIndex++) {
if (typedArray[currentIndex] === element) {
return currentIndex;
}
}
return -1;
};
var typedArray = {
typedArrayIndexOf: typedArrayIndexOf$1
};
var typedArrayIndexOf = typedArray.typedArrayIndexOf,
// Frames that allow different types of text encoding contain a text
// encoding description byte [ID3v2.4.0 section 4.]
textEncodingDescriptionByte = {
Iso88591: 0x00,
// ISO-8859-1, terminated with \0.
Utf16: 0x01,
// UTF-16 encoded Unicode BOM, terminated with \0\0
Utf16be: 0x02,
// UTF-16BE encoded Unicode, without BOM, terminated with \0\0
Utf8: 0x03 // UTF-8 encoded Unicode, terminated with \0
},
// return a percent-encoded representation of the specified byte range
// @see http://en.wikipedia.org/wiki/Percent-encoding
percentEncode$1 = function percentEncode(bytes, start, end) {
var i,
result = '';
for (i = start; i < end; i++) {
result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
}
return result;
},
// return the string representation of the specified byte range,
// interpreted as UTf-8.
parseUtf8 = function parseUtf8(bytes, start, end) {
return decodeURIComponent(percentEncode$1(bytes, start, end));
},
// return the string representation of the specified byte range,
// interpreted as ISO-8859-1.
parseIso88591$1 = function parseIso88591(bytes, start, end) {
return unescape(percentEncode$1(bytes, start, end)); // jshint ignore:line
},
parseSyncSafeInteger$1 = function parseSyncSafeInteger(data) {
return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
},
frameParsers = {
'APIC': function APIC(frame) {
var i = 1,
mimeTypeEndIndex,
descriptionEndIndex,
LINK_MIME_TYPE = '-->';
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
} // parsing fields [ID3v2.4.0 section 4.14.]
mimeTypeEndIndex = typedArrayIndexOf(frame.data, 0, i);
if (mimeTypeEndIndex < 0) {
// malformed frame
return;
} // parsing Mime type field (terminated with \0)
frame.mimeType = parseIso88591$1(frame.data, i, mimeTypeEndIndex);
i = mimeTypeEndIndex + 1; // parsing 1-byte Picture Type field
frame.pictureType = frame.data[i];
i++;
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, i);
if (descriptionEndIndex < 0) {
// malformed frame
return;
} // parsing Description field (terminated with \0)
frame.description = parseUtf8(frame.data, i, descriptionEndIndex);
i = descriptionEndIndex + 1;
if (frame.mimeType === LINK_MIME_TYPE) {
// parsing Picture Data field as URL (always represented as ISO-8859-1 [ID3v2.4.0 section 4.])
frame.url = parseIso88591$1(frame.data, i, frame.data.length);
} else {
// parsing Picture Data field as binary data
frame.pictureData = frame.data.subarray(i, frame.data.length);
}
},
'T*': function T(frame) {
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
} // parse text field, do not include null terminator in the frame value
// frames that allow different types of encoding contain terminated text [ID3v2.4.0 section 4.]
frame.value = parseUtf8(frame.data, 1, frame.data.length).replace(/\0*$/, ''); // text information frames supports multiple strings, stored as a terminator separated list [ID3v2.4.0 section 4.2.]
frame.values = frame.value.split('\0');
},
'TXXX': function TXXX(frame) {
var descriptionEndIndex;
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
}
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
if (descriptionEndIndex === -1) {
return;
} // parse the text fields
frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // do not include the null terminator in the tag value
// frames that allow different types of encoding contain terminated text
// [ID3v2.4.0 section 4.]
frame.value = parseUtf8(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\0*$/, '');
frame.data = frame.value;
},
'W*': function W(frame) {
// parse URL field; URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]
// if the value is followed by a string termination all the following information should be ignored [ID3v2.4.0 section 4.3]
frame.url = parseIso88591$1(frame.data, 0, frame.data.length).replace(/\0.*$/, '');
},
'WXXX': function WXXX(frame) {
var descriptionEndIndex;
if (frame.data[0] !== textEncodingDescriptionByte.Utf8) {
// ignore frames with unrecognized character encodings
return;
}
descriptionEndIndex = typedArrayIndexOf(frame.data, 0, 1);
if (descriptionEndIndex === -1) {
return;
} // parse the description and URL fields
frame.description = parseUtf8(frame.data, 1, descriptionEndIndex); // URL fields are always represented as ISO-8859-1 [ID3v2.4.0 section 4.]
// if the value is followed by a string termination all the following information
// should be ignored [ID3v2.4.0 section 4.3]
frame.url = parseIso88591$1(frame.data, descriptionEndIndex + 1, frame.data.length).replace(/\0.*$/, '');
},
'PRIV': function PRIV(frame) {
var i;
for (i = 0; i < frame.data.length; i++) {
if (frame.data[i] === 0) {
// parse the description and URL fields
frame.owner = parseIso88591$1(frame.data, 0, i);
break;
}
}
frame.privateData = frame.data.subarray(i + 1);
frame.data = frame.privateData;
}
};
var parseId3Frames$1 = function parseId3Frames(data) {
var frameSize,
frameHeader,
frameStart = 10,
tagSize = 0,
frames = []; // If we don't have enough data for a header, 10 bytes,
// or 'ID3' in the first 3 bytes this is not a valid ID3 tag.
if (data.length < 10 || data[0] !== 'I'.charCodeAt(0) || data[1] !== 'D'.charCodeAt(0) || data[2] !== '3'.charCodeAt(0)) {
return;
} // the frame size is transmitted as a 28-bit integer in the
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger$1(data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10; // check bit 6 of byte 5 for the extended header flag.
var hasExtendedHeader = data[5] & 0x40;
if (hasExtendedHeader) {
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger$1(data.subarray(10, 14));
tagSize -= parseSyncSafeInteger$1(data.subarray(16, 20)); // clip any padding off the end
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger$1(data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
break;
}
frameHeader = String.fromCharCode(data[frameStart], data[frameStart + 1], data[frameStart + 2], data[frameStart + 3]);
var frame = {
id: frameHeader,
data: data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id; // parse frame values
if (frameParsers[frame.id]) {
// use frame specific parser
frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
frameParsers['W*'](frame);
}
frames.push(frame);
frameStart += 10; // advance past the frame header
frameStart += frameSize; // advance past the frame body
} while (frameStart < tagSize);
return frames;
};
var parseId3 = {
parseId3Frames: parseId3Frames$1,
parseSyncSafeInteger: parseSyncSafeInteger$1,
frameParsers: frameParsers
};
var toUnsigned = bin.toUnsigned;
var toHexString = bin.toHexString;
var getUint64$2 = numbers.getUint64;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader, getEmsgID3;
var parseId3Frames = parseId3.parseId3Frames;
/**
* Parses an MP4 initialization segment and extracts the timescale
* values for any declared tracks. Timescale values indicate the
@ -2292,6 +2675,34 @@
});
return tracks;
};
/**
* Returns an array of emsg ID3 data from the provided segmentData.
* An offset can also be provided as the Latest Arrival Time to calculate
* the Event Start Time of v0 EMSG boxes.
* See: https://dashif-documents.azurewebsites.net/Events/master/event.html#Inband-event-timing
*
* @param {Uint8Array} segmentData the segment byte array.
* @param {number} offset the segment start time or Latest Arrival Time,
* @return {Object[]} an array of ID3 parsed from EMSG boxes
*/
getEmsgID3 = function getEmsgID3(segmentData, offset) {
if (offset === void 0) {
offset = 0;
}
var emsgBoxes = findBox_1(segmentData, ['emsg']);
return emsgBoxes.map(function (data) {
var parsedBox = emsg.parseEmsgBox(new Uint8Array(data));
var parsedId3Frames = parseId3Frames(parsedBox.message_data);
return {
cueTime: emsg.scaleTime(parsedBox.presentation_time, parsedBox.timescale, parsedBox.presentation_time_delta, offset),
duration: emsg.scaleTime(parsedBox.event_duration, parsedBox.timescale),
frames: parsedId3Frames
};
});
};
var probe$2 = {
// export mp4 inspector's findBox and parseType for backwards compatibility
@ -2302,7 +2713,8 @@
compositionStartTime: compositionStartTime,
videoTrackIds: getVideoTrackIds,
tracks: getTracks,
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader,
getEmsgID3: getEmsgID3
};
/**
@ -5058,83 +5470,7 @@
handleRollover: handleRollover$1
};
var percentEncode$1 = function percentEncode(bytes, start, end) {
var i,
result = '';
for (i = start; i < end; i++) {
result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
}
return result;
},
// return the string representation of the specified byte range,
// interpreted as UTf-8.
parseUtf8 = function parseUtf8(bytes, start, end) {
return decodeURIComponent(percentEncode$1(bytes, start, end));
},
// return the string representation of the specified byte range,
// interpreted as ISO-8859-1.
parseIso88591$1 = function parseIso88591(bytes, start, end) {
return unescape(percentEncode$1(bytes, start, end)); // jshint ignore:line
},
parseSyncSafeInteger$1 = function parseSyncSafeInteger(data) {
return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
},
tagParsers = {
TXXX: function TXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the text fields
tag.description = parseUtf8(tag.data, 1, i); // do not include the null terminator in the tag value
tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, '');
break;
}
}
tag.data = tag.value;
},
WXXX: function WXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.description = parseUtf8(tag.data, 1, i);
tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
break;
}
}
},
PRIV: function PRIV(tag) {
var i;
for (i = 0; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.owner = parseIso88591$1(tag.data, 0, i);
break;
}
}
tag.privateData = tag.data.subarray(i + 1);
tag.data = tag.privateData;
}
},
_MetadataStream;
var _MetadataStream;
_MetadataStream = function MetadataStream(options) {
var settings = {
@ -5196,7 +5532,7 @@
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger$1(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
tagSize = parseId3.parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10;
@ -5229,23 +5565,25 @@
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger$1(tag.data.subarray(10, 14)); // clip any padding off the end
frameStart += parseId3.parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
tagSize -= parseSyncSafeInteger$1(tag.data.subarray(16, 20));
tagSize -= parseId3.parseSyncSafeInteger(tag.data.subarray(16, 20));
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger$1(tag.data.subarray(frameStart + 4, frameStart + 8));
frameSize = parseId3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
this.trigger('log', {
level: 'warn',
message: 'Malformed ID3 frame encountered. Skipping metadata parsing.'
});
return;
message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'
}); // If the frame is malformed, don't parse any further frames but allow previous valid parsed frames
// to be sent along.
break;
}
frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]);
@ -5253,29 +5591,37 @@
id: frameHeader,
data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id;
frame.key = frame.id; // parse frame values
if (tagParsers[frame.id]) {
tagParsers[frame.id](frame); // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (parseId3.frameParsers[frame.id]) {
// use frame specific parser
parseId3.frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
parseId3.frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
parseId3.frameParsers['W*'](frame);
} // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
this.trigger('timestamp', frame);
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
this.trigger('timestamp', frame);
}
tag.frames.push(frame);

File diff suppressed because one or more lines are too long

View file

@ -12,84 +12,7 @@
var Stream = require('../utils/stream'),
StreamTypes = require('./stream-types'),
// return a percent-encoded representation of the specified byte range
// @see http://en.wikipedia.org/wiki/Percent-encoding
percentEncode = function percentEncode(bytes, start, end) {
var i,
result = '';
for (i = start; i < end; i++) {
result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
}
return result;
},
// return the string representation of the specified byte range,
// interpreted as UTf-8.
parseUtf8 = function parseUtf8(bytes, start, end) {
return decodeURIComponent(percentEncode(bytes, start, end));
},
// return the string representation of the specified byte range,
// interpreted as ISO-8859-1.
parseIso88591 = function parseIso88591(bytes, start, end) {
return unescape(percentEncode(bytes, start, end)); // jshint ignore:line
},
parseSyncSafeInteger = function parseSyncSafeInteger(data) {
return data[0] << 21 | data[1] << 14 | data[2] << 7 | data[3];
},
tagParsers = {
TXXX: function TXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the text fields
tag.description = parseUtf8(tag.data, 1, i); // do not include the null terminator in the tag value
tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, '');
break;
}
}
tag.data = tag.value;
},
WXXX: function WXXX(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.description = parseUtf8(tag.data, 1, i);
tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
break;
}
}
},
PRIV: function PRIV(tag) {
var i;
for (i = 0; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.owner = parseIso88591(tag.data, 0, i);
break;
}
}
tag.privateData = tag.data.subarray(i + 1);
tag.data = tag.privateData;
}
},
id3 = require('../tools/parse-id3'),
_MetadataStream;
_MetadataStream = function MetadataStream(options) {
@ -152,7 +75,7 @@ _MetadataStream = function MetadataStream(options) {
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
tagSize = id3.parseSyncSafeInteger(chunk.data.subarray(6, 10)); // ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
tagSize += 10;
@ -185,23 +108,25 @@ _MetadataStream = function MetadataStream(options) {
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
frameStart += id3.parseSyncSafeInteger(tag.data.subarray(10, 14)); // clip any padding off the end
tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20));
tagSize -= id3.parseSyncSafeInteger(tag.data.subarray(16, 20));
} // parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
frameSize = id3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
this.trigger('log', {
level: 'warn',
message: 'Malformed ID3 frame encountered. Skipping metadata parsing.'
});
return;
message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'
}); // If the frame is malformed, don't parse any further frames but allow previous valid parsed frames
// to be sent along.
break;
}
frameHeader = String.fromCharCode(tag.data[frameStart], tag.data[frameStart + 1], tag.data[frameStart + 2], tag.data[frameStart + 3]);
@ -209,29 +134,37 @@ _MetadataStream = function MetadataStream(options) {
id: frameHeader,
data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id;
frame.key = frame.id; // parse frame values
if (tagParsers[frame.id]) {
tagParsers[frame.id](frame); // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (id3.frameParsers[frame.id]) {
// use frame specific parser
id3.frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
id3.frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
id3.frameParsers['W*'](frame);
} // handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var d = frame.data,
size = (d[3] & 0x01) << 30 | d[4] << 22 | d[5] << 14 | d[6] << 6 | d[7] >>> 2;
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size; // in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
this.trigger('timestamp', frame);
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
this.trigger('timestamp', frame);
}
tag.frames.push(frame);

37
node_modules/mux.js/es/mp4/probe.js generated vendored
View file

@ -16,6 +16,8 @@ var findBox = require('../mp4/find-box.js');
var parseType = require('../mp4/parse-type.js');
var emsg = require('../mp4/emsg.js');
var parseTfhd = require('../tools/parse-tfhd.js');
var parseTrun = require('../tools/parse-trun.js');
@ -24,9 +26,11 @@ var parseTfdt = require('../tools/parse-tfdt.js');
var getUint64 = require('../utils/numbers.js').getUint64;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks, getTimescaleFromMediaHeader, getEmsgID3;
var window = require('global/window');
var parseId3Frames = require('../tools/parse-id3.js').parseId3Frames;
/**
* Parses an MP4 initialization segment and extracts the timescale
* values for any declared tracks. Timescale values indicate the
@ -346,6 +350,34 @@ getTracks = function getTracks(init) {
});
return tracks;
};
/**
* Returns an array of emsg ID3 data from the provided segmentData.
* An offset can also be provided as the Latest Arrival Time to calculate
* the Event Start Time of v0 EMSG boxes.
* See: https://dashif-documents.azurewebsites.net/Events/master/event.html#Inband-event-timing
*
* @param {Uint8Array} segmentData the segment byte array.
* @param {number} offset the segment start time or Latest Arrival Time,
* @return {Object[]} an array of ID3 parsed from EMSG boxes
*/
getEmsgID3 = function getEmsgID3(segmentData, offset) {
if (offset === void 0) {
offset = 0;
}
var emsgBoxes = findBox(segmentData, ['emsg']);
return emsgBoxes.map(function (data) {
var parsedBox = emsg.parseEmsgBox(new Uint8Array(data));
var parsedId3Frames = parseId3Frames(parsedBox.message_data);
return {
cueTime: emsg.scaleTime(parsedBox.presentation_time, parsedBox.timescale, parsedBox.presentation_time_delta, offset),
duration: emsg.scaleTime(parsedBox.event_duration, parsedBox.timescale),
frames: parsedId3Frames
};
});
};
module.exports = {
// export mp4 inspector's findBox and parseType for backwards compatibility
@ -356,5 +388,6 @@ module.exports = {
compositionStartTime: compositionStartTime,
videoTrackIds: getVideoTrackIds,
tracks: getTracks,
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader,
getEmsgID3: getEmsgID3
};

View file

@ -12,80 +12,7 @@
var
Stream = require('../utils/stream'),
StreamTypes = require('./stream-types'),
// return a percent-encoded representation of the specified byte range
// @see http://en.wikipedia.org/wiki/Percent-encoding
percentEncode = function(bytes, start, end) {
var i, result = '';
for (i = start; i < end; i++) {
result += '%' + ('00' + bytes[i].toString(16)).slice(-2);
}
return result;
},
// return the string representation of the specified byte range,
// interpreted as UTf-8.
parseUtf8 = function(bytes, start, end) {
return decodeURIComponent(percentEncode(bytes, start, end));
},
// return the string representation of the specified byte range,
// interpreted as ISO-8859-1.
parseIso88591 = function(bytes, start, end) {
return unescape(percentEncode(bytes, start, end)); // jshint ignore:line
},
parseSyncSafeInteger = function(data) {
return (data[0] << 21) |
(data[1] << 14) |
(data[2] << 7) |
(data[3]);
},
tagParsers = {
TXXX: function(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the text fields
tag.description = parseUtf8(tag.data, 1, i);
// do not include the null terminator in the tag value
tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, '');
break;
}
}
tag.data = tag.value;
},
WXXX: function(tag) {
var i;
if (tag.data[0] !== 3) {
// ignore frames with unrecognized character encodings
return;
}
for (i = 1; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.description = parseUtf8(tag.data, 1, i);
tag.url = parseUtf8(tag.data, i + 1, tag.data.length);
break;
}
}
},
PRIV: function(tag) {
var i;
for (i = 0; i < tag.data.length; i++) {
if (tag.data[i] === 0) {
// parse the description and URL fields
tag.owner = parseIso88591(tag.data, 0, i);
break;
}
}
tag.privateData = tag.data.subarray(i + 1);
tag.data = tag.privateData;
}
},
id3 = require('../tools/parse-id3'),
MetadataStream;
MetadataStream = function(options) {
@ -153,7 +80,7 @@ MetadataStream = function(options) {
// last four bytes of the ID3 header.
// The most significant bit of each byte is dropped and the
// results concatenated to recover the actual value.
tagSize = parseSyncSafeInteger(chunk.data.subarray(6, 10));
tagSize = id3.parseSyncSafeInteger(chunk.data.subarray(6, 10));
// ID3 reports the tag size excluding the header but it's more
// convenient for our comparisons to include it
@ -184,23 +111,25 @@ MetadataStream = function(options) {
if (tag.data[5] & 0x40) {
// advance the frame start past the extended header
frameStart += 4; // header size field
frameStart += parseSyncSafeInteger(tag.data.subarray(10, 14));
frameStart += id3.parseSyncSafeInteger(tag.data.subarray(10, 14));
// clip any padding off the end
tagSize -= parseSyncSafeInteger(tag.data.subarray(16, 20));
tagSize -= id3.parseSyncSafeInteger(tag.data.subarray(16, 20));
}
// parse one or more ID3 frames
// http://id3.org/id3v2.3.0#ID3v2_frame_overview
do {
// determine the number of bytes in this frame
frameSize = parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
frameSize = id3.parseSyncSafeInteger(tag.data.subarray(frameStart + 4, frameStart + 8));
if (frameSize < 1) {
this.trigger('log', {
level: 'warn',
message: 'Malformed ID3 frame encountered. Skipping metadata parsing.'
message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'
});
return;
// If the frame is malformed, don't parse any further frames but allow previous valid parsed frames
// to be sent along.
break;
}
frameHeader = String.fromCharCode(tag.data[frameStart],
tag.data[frameStart + 1],
@ -213,34 +142,44 @@ MetadataStream = function(options) {
data: tag.data.subarray(frameStart + 10, frameStart + frameSize + 10)
};
frame.key = frame.id;
if (tagParsers[frame.id]) {
tagParsers[frame.id](frame);
// handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var
d = frame.data,
size = ((d[3] & 0x01) << 30) |
(d[4] << 22) |
(d[5] << 14) |
(d[6] << 6) |
(d[7] >>> 2);
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size;
// in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
this.trigger('timestamp', frame);
}
// parse frame values
if (id3.frameParsers[frame.id]) {
// use frame specific parser
id3.frameParsers[frame.id](frame);
} else if (frame.id[0] === 'T') {
// use text frame generic parser
id3.frameParsers['T*'](frame);
} else if (frame.id[0] === 'W') {
// use URL link frame generic parser
id3.frameParsers['W*'](frame);
}
// handle the special PRIV frame used to indicate the start
// time for raw AAC data
if (frame.owner === 'com.apple.streaming.transportStreamTimestamp') {
var
d = frame.data,
size = ((d[3] & 0x01) << 30) |
(d[4] << 22) |
(d[5] << 14) |
(d[6] << 6) |
(d[7] >>> 2);
size *= 4;
size += d[7] & 0x03;
frame.timeStamp = size;
// in raw AAC, all subsequent data will be timestamped based
// on the value of this frame
// we couldn't have known the appropriate pts and dts before
// parsing this ID3 tag so set those values now
if (tag.pts === undefined && tag.dts === undefined) {
tag.pts = frame.timeStamp;
tag.dts = frame.timeStamp;
}
this.trigger('timestamp', frame);
}
tag.frames.push(frame);
frameStart += 10; // advance past the frame header

30
node_modules/mux.js/lib/mp4/probe.js generated vendored
View file

@ -12,13 +12,15 @@ var toUnsigned = require('../utils/bin').toUnsigned;
var toHexString = require('../utils/bin').toHexString;
var findBox = require('../mp4/find-box.js');
var parseType = require('../mp4/parse-type.js');
var emsg = require('../mp4/emsg.js');
var parseTfhd = require('../tools/parse-tfhd.js');
var parseTrun = require('../tools/parse-trun.js');
var parseTfdt = require('../tools/parse-tfdt.js');
var getUint64 = require('../utils/numbers.js').getUint64;
var timescale, startTime, compositionStartTime, getVideoTrackIds, getTracks,
getTimescaleFromMediaHeader;
getTimescaleFromMediaHeader, getEmsgID3;
var window = require('global/window');
var parseId3Frames = require('../tools/parse-id3.js').parseId3Frames;
/**
@ -370,6 +372,29 @@ getTracks = function(init) {
return tracks;
};
/**
* Returns an array of emsg ID3 data from the provided segmentData.
* An offset can also be provided as the Latest Arrival Time to calculate
* the Event Start Time of v0 EMSG boxes.
* See: https://dashif-documents.azurewebsites.net/Events/master/event.html#Inband-event-timing
*
* @param {Uint8Array} segmentData the segment byte array.
* @param {number} offset the segment start time or Latest Arrival Time,
* @return {Object[]} an array of ID3 parsed from EMSG boxes
*/
getEmsgID3 = function(segmentData, offset = 0) {
var emsgBoxes = findBox(segmentData, ['emsg']);
return emsgBoxes.map((data) => {
var parsedBox = emsg.parseEmsgBox(new Uint8Array(data));
var parsedId3Frames = parseId3Frames(parsedBox.message_data);
return {
cueTime: emsg.scaleTime(parsedBox.presentation_time, parsedBox.timescale, parsedBox.presentation_time_delta, offset),
duration: emsg.scaleTime(parsedBox.event_duration, parsedBox.timescale),
frames: parsedId3Frames
};
});
};
module.exports = {
// export mp4 inspector's findBox and parseType for backwards compatibility
findBox: findBox,
@ -379,5 +404,6 @@ module.exports = {
compositionStartTime: compositionStartTime,
videoTrackIds: getVideoTrackIds,
tracks: getTracks,
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader
getTimescaleFromMediaHeader: getTimescaleFromMediaHeader,
getEmsgID3: getEmsgID3,
};

2
node_modules/mux.js/package.json generated vendored
View file

@ -1,6 +1,6 @@
{
"name": "mux.js",
"version": "6.0.1",
"version": "6.3.0",
"description": "A collection of lightweight utilities for inspecting and manipulating video container formats.",
"repository": {
"type": "git",

View file

@ -72,7 +72,7 @@ QUnit.test('triggers log for non-id3/invalid data', function(assert) {
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 metadata parsing.'}
{level: 'warn', message: 'Malformed ID3 frame encountered. Skipping remaining metadata parsing.'}
], 'logs as expected.');
});
@ -518,6 +518,65 @@ QUnit.test('constructs the dispatch type', function(assert) {
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'),
@ -570,6 +629,60 @@ QUnit.test('can parse TXXX frames in web worker', function(assert) {
});
});
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),

View file

@ -5,6 +5,7 @@ var
probe = require('../lib/mp4/probe'),
mp4Helpers = require('./utils/mp4-helpers'),
box = mp4Helpers.box,
id3 = require('./utils/id3-generator'),
// defined below
moovWithoutMdhd,
@ -143,6 +144,79 @@ QUnit.test('getTimescaleFromMediaHeader gets timescale for version 0 mdhd', func
);
});
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
// ---------

View file

@ -311,9 +311,70 @@ var sampleMoov =
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
box,
generateEmsgBoxData
};