@brightcove/videojs-flashls-source-handler
Advanced tools
Comparing version 1.3.1 to 1.4.0
/** | ||
* @brightcove/videojs-flashls-source-handler | ||
* @version 1.3.1 | ||
* @version 1.4.0 | ||
* @copyright 2017 Brightcove | ||
@@ -200,2 +200,3 @@ * @license Apache-2.0 | ||
* @see https://en.wikipedia.org/wiki/CEA-708 | ||
* @see https://www.gpo.gov/fdsys/pkg/CFR-2007-title47-vol1/pdf/CFR-2007-title47-vol1-sec15-119.pdf | ||
*/ | ||
@@ -333,2 +334,3 @@ | ||
var CaptionStream = function() { | ||
CaptionStream.prototype.init.call(this); | ||
@@ -338,8 +340,19 @@ | ||
this.field1_ = new Cea608Stream(); // eslint-disable-line no-use-before-define | ||
this.ccStreams_ = [ | ||
new Cea608Stream(0, 0), // eslint-disable-line no-use-before-define | ||
new Cea608Stream(0, 1), // eslint-disable-line no-use-before-define | ||
new Cea608Stream(1, 0), // eslint-disable-line no-use-before-define | ||
new Cea608Stream(1, 1) // eslint-disable-line no-use-before-define | ||
]; | ||
// forward data and done events from field1_ to this CaptionStream | ||
this.field1_.on('data', this.trigger.bind(this, 'data')); | ||
this.field1_.on('done', this.trigger.bind(this, 'done')); | ||
this.reset(); | ||
// forward data and done events from CCs to this CaptionStream | ||
this.ccStreams_.forEach(function(cc) { | ||
cc.on('data', this.trigger.bind(this, 'data')); | ||
cc.on('done', this.trigger.bind(this, 'done')); | ||
}, this); | ||
}; | ||
CaptionStream.prototype = new Stream(); | ||
@@ -370,4 +383,22 @@ CaptionStream.prototype.push = function(event) { | ||
// Sometimes, the same segment # will be downloaded twice. To stop the | ||
// caption data from being processed twice, we track the latest dts we've | ||
// received and ignore everything with a dts before that. However, since | ||
// data for a specific dts can be split across 2 packets on either side of | ||
// a segment boundary, we need to make sure we *don't* ignore the second | ||
// dts packet we receive that has dts === this.latestDts_. And thus, the | ||
// ignoreNextEqualDts_ flag was born. | ||
if (event.dts < this.latestDts_) { | ||
// We've started getting older data, so set the flag. | ||
this.ignoreNextEqualDts_ = true; | ||
return; | ||
} else if ((event.dts === this.latestDts_) && (this.ignoreNextEqualDts_)) { | ||
// We've received the last duplicate packet, time to start processing again | ||
this.ignoreNextEqualDts_ = false; | ||
return; | ||
} | ||
// parse out CC data packets and save them for later | ||
this.captionPackets_ = this.captionPackets_.concat(parseCaptionPackets(event.pts, userData)); | ||
this.latestDts_ = event.dts; | ||
}; | ||
@@ -378,3 +409,5 @@ | ||
if (!this.captionPackets_.length) { | ||
this.field1_.flush(); | ||
this.ccStreams_.forEach(function(cc) { | ||
cc.flush(); | ||
}, this); | ||
return; | ||
@@ -397,9 +430,49 @@ } | ||
// Push each caption into Cea608Stream | ||
this.captionPackets_.forEach(this.field1_.push, this.field1_); | ||
this.captionPackets_.forEach(function(packet) { | ||
if (packet.type < 2) { | ||
// Dispatch packet to the right Cea608Stream | ||
this.dispatchCea608Packet(packet); | ||
} | ||
// this is where an 'else' would go for a dispatching packets | ||
// to a theoretical Cea708Stream that handles SERVICEn data | ||
}, this); | ||
this.captionPackets_.length = 0; | ||
this.field1_.flush(); | ||
this.ccStreams_.forEach(function(cc) { | ||
cc.flush(); | ||
}, this); | ||
return; | ||
}; | ||
CaptionStream.prototype.reset = function() { | ||
this.latestDts_ = null; | ||
this.ignoreNextEqualDts_ = false; | ||
this.activeCea608Channel_ = [null, null]; | ||
this.ccStreams_.forEach(function(ccStream) { | ||
ccStream.reset(); | ||
}); | ||
}; | ||
CaptionStream.prototype.dispatchCea608Packet = function(packet) { | ||
// NOTE: packet.type is the CEA608 field | ||
if (this.setsChannel1Active(packet)) { | ||
this.activeCea608Channel_[packet.type] = 0; | ||
} else if (this.setsChannel2Active(packet)) { | ||
this.activeCea608Channel_[packet.type] = 1; | ||
} | ||
if (this.activeCea608Channel_[packet.type] === null) { | ||
// If we haven't received anything to set the active channel, discard the | ||
// data; we don't want jumbled captions | ||
return; | ||
} | ||
this.ccStreams_[(packet.type << 1) + this.activeCea608Channel_[packet.type]].push(packet); | ||
}; | ||
CaptionStream.prototype.setsChannel1Active = function(packet) { | ||
return ((packet.ccData & 0x7800) === 0x1000); | ||
}; | ||
CaptionStream.prototype.setsChannel2Active = function(packet) { | ||
return ((packet.ccData & 0x7800) === 0x1800); | ||
}; | ||
// ---------------------- | ||
@@ -409,13 +482,93 @@ // Session to Application | ||
var BASIC_CHARACTER_TRANSLATION = { | ||
0x2a: 0xe1, | ||
0x5c: 0xe9, | ||
0x5e: 0xed, | ||
0x5f: 0xf3, | ||
0x60: 0xfa, | ||
0x7b: 0xe7, | ||
0x7c: 0xf7, | ||
0x7d: 0xd1, | ||
0x7e: 0xf1, | ||
0x7f: 0x2588 | ||
var CHARACTER_TRANSLATION = { | ||
0x2a: 0xe1, // á | ||
0x5c: 0xe9, // é | ||
0x5e: 0xed, // í | ||
0x5f: 0xf3, // ó | ||
0x60: 0xfa, // ú | ||
0x7b: 0xe7, // ç | ||
0x7c: 0xf7, // ÷ | ||
0x7d: 0xd1, // Ñ | ||
0x7e: 0xf1, // ñ | ||
0x7f: 0x2588, // █ | ||
0x0130: 0xae, // ® | ||
0x0131: 0xb0, // ° | ||
0x0132: 0xbd, // ½ | ||
0x0133: 0xbf, // ¿ | ||
0x0134: 0x2122, // ™ | ||
0x0135: 0xa2, // ¢ | ||
0x0136: 0xa3, // £ | ||
0x0137: 0x266a, // ♪ | ||
0x0138: 0xe0, // à | ||
0x0139: 0xa0, // | ||
0x013a: 0xe8, // è | ||
0x013b: 0xe2, // â | ||
0x013c: 0xea, // ê | ||
0x013d: 0xee, // î | ||
0x013e: 0xf4, // ô | ||
0x013f: 0xfb, // û | ||
0x0220: 0xc1, // Á | ||
0x0221: 0xc9, // É | ||
0x0222: 0xd3, // Ó | ||
0x0223: 0xda, // Ú | ||
0x0224: 0xdc, // Ü | ||
0x0225: 0xfc, // ü | ||
0x0226: 0x2018, // ‘ | ||
0x0227: 0xa1, // ¡ | ||
0x0228: 0x2a, // * | ||
0x0229: 0x27, // ' | ||
0x022a: 0x2014, // — | ||
0x022b: 0xa9, // © | ||
0x022c: 0x2120, // ℠ | ||
0x022d: 0x2022, // • | ||
0x022e: 0x201c, // “ | ||
0x022f: 0x201d, // ” | ||
0x0230: 0xc0, // À | ||
0x0231: 0xc2, // Â | ||
0x0232: 0xc7, // Ç | ||
0x0233: 0xc8, // È | ||
0x0234: 0xca, // Ê | ||
0x0235: 0xcb, // Ë | ||
0x0236: 0xeb, // ë | ||
0x0237: 0xce, // Î | ||
0x0238: 0xcf, // Ï | ||
0x0239: 0xef, // ï | ||
0x023a: 0xd4, // Ô | ||
0x023b: 0xd9, // Ù | ||
0x023c: 0xf9, // ù | ||
0x023d: 0xdb, // Û | ||
0x023e: 0xab, // « | ||
0x023f: 0xbb, // » | ||
0x0320: 0xc3, // Ã | ||
0x0321: 0xe3, // ã | ||
0x0322: 0xcd, // Í | ||
0x0323: 0xcc, // Ì | ||
0x0324: 0xec, // ì | ||
0x0325: 0xd2, // Ò | ||
0x0326: 0xf2, // ò | ||
0x0327: 0xd5, // Õ | ||
0x0328: 0xf5, // õ | ||
0x0329: 0x7b, // { | ||
0x032a: 0x7d, // } | ||
0x032b: 0x5c, // \ | ||
0x032c: 0x5e, // ^ | ||
0x032d: 0x5f, // _ | ||
0x032e: 0x7c, // | | ||
0x032f: 0x7e, // ~ | ||
0x0330: 0xc4, // Ä | ||
0x0331: 0xe4, // ä | ||
0x0332: 0xd6, // Ö | ||
0x0333: 0xf6, // ö | ||
0x0334: 0xdf, // ß | ||
0x0335: 0xa5, // ¥ | ||
0x0336: 0xa4, // ¤ | ||
0x0337: 0x2502, // │ | ||
0x0338: 0xc5, // Å | ||
0x0339: 0xe5, // å | ||
0x033a: 0xd8, // Ø | ||
0x033b: 0xf8, // ø | ||
0x033c: 0x250c, // ┌ | ||
0x033d: 0x2510, // ┐ | ||
0x033e: 0x2514, // └ | ||
0x033f: 0x2518 // ┘ | ||
}; | ||
@@ -427,28 +580,14 @@ | ||
} | ||
code = BASIC_CHARACTER_TRANSLATION[code] || code; | ||
code = CHARACTER_TRANSLATION[code] || code; | ||
return String.fromCharCode(code); | ||
}; | ||
// Constants for the byte codes recognized by Cea608Stream. This | ||
// list is not exhaustive. For a more comprehensive listing and | ||
// semantics see | ||
// http://www.gpo.gov/fdsys/pkg/CFR-2010-title47-vol1/pdf/CFR-2010-title47-vol1-sec15-119.pdf | ||
var PADDING = 0x0000, | ||
// the index of the last row in a CEA-608 display buffer | ||
var BOTTOM_ROW = 14; | ||
// Pop-on Mode | ||
RESUME_CAPTION_LOADING = 0x1420, | ||
END_OF_CAPTION = 0x142f, | ||
// This array is used for mapping PACs -> row #, since there's no way of | ||
// getting it through bit logic. | ||
var ROWS = [0x1100, 0x1120, 0x1200, 0x1220, 0x1500, 0x1520, 0x1600, 0x1620, | ||
0x1700, 0x1720, 0x1000, 0x1300, 0x1320, 0x1400, 0x1420]; | ||
// Roll-up Mode | ||
ROLL_UP_2_ROWS = 0x1425, | ||
ROLL_UP_3_ROWS = 0x1426, | ||
ROLL_UP_4_ROWS = 0x1427, | ||
CARRIAGE_RETURN = 0x142d, | ||
// Erasure | ||
BACKSPACE = 0x1421, | ||
ERASE_DISPLAYED_MEMORY = 0x142c, | ||
ERASE_NON_DISPLAYED_MEMORY = 0x142e; | ||
// the index of the last row in a CEA-608 display buffer | ||
var BOTTOM_ROW = 14; | ||
// CEA-608 captions are rendered onto a 34x15 matrix of character | ||
@@ -464,26 +603,19 @@ // cells. The "bottom" row is the last element in the outer array. | ||
var Cea608Stream = function() { | ||
var Cea608Stream = function(field, dataChannel) { | ||
Cea608Stream.prototype.init.call(this); | ||
this.mode_ = 'popOn'; | ||
// When in roll-up mode, the index of the last row that will | ||
// actually display captions. If a caption is shifted to a row | ||
// with a lower index than this, it is cleared from the display | ||
// buffer | ||
this.topRow_ = 0; | ||
this.startPts_ = 0; | ||
this.displayed_ = createDisplayBuffer(); | ||
this.nonDisplayed_ = createDisplayBuffer(); | ||
this.lastControlCode_ = null; | ||
this.field_ = field || 0; | ||
this.dataChannel_ = dataChannel || 0; | ||
this.name_ = 'CC' + (((this.field_ << 1) | this.dataChannel_) + 1); | ||
this.setConstants(); | ||
this.reset(); | ||
this.push = function(packet) { | ||
// Ignore other channels | ||
if (packet.type !== 0) { | ||
return; | ||
} | ||
var data, swap, char0, char1; | ||
var data, swap, char0, char1, text; | ||
// remove the parity bits | ||
data = packet.ccData & 0x7f7f; | ||
// ignore duplicate control codes | ||
// ignore duplicate control codes; the spec demands they're sent twice | ||
if (data === this.lastControlCode_) { | ||
@@ -497,13 +629,17 @@ this.lastControlCode_ = null; | ||
this.lastControlCode_ = data; | ||
} else { | ||
} else if (data !== this.PADDING_) { | ||
this.lastControlCode_ = null; | ||
} | ||
switch (data) { | ||
case PADDING: | ||
break; | ||
case RESUME_CAPTION_LOADING: | ||
char0 = data >>> 8; | ||
char1 = data & 0xff; | ||
if (data === this.PADDING_) { | ||
return; | ||
} else if (data === this.RESUME_CAPTION_LOADING_) { | ||
this.mode_ = 'popOn'; | ||
break; | ||
case END_OF_CAPTION: | ||
} else if (data === this.END_OF_CAPTION_) { | ||
this.clearFormatting(packet.pts); | ||
// if a caption was being displayed, it's gone now | ||
@@ -519,23 +655,19 @@ this.flushDisplayed(packet.pts); | ||
this.startPts_ = packet.pts; | ||
break; | ||
case ROLL_UP_2_ROWS: | ||
} else if (data === this.ROLL_UP_2_ROWS_) { | ||
this.topRow_ = BOTTOM_ROW - 1; | ||
this.mode_ = 'rollUp'; | ||
break; | ||
case ROLL_UP_3_ROWS: | ||
} else if (data === this.ROLL_UP_3_ROWS_) { | ||
this.topRow_ = BOTTOM_ROW - 2; | ||
this.mode_ = 'rollUp'; | ||
break; | ||
case ROLL_UP_4_ROWS: | ||
} else if (data === this.ROLL_UP_4_ROWS_) { | ||
this.topRow_ = BOTTOM_ROW - 3; | ||
this.mode_ = 'rollUp'; | ||
break; | ||
case CARRIAGE_RETURN: | ||
} else if (data === this.CARRIAGE_RETURN_) { | ||
this.clearFormatting(packet.pts); | ||
this.flushDisplayed(packet.pts); | ||
this.shiftRowsUp_(); | ||
this.startPts_ = packet.pts; | ||
break; | ||
case BACKSPACE: | ||
} else if (data === this.BACKSPACE_) { | ||
if (this.mode_ === 'popOn') { | ||
@@ -546,50 +678,119 @@ this.nonDisplayed_[BOTTOM_ROW] = this.nonDisplayed_[BOTTOM_ROW].slice(0, -1); | ||
} | ||
break; | ||
case ERASE_DISPLAYED_MEMORY: | ||
} else if (data === this.ERASE_DISPLAYED_MEMORY_) { | ||
this.flushDisplayed(packet.pts); | ||
this.displayed_ = createDisplayBuffer(); | ||
break; | ||
case ERASE_NON_DISPLAYED_MEMORY: | ||
} else if (data === this.ERASE_NON_DISPLAYED_MEMORY_) { | ||
this.nonDisplayed_ = createDisplayBuffer(); | ||
break; | ||
default: | ||
char0 = data >>> 8; | ||
char1 = data & 0xff; | ||
// Look for a Channel 1 Preamble Address Code | ||
if (char0 >= 0x10 && char0 <= 0x17 && | ||
char1 >= 0x40 && char1 <= 0x7F && | ||
(char0 !== 0x10 || char1 < 0x60)) { | ||
// Follow Safari's lead and replace the PAC with a space | ||
char0 = 0x20; | ||
// we only want one space so make the second character null | ||
// which will get become '' in getCharFromCode | ||
char1 = null; | ||
} else if (data === this.RESUME_DIRECT_CAPTIONING_) { | ||
this.mode_ = 'paintOn'; | ||
// Append special characters to caption text | ||
} else if (this.isSpecialCharacter(char0, char1)) { | ||
// Bitmask char0 so that we can apply character transformations | ||
// regardless of field and data channel. | ||
// Then byte-shift to the left and OR with char1 so we can pass the | ||
// entire character code to `getCharFromCode`. | ||
char0 = (char0 & 0x03) << 8; | ||
text = getCharFromCode(char0 | char1); | ||
this[this.mode_](packet.pts, text); | ||
this.column_++; | ||
// Append extended characters to caption text | ||
} else if (this.isExtCharacter(char0, char1)) { | ||
// Extended characters always follow their "non-extended" equivalents. | ||
// IE if a "è" is desired, you'll always receive "eè"; non-compliant | ||
// decoders are supposed to drop the "è", while compliant decoders | ||
// backspace the "e" and insert "è". | ||
// Delete the previous character | ||
if (this.mode_ === 'popOn') { | ||
this.nonDisplayed_[this.row_] = this.nonDisplayed_[this.row_].slice(0, -1); | ||
} else { | ||
this.displayed_[BOTTOM_ROW] = this.displayed_[BOTTOM_ROW].slice(0, -1); | ||
} | ||
// Look for special character sets | ||
if ((char0 === 0x11 || char0 === 0x19) && | ||
(char1 >= 0x30 && char1 <= 0x3F)) { | ||
// Put in eigth note and space | ||
char0 = 0x266A; | ||
char1 = ''; | ||
// Bitmask char0 so that we can apply character transformations | ||
// regardless of field and data channel. | ||
// Then byte-shift to the left and OR with char1 so we can pass the | ||
// entire character code to `getCharFromCode`. | ||
char0 = (char0 & 0x03) << 8; | ||
text = getCharFromCode(char0 | char1); | ||
this[this.mode_](packet.pts, text); | ||
this.column_++; | ||
// Process mid-row codes | ||
} else if (this.isMidRowCode(char0, char1)) { | ||
// Attributes are not additive, so clear all formatting | ||
this.clearFormatting(packet.pts); | ||
// According to the standard, mid-row codes | ||
// should be replaced with spaces, so add one now | ||
this[this.mode_](packet.pts, ' '); | ||
this.column_++; | ||
if ((char1 & 0xe) === 0xe) { | ||
this.addFormatting(packet.pts, ['i']); | ||
} | ||
// ignore unsupported control codes | ||
if ((char0 & 0xf0) === 0x10) { | ||
return; | ||
if ((char1 & 0x1) === 0x1) { | ||
this.addFormatting(packet.pts, ['u']); | ||
} | ||
// remove null chars | ||
if (char0 === 0x00) { | ||
char0 = null; | ||
// Detect offset control codes and adjust cursor | ||
} else if (this.isOffsetControlCode(char0, char1)) { | ||
// Cursor position is set by indent PAC (see below) in 4-column | ||
// increments, with an additional offset code of 1-3 to reach any | ||
// of the 32 columns specified by CEA-608. So all we need to do | ||
// here is increment the column cursor by the given offset. | ||
this.column_ += (char1 & 0x03); | ||
// Detect PACs (Preamble Address Codes) | ||
} else if (this.isPAC(char0, char1)) { | ||
// There's no logic for PAC -> row mapping, so we have to just | ||
// find the row code in an array and use its index :( | ||
var row = ROWS.indexOf(data & 0x1f20); | ||
if (row !== this.row_) { | ||
// formatting is only persistent for current row | ||
this.clearFormatting(packet.pts); | ||
this.row_ = row; | ||
} | ||
// All PACs can apply underline, so detect and apply | ||
// (All odd-numbered second bytes set underline) | ||
if ((char1 & 0x1) && (this.formatting_.indexOf('u') === -1)) { | ||
this.addFormatting(packet.pts, ['u']); | ||
} | ||
if ((data & 0x10) === 0x10) { | ||
// We've got an indent level code. Each successive even number | ||
// increments the column cursor by 4, so we can get the desired | ||
// column position by bit-shifting to the right (to get n/2) | ||
// and multiplying by 4. | ||
this.column_ = ((data & 0xe) >> 1) * 4; | ||
} | ||
if (this.isColorPAC(char1)) { | ||
// it's a color code, though we only support white, which | ||
// can be either normal or italicized. white italics can be | ||
// either 0x4e or 0x6e depending on the row, so we just | ||
// bitwise-and with 0xe to see if italics should be turned on | ||
if ((char1 & 0xe) === 0xe) { | ||
this.addFormatting(packet.pts, ['i']); | ||
} | ||
} | ||
// We have a normal character in char0, and possibly one in char1 | ||
} else if (this.isNormalChar(char0)) { | ||
if (char1 === 0x00) { | ||
char1 = null; | ||
} | ||
text = getCharFromCode(char0); | ||
text += getCharFromCode(char1); | ||
this[this.mode_](packet.pts, text); | ||
this.column_ += text.length; | ||
// character handling is dependent on the current mode | ||
this[this.mode_](packet.pts, char0, char1); | ||
break; | ||
} | ||
} // finish data processing | ||
}; | ||
@@ -606,8 +807,6 @@ }; | ||
}) | ||
// remove empty rows | ||
.filter(function(row) { | ||
return row.length; | ||
}) | ||
// combine all text rows to display in one cue | ||
.join('\n'); | ||
.join('\n') | ||
// and remove blank rows from the start and end, but not the middle | ||
.replace(/^\n+|\n+$/g, ''); | ||
@@ -618,3 +817,4 @@ if (content.length) { | ||
endPts: pts, | ||
text: content | ||
text: content, | ||
stream: this.name_ | ||
}); | ||
@@ -624,27 +824,216 @@ } | ||
/** | ||
* Zero out the data, used for startup and on seek | ||
*/ | ||
Cea608Stream.prototype.reset = function() { | ||
this.mode_ = 'popOn'; | ||
// When in roll-up mode, the index of the last row that will | ||
// actually display captions. If a caption is shifted to a row | ||
// with a lower index than this, it is cleared from the display | ||
// buffer | ||
this.topRow_ = 0; | ||
this.startPts_ = 0; | ||
this.displayed_ = createDisplayBuffer(); | ||
this.nonDisplayed_ = createDisplayBuffer(); | ||
this.lastControlCode_ = null; | ||
// Track row and column for proper line-breaking and spacing | ||
this.column_ = 0; | ||
this.row_ = BOTTOM_ROW; | ||
// This variable holds currently-applied formatting | ||
this.formatting_ = []; | ||
}; | ||
/** | ||
* Sets up control code and related constants for this instance | ||
*/ | ||
Cea608Stream.prototype.setConstants = function() { | ||
// The following attributes have these uses: | ||
// ext_ : char0 for mid-row codes, and the base for extended | ||
// chars (ext_+0, ext_+1, and ext_+2 are char0s for | ||
// extended codes) | ||
// control_: char0 for control codes, except byte-shifted to the | ||
// left so that we can do this.control_ | CONTROL_CODE | ||
// offset_: char0 for tab offset codes | ||
// | ||
// It's also worth noting that control codes, and _only_ control codes, | ||
// differ between field 1 and field2. Field 2 control codes are always | ||
// their field 1 value plus 1. That's why there's the "| field" on the | ||
// control value. | ||
if (this.dataChannel_ === 0) { | ||
this.BASE_ = 0x10; | ||
this.EXT_ = 0x11; | ||
this.CONTROL_ = (0x14 | this.field_) << 8; | ||
this.OFFSET_ = 0x17; | ||
} else if (this.dataChannel_ === 1) { | ||
this.BASE_ = 0x18; | ||
this.EXT_ = 0x19; | ||
this.CONTROL_ = (0x1c | this.field_) << 8; | ||
this.OFFSET_ = 0x1f; | ||
} | ||
// Constants for the LSByte command codes recognized by Cea608Stream. This | ||
// list is not exhaustive. For a more comprehensive listing and semantics see | ||
// http://www.gpo.gov/fdsys/pkg/CFR-2010-title47-vol1/pdf/CFR-2010-title47-vol1-sec15-119.pdf | ||
// Padding | ||
this.PADDING_ = 0x0000; | ||
// Pop-on Mode | ||
this.RESUME_CAPTION_LOADING_ = this.CONTROL_ | 0x20; | ||
this.END_OF_CAPTION_ = this.CONTROL_ | 0x2f; | ||
// Roll-up Mode | ||
this.ROLL_UP_2_ROWS_ = this.CONTROL_ | 0x25; | ||
this.ROLL_UP_3_ROWS_ = this.CONTROL_ | 0x26; | ||
this.ROLL_UP_4_ROWS_ = this.CONTROL_ | 0x27; | ||
this.CARRIAGE_RETURN_ = this.CONTROL_ | 0x2d; | ||
// paint-on mode (not supported) | ||
this.RESUME_DIRECT_CAPTIONING_ = this.CONTROL_ | 0x29; | ||
// Erasure | ||
this.BACKSPACE_ = this.CONTROL_ | 0x21; | ||
this.ERASE_DISPLAYED_MEMORY_ = this.CONTROL_ | 0x2c; | ||
this.ERASE_NON_DISPLAYED_MEMORY_ = this.CONTROL_ | 0x2e; | ||
}; | ||
/** | ||
* Detects if the 2-byte packet data is a special character | ||
* | ||
* Special characters have a second byte in the range 0x30 to 0x3f, | ||
* with the first byte being 0x11 (for data channel 1) or 0x19 (for | ||
* data channel 2). | ||
* | ||
* @param {Integer} char0 The first byte | ||
* @param {Integer} char1 The second byte | ||
* @return {Boolean} Whether the 2 bytes are an special character | ||
*/ | ||
Cea608Stream.prototype.isSpecialCharacter = function(char0, char1) { | ||
return (char0 === this.EXT_ && char1 >= 0x30 && char1 <= 0x3f); | ||
}; | ||
/** | ||
* Detects if the 2-byte packet data is an extended character | ||
* | ||
* Extended characters have a second byte in the range 0x20 to 0x3f, | ||
* with the first byte being 0x12 or 0x13 (for data channel 1) or | ||
* 0x1a or 0x1b (for data channel 2). | ||
* | ||
* @param {Integer} char0 The first byte | ||
* @param {Integer} char1 The second byte | ||
* @return {Boolean} Whether the 2 bytes are an extended character | ||
*/ | ||
Cea608Stream.prototype.isExtCharacter = function(char0, char1) { | ||
return ((char0 === (this.EXT_ + 1) || char0 === (this.EXT_ + 2)) && | ||
(char1 >= 0x20 && char1 <= 0x3f)); | ||
}; | ||
/** | ||
* Detects if the 2-byte packet is a mid-row code | ||
* | ||
* Mid-row codes have a second byte in the range 0x20 to 0x2f, with | ||
* the first byte being 0x11 (for data channel 1) or 0x19 (for data | ||
* channel 2). | ||
* | ||
* @param {Integer} char0 The first byte | ||
* @param {Integer} char1 The second byte | ||
* @return {Boolean} Whether the 2 bytes are a mid-row code | ||
*/ | ||
Cea608Stream.prototype.isMidRowCode = function(char0, char1) { | ||
return (char0 === this.EXT_ && (char1 >= 0x20 && char1 <= 0x2f)); | ||
}; | ||
/** | ||
* Detects if the 2-byte packet is an offset control code | ||
* | ||
* Offset control codes have a second byte in the range 0x21 to 0x23, | ||
* with the first byte being 0x17 (for data channel 1) or 0x1f (for | ||
* data channel 2). | ||
* | ||
* @param {Integer} char0 The first byte | ||
* @param {Integer} char1 The second byte | ||
* @return {Boolean} Whether the 2 bytes are an offset control code | ||
*/ | ||
Cea608Stream.prototype.isOffsetControlCode = function(char0, char1) { | ||
return (char0 === this.OFFSET_ && (char1 >= 0x21 && char1 <= 0x23)); | ||
}; | ||
/** | ||
* Detects if the 2-byte packet is a Preamble Address Code | ||
* | ||
* PACs have a first byte in the range 0x10 to 0x17 (for data channel 1) | ||
* or 0x18 to 0x1f (for data channel 2), with the second byte in the | ||
* range 0x40 to 0x7f. | ||
* | ||
* @param {Integer} char0 The first byte | ||
* @param {Integer} char1 The second byte | ||
* @return {Boolean} Whether the 2 bytes are a PAC | ||
*/ | ||
Cea608Stream.prototype.isPAC = function(char0, char1) { | ||
return (char0 >= this.BASE_ && char0 < (this.BASE_ + 8) && | ||
(char1 >= 0x40 && char1 <= 0x7f)); | ||
}; | ||
/** | ||
* Detects if a packet's second byte is in the range of a PAC color code | ||
* | ||
* PAC color codes have the second byte be in the range 0x40 to 0x4f, or | ||
* 0x60 to 0x6f. | ||
* | ||
* @param {Integer} char1 The second byte | ||
* @return {Boolean} Whether the byte is a color PAC | ||
*/ | ||
Cea608Stream.prototype.isColorPAC = function(char1) { | ||
return ((char1 >= 0x40 && char1 <= 0x4f) || (char1 >= 0x60 && char1 <= 0x7f)); | ||
}; | ||
/** | ||
* Detects if a single byte is in the range of a normal character | ||
* | ||
* Normal text bytes are in the range 0x20 to 0x7f. | ||
* | ||
* @param {Integer} char The byte | ||
* @return {Boolean} Whether the byte is a normal character | ||
*/ | ||
Cea608Stream.prototype.isNormalChar = function(char) { | ||
return (char >= 0x20 && char <= 0x7f); | ||
}; | ||
// Adds the opening HTML tag for the passed character to the caption text, | ||
// and keeps track of it for later closing | ||
Cea608Stream.prototype.addFormatting = function(pts, format) { | ||
this.formatting_ = this.formatting_.concat(format); | ||
var text = format.reduce(function(text, format) { | ||
return text + '<' + format + '>'; | ||
}, ''); | ||
this[this.mode_](pts, text); | ||
}; | ||
// Adds HTML closing tags for current formatting to caption text and | ||
// clears remembered formatting | ||
Cea608Stream.prototype.clearFormatting = function(pts) { | ||
if (!this.formatting_.length) { | ||
return; | ||
} | ||
var text = this.formatting_.reverse().reduce(function(text, format) { | ||
return text + '</' + format + '>'; | ||
}, ''); | ||
this.formatting_ = []; | ||
this[this.mode_](pts, text); | ||
}; | ||
// Mode Implementations | ||
Cea608Stream.prototype.popOn = function(pts, char0, char1) { | ||
var baseRow = this.nonDisplayed_[BOTTOM_ROW]; | ||
Cea608Stream.prototype.popOn = function(pts, text) { | ||
var baseRow = this.nonDisplayed_[this.row_]; | ||
// buffer characters | ||
baseRow += getCharFromCode(char0); | ||
baseRow += getCharFromCode(char1); | ||
this.nonDisplayed_[BOTTOM_ROW] = baseRow; | ||
baseRow += text; | ||
this.nonDisplayed_[this.row_] = baseRow; | ||
}; | ||
Cea608Stream.prototype.rollUp = function(pts, char0, char1) { | ||
Cea608Stream.prototype.rollUp = function(pts, text) { | ||
var baseRow = this.displayed_[BOTTOM_ROW]; | ||
if (baseRow === '') { | ||
// we're starting to buffer new display input, so flush out the | ||
// current display | ||
this.flushDisplayed(pts); | ||
this.startPts_ = pts; | ||
} | ||
baseRow += text; | ||
this.displayed_[BOTTOM_ROW] = baseRow; | ||
baseRow += getCharFromCode(char0); | ||
baseRow += getCharFromCode(char1); | ||
}; | ||
this.displayed_[BOTTOM_ROW] = baseRow; | ||
}; | ||
Cea608Stream.prototype.shiftRowsUp_ = function() { | ||
@@ -664,2 +1053,5 @@ var i; | ||
// paintOn mode is not implemented | ||
Cea608Stream.prototype.paintOn = function() {}; | ||
// exports | ||
@@ -719,3 +1111,3 @@ module.exports = { | ||
// do not include the null terminator in the tag value | ||
tag.value = parseUtf8(tag.data, i + 1, tag.data.length - 1); | ||
tag.value = parseUtf8(tag.data, i + 1, tag.data.length).replace(/\0*$/, ''); | ||
break; | ||
@@ -1138,33 +1530,2 @@ } | ||
// see CEA-708-D, section 4.4 | ||
var parseCaptionPackets = function parseCaptionPackets(pts, userData) { | ||
var results = []; | ||
var i = void 0; | ||
var count = void 0; | ||
var offset = void 0; | ||
var data = void 0; | ||
// if this is just filler, return immediately | ||
if (!(userData[0] & 0x40)) { | ||
return results; | ||
} | ||
// parse out the cc_data_1 and cc_data_2 fields | ||
count = userData[0] & 0x1f; | ||
for (i = 0; i < count; i++) { | ||
offset = i * 3; | ||
data = { | ||
type: userData[offset + 2] & 0x03, | ||
pts: pts | ||
}; | ||
// capture cc data when cc_valid is 1 | ||
if (userData[offset + 2] & 0x04) { | ||
data.ccData = userData[offset + 3] << 8 | userData[offset + 4]; | ||
results.push(data); | ||
} | ||
} | ||
return results; | ||
}; | ||
/** | ||
@@ -1242,2 +1603,33 @@ * Remove cues from a track on video.js. | ||
// Fudge factor to account for TimeRanges rounding | ||
var TIME_FUDGE_FACTOR = 1 / 30; | ||
var filterRanges = function filterRanges(timeRanges, predicate) { | ||
var results = []; | ||
if (timeRanges && timeRanges.length) { | ||
// Search for ranges that match the predicate | ||
for (var i = 0; i < timeRanges.length; i++) { | ||
if (predicate(timeRanges.start(i), timeRanges.end(i))) { | ||
results.push([timeRanges.start(i), timeRanges.end(i)]); | ||
} | ||
} | ||
} | ||
return _video2['default'].createTimeRanges(results); | ||
}; | ||
/** | ||
* Attempts to find the buffered TimeRange that contains the specified | ||
* time. | ||
* @param {TimeRanges} buffered - the TimeRanges object to query | ||
* @param {number} time - the time to filter on. | ||
* @returns {TimeRanges} a new TimeRanges object | ||
*/ | ||
var findRange = function findRange(buffered, time) { | ||
return filterRanges(buffered, function (start, end) { | ||
return start - TIME_FUDGE_FACTOR <= time && end + TIME_FUDGE_FACTOR >= time; | ||
}); | ||
}; | ||
var FlashlsHandler = exports.FlashlsHandler = function () { | ||
@@ -1280,30 +1672,32 @@ function FlashlsHandler(source, tech, options) { | ||
this.metadataTrack_ = null; | ||
this.inbandTextTrack_ = null; | ||
this.inbandTextTracks_ = {}; | ||
this.metadataStream_ = new _metadataStream2['default'](); | ||
this.cea608Stream_ = new _captionStream.Cea608Stream(); | ||
this.captionPackets_ = []; | ||
this.captionStream_ = new _captionStream.CaptionStream(); | ||
// bind event listeners to this context | ||
this.onLoadedmetadata_ = this.onLoadedmetadata_.bind(this); | ||
this.onSeeked_ = this.onSeeked_.bind(this); | ||
this.onSeeking_ = this.onSeeking_.bind(this); | ||
this.onId3updated_ = this.onId3updated_.bind(this); | ||
this.onCaptionData_ = this.onCaptionData_.bind(this); | ||
this.onMetadataStreamData_ = this.onMetadataStreamData_.bind(this); | ||
this.onCea608StreamData_ = this.onCea608StreamData_.bind(this); | ||
this.onCaptionStreamData_ = this.onCaptionStreamData_.bind(this); | ||
this.onLevelSwitch_ = this.onLevelSwitch_.bind(this); | ||
this.onLevelLoaded_ = this.onLevelLoaded_.bind(this); | ||
this.onFragmentLoaded_ = this.onFragmentLoaded_.bind(this); | ||
this.onAudioTrackChanged = this.onAudioTrackChanged.bind(this); | ||
this.tech_.on('loadedmetadata', this.onLoadedmetadata_); | ||
this.tech_.on('seeked', this.onSeeked_); | ||
this.tech_.on('seeking', this.onSeeking_); | ||
this.tech_.on('id3updated', this.onId3updated_); | ||
this.tech_.on('captiondata', this.onCaptionData_); | ||
this.tech_.on('levelswitch', this.onLevelSwitch_); | ||
this.tech_.on('levelloaded', this.onLevelLoaded_); | ||
this.tech_.on('fragmentloaded', this.onFragmentLoaded_); | ||
this.metadataStream_.on('data', this.onMetadataStreamData_); | ||
this.cea608Stream_.on('data', this.onCea608StreamData_); | ||
this.captionStream_.on('data', this.onCaptionStreamData_); | ||
this.playlists = { | ||
media: function media() { | ||
return _this.media_(); | ||
} | ||
this.playlists = new _video2['default'].EventTarget(); | ||
this.playlists.media = function () { | ||
return _this.media_(); | ||
}; | ||
@@ -1412,2 +1806,3 @@ } | ||
} | ||
this.playlists.trigger('mediachange'); | ||
this.tech_.trigger({ type: 'mediachange', bubbles: true }); | ||
@@ -1417,17 +1812,38 @@ }; | ||
/** | ||
* Event listener for the seeked event. This will remove cues from the metadata track | ||
* and inband text track after seeks | ||
* Event listener for the levelloaded event. | ||
*/ | ||
FlashlsHandler.prototype.onSeeked_ = function onSeeked_() { | ||
FlashlsHandler.prototype.onLevelLoaded_ = function onLevelLoaded_() { | ||
this.playlists.trigger('loadedplaylist'); | ||
}; | ||
/** | ||
* Event listener for the fragmentloaded event. | ||
*/ | ||
FlashlsHandler.prototype.onFragmentLoaded_ = function onFragmentLoaded_() { | ||
this.tech_.trigger('bandwidthupdate'); | ||
this.captionStream_.flush(); | ||
}; | ||
/** | ||
* Event listener for the seeking event. This will remove cues from the metadata track | ||
* and inband text tracks during seeks | ||
*/ | ||
FlashlsHandler.prototype.onSeeking_ = function onSeeking_() { | ||
var _this3 = this; | ||
removeCuesFromTrack(0, Infinity, this.metadataTrack_); | ||
var buffered = this.tech_.buffered(); | ||
var buffered = findRange(this.tech_.buffered(), this.tech_.currentTime()); | ||
if (buffered.length === 1) { | ||
removeCuesFromTrack(0, buffered.start(0), this.inbandTextTrack_); | ||
removeCuesFromTrack(buffered.end(0), Infinity, this.inbandTextTrack_); | ||
} else { | ||
removeCuesFromTrack(0, Infinity, this.inbandTextTrack_); | ||
if (!buffered.length) { | ||
Object.keys(this.inbandTextTracks_).forEach(function (id) { | ||
removeCuesFromTrack(0, Infinity, _this3.inbandTextTracks_[id]); | ||
}); | ||
this.captionStream_.reset(); | ||
} | ||
@@ -1468,3 +1884,3 @@ }; | ||
FlashlsHandler.prototype.onMetadataStreamData_ = function onMetadataStreamData_(tag) { | ||
var _this3 = this; | ||
var _this4 = this; | ||
@@ -1491,3 +1907,3 @@ if (!this.metadataTrack_) { | ||
deprecateOldCue(cue); | ||
_this3.metadataTrack_.addCue(cue); | ||
_this4.metadataTrack_.addCue(cue); | ||
}); | ||
@@ -1533,35 +1949,12 @@ | ||
FlashlsHandler.prototype.onCaptionData_ = function onCaptionData_(event, data) { | ||
var _this4 = this; | ||
var _this5 = this; | ||
var captions = data[0].map(function (d) { | ||
return { | ||
data[0].forEach(function (d) { | ||
_this5.captionStream_.push({ | ||
pts: d.pos * 90000, | ||
bytes: stringToByteArray(_window2['default'].atob(d.data)) | ||
}; | ||
dts: d.dts * 90000, | ||
escapedRBSP: stringToByteArray(_window2['default'].atob(d.data)), | ||
nalUnitType: 'sei_rbsp' | ||
}); | ||
}); | ||
captions.forEach(function (caption) { | ||
_this4.captionPackets_ = _this4.captionPackets_.concat(parseCaptionPackets(caption.pts, caption.bytes)); | ||
}); | ||
if (this.captionPackets_.length) { | ||
// In Chrome, the Array#sort function is not stable so add a | ||
// presortIndex that we can use to ensure we get a stable-sort | ||
this.captionPackets_.forEach(function (elem, idx) { | ||
elem.presortIndex = idx; | ||
}); | ||
// sort caption byte-pairs based on their PTS values | ||
this.captionPackets_.sort(function (a, b) { | ||
if (a.pts === b.pts) { | ||
return a.presortIndex - b.presortIndex; | ||
} | ||
return a.pts - b.pts; | ||
}); | ||
// Push each caption into Cea608Stream | ||
this.captionPackets_.forEach(this.cea608Stream_.push, this.cea608Stream_); | ||
this.captionPackets_.length = 0; | ||
this.cea608Stream_.flush(); | ||
} | ||
}; | ||
@@ -1578,15 +1971,16 @@ | ||
FlashlsHandler.prototype.onCea608StreamData_ = function onCea608StreamData_(caption) { | ||
FlashlsHandler.prototype.onCaptionStreamData_ = function onCaptionStreamData_(caption) { | ||
if (caption) { | ||
if (!this.inbandTextTrack_) { | ||
removeExistingTrack(this.tech_, 'captions', 'cc1'); | ||
this.inbandTextTrack_ = this.tech_.addRemoteTextTrack({ | ||
if (!this.inbandTextTracks_[caption.stream]) { | ||
removeExistingTrack(this.tech_, 'captions', caption.stream); | ||
this.inbandTextTracks_[caption.stream] = this.tech_.addRemoteTextTrack({ | ||
kind: 'captions', | ||
label: 'cc1' | ||
label: caption.stream, | ||
id: caption.stream | ||
}, false).track; | ||
} | ||
removeOldCues(this.tech_.buffered(), this.inbandTextTrack_); | ||
removeOldCues(this.tech_.buffered(), this.inbandTextTracks_[caption.stream]); | ||
this.inbandTextTrack_.addCue(new _window2['default'].VTTCue(caption.startPts / 90000, caption.endPts / 90000, caption.text)); | ||
this.inbandTextTracks_[caption.stream].addCue(new _window2['default'].VTTCue(caption.startPts / 90000, caption.endPts / 90000, caption.text)); | ||
} | ||
@@ -1597,3 +1991,3 @@ }; | ||
this.tech_.off('loadedmetadata', this.onLoadedmetadata_); | ||
this.tech_.off('seeked', this.onSeeked_); | ||
this.tech_.off('seeked', this.onSeeking_); | ||
this.tech_.off('id3updated', this.onId3updated_); | ||
@@ -1603,2 +1997,4 @@ this.tech_.off('captiondata', this.onCaptionData_); | ||
this.tech_.off('levelswitch', this.onLevelSwitch_); | ||
this.tech_.off('levelloaded', this.onLevelLoaded_); | ||
this.tech_.off('fragmentloaded', this.onFragmentLoaded_); | ||
@@ -1680,3 +2076,3 @@ if (this.qualityLevels_) { | ||
// Include the version number. | ||
FlashlsSourceHandler.VERSION = '1.3.1'; | ||
FlashlsSourceHandler.VERSION = '1.4.0'; | ||
@@ -1683,0 +2079,0 @@ exports['default'] = FlashlsSourceHandler; |
@@ -1,1 +0,1 @@ | ||
!function t(e,a,i){function n(s,o){if(!a[s]){if(!e[s]){var d="function"==typeof require&&require;if(!o&&d)return d(s,!0);if(r)return r(s,!0);var l=new Error("Cannot find module '"+s+"'");throw l.code="MODULE_NOT_FOUND",l}var h=a[s]={exports:{}};e[s][0].call(h.exports,function(t){var a=e[s][1][t];return n(a||t)},h,h.exports,t,e,a,i)}return a[s].exports}for(var r="function"==typeof require&&require,s=0;s<i.length;s++)n(i[s]);return n}({1:[function(t,e,a){(function(t){"use strict";a.__esModule=!0,a.setupAudioTracks=a.updateAudioTrack=void 0;var e="undefined"!=typeof window?window.videojs:void 0!==t?t.videojs:null,i=function(t){return t&&t.__esModule?t:{default:t}}(e);a.updateAudioTrack=function(t){for(var e=t.el_.vjs_getProperty("audioTracks"),a=t.audioTracks(),i=null,n=0;n<a.length;n++)if(a[n].enabled){i=a[n].id;break}if(null!==i)for(var r=0;r<e.length;r++)if(i===e[r].title)return void t.el_.vjs_setProperty("audioTrack",r)},a.setupAudioTracks=function(t){var e=t.el_.vjs_getProperty("altAudioTracks"),a=t.el_.vjs_getProperty("audioTracks"),n=t.el_.vjs_getProperty("audioTrack");a.forEach(function(a,r){var s=e[a.id];t.audioTracks().addTrack(new i.default.AudioTrack({id:s.name,enabled:n===r,language:s.lang,default:s.default_track,label:s.name}))})}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(t,e,a){"use strict";a.__esModule=!0;var i=a.createRepresentation=function(t,e){var a={id:e.index+"",width:e.width,height:e.height,bandwidth:e.bitrate,isEnabled_:!0};return a.enabled=function(e){if(void 0===e)return a.isEnabled_;e!==a.isEnabled_&&(!0!==e&&!1!==e||(a.isEnabled_=e,t()))},a};a.createRepresentations=function(t){var e=null,a=function(){var a=e.filter(function(t){return t.enabled()});if(a.length===e.length||0===a.length)return t.el_.vjs_setProperty("autoLevelCapping",-1),void t.el_.vjs_setProperty("level",-1);if(1===a.length)return t.el_.vjs_setProperty("level",parseInt(a[0].id,10)),void t.el_.vjs_setProperty("autoLevelCapping",-1);var i=a[a.length-1].id;t.el_.vjs_setProperty("autoLevelCapping",parseInt(i,10)),t.el_.vjs_setProperty("level",-1)};return function(){if(!e){var n=t.el_.vjs_getProperty("levels");e=n.filter(function(t){return!t.audio}).map(i.bind(null,a))}return e}}},{}],3:[function(t,e,a){(function(t){var a;a="undefined"!=typeof window?window:void 0!==t?t:"undefined"!=typeof self?self:{},e.exports=a}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],4:[function(t,e,a){"use strict";var i=t(7),n=function(t){for(var e=0,a={payloadType:-1,payloadSize:0},i=0,n=0;e<t.byteLength&&128!==t[e];){for(;255===t[e];)i+=255,e++;for(i+=t[e++];255===t[e];)n+=255,e++;if(n+=t[e++],!a.payload&&4===i){a.payloadType=i,a.payloadSize=n,a.payload=t.subarray(e,e+n);break}e+=n,i=0,n=0}return a},r=function(t){return 181!==t.payload[0]?null:49!=(t.payload[1]<<8|t.payload[2])?null:"GA94"!==String.fromCharCode(t.payload[3],t.payload[4],t.payload[5],t.payload[6])?null:3!==t.payload[7]?null:t.payload.subarray(8,t.payload.length-1)},s=function(t,e){var a,i,n,r,s=[];if(!(64&e[0]))return s;for(i=31&e[0],a=0;a<i;a++)n=3*a,r={type:3&e[n+2],pts:t},4&e[n+2]&&(r.ccData=e[n+3]<<8|e[n+4],s.push(r));return s},o=function(){o.prototype.init.call(this),this.captionPackets_=[],this.field1_=new c,this.field1_.on("data",this.trigger.bind(this,"data")),this.field1_.on("done",this.trigger.bind(this,"done"))};o.prototype=new i,o.prototype.push=function(t){var e,a;"sei_rbsp"===t.nalUnitType&&(e=n(t.escapedRBSP),4===e.payloadType&&(a=r(e))&&(this.captionPackets_=this.captionPackets_.concat(s(t.pts,a))))},o.prototype.flush=function(){if(!this.captionPackets_.length)return void this.field1_.flush();this.captionPackets_.forEach(function(t,e){t.presortIndex=e}),this.captionPackets_.sort(function(t,e){return t.pts===e.pts?t.presortIndex-e.presortIndex:t.pts-e.pts}),this.captionPackets_.forEach(this.field1_.push,this.field1_),this.captionPackets_.length=0,this.field1_.flush()};var d={42:225,92:233,94:237,95:243,96:250,123:231,124:247,125:209,126:241,127:9608},l=function(t){return null===t?"":(t=d[t]||t,String.fromCharCode(t))},h=function(){for(var t=[],e=15;e--;)t.push("");return t},c=function(){c.prototype.init.call(this),this.mode_="popOn",this.topRow_=0,this.startPts_=0,this.displayed_=h(),this.nonDisplayed_=h(),this.lastControlCode_=null,this.push=function(t){if(0===t.type){var e,a,i,n;if((e=32639&t.ccData)===this.lastControlCode_)return void(this.lastControlCode_=null);switch(this.lastControlCode_=4096==(61440&e)?e:null,e){case 0:break;case 5152:this.mode_="popOn";break;case 5167:this.flushDisplayed(t.pts),a=this.displayed_,this.displayed_=this.nonDisplayed_,this.nonDisplayed_=a,this.startPts_=t.pts;break;case 5157:this.topRow_=13,this.mode_="rollUp";break;case 5158:this.topRow_=12,this.mode_="rollUp";break;case 5159:this.topRow_=11,this.mode_="rollUp";break;case 5165:this.flushDisplayed(t.pts),this.shiftRowsUp_(),this.startPts_=t.pts;break;case 5153:"popOn"===this.mode_?this.nonDisplayed_[14]=this.nonDisplayed_[14].slice(0,-1):this.displayed_[14]=this.displayed_[14].slice(0,-1);break;case 5164:this.flushDisplayed(t.pts),this.displayed_=h();break;case 5166:this.nonDisplayed_=h();break;default:if(i=e>>>8,n=255&e,i>=16&&i<=23&&n>=64&&n<=127&&(16!==i||n<96)&&(i=32,n=null),(17===i||25===i)&&n>=48&&n<=63&&(i=9834,n=""),16==(240&i))return;0===i&&(i=null),0===n&&(n=null),this[this.mode_](t.pts,i,n)}}}};c.prototype=new i,c.prototype.flushDisplayed=function(t){var e=this.displayed_.map(function(t){return t.trim()}).filter(function(t){return t.length}).join("\n");e.length&&this.trigger("data",{startPts:this.startPts_,endPts:t,text:e})},c.prototype.popOn=function(t,e,a){var i=this.nonDisplayed_[14];i+=l(e),i+=l(a),this.nonDisplayed_[14]=i},c.prototype.rollUp=function(t,e,a){var i=this.displayed_[14];""===i&&(this.flushDisplayed(t),this.startPts_=t),i+=l(e),i+=l(a),this.displayed_[14]=i},c.prototype.shiftRowsUp_=function(){var t;for(t=0;t<this.topRow_;t++)this.displayed_[t]="";for(t=this.topRow_;t<14;t++)this.displayed_[t]=this.displayed_[t+1];this.displayed_[14]=""},e.exports={CaptionStream:o,Cea608Stream:c}},{}],5:[function(t,e,a){"use strict";var i,n=t(7),r=t(6),s=function(t,e,a){var i,n="";for(i=e;i<a;i++)n+="%"+("00"+t[i].toString(16)).slice(-2);return n},o=function(t,e,a){return decodeURIComponent(s(t,e,a))},d=function(t,e,a){return unescape(s(t,e,a))},l=function(t){return t[0]<<21|t[1]<<14|t[2]<<7|t[3]},h={TXXX:function(t){var e;if(3===t.data[0]){for(e=1;e<t.data.length;e++)if(0===t.data[e]){t.description=o(t.data,1,e),t.value=o(t.data,e+1,t.data.length-1);break}t.data=t.value}},WXXX:function(t){var e;if(3===t.data[0])for(e=1;e<t.data.length;e++)if(0===t.data[e]){t.description=o(t.data,1,e),t.url=o(t.data,e+1,t.data.length);break}},PRIV:function(t){var e;for(e=0;e<t.data.length;e++)if(0===t.data[e]){t.owner=d(t.data,0,e);break}t.privateData=t.data.subarray(e+1),t.data=t.privateData}};i=function(t){var e,a={debug:!(!t||!t.debug),descriptor:t&&t.descriptor},n=0,s=[],o=0;if(i.prototype.init.call(this),this.dispatchType=r.METADATA_STREAM_TYPE.toString(16),a.descriptor)for(e=0;e<a.descriptor.length;e++)this.dispatchType+=("00"+a.descriptor[e].toString(16)).slice(-2);this.push=function(t){var e,i,r,d,c,u;if("timed-metadata"===t.type){if(t.dataAlignmentIndicator&&(o=0,s.length=0),0===s.length&&(t.data.length<10||t.data[0]!=="I".charCodeAt(0)||t.data[1]!=="D".charCodeAt(0)||t.data[2]!=="3".charCodeAt(0)))return void(a.debug&&console.log("Skipping unrecognized metadata packet"));if(s.push(t),o+=t.data.byteLength,1===s.length&&(n=l(t.data.subarray(6,10)),n+=10),!(o<n)){for(e={data:new Uint8Array(n),frames:[],pts:s[0].pts,dts:s[0].dts},c=0;c<n;)e.data.set(s[0].data.subarray(0,n-c),c),c+=s[0].data.byteLength,o-=s[0].data.byteLength,s.shift();i=10,64&e.data[5]&&(i+=4,i+=l(e.data.subarray(10,14)),n-=l(e.data.subarray(16,20)));do{if((r=l(e.data.subarray(i+4,i+8)))<1)return console.log("Malformed ID3 frame encountered. Skipping metadata parsing.");if(u=String.fromCharCode(e.data[i],e.data[i+1],e.data[i+2],e.data[i+3]),d={id:u,data:e.data.subarray(i+10,i+r+10)},d.key=d.id,h[d.id]&&(h[d.id](d),"com.apple.streaming.transportStreamTimestamp"===d.owner)){var p=d.data,f=(1&p[3])<<30|p[4]<<22|p[5]<<14|p[6]<<6|p[7]>>>2;f*=4,f+=3&p[7],d.timeStamp=f,void 0===e.pts&&void 0===e.dts&&(e.pts=d.timeStamp,e.dts=d.timeStamp),this.trigger("timestamp",d)}e.frames.push(d),i+=10,i+=r}while(i<n);this.trigger("data",e)}}}},i.prototype=new n,e.exports=i},{}],6:[function(t,e,a){"use strict";e.exports={H264_STREAM_TYPE:27,ADTS_STREAM_TYPE:15,METADATA_STREAM_TYPE:21}},{}],7:[function(t,e,a){"use strict";var i=function(){this.init=function(){var t={};this.on=function(e,a){t[e]||(t[e]=[]),t[e]=t[e].concat(a)},this.off=function(e,a){var i;return!!t[e]&&(i=t[e].indexOf(a),t[e]=t[e].slice(),t[e].splice(i,1),i>-1)},this.trigger=function(e){var a,i,n,r;if(a=t[e])if(2===arguments.length)for(n=a.length,i=0;i<n;++i)a[i].call(this,arguments[1]);else{for(r=[],i=arguments.length,i=1;i<arguments.length;++i)r.push(arguments[i]);for(n=a.length,i=0;i<n;++i)a[i].apply(this,r)}},this.dispose=function(){t={}}}};i.prototype.pipe=function(t){return this.on("data",function(e){t.push(e)}),this.on("done",function(e){t.flush(e)}),t},i.prototype.push=function(t){this.trigger("data",t)},i.prototype.flush=function(t){this.trigger("done",t)},e.exports=i},{}],8:[function(t,e,a){(function(e){"use strict";function i(t){return t&&t.__esModule?t:{default:t}}function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}a.__esModule=!0,a.FlashlsHandler=void 0;var r="undefined"!=typeof window?window.videojs:void 0!==e?e.videojs:null,s=i(r),o=t(3),d=i(o),l=t(4),h=t(5),c=i(h),u=t(2),p=t(1),f=function(t){Object.defineProperties(t.frame,{id:{get:function(){return s.default.log.warn("cue.frame.id is deprecated. Use cue.value.key instead."),t.value.key}},value:{get:function(){return s.default.log.warn("cue.frame.value is deprecated. Use cue.value.data instead."),t.value.data}},privateData:{get:function(){return s.default.log.warn("cue.frame.privateData is deprecated. Use cue.value.data instead."),t.value.data}}})},_=function(t,e,a){for(var i=t.remoteTextTracks()||[],n=0;n<i.length;n++){var r=i[n];r.kind===e&&r.label===a&&t.removeRemoteTextTrack(r)}},y=function(t){for(var e=new Uint8Array(t.length),a=0;a<t.length;a++)e[a]=t.charCodeAt(a);return e},v=function(t,e){var a=[],i=void 0,n=void 0,r=void 0,s=void 0;if(!(64&e[0]))return a;for(n=31&e[0],i=0;i<n;i++)r=3*i,s={type:3&e[r+2],pts:t},4&e[r+2]&&(s.ccData=e[r+3]<<8|e[r+4],a.push(s));return a},g=function(t,e,a){var i=void 0,n=void 0;if(a&&a.cues)for(i=a.cues.length;i--;)n=a.cues[i],n.startTime<=e&&n.endTime>=t&&a.removeCue(n)},m=function(t,e){t.length&&g(0,t.start(0),e)},T=function(t,e){for(var a=-1,i=0;i<t.length;i++)if(t[i].id===e){a=i;break}t.selectedIndex_=a,t.trigger({selectedIndex:a,type:"change"})},k=a.FlashlsHandler=function(){function t(e,a,i){var r=this;if(n(this,t),a.options_&&a.options_.playerId){var o=(0,s.default)(a.options_.playerId);o.hasOwnProperty("hls")||Object.defineProperty(o,"hls",{get:function(){return s.default.log.warn("player.hls is deprecated. Use player.tech_.hls instead."),a.trigger({type:"usage",name:"flashls-player-access"}),r}})}Object.defineProperties(this,{stats:{get:function(){return this.tech_.el_.vjs_getProperty("stats")}},bandwidth:{get:function(){return this.tech_.el_.vjs_getProperty("stats").bandwidth}}}),this.tech_=a,this.metadataTrack_=null,this.inbandTextTrack_=null,this.metadataStream_=new c.default,this.cea608Stream_=new l.Cea608Stream,this.captionPackets_=[],this.onLoadedmetadata_=this.onLoadedmetadata_.bind(this),this.onSeeked_=this.onSeeked_.bind(this),this.onId3updated_=this.onId3updated_.bind(this),this.onCaptionData_=this.onCaptionData_.bind(this),this.onMetadataStreamData_=this.onMetadataStreamData_.bind(this),this.onCea608StreamData_=this.onCea608StreamData_.bind(this),this.onLevelSwitch_=this.onLevelSwitch_.bind(this),this.onAudioTrackChanged=this.onAudioTrackChanged.bind(this),this.tech_.on("loadedmetadata",this.onLoadedmetadata_),this.tech_.on("seeked",this.onSeeked_),this.tech_.on("id3updated",this.onId3updated_),this.tech_.on("captiondata",this.onCaptionData_),this.tech_.on("levelswitch",this.onLevelSwitch_),this.metadataStream_.on("data",this.onMetadataStreamData_),this.cea608Stream_.on("data",this.onCea608StreamData_),this.playlists={media:function(){return r.media_()}}}return t.prototype.src=function(t){t&&this.tech_.setSrc(t.src)},t.prototype.seekable=function(){var t=this.tech_.el_.vjs_getProperty("seekableStart"),e=this.tech_.el_.vjs_getProperty("seekableEnd");return 0===e?s.default.createTimeRange():s.default.createTimeRange(t,e)},t.prototype.media_=function(){var t=this.tech_.el_.vjs_getProperty("levels"),e=this.tech_.el_.vjs_getProperty("level"),a=void 0;return t.length&&(a={resolvedUri:t[e].url,attributes:{BANDWIDTH:t[e].bitrate,RESOLUTION:{width:t[e].width,height:t[e].height}}}),a},t.prototype.onLoadedmetadata_=function(){var t=this;this.representations=(0,u.createRepresentations)(this.tech_);var e=s.default.players[this.tech_.options_.playerId];e&&e.qualityLevels&&(this.qualityLevels_=e.qualityLevels(),this.representations().forEach(function(e){t.qualityLevels_.addQualityLevel(e)}),T(this.qualityLevels_,this.tech_.el_.vjs_getProperty("level")+"")),(0,p.setupAudioTracks)(this.tech_),this.tech_.audioTracks().on("change",this.onAudioTrackChanged)},t.prototype.onAudioTrackChanged=function(){(0,p.updateAudioTrack)(this.tech_)},t.prototype.onLevelSwitch_=function(t,e){this.qualityLevels_&&T(this.qualityLevels_,e[0].levelIndex+""),this.tech_.trigger({type:"mediachange",bubbles:!0})},t.prototype.onSeeked_=function(){g(0,1/0,this.metadataTrack_);var t=this.tech_.buffered();1===t.length?(g(0,t.start(0),this.inbandTextTrack_),g(t.end(0),1/0,this.inbandTextTrack_)):g(0,1/0,this.inbandTextTrack_)},t.prototype.onId3updated_=function(t,e){var a=d.default.atob(e[0]),i=y(a),n={type:"timed-metadata",dataAlignmentIndicator:!0,data:i};this.metadataStream_.push(n)},t.prototype.onMetadataStreamData_=function(t){var e=this;this.metadataTrack_||(this.metadataTrack_=this.tech_.addRemoteTextTrack({kind:"metadata",label:"Timed Metadata"},!1).track,this.metadataTrack_.inBandMetadataTrackDispatchType=""),m(this.tech_.buffered(),this.metadataTrack_);var a=this.tech_.currentTime();if(t.frames.forEach(function(t){var i=new d.default.VTTCue(a,a+.1,t.value||t.url||t.data||"");i.frame=t,i.value=t,f(i),e.metadataTrack_.addCue(i)}),this.metadataTrack_.cues&&this.metadataTrack_.cues.length){var i=this.metadataTrack_.cues,n=[],r=this.tech_.duration();(isNaN(r)||Math.abs(r)===1/0)&&(r=Number.MAX_VALUE);for(var s=0;s<i.length;s++)n.push(i[s]);n.sort(function(t,e){return t.startTime-e.startTime});for(var o=0;o<n.length-1;o++)n[o].endTime!==n[o+1].startTime&&(n[o].endTime=n[o+1].startTime);n[n.length-1].endTime=r}},t.prototype.onCaptionData_=function(t,e){var a=this;e[0].map(function(t){return{pts:9e4*t.pos,bytes:y(d.default.atob(t.data))}}).forEach(function(t){a.captionPackets_=a.captionPackets_.concat(v(t.pts,t.bytes))}),this.captionPackets_.length&&(this.captionPackets_.forEach(function(t,e){t.presortIndex=e}),this.captionPackets_.sort(function(t,e){return t.pts===e.pts?t.presortIndex-e.presortIndex:t.pts-e.pts}),this.captionPackets_.forEach(this.cea608Stream_.push,this.cea608Stream_),this.captionPackets_.length=0,this.cea608Stream_.flush())},t.prototype.onCea608StreamData_=function(t){t&&(this.inbandTextTrack_||(_(this.tech_,"captions","cc1"),this.inbandTextTrack_=this.tech_.addRemoteTextTrack({kind:"captions",label:"cc1"},!1).track),m(this.tech_.buffered(),this.inbandTextTrack_),this.inbandTextTrack_.addCue(new d.default.VTTCue(t.startPts/9e4,t.endPts/9e4,t.text)))},t.prototype.dispose=function(){this.tech_.off("loadedmetadata",this.onLoadedmetadata_),this.tech_.off("seeked",this.onSeeked_),this.tech_.off("id3updated",this.onId3updated_),this.tech_.off("captiondata",this.onCaptionData_),this.tech_.audioTracks().off("change",this.onAudioTrackChanged),this.tech_.off("levelswitch",this.onLevelSwitch_),this.qualityLevels_&&this.qualityLevels_.dispose()},t}(),b={},w=/^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i;b.canPlayType=function(t){return w.test(t)?"maybe":""},b.canHandleSource=function(t,e){return"maybe"===b.canPlayType(t.type)},b.handleSource=function(t,e,a){return e.hls=new k(t,e,a),e.hls.src(t),e.hls},s.default.getTech("Flash").registerSourceHandler(b,0),b.VERSION="1.3.1",a.default=b}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[8]); | ||
!function t(e,i,a){function n(o,r){if(!i[o]){if(!e[o]){var d="function"==typeof require&&require;if(!r&&d)return d(o,!0);if(s)return s(o,!0);var h=new Error("Cannot find module '"+o+"'");throw h.code="MODULE_NOT_FOUND",h}var l=i[o]={exports:{}};e[o][0].call(l.exports,function(t){var i=e[o][1][t];return n(i||t)},l,l.exports,t,e,i,a)}return i[o].exports}for(var s="function"==typeof require&&require,o=0;o<a.length;o++)n(a[o]);return n}({1:[function(t,e,i){(function(t){"use strict";i.__esModule=!0,i.setupAudioTracks=i.updateAudioTrack=void 0;var e="undefined"!=typeof window?window.videojs:void 0!==t?t.videojs:null,a=function(t){return t&&t.__esModule?t:{default:t}}(e);i.updateAudioTrack=function(t){for(var e=t.el_.vjs_getProperty("audioTracks"),i=t.audioTracks(),a=null,n=0;n<i.length;n++)if(i[n].enabled){a=i[n].id;break}if(null!==a)for(var s=0;s<e.length;s++)if(a===e[s].title)return void t.el_.vjs_setProperty("audioTrack",s)},i.setupAudioTracks=function(t){var e=t.el_.vjs_getProperty("altAudioTracks"),i=t.el_.vjs_getProperty("audioTracks"),n=t.el_.vjs_getProperty("audioTrack");i.forEach(function(i,s){var o=e[i.id];t.audioTracks().addTrack(new a.default.AudioTrack({id:o.name,enabled:n===s,language:o.lang,default:o.default_track,label:o.name}))})}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(t,e,i){"use strict";i.__esModule=!0;var a=i.createRepresentation=function(t,e){var i={id:e.index+"",width:e.width,height:e.height,bandwidth:e.bitrate,isEnabled_:!0};return i.enabled=function(e){if(void 0===e)return i.isEnabled_;e!==i.isEnabled_&&(!0!==e&&!1!==e||(i.isEnabled_=e,t()))},i};i.createRepresentations=function(t){var e=null,i=function(){var i=e.filter(function(t){return t.enabled()});if(i.length===e.length||0===i.length)return t.el_.vjs_setProperty("autoLevelCapping",-1),void t.el_.vjs_setProperty("level",-1);if(1===i.length)return t.el_.vjs_setProperty("level",parseInt(i[0].id,10)),void t.el_.vjs_setProperty("autoLevelCapping",-1);var a=i[i.length-1].id;t.el_.vjs_setProperty("autoLevelCapping",parseInt(a,10)),t.el_.vjs_setProperty("level",-1)};return function(){if(!e){var n=t.el_.vjs_getProperty("levels");e=n.filter(function(t){return!t.audio}).map(a.bind(null,i))}return e}}},{}],3:[function(t,e,i){(function(t){var i;i="undefined"!=typeof window?window:void 0!==t?t:"undefined"!=typeof self?self:{},e.exports=i}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],4:[function(t,e,i){"use strict";var a=t(7),n=function(t){for(var e=0,i={payloadType:-1,payloadSize:0},a=0,n=0;e<t.byteLength&&128!==t[e];){for(;255===t[e];)a+=255,e++;for(a+=t[e++];255===t[e];)n+=255,e++;if(n+=t[e++],!i.payload&&4===a){i.payloadType=a,i.payloadSize=n,i.payload=t.subarray(e,e+n);break}e+=n,a=0,n=0}return i},s=function(t){return 181!==t.payload[0]?null:49!=(t.payload[1]<<8|t.payload[2])?null:"GA94"!==String.fromCharCode(t.payload[3],t.payload[4],t.payload[5],t.payload[6])?null:3!==t.payload[7]?null:t.payload.subarray(8,t.payload.length-1)},o=function(t,e){var i,a,n,s,o=[];if(!(64&e[0]))return o;for(a=31&e[0],i=0;i<a;i++)n=3*i,s={type:3&e[n+2],pts:t},4&e[n+2]&&(s.ccData=e[n+3]<<8|e[n+4],o.push(s));return o},r=function(){r.prototype.init.call(this),this.captionPackets_=[],this.ccStreams_=[new u(0,0),new u(0,1),new u(1,0),new u(1,1)],this.reset(),this.ccStreams_.forEach(function(t){t.on("data",this.trigger.bind(this,"data")),t.on("done",this.trigger.bind(this,"done"))},this)};r.prototype=new a,r.prototype.push=function(t){var e,i;if("sei_rbsp"===t.nalUnitType&&(e=n(t.escapedRBSP),4===e.payloadType&&(i=s(e)))){if(t.dts<this.latestDts_)return void(this.ignoreNextEqualDts_=!0);if(t.dts===this.latestDts_&&this.ignoreNextEqualDts_)return void(this.ignoreNextEqualDts_=!1);this.captionPackets_=this.captionPackets_.concat(o(t.pts,i)),this.latestDts_=t.dts}},r.prototype.flush=function(){if(!this.captionPackets_.length)return void this.ccStreams_.forEach(function(t){t.flush()},this);this.captionPackets_.forEach(function(t,e){t.presortIndex=e}),this.captionPackets_.sort(function(t,e){return t.pts===e.pts?t.presortIndex-e.presortIndex:t.pts-e.pts}),this.captionPackets_.forEach(function(t){t.type<2&&this.dispatchCea608Packet(t)},this),this.captionPackets_.length=0,this.ccStreams_.forEach(function(t){t.flush()},this)},r.prototype.reset=function(){this.latestDts_=null,this.ignoreNextEqualDts_=!1,this.activeCea608Channel_=[null,null],this.ccStreams_.forEach(function(t){t.reset()})},r.prototype.dispatchCea608Packet=function(t){this.setsChannel1Active(t)?this.activeCea608Channel_[t.type]=0:this.setsChannel2Active(t)&&(this.activeCea608Channel_[t.type]=1),null!==this.activeCea608Channel_[t.type]&&this.ccStreams_[(t.type<<1)+this.activeCea608Channel_[t.type]].push(t)},r.prototype.setsChannel1Active=function(t){return 4096==(30720&t.ccData)},r.prototype.setsChannel2Active=function(t){return 6144==(30720&t.ccData)};var d={42:225,92:233,94:237,95:243,96:250,123:231,124:247,125:209,126:241,127:9608,304:174,305:176,306:189,307:191,308:8482,309:162,310:163,311:9834,312:224,313:160,314:232,315:226,316:234,317:238,318:244,319:251,544:193,545:201,546:211,547:218,548:220,549:252,550:8216,551:161,552:42,553:39,554:8212,555:169,556:8480,557:8226,558:8220,559:8221,560:192,561:194,562:199,563:200,564:202,565:203,566:235,567:206,568:207,569:239,570:212,571:217,572:249,573:219,574:171,575:187,800:195,801:227,802:205,803:204,804:236,805:210,806:242,807:213,808:245,809:123,810:125,811:92,812:94,813:95,814:124,815:126,816:196,817:228,818:214,819:246,820:223,821:165,822:164,823:9474,824:197,825:229,826:216,827:248,828:9484,829:9488,830:9492,831:9496},h=function(t){return null===t?"":(t=d[t]||t,String.fromCharCode(t))},l=[4352,4384,4608,4640,5376,5408,5632,5664,5888,5920,4096,4864,4896,5120,5152],c=function(){for(var t=[],e=15;e--;)t.push("");return t},u=function(t,e){u.prototype.init.call(this),this.field_=t||0,this.dataChannel_=e||0,this.name_="CC"+(1+(this.field_<<1|this.dataChannel_)),this.setConstants(),this.reset(),this.push=function(t){var e,i,a,n,s;if((e=32639&t.ccData)===this.lastControlCode_)return void(this.lastControlCode_=null);if(4096==(61440&e)?this.lastControlCode_=e:e!==this.PADDING_&&(this.lastControlCode_=null),a=e>>>8,n=255&e,e!==this.PADDING_)if(e===this.RESUME_CAPTION_LOADING_)this.mode_="popOn";else if(e===this.END_OF_CAPTION_)this.clearFormatting(t.pts),this.flushDisplayed(t.pts),i=this.displayed_,this.displayed_=this.nonDisplayed_,this.nonDisplayed_=i,this.startPts_=t.pts;else if(e===this.ROLL_UP_2_ROWS_)this.topRow_=13,this.mode_="rollUp";else if(e===this.ROLL_UP_3_ROWS_)this.topRow_=12,this.mode_="rollUp";else if(e===this.ROLL_UP_4_ROWS_)this.topRow_=11,this.mode_="rollUp";else if(e===this.CARRIAGE_RETURN_)this.clearFormatting(t.pts),this.flushDisplayed(t.pts),this.shiftRowsUp_(),this.startPts_=t.pts;else if(e===this.BACKSPACE_)"popOn"===this.mode_?this.nonDisplayed_[14]=this.nonDisplayed_[14].slice(0,-1):this.displayed_[14]=this.displayed_[14].slice(0,-1);else if(e===this.ERASE_DISPLAYED_MEMORY_)this.flushDisplayed(t.pts),this.displayed_=c();else if(e===this.ERASE_NON_DISPLAYED_MEMORY_)this.nonDisplayed_=c();else if(e===this.RESUME_DIRECT_CAPTIONING_)this.mode_="paintOn";else if(this.isSpecialCharacter(a,n))a=(3&a)<<8,s=h(a|n),this[this.mode_](t.pts,s),this.column_++;else if(this.isExtCharacter(a,n))"popOn"===this.mode_?this.nonDisplayed_[this.row_]=this.nonDisplayed_[this.row_].slice(0,-1):this.displayed_[14]=this.displayed_[14].slice(0,-1),a=(3&a)<<8,s=h(a|n),this[this.mode_](t.pts,s),this.column_++;else if(this.isMidRowCode(a,n))this.clearFormatting(t.pts),this[this.mode_](t.pts," "),this.column_++,14==(14&n)&&this.addFormatting(t.pts,["i"]),1==(1&n)&&this.addFormatting(t.pts,["u"]);else if(this.isOffsetControlCode(a,n))this.column_+=3&n;else if(this.isPAC(a,n)){var o=l.indexOf(7968&e);o!==this.row_&&(this.clearFormatting(t.pts),this.row_=o),1&n&&-1===this.formatting_.indexOf("u")&&this.addFormatting(t.pts,["u"]),16==(16&e)&&(this.column_=4*((14&e)>>1)),this.isColorPAC(n)&&14==(14&n)&&this.addFormatting(t.pts,["i"])}else this.isNormalChar(a)&&(0===n&&(n=null),s=h(a),s+=h(n),this[this.mode_](t.pts,s),this.column_+=s.length)}};u.prototype=new a,u.prototype.flushDisplayed=function(t){var e=this.displayed_.map(function(t){return t.trim()}).join("\n").replace(/^\n+|\n+$/g,"");e.length&&this.trigger("data",{startPts:this.startPts_,endPts:t,text:e,stream:this.name_})},u.prototype.reset=function(){this.mode_="popOn",this.topRow_=0,this.startPts_=0,this.displayed_=c(),this.nonDisplayed_=c(),this.lastControlCode_=null,this.column_=0,this.row_=14,this.formatting_=[]},u.prototype.setConstants=function(){0===this.dataChannel_?(this.BASE_=16,this.EXT_=17,this.CONTROL_=(20|this.field_)<<8,this.OFFSET_=23):1===this.dataChannel_&&(this.BASE_=24,this.EXT_=25,this.CONTROL_=(28|this.field_)<<8,this.OFFSET_=31),this.PADDING_=0,this.RESUME_CAPTION_LOADING_=32|this.CONTROL_,this.END_OF_CAPTION_=47|this.CONTROL_,this.ROLL_UP_2_ROWS_=37|this.CONTROL_,this.ROLL_UP_3_ROWS_=38|this.CONTROL_,this.ROLL_UP_4_ROWS_=39|this.CONTROL_,this.CARRIAGE_RETURN_=45|this.CONTROL_,this.RESUME_DIRECT_CAPTIONING_=41|this.CONTROL_,this.BACKSPACE_=33|this.CONTROL_,this.ERASE_DISPLAYED_MEMORY_=44|this.CONTROL_,this.ERASE_NON_DISPLAYED_MEMORY_=46|this.CONTROL_},u.prototype.isSpecialCharacter=function(t,e){return t===this.EXT_&&e>=48&&e<=63},u.prototype.isExtCharacter=function(t,e){return(t===this.EXT_+1||t===this.EXT_+2)&&e>=32&&e<=63},u.prototype.isMidRowCode=function(t,e){return t===this.EXT_&&e>=32&&e<=47},u.prototype.isOffsetControlCode=function(t,e){return t===this.OFFSET_&&e>=33&&e<=35},u.prototype.isPAC=function(t,e){return t>=this.BASE_&&t<this.BASE_+8&&e>=64&&e<=127},u.prototype.isColorPAC=function(t){return t>=64&&t<=79||t>=96&&t<=127},u.prototype.isNormalChar=function(t){return t>=32&&t<=127},u.prototype.addFormatting=function(t,e){this.formatting_=this.formatting_.concat(e);var i=e.reduce(function(t,e){return t+"<"+e+">"},"");this[this.mode_](t,i)},u.prototype.clearFormatting=function(t){if(this.formatting_.length){var e=this.formatting_.reverse().reduce(function(t,e){return t+"</"+e+">"},"");this.formatting_=[],this[this.mode_](t,e)}},u.prototype.popOn=function(t,e){var i=this.nonDisplayed_[this.row_];i+=e,this.nonDisplayed_[this.row_]=i},u.prototype.rollUp=function(t,e){var i=this.displayed_[14];i+=e,this.displayed_[14]=i},u.prototype.shiftRowsUp_=function(){var t;for(t=0;t<this.topRow_;t++)this.displayed_[t]="";for(t=this.topRow_;t<14;t++)this.displayed_[t]=this.displayed_[t+1];this.displayed_[14]=""},u.prototype.paintOn=function(){},e.exports={CaptionStream:r,Cea608Stream:u}},{}],5:[function(t,e,i){"use strict";var a,n=t(7),s=t(6),o=function(t,e,i){var a,n="";for(a=e;a<i;a++)n+="%"+("00"+t[a].toString(16)).slice(-2);return n},r=function(t,e,i){return decodeURIComponent(o(t,e,i))},d=function(t,e,i){return unescape(o(t,e,i))},h=function(t){return t[0]<<21|t[1]<<14|t[2]<<7|t[3]},l={TXXX:function(t){var e;if(3===t.data[0]){for(e=1;e<t.data.length;e++)if(0===t.data[e]){t.description=r(t.data,1,e),t.value=r(t.data,e+1,t.data.length).replace(/\0*$/,"");break}t.data=t.value}},WXXX:function(t){var e;if(3===t.data[0])for(e=1;e<t.data.length;e++)if(0===t.data[e]){t.description=r(t.data,1,e),t.url=r(t.data,e+1,t.data.length);break}},PRIV:function(t){var e;for(e=0;e<t.data.length;e++)if(0===t.data[e]){t.owner=d(t.data,0,e);break}t.privateData=t.data.subarray(e+1),t.data=t.privateData}};a=function(t){var e,i={debug:!(!t||!t.debug),descriptor:t&&t.descriptor},n=0,o=[],r=0;if(a.prototype.init.call(this),this.dispatchType=s.METADATA_STREAM_TYPE.toString(16),i.descriptor)for(e=0;e<i.descriptor.length;e++)this.dispatchType+=("00"+i.descriptor[e].toString(16)).slice(-2);this.push=function(t){var e,a,s,d,c,u;if("timed-metadata"===t.type){if(t.dataAlignmentIndicator&&(r=0,o.length=0),0===o.length&&(t.data.length<10||t.data[0]!=="I".charCodeAt(0)||t.data[1]!=="D".charCodeAt(0)||t.data[2]!=="3".charCodeAt(0)))return void(i.debug&&console.log("Skipping unrecognized metadata packet"));if(o.push(t),r+=t.data.byteLength,1===o.length&&(n=h(t.data.subarray(6,10)),n+=10),!(r<n)){for(e={data:new Uint8Array(n),frames:[],pts:o[0].pts,dts:o[0].dts},c=0;c<n;)e.data.set(o[0].data.subarray(0,n-c),c),c+=o[0].data.byteLength,r-=o[0].data.byteLength,o.shift();a=10,64&e.data[5]&&(a+=4,a+=h(e.data.subarray(10,14)),n-=h(e.data.subarray(16,20)));do{if((s=h(e.data.subarray(a+4,a+8)))<1)return console.log("Malformed ID3 frame encountered. Skipping metadata parsing.");if(u=String.fromCharCode(e.data[a],e.data[a+1],e.data[a+2],e.data[a+3]),d={id:u,data:e.data.subarray(a+10,a+s+10)},d.key=d.id,l[d.id]&&(l[d.id](d),"com.apple.streaming.transportStreamTimestamp"===d.owner)){var p=d.data,_=(1&p[3])<<30|p[4]<<22|p[5]<<14|p[6]<<6|p[7]>>>2;_*=4,_+=3&p[7],d.timeStamp=_,void 0===e.pts&&void 0===e.dts&&(e.pts=d.timeStamp,e.dts=d.timeStamp),this.trigger("timestamp",d)}e.frames.push(d),a+=10,a+=s}while(a<n);this.trigger("data",e)}}}},a.prototype=new n,e.exports=a},{}],6:[function(t,e,i){"use strict";e.exports={H264_STREAM_TYPE:27,ADTS_STREAM_TYPE:15,METADATA_STREAM_TYPE:21}},{}],7:[function(t,e,i){"use strict";var a=function(){this.init=function(){var t={};this.on=function(e,i){t[e]||(t[e]=[]),t[e]=t[e].concat(i)},this.off=function(e,i){var a;return!!t[e]&&(a=t[e].indexOf(i),t[e]=t[e].slice(),t[e].splice(a,1),a>-1)},this.trigger=function(e){var i,a,n,s;if(i=t[e])if(2===arguments.length)for(n=i.length,a=0;a<n;++a)i[a].call(this,arguments[1]);else{for(s=[],a=arguments.length,a=1;a<arguments.length;++a)s.push(arguments[a]);for(n=i.length,a=0;a<n;++a)i[a].apply(this,s)}},this.dispose=function(){t={}}}};a.prototype.pipe=function(t){return this.on("data",function(e){t.push(e)}),this.on("done",function(e){t.flush(e)}),t},a.prototype.push=function(t){this.trigger("data",t)},a.prototype.flush=function(t){this.trigger("done",t)},e.exports=a},{}],8:[function(t,e,i){(function(e){"use strict";function a(t){return t&&t.__esModule?t:{default:t}}function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}i.__esModule=!0,i.FlashlsHandler=void 0;var s="undefined"!=typeof window?window.videojs:void 0!==e?e.videojs:null,o=a(s),r=t(3),d=a(r),h=t(4),l=t(5),c=a(l),u=t(2),p=t(1),_=function(t){Object.defineProperties(t.frame,{id:{get:function(){return o.default.log.warn("cue.frame.id is deprecated. Use cue.value.key instead."),t.value.key}},value:{get:function(){return o.default.log.warn("cue.frame.value is deprecated. Use cue.value.data instead."),t.value.data}},privateData:{get:function(){return o.default.log.warn("cue.frame.privateData is deprecated. Use cue.value.data instead."),t.value.data}}})},f=function(t,e,i){for(var a=t.remoteTextTracks()||[],n=0;n<a.length;n++){var s=a[n];s.kind===e&&s.label===i&&t.removeRemoteTextTrack(s)}},y=function(t){for(var e=new Uint8Array(t.length),i=0;i<t.length;i++)e[i]=t.charCodeAt(i);return e},g=function(t,e,i){var a=void 0,n=void 0;if(i&&i.cues)for(a=i.cues.length;a--;)n=i.cues[a],n.startTime<=e&&n.endTime>=t&&i.removeCue(n)},m=function(t,e){t.length&&g(0,t.start(0),e)},v=function(t,e){for(var i=-1,a=0;a<t.length;a++)if(t[a].id===e){i=a;break}t.selectedIndex_=i,t.trigger({selectedIndex:i,type:"change"})},T=function(t,e){var i=[];if(t&&t.length)for(var a=0;a<t.length;a++)e(t.start(a),t.end(a))&&i.push([t.start(a),t.end(a)]);return o.default.createTimeRanges(i)},C=function(t,e){return T(t,function(t,i){return t-1/30<=e&&i+1/30>=e})},S=i.FlashlsHandler=function(){function t(e,i,a){var s=this;if(n(this,t),i.options_&&i.options_.playerId){var r=(0,o.default)(i.options_.playerId);r.hasOwnProperty("hls")||Object.defineProperty(r,"hls",{get:function(){return o.default.log.warn("player.hls is deprecated. Use player.tech_.hls instead."),i.trigger({type:"usage",name:"flashls-player-access"}),s}})}Object.defineProperties(this,{stats:{get:function(){return this.tech_.el_.vjs_getProperty("stats")}},bandwidth:{get:function(){return this.tech_.el_.vjs_getProperty("stats").bandwidth}}}),this.tech_=i,this.metadataTrack_=null,this.inbandTextTracks_={},this.metadataStream_=new c.default,this.captionStream_=new h.CaptionStream,this.onLoadedmetadata_=this.onLoadedmetadata_.bind(this),this.onSeeking_=this.onSeeking_.bind(this),this.onId3updated_=this.onId3updated_.bind(this),this.onCaptionData_=this.onCaptionData_.bind(this),this.onMetadataStreamData_=this.onMetadataStreamData_.bind(this),this.onCaptionStreamData_=this.onCaptionStreamData_.bind(this),this.onLevelSwitch_=this.onLevelSwitch_.bind(this),this.onLevelLoaded_=this.onLevelLoaded_.bind(this),this.onFragmentLoaded_=this.onFragmentLoaded_.bind(this),this.onAudioTrackChanged=this.onAudioTrackChanged.bind(this),this.tech_.on("loadedmetadata",this.onLoadedmetadata_),this.tech_.on("seeking",this.onSeeking_),this.tech_.on("id3updated",this.onId3updated_),this.tech_.on("captiondata",this.onCaptionData_),this.tech_.on("levelswitch",this.onLevelSwitch_),this.tech_.on("levelloaded",this.onLevelLoaded_),this.tech_.on("fragmentloaded",this.onFragmentLoaded_),this.metadataStream_.on("data",this.onMetadataStreamData_),this.captionStream_.on("data",this.onCaptionStreamData_),this.playlists=new o.default.EventTarget,this.playlists.media=function(){return s.media_()}}return t.prototype.src=function(t){t&&this.tech_.setSrc(t.src)},t.prototype.seekable=function(){var t=this.tech_.el_.vjs_getProperty("seekableStart"),e=this.tech_.el_.vjs_getProperty("seekableEnd");return 0===e?o.default.createTimeRange():o.default.createTimeRange(t,e)},t.prototype.media_=function(){var t=this.tech_.el_.vjs_getProperty("levels"),e=this.tech_.el_.vjs_getProperty("level"),i=void 0;return t.length&&(i={resolvedUri:t[e].url,attributes:{BANDWIDTH:t[e].bitrate,RESOLUTION:{width:t[e].width,height:t[e].height}}}),i},t.prototype.onLoadedmetadata_=function(){var t=this;this.representations=(0,u.createRepresentations)(this.tech_);var e=o.default.players[this.tech_.options_.playerId];e&&e.qualityLevels&&(this.qualityLevels_=e.qualityLevels(),this.representations().forEach(function(e){t.qualityLevels_.addQualityLevel(e)}),v(this.qualityLevels_,this.tech_.el_.vjs_getProperty("level")+"")),(0,p.setupAudioTracks)(this.tech_),this.tech_.audioTracks().on("change",this.onAudioTrackChanged)},t.prototype.onAudioTrackChanged=function(){(0,p.updateAudioTrack)(this.tech_)},t.prototype.onLevelSwitch_=function(t,e){this.qualityLevels_&&v(this.qualityLevels_,e[0].levelIndex+""),this.playlists.trigger("mediachange"),this.tech_.trigger({type:"mediachange",bubbles:!0})},t.prototype.onLevelLoaded_=function(){this.playlists.trigger("loadedplaylist")},t.prototype.onFragmentLoaded_=function(){this.tech_.trigger("bandwidthupdate"),this.captionStream_.flush()},t.prototype.onSeeking_=function(){var t=this;g(0,1/0,this.metadataTrack_),C(this.tech_.buffered(),this.tech_.currentTime()).length||(Object.keys(this.inbandTextTracks_).forEach(function(e){g(0,1/0,t.inbandTextTracks_[e])}),this.captionStream_.reset())},t.prototype.onId3updated_=function(t,e){var i=d.default.atob(e[0]),a=y(i),n={type:"timed-metadata",dataAlignmentIndicator:!0,data:a};this.metadataStream_.push(n)},t.prototype.onMetadataStreamData_=function(t){var e=this;this.metadataTrack_||(this.metadataTrack_=this.tech_.addRemoteTextTrack({kind:"metadata",label:"Timed Metadata"},!1).track,this.metadataTrack_.inBandMetadataTrackDispatchType=""),m(this.tech_.buffered(),this.metadataTrack_);var i=this.tech_.currentTime();if(t.frames.forEach(function(t){var a=new d.default.VTTCue(i,i+.1,t.value||t.url||t.data||"");a.frame=t,a.value=t,_(a),e.metadataTrack_.addCue(a)}),this.metadataTrack_.cues&&this.metadataTrack_.cues.length){var a=this.metadataTrack_.cues,n=[],s=this.tech_.duration();(isNaN(s)||Math.abs(s)===1/0)&&(s=Number.MAX_VALUE);for(var o=0;o<a.length;o++)n.push(a[o]);n.sort(function(t,e){return t.startTime-e.startTime});for(var r=0;r<n.length-1;r++)n[r].endTime!==n[r+1].startTime&&(n[r].endTime=n[r+1].startTime);n[n.length-1].endTime=s}},t.prototype.onCaptionData_=function(t,e){var i=this;e[0].forEach(function(t){i.captionStream_.push({pts:9e4*t.pos,dts:9e4*t.dts,escapedRBSP:y(d.default.atob(t.data)),nalUnitType:"sei_rbsp"})})},t.prototype.onCaptionStreamData_=function(t){t&&(this.inbandTextTracks_[t.stream]||(f(this.tech_,"captions",t.stream),this.inbandTextTracks_[t.stream]=this.tech_.addRemoteTextTrack({kind:"captions",label:t.stream,id:t.stream},!1).track),m(this.tech_.buffered(),this.inbandTextTracks_[t.stream]),this.inbandTextTracks_[t.stream].addCue(new d.default.VTTCue(t.startPts/9e4,t.endPts/9e4,t.text)))},t.prototype.dispose=function(){this.tech_.off("loadedmetadata",this.onLoadedmetadata_),this.tech_.off("seeked",this.onSeeking_),this.tech_.off("id3updated",this.onId3updated_),this.tech_.off("captiondata",this.onCaptionData_),this.tech_.audioTracks().off("change",this.onAudioTrackChanged),this.tech_.off("levelswitch",this.onLevelSwitch_),this.tech_.off("levelloaded",this.onLevelLoaded_),this.tech_.off("fragmentloaded",this.onFragmentLoaded_),this.qualityLevels_&&this.qualityLevels_.dispose()},t}(),b={},E=/^(audio|video|application)\/(x-|vnd\.apple\.)?mpegurl/i;b.canPlayType=function(t){return E.test(t)?"maybe":""},b.canHandleSource=function(t,e){return"maybe"===b.canPlayType(t.type)},b.handleSource=function(t,e,i){return e.hls=new S(t,e,i),e.hls.src(t),e.hls},o.default.getTech("Flash").registerSourceHandler(b,0),b.VERSION="1.4.0",i.default=b}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[8]); |
186
es5/index.js
@@ -87,33 +87,2 @@ 'use strict'; | ||
// see CEA-708-D, section 4.4 | ||
var parseCaptionPackets = function parseCaptionPackets(pts, userData) { | ||
var results = []; | ||
var i = void 0; | ||
var count = void 0; | ||
var offset = void 0; | ||
var data = void 0; | ||
// if this is just filler, return immediately | ||
if (!(userData[0] & 0x40)) { | ||
return results; | ||
} | ||
// parse out the cc_data_1 and cc_data_2 fields | ||
count = userData[0] & 0x1f; | ||
for (i = 0; i < count; i++) { | ||
offset = i * 3; | ||
data = { | ||
type: userData[offset + 2] & 0x03, | ||
pts: pts | ||
}; | ||
// capture cc data when cc_valid is 1 | ||
if (userData[offset + 2] & 0x04) { | ||
data.ccData = userData[offset + 3] << 8 | userData[offset + 4]; | ||
results.push(data); | ||
} | ||
} | ||
return results; | ||
}; | ||
/** | ||
@@ -191,2 +160,33 @@ * Remove cues from a track on video.js. | ||
// Fudge factor to account for TimeRanges rounding | ||
var TIME_FUDGE_FACTOR = 1 / 30; | ||
var filterRanges = function filterRanges(timeRanges, predicate) { | ||
var results = []; | ||
if (timeRanges && timeRanges.length) { | ||
// Search for ranges that match the predicate | ||
for (var i = 0; i < timeRanges.length; i++) { | ||
if (predicate(timeRanges.start(i), timeRanges.end(i))) { | ||
results.push([timeRanges.start(i), timeRanges.end(i)]); | ||
} | ||
} | ||
} | ||
return _video2['default'].createTimeRanges(results); | ||
}; | ||
/** | ||
* Attempts to find the buffered TimeRange that contains the specified | ||
* time. | ||
* @param {TimeRanges} buffered - the TimeRanges object to query | ||
* @param {number} time - the time to filter on. | ||
* @returns {TimeRanges} a new TimeRanges object | ||
*/ | ||
var findRange = function findRange(buffered, time) { | ||
return filterRanges(buffered, function (start, end) { | ||
return start - TIME_FUDGE_FACTOR <= time && end + TIME_FUDGE_FACTOR >= time; | ||
}); | ||
}; | ||
var FlashlsHandler = exports.FlashlsHandler = function () { | ||
@@ -229,30 +229,32 @@ function FlashlsHandler(source, tech, options) { | ||
this.metadataTrack_ = null; | ||
this.inbandTextTrack_ = null; | ||
this.inbandTextTracks_ = {}; | ||
this.metadataStream_ = new _metadataStream2['default'](); | ||
this.cea608Stream_ = new _captionStream.Cea608Stream(); | ||
this.captionPackets_ = []; | ||
this.captionStream_ = new _captionStream.CaptionStream(); | ||
// bind event listeners to this context | ||
this.onLoadedmetadata_ = this.onLoadedmetadata_.bind(this); | ||
this.onSeeked_ = this.onSeeked_.bind(this); | ||
this.onSeeking_ = this.onSeeking_.bind(this); | ||
this.onId3updated_ = this.onId3updated_.bind(this); | ||
this.onCaptionData_ = this.onCaptionData_.bind(this); | ||
this.onMetadataStreamData_ = this.onMetadataStreamData_.bind(this); | ||
this.onCea608StreamData_ = this.onCea608StreamData_.bind(this); | ||
this.onCaptionStreamData_ = this.onCaptionStreamData_.bind(this); | ||
this.onLevelSwitch_ = this.onLevelSwitch_.bind(this); | ||
this.onLevelLoaded_ = this.onLevelLoaded_.bind(this); | ||
this.onFragmentLoaded_ = this.onFragmentLoaded_.bind(this); | ||
this.onAudioTrackChanged = this.onAudioTrackChanged.bind(this); | ||
this.tech_.on('loadedmetadata', this.onLoadedmetadata_); | ||
this.tech_.on('seeked', this.onSeeked_); | ||
this.tech_.on('seeking', this.onSeeking_); | ||
this.tech_.on('id3updated', this.onId3updated_); | ||
this.tech_.on('captiondata', this.onCaptionData_); | ||
this.tech_.on('levelswitch', this.onLevelSwitch_); | ||
this.tech_.on('levelloaded', this.onLevelLoaded_); | ||
this.tech_.on('fragmentloaded', this.onFragmentLoaded_); | ||
this.metadataStream_.on('data', this.onMetadataStreamData_); | ||
this.cea608Stream_.on('data', this.onCea608StreamData_); | ||
this.captionStream_.on('data', this.onCaptionStreamData_); | ||
this.playlists = { | ||
media: function media() { | ||
return _this.media_(); | ||
} | ||
this.playlists = new _video2['default'].EventTarget(); | ||
this.playlists.media = function () { | ||
return _this.media_(); | ||
}; | ||
@@ -361,2 +363,3 @@ } | ||
} | ||
this.playlists.trigger('mediachange'); | ||
this.tech_.trigger({ type: 'mediachange', bubbles: true }); | ||
@@ -366,17 +369,38 @@ }; | ||
/** | ||
* Event listener for the seeked event. This will remove cues from the metadata track | ||
* and inband text track after seeks | ||
* Event listener for the levelloaded event. | ||
*/ | ||
FlashlsHandler.prototype.onSeeked_ = function onSeeked_() { | ||
FlashlsHandler.prototype.onLevelLoaded_ = function onLevelLoaded_() { | ||
this.playlists.trigger('loadedplaylist'); | ||
}; | ||
/** | ||
* Event listener for the fragmentloaded event. | ||
*/ | ||
FlashlsHandler.prototype.onFragmentLoaded_ = function onFragmentLoaded_() { | ||
this.tech_.trigger('bandwidthupdate'); | ||
this.captionStream_.flush(); | ||
}; | ||
/** | ||
* Event listener for the seeking event. This will remove cues from the metadata track | ||
* and inband text tracks during seeks | ||
*/ | ||
FlashlsHandler.prototype.onSeeking_ = function onSeeking_() { | ||
var _this3 = this; | ||
removeCuesFromTrack(0, Infinity, this.metadataTrack_); | ||
var buffered = this.tech_.buffered(); | ||
var buffered = findRange(this.tech_.buffered(), this.tech_.currentTime()); | ||
if (buffered.length === 1) { | ||
removeCuesFromTrack(0, buffered.start(0), this.inbandTextTrack_); | ||
removeCuesFromTrack(buffered.end(0), Infinity, this.inbandTextTrack_); | ||
} else { | ||
removeCuesFromTrack(0, Infinity, this.inbandTextTrack_); | ||
if (!buffered.length) { | ||
Object.keys(this.inbandTextTracks_).forEach(function (id) { | ||
removeCuesFromTrack(0, Infinity, _this3.inbandTextTracks_[id]); | ||
}); | ||
this.captionStream_.reset(); | ||
} | ||
@@ -417,3 +441,3 @@ }; | ||
FlashlsHandler.prototype.onMetadataStreamData_ = function onMetadataStreamData_(tag) { | ||
var _this3 = this; | ||
var _this4 = this; | ||
@@ -440,3 +464,3 @@ if (!this.metadataTrack_) { | ||
deprecateOldCue(cue); | ||
_this3.metadataTrack_.addCue(cue); | ||
_this4.metadataTrack_.addCue(cue); | ||
}); | ||
@@ -482,35 +506,12 @@ | ||
FlashlsHandler.prototype.onCaptionData_ = function onCaptionData_(event, data) { | ||
var _this4 = this; | ||
var _this5 = this; | ||
var captions = data[0].map(function (d) { | ||
return { | ||
data[0].forEach(function (d) { | ||
_this5.captionStream_.push({ | ||
pts: d.pos * 90000, | ||
bytes: stringToByteArray(_window2['default'].atob(d.data)) | ||
}; | ||
dts: d.dts * 90000, | ||
escapedRBSP: stringToByteArray(_window2['default'].atob(d.data)), | ||
nalUnitType: 'sei_rbsp' | ||
}); | ||
}); | ||
captions.forEach(function (caption) { | ||
_this4.captionPackets_ = _this4.captionPackets_.concat(parseCaptionPackets(caption.pts, caption.bytes)); | ||
}); | ||
if (this.captionPackets_.length) { | ||
// In Chrome, the Array#sort function is not stable so add a | ||
// presortIndex that we can use to ensure we get a stable-sort | ||
this.captionPackets_.forEach(function (elem, idx) { | ||
elem.presortIndex = idx; | ||
}); | ||
// sort caption byte-pairs based on their PTS values | ||
this.captionPackets_.sort(function (a, b) { | ||
if (a.pts === b.pts) { | ||
return a.presortIndex - b.presortIndex; | ||
} | ||
return a.pts - b.pts; | ||
}); | ||
// Push each caption into Cea608Stream | ||
this.captionPackets_.forEach(this.cea608Stream_.push, this.cea608Stream_); | ||
this.captionPackets_.length = 0; | ||
this.cea608Stream_.flush(); | ||
} | ||
}; | ||
@@ -527,15 +528,16 @@ | ||
FlashlsHandler.prototype.onCea608StreamData_ = function onCea608StreamData_(caption) { | ||
FlashlsHandler.prototype.onCaptionStreamData_ = function onCaptionStreamData_(caption) { | ||
if (caption) { | ||
if (!this.inbandTextTrack_) { | ||
removeExistingTrack(this.tech_, 'captions', 'cc1'); | ||
this.inbandTextTrack_ = this.tech_.addRemoteTextTrack({ | ||
if (!this.inbandTextTracks_[caption.stream]) { | ||
removeExistingTrack(this.tech_, 'captions', caption.stream); | ||
this.inbandTextTracks_[caption.stream] = this.tech_.addRemoteTextTrack({ | ||
kind: 'captions', | ||
label: 'cc1' | ||
label: caption.stream, | ||
id: caption.stream | ||
}, false).track; | ||
} | ||
removeOldCues(this.tech_.buffered(), this.inbandTextTrack_); | ||
removeOldCues(this.tech_.buffered(), this.inbandTextTracks_[caption.stream]); | ||
this.inbandTextTrack_.addCue(new _window2['default'].VTTCue(caption.startPts / 90000, caption.endPts / 90000, caption.text)); | ||
this.inbandTextTracks_[caption.stream].addCue(new _window2['default'].VTTCue(caption.startPts / 90000, caption.endPts / 90000, caption.text)); | ||
} | ||
@@ -546,3 +548,3 @@ }; | ||
this.tech_.off('loadedmetadata', this.onLoadedmetadata_); | ||
this.tech_.off('seeked', this.onSeeked_); | ||
this.tech_.off('seeked', this.onSeeking_); | ||
this.tech_.off('id3updated', this.onId3updated_); | ||
@@ -552,2 +554,4 @@ this.tech_.off('captiondata', this.onCaptionData_); | ||
this.tech_.off('levelswitch', this.onLevelSwitch_); | ||
this.tech_.off('levelloaded', this.onLevelLoaded_); | ||
this.tech_.off('fragmentloaded', this.onFragmentLoaded_); | ||
@@ -554,0 +558,0 @@ if (this.qualityLevels_) { |
{ | ||
"name": "@brightcove/videojs-flashls-source-handler", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"description": "A source handler to integrate flashls with video.js", | ||
@@ -75,6 +75,6 @@ "main": "es5/index.js", | ||
"dependencies": { | ||
"@brightcove/videojs-flashls-swf": "^6.1.0", | ||
"@brightcove/videojs-flashls-swf": "6.3.0", | ||
"browserify-versionify": "^1.0.6", | ||
"global": "^4.3.0", | ||
"mux.js": "^3.0.4", | ||
"mux.js": "^4.3.2", | ||
"video.js": "^5.10.1" | ||
@@ -81,0 +81,0 @@ }, |
176
src/index.js
import videojs from 'video.js'; | ||
import window from 'global/window'; | ||
import { Cea608Stream } from 'mux.js/lib/m2ts/caption-stream'; | ||
import { CaptionStream } from 'mux.js/lib/m2ts/caption-stream'; | ||
import MetadataStream from 'mux.js/lib/m2ts/metadata-stream'; | ||
@@ -73,33 +73,2 @@ import { createRepresentations } from './representations.js'; | ||
// see CEA-708-D, section 4.4 | ||
const parseCaptionPackets = function(pts, userData) { | ||
let results = []; | ||
let i; | ||
let count; | ||
let offset; | ||
let data; | ||
// if this is just filler, return immediately | ||
if (!(userData[0] & 0x40)) { | ||
return results; | ||
} | ||
// parse out the cc_data_1 and cc_data_2 fields | ||
count = userData[0] & 0x1f; | ||
for (i = 0; i < count; i++) { | ||
offset = i * 3; | ||
data = { | ||
type: userData[offset + 2] & 0x03, | ||
pts | ||
}; | ||
// capture cc data when cc_valid is 1 | ||
if (userData[offset + 2] & 0x04) { | ||
data.ccData = (userData[offset + 3] << 8) | userData[offset + 4]; | ||
results.push(data); | ||
} | ||
} | ||
return results; | ||
}; | ||
/** | ||
@@ -177,2 +146,34 @@ * Remove cues from a track on video.js. | ||
// Fudge factor to account for TimeRanges rounding | ||
const TIME_FUDGE_FACTOR = 1 / 30; | ||
const filterRanges = function(timeRanges, predicate) { | ||
const results = []; | ||
if (timeRanges && timeRanges.length) { | ||
// Search for ranges that match the predicate | ||
for (let i = 0; i < timeRanges.length; i++) { | ||
if (predicate(timeRanges.start(i), timeRanges.end(i))) { | ||
results.push([timeRanges.start(i), timeRanges.end(i)]); | ||
} | ||
} | ||
} | ||
return videojs.createTimeRanges(results); | ||
}; | ||
/** | ||
* Attempts to find the buffered TimeRange that contains the specified | ||
* time. | ||
* @param {TimeRanges} buffered - the TimeRanges object to query | ||
* @param {number} time - the time to filter on. | ||
* @returns {TimeRanges} a new TimeRanges object | ||
*/ | ||
const findRange = function(buffered, time) { | ||
return filterRanges(buffered, function(start, end) { | ||
return start - TIME_FUDGE_FACTOR <= time && | ||
end + TIME_FUDGE_FACTOR >= time; | ||
}); | ||
}; | ||
export class FlashlsHandler { | ||
@@ -211,29 +212,31 @@ constructor(source, tech, options) { | ||
this.metadataTrack_ = null; | ||
this.inbandTextTrack_ = null; | ||
this.inbandTextTracks_ = {}; | ||
this.metadataStream_ = new MetadataStream(); | ||
this.cea608Stream_ = new Cea608Stream(); | ||
this.captionPackets_ = []; | ||
this.captionStream_ = new CaptionStream(); | ||
// bind event listeners to this context | ||
this.onLoadedmetadata_ = this.onLoadedmetadata_.bind(this); | ||
this.onSeeked_ = this.onSeeked_.bind(this); | ||
this.onSeeking_ = this.onSeeking_.bind(this); | ||
this.onId3updated_ = this.onId3updated_.bind(this); | ||
this.onCaptionData_ = this.onCaptionData_.bind(this); | ||
this.onMetadataStreamData_ = this.onMetadataStreamData_.bind(this); | ||
this.onCea608StreamData_ = this.onCea608StreamData_.bind(this); | ||
this.onCaptionStreamData_ = this.onCaptionStreamData_.bind(this); | ||
this.onLevelSwitch_ = this.onLevelSwitch_.bind(this); | ||
this.onLevelLoaded_ = this.onLevelLoaded_.bind(this); | ||
this.onFragmentLoaded_ = this.onFragmentLoaded_.bind(this); | ||
this.onAudioTrackChanged = this.onAudioTrackChanged.bind(this); | ||
this.tech_.on('loadedmetadata', this.onLoadedmetadata_); | ||
this.tech_.on('seeked', this.onSeeked_); | ||
this.tech_.on('seeking', this.onSeeking_); | ||
this.tech_.on('id3updated', this.onId3updated_); | ||
this.tech_.on('captiondata', this.onCaptionData_); | ||
this.tech_.on('levelswitch', this.onLevelSwitch_); | ||
this.tech_.on('levelloaded', this.onLevelLoaded_); | ||
this.tech_.on('fragmentloaded', this.onFragmentLoaded_); | ||
this.metadataStream_.on('data', this.onMetadataStreamData_); | ||
this.cea608Stream_.on('data', this.onCea608StreamData_); | ||
this.captionStream_.on('data', this.onCaptionStreamData_); | ||
this.playlists = { | ||
media: () => this.media_() | ||
}; | ||
this.playlists = new videojs.EventTarget(); | ||
this.playlists.media = () => this.media_(); | ||
} | ||
@@ -332,2 +335,3 @@ | ||
} | ||
this.playlists.trigger('mediachange'); | ||
this.tech_.trigger({ type: 'mediachange', bubbles: true}); | ||
@@ -337,15 +341,30 @@ } | ||
/** | ||
* Event listener for the seeked event. This will remove cues from the metadata track | ||
* and inband text track after seeks | ||
* Event listener for the levelloaded event. | ||
*/ | ||
onSeeked_() { | ||
onLevelLoaded_() { | ||
this.playlists.trigger('loadedplaylist'); | ||
} | ||
/** | ||
* Event listener for the fragmentloaded event. | ||
*/ | ||
onFragmentLoaded_() { | ||
this.tech_.trigger('bandwidthupdate'); | ||
this.captionStream_.flush(); | ||
} | ||
/** | ||
* Event listener for the seeking event. This will remove cues from the metadata track | ||
* and inband text tracks during seeks | ||
*/ | ||
onSeeking_() { | ||
removeCuesFromTrack(0, Infinity, this.metadataTrack_); | ||
let buffered = this.tech_.buffered(); | ||
const buffered = findRange(this.tech_.buffered(), this.tech_.currentTime()); | ||
if (buffered.length === 1) { | ||
removeCuesFromTrack(0, buffered.start(0), this.inbandTextTrack_); | ||
removeCuesFromTrack(buffered.end(0), Infinity, this.inbandTextTrack_); | ||
} else { | ||
removeCuesFromTrack(0, Infinity, this.inbandTextTrack_); | ||
if (!buffered.length) { | ||
Object.keys(this.inbandTextTracks_).forEach((id) => { | ||
removeCuesFromTrack(0, Infinity, this.inbandTextTracks_[id]); | ||
}); | ||
this.captionStream_.reset(); | ||
} | ||
@@ -442,34 +461,10 @@ } | ||
onCaptionData_(event, data) { | ||
let captions = data[0].map((d) => { | ||
return { | ||
data[0].forEach((d) => { | ||
this.captionStream_.push({ | ||
pts: d.pos * 90000, | ||
bytes: stringToByteArray(window.atob(d.data)) | ||
}; | ||
dts: d.dts * 90000, | ||
escapedRBSP: stringToByteArray(window.atob(d.data)), | ||
nalUnitType: 'sei_rbsp' | ||
}); | ||
}); | ||
captions.forEach((caption) => { | ||
this.captionPackets_ = this.captionPackets_.concat( | ||
parseCaptionPackets(caption.pts, caption.bytes)); | ||
}); | ||
if (this.captionPackets_.length) { | ||
// In Chrome, the Array#sort function is not stable so add a | ||
// presortIndex that we can use to ensure we get a stable-sort | ||
this.captionPackets_.forEach((elem, idx) => { | ||
elem.presortIndex = idx; | ||
}); | ||
// sort caption byte-pairs based on their PTS values | ||
this.captionPackets_.sort((a, b) => { | ||
if (a.pts === b.pts) { | ||
return a.presortIndex - b.presortIndex; | ||
} | ||
return a.pts - b.pts; | ||
}); | ||
// Push each caption into Cea608Stream | ||
this.captionPackets_.forEach(this.cea608Stream_.push, this.cea608Stream_); | ||
this.captionPackets_.length = 0; | ||
this.cea608Stream_.flush(); | ||
} | ||
} | ||
@@ -484,15 +479,16 @@ | ||
*/ | ||
onCea608StreamData_(caption) { | ||
onCaptionStreamData_(caption) { | ||
if (caption) { | ||
if (!this.inbandTextTrack_) { | ||
removeExistingTrack(this.tech_, 'captions', 'cc1'); | ||
this.inbandTextTrack_ = this.tech_.addRemoteTextTrack({ | ||
if (!this.inbandTextTracks_[caption.stream]) { | ||
removeExistingTrack(this.tech_, 'captions', caption.stream); | ||
this.inbandTextTracks_[caption.stream] = this.tech_.addRemoteTextTrack({ | ||
kind: 'captions', | ||
label: 'cc1' | ||
label: caption.stream, | ||
id: caption.stream | ||
}, false).track; | ||
} | ||
removeOldCues(this.tech_.buffered(), this.inbandTextTrack_); | ||
removeOldCues(this.tech_.buffered(), this.inbandTextTracks_[caption.stream]); | ||
this.inbandTextTrack_.addCue( | ||
this.inbandTextTracks_[caption.stream].addCue( | ||
new window.VTTCue(caption.startPts / 90000, | ||
@@ -506,3 +502,3 @@ caption.endPts / 90000, | ||
this.tech_.off('loadedmetadata', this.onLoadedmetadata_); | ||
this.tech_.off('seeked', this.onSeeked_); | ||
this.tech_.off('seeked', this.onSeeking_); | ||
this.tech_.off('id3updated', this.onId3updated_); | ||
@@ -512,2 +508,4 @@ this.tech_.off('captiondata', this.onCaptionData_); | ||
this.tech_.off('levelswitch', this.onLevelSwitch_); | ||
this.tech_.off('levelloaded', this.onLevelLoaded_); | ||
this.tech_.off('fragmentloaded', this.onFragmentLoaded_); | ||
@@ -514,0 +512,0 @@ if (this.qualityLevels_) { |
@@ -8,19 +8,28 @@ import QUnit from 'qunit'; | ||
QUnit.test('triggers an event when the active media changes', function(assert) { | ||
let mediaChange = 0; | ||
let techMediaChange = 0; | ||
let playlistsMediaChange = 0; | ||
const tech = makeMochTech({}); | ||
/* eslint-disable no-unused-vars */ | ||
// need to create handler to setup event listeners | ||
const handler = new FlashlsHandler('this.m3u8', tech, {}); | ||
/* eslint-enable no-unused-vars */ | ||
tech.on('mediachange', () => { | ||
mediaChange++; | ||
}); | ||
tech.on('mediachange', () => techMediaChange++); | ||
handler.playlists.on('mediachange', () => playlistsMediaChange++); | ||
tech.trigger('levelswitch'); | ||
assert.equal(mediaChange, 1, 'fired a mediachange'); | ||
assert.equal(techMediaChange, 1, 'tech fired a mediachange'); | ||
assert.equal(playlistsMediaChange, 1, 'playlists fired a mediachange'); | ||
}); | ||
QUnit.test('triggers an event when a playlist is loaded', function(assert) { | ||
let loadedplaylist = 0; | ||
const tech = makeMochTech({}); | ||
const handler = new FlashlsHandler('this.m3u8', tech, {}); | ||
handler.playlists.on('loadedplaylist', () => loadedplaylist++); | ||
tech.trigger('levelloaded'); | ||
assert.equal(loadedplaylist, 1, 'playlists fired a loadedplaylist'); | ||
}); | ||
QUnit.test('mediachange changes playlist.media function', function(assert) { | ||
@@ -27,0 +36,0 @@ const levels = [ |
@@ -36,1 +36,17 @@ import QUnit from 'qunit'; | ||
QUnit.test('triggers an event when bandwidth updates after segment load', | ||
function(assert) { | ||
let bandwidthupdate = 0; | ||
const tech = makeMochTech({}); | ||
/* eslint-disable no-unused-vars */ | ||
// need to create handler to setup event listeners | ||
const handler = new FlashlsHandler('this.m3u8', tech, {}); | ||
/* eslint-enable no-unused-vars */ | ||
tech.on('bandwidthupdate', () => bandwidthupdate++); | ||
tech.trigger('fragmentloaded'); | ||
assert.equal(bandwidthupdate, 1, 'tech fired a bandwidthupdate'); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
AI-detected potential security risk
Supply chain riskAI has determined that this package may contain potential security issues or vulnerabilities.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
313394
5957
13
4
+ Added@brightcove/flashls@1.2.0(transitive)
+ Added@brightcove/videojs-flashls-swf@6.3.0(transitive)
+ Addedmux.js@4.5.1(transitive)
- Removed@brightcove/flashls@1.2.4(transitive)
- Removed@brightcove/videojs-flashls-swf@6.4.5(transitive)
- Removedmux.js@3.1.0(transitive)
Updatedmux.js@^4.3.2