mirror of
https://github.com/DanielnetoDotCom/YouPHPTube
synced 2025-10-03 09:49:28 +02:00
This commit is contained in:
parent
746e163d01
commit
1c7ea28b46
808 changed files with 316395 additions and 381162 deletions
29
node_modules/mux.js/CHANGELOG.md
generated
vendored
29
node_modules/mux.js/CHANGELOG.md
generated
vendored
|
@ -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)
|
||||
|
||||
|
|
139
node_modules/mux.js/cjs/m2ts/metadata-stream.js
generated
vendored
139
node_modules/mux.js/cjs/m2ts/metadata-stream.js
generated
vendored
|
@ -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
37
node_modules/mux.js/cjs/mp4/probe.js
generated
vendored
|
@ -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
307
node_modules/mux.js/dist/mux-flv.js
generated
vendored
|
@ -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);
|
||||
|
|
4
node_modules/mux.js/dist/mux-flv.min.js
generated
vendored
4
node_modules/mux.js/dist/mux-flv.min.js
generated
vendored
File diff suppressed because one or more lines are too long
560
node_modules/mux.js/dist/mux-mp4.js
generated
vendored
560
node_modules/mux.js/dist/mux-mp4.js
generated
vendored
|
@ -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);
|
||||
|
|
4
node_modules/mux.js/dist/mux-mp4.min.js
generated
vendored
4
node_modules/mux.js/dist/mux-mp4.min.js
generated
vendored
File diff suppressed because one or more lines are too long
560
node_modules/mux.js/dist/mux.js
generated
vendored
560
node_modules/mux.js/dist/mux.js
generated
vendored
|
@ -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);
|
||||
|
|
4
node_modules/mux.js/dist/mux.min.js
generated
vendored
4
node_modules/mux.js/dist/mux.min.js
generated
vendored
File diff suppressed because one or more lines are too long
139
node_modules/mux.js/es/m2ts/metadata-stream.js
generated
vendored
139
node_modules/mux.js/es/m2ts/metadata-stream.js
generated
vendored
|
@ -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
37
node_modules/mux.js/es/mp4/probe.js
generated
vendored
|
@ -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
|
||||
};
|
151
node_modules/mux.js/lib/m2ts/metadata-stream.js
generated
vendored
151
node_modules/mux.js/lib/m2ts/metadata-stream.js
generated
vendored
|
@ -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
30
node_modules/mux.js/lib/mp4/probe.js
generated
vendored
|
@ -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
2
node_modules/mux.js/package.json
generated
vendored
|
@ -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",
|
||||
|
|
115
node_modules/mux.js/test/metadata-stream.test.js
generated
vendored
115
node_modules/mux.js/test/metadata-stream.test.js
generated
vendored
|
@ -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),
|
||||
|
|
74
node_modules/mux.js/test/mp4-probe.test.js
generated
vendored
74
node_modules/mux.js/test/mp4-probe.test.js
generated
vendored
|
@ -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
|
||||
// ---------
|
||||
|
|
63
node_modules/mux.js/test/utils/mp4-helpers.js
generated
vendored
63
node_modules/mux.js/test/utils/mp4-helpers.js
generated
vendored
|
@ -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
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue