UNPKG

cloudinary-video-player

Version:

Cloudinary Video Player

1,740 lines (1,537 loc) 2.64 MB
(self["cloudinaryVideoPlayerChunkLoading"] = self["cloudinaryVideoPlayerChunkLoading"] || []).push([["dash"],{ /***/ "../node_modules/global/document.js": /*!******************************************!*\ !*** ../node_modules/global/document.js ***! \******************************************/ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { var topLevel = typeof __webpack_require__.g !== 'undefined' ? __webpack_require__.g : typeof window !== 'undefined' ? window : {} var minDoc = __webpack_require__(/*! min-document */ "?9835"); var doccy; if (typeof document !== 'undefined') { doccy = document; } else { doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; if (!doccy) { doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; } } module.exports = doccy; /***/ }), /***/ "../node_modules/global/window.js": /*!****************************************!*\ !*** ../node_modules/global/window.js ***! \****************************************/ /***/ ((module, __unused_webpack_exports, __webpack_require__) => { var win; if (typeof window !== "undefined") { win = window; } else if (typeof __webpack_require__.g !== "undefined") { win = __webpack_require__.g; } else if (typeof self !== "undefined"){ win = self; } else { win = {}; } module.exports = win; /***/ }), /***/ "../node_modules/videojs-contrib-dash/dist/videojs-dash.es.js": /*!********************************************************************!*\ !*** ../node_modules/videojs-contrib-dash/dist/videojs-dash.es.js ***! \********************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); /* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! video.js */ "../node_modules/video.js/dist/alt/video.core-exposed.js"); /* harmony import */ var video_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(video_js__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! global/window */ "../node_modules/global/window.js"); /* harmony import */ var global_window__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(global_window__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! global/document */ "../node_modules/global/document.js"); /* harmony import */ var global_document__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(global_document__WEBPACK_IMPORTED_MODULE_2__); /*! @name videojs-contrib-dash @version 5.1.1 @license Apache-2.0 */ function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var dash_all_debug = createCommonjsModule(function (module, exports) { (function webpackUniversalModuleDefinition(root, factory) { module.exports = factory(); })(window, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __nested_webpack_require_800__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __nested_webpack_require_800__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __nested_webpack_require_800__.m = modules; /******/ /******/ // expose the module cache /******/ __nested_webpack_require_800__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __nested_webpack_require_800__.d = function(exports, name, getter) { /******/ if(!__nested_webpack_require_800__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __nested_webpack_require_800__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __nested_webpack_require_800__.t = function(value, mode) { /******/ if(mode & 1) value = __nested_webpack_require_800__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __nested_webpack_require_800__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __nested_webpack_require_800__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __nested_webpack_require_800__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __nested_webpack_require_800__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __nested_webpack_require_800__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __nested_webpack_require_800__.p = "/dist/"; /******/ /******/ /******/ // Load entry module and return exports /******/ return __nested_webpack_require_800__(__nested_webpack_require_800__.s = "./index.js"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./externals/base64.js": /*!*****************************!*\ !*** ./externals/base64.js ***! \*****************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /* $Date: 2007-06-12 18:02:31 $ */ // from: http://bannister.us/weblog/2007/06/09/simple-base64-encodedecode-javascript/ // Handles encode/decode of ASCII and Unicode strings. var UTF8 = {}; UTF8.encode = function (s) { var u = []; for (var i = 0; i < s.length; ++i) { var c = s.charCodeAt(i); if (c < 0x80) { u.push(c); } else if (c < 0x800) { u.push(0xC0 | c >> 6); u.push(0x80 | 63 & c); } else if (c < 0x10000) { u.push(0xE0 | c >> 12); u.push(0x80 | 63 & c >> 6); u.push(0x80 | 63 & c); } else { u.push(0xF0 | c >> 18); u.push(0x80 | 63 & c >> 12); u.push(0x80 | 63 & c >> 6); u.push(0x80 | 63 & c); } } return u; }; UTF8.decode = function (u) { var a = []; var i = 0; while (i < u.length) { var v = u[i++]; if (v < 0x80) ; else if (v < 0xE0) { v = (31 & v) << 6; v |= 63 & u[i++]; } else if (v < 0xF0) { v = (15 & v) << 12; v |= (63 & u[i++]) << 6; v |= 63 & u[i++]; } else { v = (7 & v) << 18; v |= (63 & u[i++]) << 12; v |= (63 & u[i++]) << 6; v |= 63 & u[i++]; } a.push(String.fromCharCode(v)); } return a.join(''); }; var BASE64 = {}; (function (T) { var encodeArray = function encodeArray(u) { var i = 0; var a = []; var n = 0 | u.length / 3; while (0 < n--) { var v = (u[i] << 16) + (u[i + 1] << 8) + u[i + 2]; i += 3; a.push(T.charAt(63 & v >> 18)); a.push(T.charAt(63 & v >> 12)); a.push(T.charAt(63 & v >> 6)); a.push(T.charAt(63 & v)); } if (2 == u.length - i) { var v = (u[i] << 16) + (u[i + 1] << 8); a.push(T.charAt(63 & v >> 18)); a.push(T.charAt(63 & v >> 12)); a.push(T.charAt(63 & v >> 6)); a.push('='); } else if (1 == u.length - i) { var v = u[i] << 16; a.push(T.charAt(63 & v >> 18)); a.push(T.charAt(63 & v >> 12)); a.push('=='); } return a.join(''); }; var R = function () { var a = []; for (var i = 0; i < T.length; ++i) { a[T.charCodeAt(i)] = i; } a['='.charCodeAt(0)] = 0; return a; }(); var decodeArray = function decodeArray(s) { var i = 0; var u = []; var n = 0 | s.length / 4; while (0 < n--) { var v = (R[s.charCodeAt(i)] << 18) + (R[s.charCodeAt(i + 1)] << 12) + (R[s.charCodeAt(i + 2)] << 6) + R[s.charCodeAt(i + 3)]; u.push(255 & v >> 16); u.push(255 & v >> 8); u.push(255 & v); i += 4; } if (u) { if ('=' == s.charAt(i - 2)) { u.pop(); u.pop(); } else if ('=' == s.charAt(i - 1)) { u.pop(); } } return u; }; var ASCII = {}; ASCII.encode = function (s) { var u = []; for (var i = 0; i < s.length; ++i) { u.push(s.charCodeAt(i)); } return u; }; ASCII.decode = function (u) { for (var i = 0; i < s.length; ++i) { a[i] = String.fromCharCode(a[i]); } return a.join(''); }; BASE64.decodeArray = function (s) { var u = decodeArray(s); return new Uint8Array(u); }; BASE64.encodeASCII = function (s) { var u = ASCII.encode(s); return encodeArray(u); }; BASE64.decodeASCII = function (s) { var a = decodeArray(s); return ASCII.decode(a); }; BASE64.encode = function (s) { var u = UTF8.encode(s); return encodeArray(u); }; BASE64.decode = function (s) { var u = decodeArray(s); return UTF8.decode(u); }; })("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); /*The following polyfills are not used in dash.js but have caused multiplayer integration issues. Therefore commenting them out. if (undefined === btoa) { var btoa = BASE64.encode; } if (undefined === atob) { var atob = BASE64.decode; } */ { exports.decode = BASE64.decode; exports.decodeArray = BASE64.decodeArray; exports.encode = BASE64.encode; exports.encodeASCII = BASE64.encodeASCII; } /***/ }), /***/ "./externals/cea608-parser.js": /*!************************************!*\ !*** ./externals/cea608-parser.js ***! \************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { /** * The copyright in this software is being made available under the BSD License, * included below. This software may be subject to other third party and contributor * rights, including patent rights, and no such rights are granted under this license. * * Copyright (c) 2015-2016, DASH Industry Forum. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * 2. Neither the name of Dash Industry Forum nor the names of its * contributors may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ (function (exports) { /** * Exceptions from regular ASCII. CodePoints are mapped to UTF-16 codes */ var specialCea608CharsCodes = { 0x2a: 0xe1, // lowercase a, acute accent 0x5c: 0xe9, // lowercase e, acute accent 0x5e: 0xed, // lowercase i, acute accent 0x5f: 0xf3, // lowercase o, acute accent 0x60: 0xfa, // lowercase u, acute accent 0x7b: 0xe7, // lowercase c with cedilla 0x7c: 0xf7, // division symbol 0x7d: 0xd1, // uppercase N tilde 0x7e: 0xf1, // lowercase n tilde 0x7f: 0x2588, // Full block // THIS BLOCK INCLUDES THE 16 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS // THAT COME FROM HI BYTE=0x11 AND LOW BETWEEN 0x30 AND 0x3F // THIS MEANS THAT \x50 MUST BE ADDED TO THE VALUES 0x80: 0xae, // Registered symbol (R) 0x81: 0xb0, // degree sign 0x82: 0xbd, // 1/2 symbol 0x83: 0xbf, // Inverted (open) question mark 0x84: 0x2122, // Trademark symbol (TM) 0x85: 0xa2, // Cents symbol 0x86: 0xa3, // Pounds sterling 0x87: 0x266a, // Music 8'th note 0x88: 0xe0, // lowercase a, grave accent 0x89: 0x20, // transparent space (regular) 0x8a: 0xe8, // lowercase e, grave accent 0x8b: 0xe2, // lowercase a, circumflex accent 0x8c: 0xea, // lowercase e, circumflex accent 0x8d: 0xee, // lowercase i, circumflex accent 0x8e: 0xf4, // lowercase o, circumflex accent 0x8f: 0xfb, // lowercase u, circumflex accent // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS // THAT COME FROM HI BYTE=0x12 AND LOW BETWEEN 0x20 AND 0x3F 0x90: 0xc1, // capital letter A with acute 0x91: 0xc9, // capital letter E with acute 0x92: 0xd3, // capital letter O with acute 0x93: 0xda, // capital letter U with acute 0x94: 0xdc, // capital letter U with diaresis 0x95: 0xfc, // lowercase letter U with diaeresis 0x96: 0x2018, // opening single quote 0x97: 0xa1, // inverted exclamation mark 0x98: 0x2a, // asterisk 0x99: 0x2019, // closing single quote 0x9a: 0x2501, // box drawings heavy horizontal 0x9b: 0xa9, // copyright sign 0x9c: 0x2120, // Service mark 0x9d: 0x2022, // (round) bullet 0x9e: 0x201c, // Left double quotation mark 0x9f: 0x201d, // Right double quotation mark 0xa0: 0xc0, // uppercase A, grave accent 0xa1: 0xc2, // uppercase A, circumflex 0xa2: 0xc7, // uppercase C with cedilla 0xa3: 0xc8, // uppercase E, grave accent 0xa4: 0xca, // uppercase E, circumflex 0xa5: 0xcb, // capital letter E with diaresis 0xa6: 0xeb, // lowercase letter e with diaresis 0xa7: 0xce, // uppercase I, circumflex 0xa8: 0xcf, // uppercase I, with diaresis 0xa9: 0xef, // lowercase i, with diaresis 0xaa: 0xd4, // uppercase O, circumflex 0xab: 0xd9, // uppercase U, grave accent 0xac: 0xf9, // lowercase u, grave accent 0xad: 0xdb, // uppercase U, circumflex 0xae: 0xab, // left-pointing double angle quotation mark 0xaf: 0xbb, // right-pointing double angle quotation mark // THIS BLOCK INCLUDES THE 32 EXTENDED (TWO-BYTE) LINE 21 CHARACTERS // THAT COME FROM HI BYTE=0x13 AND LOW BETWEEN 0x20 AND 0x3F 0xb0: 0xc3, // Uppercase A, tilde 0xb1: 0xe3, // Lowercase a, tilde 0xb2: 0xcd, // Uppercase I, acute accent 0xb3: 0xcc, // Uppercase I, grave accent 0xb4: 0xec, // Lowercase i, grave accent 0xb5: 0xd2, // Uppercase O, grave accent 0xb6: 0xf2, // Lowercase o, grave accent 0xb7: 0xd5, // Uppercase O, tilde 0xb8: 0xf5, // Lowercase o, tilde 0xb9: 0x7b, // Open curly brace 0xba: 0x7d, // Closing curly brace 0xbb: 0x5c, // Backslash 0xbc: 0x5e, // Caret 0xbd: 0x5f, // Underscore 0xbe: 0x7c, // Pipe (vertical line) 0xbf: 0x223c, // Tilde operator 0xc0: 0xc4, // Uppercase A, umlaut 0xc1: 0xe4, // Lowercase A, umlaut 0xc2: 0xd6, // Uppercase O, umlaut 0xc3: 0xf6, // Lowercase o, umlaut 0xc4: 0xdf, // Esszett (sharp S) 0xc5: 0xa5, // Yen symbol 0xc6: 0xa4, // Generic currency sign 0xc7: 0x2503, // Box drawings heavy vertical 0xc8: 0xc5, // Uppercase A, ring 0xc9: 0xe5, // Lowercase A, ring 0xca: 0xd8, // Uppercase O, stroke 0xcb: 0xf8, // Lowercase o, strok 0xcc: 0x250f, // Box drawings heavy down and right 0xcd: 0x2513, // Box drawings heavy down and left 0xce: 0x2517, // Box drawings heavy up and right 0xcf: 0x251b // Box drawings heavy up and left }; /** * Get Unicode Character from CEA-608 byte code */ var getCharForByte = function getCharForByte(_byte) { var charCode = _byte; if (specialCea608CharsCodes.hasOwnProperty(_byte)) { charCode = specialCea608CharsCodes[_byte]; } return String.fromCharCode(charCode); }; var NR_ROWS = 15, NR_COLS = 32; // Tables to look up row from PAC data var rowsLowCh1 = { 0x11: 1, 0x12: 3, 0x15: 5, 0x16: 7, 0x17: 9, 0x10: 11, 0x13: 12, 0x14: 14 }; var rowsHighCh1 = { 0x11: 2, 0x12: 4, 0x15: 6, 0x16: 8, 0x17: 10, 0x13: 13, 0x14: 15 }; var rowsLowCh2 = { 0x19: 1, 0x1A: 3, 0x1D: 5, 0x1E: 7, 0x1F: 9, 0x18: 11, 0x1B: 12, 0x1C: 14 }; var rowsHighCh2 = { 0x19: 2, 0x1A: 4, 0x1D: 6, 0x1E: 8, 0x1F: 10, 0x1B: 13, 0x1C: 15 }; var backgroundColors = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'black', 'transparent']; /** * Simple logger class to be able to write with time-stamps and filter on level. */ var logger = { verboseFilter: { 'DATA': 3, 'DEBUG': 3, 'INFO': 2, 'WARNING': 2, 'TEXT': 1, 'ERROR': 0 }, time: null, verboseLevel: 0, // Only write errors setTime: function setTime(newTime) { this.time = newTime; }, log: function log(severity, msg) { var minLevel = this.verboseFilter[severity]; if (this.verboseLevel >= minLevel) { console.log(this.time + " [" + severity + "] " + msg); } } }; var numArrayToHexArray = function numArrayToHexArray(numArray) { var hexArray = []; for (var j = 0; j < numArray.length; j++) { hexArray.push(numArray[j].toString(16)); } return hexArray; }; /** * State of CEA-608 pen or character * @constructor */ var PenState = function PenState(foreground, underline, italics, background, flash) { this.foreground = foreground || "white"; this.underline = underline || false; this.italics = italics || false; this.background = background || "black"; this.flash = flash || false; }; PenState.prototype = { reset: function reset() { this.foreground = "white"; this.underline = false; this.italics = false; this.background = "black"; this.flash = false; }, setStyles: function setStyles(styles) { var attribs = ["foreground", "underline", "italics", "background", "flash"]; for (var i = 0; i < attribs.length; i++) { var style = attribs[i]; if (styles.hasOwnProperty(style)) { this[style] = styles[style]; } } }, isDefault: function isDefault() { return this.foreground === "white" && !this.underline && !this.italics && this.background === "black" && !this.flash; }, equals: function equals(other) { return this.foreground === other.foreground && this.underline === other.underline && this.italics === other.italics && this.background === other.background && this.flash === other.flash; }, copy: function copy(newPenState) { this.foreground = newPenState.foreground; this.underline = newPenState.underline; this.italics = newPenState.italics; this.background = newPenState.background; this.flash = newPenState.flash; }, toString: function toString() { return "color=" + this.foreground + ", underline=" + this.underline + ", italics=" + this.italics + ", background=" + this.background + ", flash=" + this.flash; } }; /** * Unicode character with styling and background. * @constructor */ var StyledUnicodeChar = function StyledUnicodeChar(uchar, foreground, underline, italics, background, flash) { this.uchar = uchar || ' '; // unicode character this.penState = new PenState(foreground, underline, italics, background, flash); }; StyledUnicodeChar.prototype = { reset: function reset() { this.uchar = ' '; this.penState.reset(); }, setChar: function setChar(uchar, newPenState) { this.uchar = uchar; this.penState.copy(newPenState); }, setPenState: function setPenState(newPenState) { this.penState.copy(newPenState); }, equals: function equals(other) { return this.uchar === other.uchar && this.penState.equals(other.penState); }, copy: function copy(newChar) { this.uchar = newChar.uchar; this.penState.copy(newChar.penState); }, isEmpty: function isEmpty() { return this.uchar === ' ' && this.penState.isDefault(); } }; /** * CEA-608 row consisting of NR_COLS instances of StyledUnicodeChar. * @constructor */ var Row = function Row() { this.chars = []; for (var i = 0; i < NR_COLS; i++) { this.chars.push(new StyledUnicodeChar()); } this.pos = 0; this.currPenState = new PenState(); }; Row.prototype = { equals: function equals(other) { var equal = true; for (var i = 0; i < NR_COLS; i++) { if (!this.chars[i].equals(other.chars[i])) { equal = false; break; } } return equal; }, copy: function copy(other) { for (var i = 0; i < NR_COLS; i++) { this.chars[i].copy(other.chars[i]); } }, isEmpty: function isEmpty() { var empty = true; for (var i = 0; i < NR_COLS; i++) { if (!this.chars[i].isEmpty()) { empty = false; break; } } return empty; }, /** * Set the cursor to a valid column. */ setCursor: function setCursor(absPos) { if (this.pos !== absPos) { this.pos = absPos; } if (this.pos < 0) { logger.log("ERROR", "Negative cursor position " + this.pos); this.pos = 0; } else if (this.pos > NR_COLS) { logger.log("ERROR", "Too large cursor position " + this.pos); this.pos = NR_COLS; } }, /** * Move the cursor relative to current position. */ moveCursor: function moveCursor(relPos) { var newPos = this.pos + relPos; if (relPos > 1) { for (var i = this.pos + 1; i < newPos + 1; i++) { this.chars[i].setPenState(this.currPenState); } } this.setCursor(newPos); }, /** * Backspace, move one step back and clear character. */ backSpace: function backSpace() { this.moveCursor(-1); this.chars[this.pos].setChar(' ', this.currPenState); }, insertChar: function insertChar(_byte2) { if (_byte2 >= 0x90) { //Extended char this.backSpace(); } var _char = getCharForByte(_byte2); if (this.pos >= NR_COLS) { logger.log("ERROR", "Cannot insert " + _byte2.toString(16) + " (" + _char + ") at position " + this.pos + ". Skipping it!"); return; } this.chars[this.pos].setChar(_char, this.currPenState); this.moveCursor(1); }, clearFromPos: function clearFromPos(startPos) { var i; for (i = startPos; i < NR_COLS; i++) { this.chars[i].reset(); } }, clear: function clear() { this.clearFromPos(0); this.pos = 0; this.currPenState.reset(); }, clearToEndOfRow: function clearToEndOfRow() { this.clearFromPos(this.pos); }, getTextString: function getTextString() { var chars = []; var empty = true; for (var i = 0; i < NR_COLS; i++) { var _char2 = this.chars[i].uchar; if (_char2 !== " ") { empty = false; } chars.push(_char2); } if (empty) { return ""; } else { return chars.join(""); } }, setPenStyles: function setPenStyles(styles) { this.currPenState.setStyles(styles); var currChar = this.chars[this.pos]; currChar.setPenState(this.currPenState); } }; /** * Keep a CEA-608 screen of 32x15 styled characters * @constructor */ var CaptionScreen = function CaptionScreen() { this.rows = []; for (var i = 0; i < NR_ROWS; i++) { this.rows.push(new Row()); // Note that we use zero-based numbering (0-14) } this.currRow = NR_ROWS - 1; this.nrRollUpRows = null; this.reset(); }; CaptionScreen.prototype = { reset: function reset() { for (var i = 0; i < NR_ROWS; i++) { this.rows[i].clear(); } this.currRow = NR_ROWS - 1; }, equals: function equals(other) { var equal = true; for (var i = 0; i < NR_ROWS; i++) { if (!this.rows[i].equals(other.rows[i])) { equal = false; break; } } return equal; }, copy: function copy(other) { for (var i = 0; i < NR_ROWS; i++) { this.rows[i].copy(other.rows[i]); } }, isEmpty: function isEmpty() { var empty = true; for (var i = 0; i < NR_ROWS; i++) { if (!this.rows[i].isEmpty()) { empty = false; break; } } return empty; }, backSpace: function backSpace() { var row = this.rows[this.currRow]; row.backSpace(); }, clearToEndOfRow: function clearToEndOfRow() { var row = this.rows[this.currRow]; row.clearToEndOfRow(); }, /** * Insert a character (without styling) in the current row. */ insertChar: function insertChar(_char3) { var row = this.rows[this.currRow]; row.insertChar(_char3); }, setPen: function setPen(styles) { var row = this.rows[this.currRow]; row.setPenStyles(styles); }, moveCursor: function moveCursor(relPos) { var row = this.rows[this.currRow]; row.moveCursor(relPos); }, setCursor: function setCursor(absPos) { logger.log("INFO", "setCursor: " + absPos); var row = this.rows[this.currRow]; row.setCursor(absPos); }, setPAC: function setPAC(pacData) { logger.log("INFO", "pacData = " + JSON.stringify(pacData)); var newRow = pacData.row - 1; if (this.nrRollUpRows && newRow < this.nrRollUpRows - 1) { newRow = this.nrRollUpRows - 1; } this.currRow = newRow; var row = this.rows[this.currRow]; if (pacData.indent !== null) { var indent = pacData.indent; var prevPos = Math.max(indent - 1, 0); row.setCursor(pacData.indent); pacData.color = row.chars[prevPos].penState.foreground; } var styles = { foreground: pacData.color, underline: pacData.underline, italics: pacData.italics, background: 'black', flash: false }; this.setPen(styles); }, /** * Set background/extra foreground, but first do back_space, and then insert space (backwards compatibility). */ setBkgData: function setBkgData(bkgData) { logger.log("INFO", "bkgData = " + JSON.stringify(bkgData)); this.backSpace(); this.setPen(bkgData); this.insertChar(0x20); //Space }, setRollUpRows: function setRollUpRows(nrRows) { this.nrRollUpRows = nrRows; }, rollUp: function rollUp() { if (this.nrRollUpRows === null) { logger.log("DEBUG", "roll_up but nrRollUpRows not set yet"); return; //Not properly setup } logger.log("TEXT", this.getDisplayText()); var topRowIndex = this.currRow + 1 - this.nrRollUpRows; var topRow = this.rows.splice(topRowIndex, 1)[0]; topRow.clear(); this.rows.splice(this.currRow, 0, topRow); logger.log("INFO", "Rolling up"); //logger.log("TEXT", this.get_display_text()) }, /** * Get all non-empty rows with as unicode text. */ getDisplayText: function getDisplayText(asOneRow) { asOneRow = asOneRow || false; var displayText = []; var text = ""; var rowNr = -1; for (var i = 0; i < NR_ROWS; i++) { var rowText = this.rows[i].getTextString(); if (rowText) { rowNr = i + 1; if (asOneRow) { displayText.push("Row " + rowNr + ': "' + rowText + '"'); } else { displayText.push(rowText.trim()); } } } if (displayText.length > 0) { if (asOneRow) { text = "[" + displayText.join(" | ") + "]"; } else { text = displayText.join("\n"); } } return text; }, getTextAndFormat: function getTextAndFormat() { return this.rows; } }; /** * Handle a CEA-608 channel and send decoded data to outputFilter * @constructor * @param {Number} channelNumber (1 or 2) * @param {CueHandler} outputFilter Output from channel1 newCue(startTime, endTime, captionScreen) */ var Cea608Channel = function Cea608Channel(channelNumber, outputFilter) { this.chNr = channelNumber; this.outputFilter = outputFilter; this.mode = null; this.verbose = 0; this.displayedMemory = new CaptionScreen(); this.nonDisplayedMemory = new CaptionScreen(); this.lastOutputScreen = new CaptionScreen(); this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1]; this.writeScreen = this.displayedMemory; this.mode = null; this.cueStartTime = null; // Keeps track of where a cue started. }; Cea608Channel.prototype = { modes: ["MODE_ROLL-UP", "MODE_POP-ON", "MODE_PAINT-ON", "MODE_TEXT"], reset: function reset() { this.mode = null; this.displayedMemory.reset(); this.nonDisplayedMemory.reset(); this.lastOutputScreen.reset(); this.currRollUpRow = this.displayedMemory.rows[NR_ROWS - 1]; this.writeScreen = this.displayedMemory; this.mode = null; this.cueStartTime = null; this.lastCueEndTime = null; }, getHandler: function getHandler() { return this.outputFilter; }, setHandler: function setHandler(newHandler) { this.outputFilter = newHandler; }, setPAC: function setPAC(pacData) { this.writeScreen.setPAC(pacData); }, setBkgData: function setBkgData(bkgData) { this.writeScreen.setBkgData(bkgData); }, setMode: function setMode(newMode) { if (newMode === this.mode) { return; } this.mode = newMode; logger.log("INFO", "MODE=" + newMode); if (this.mode == "MODE_POP-ON") { this.writeScreen = this.nonDisplayedMemory; } else { this.writeScreen = this.displayedMemory; this.writeScreen.reset(); } if (this.mode !== "MODE_ROLL-UP") { this.displayedMemory.nrRollUpRows = null; this.nonDisplayedMemory.nrRollUpRows = null; } this.mode = newMode; }, insertChars: function insertChars(chars) { for (var i = 0; i < chars.length; i++) { this.writeScreen.insertChar(chars[i]); } var screen = this.writeScreen === this.displayedMemory ? "DISP" : "NON_DISP"; logger.log("INFO", screen + ": " + this.writeScreen.getDisplayText(true)); if (this.mode === "MODE_PAINT-ON" || this.mode === "MODE_ROLL-UP") { logger.log("TEXT", "DISPLAYED: " + this.displayedMemory.getDisplayText(true)); this.outputDataUpdate(); } }, cc_RCL: function cc_RCL() { // Resume Caption Loading (switch mode to Pop On) logger.log("INFO", "RCL - Resume Caption Loading"); this.setMode("MODE_POP-ON"); }, cc_BS: function cc_BS() { // BackSpace logger.log("INFO", "BS - BackSpace"); if (this.mode === "MODE_TEXT") { return; } this.writeScreen.backSpace(); if (this.writeScreen === this.displayedMemory) { this.outputDataUpdate(); } }, cc_AOF: function cc_AOF() { // Reserved (formerly Alarm Off) return; }, cc_AON: function cc_AON() { // Reserved (formerly Alarm On) return; }, cc_DER: function cc_DER() { // Delete to End of Row logger.log("INFO", "DER- Delete to End of Row"); this.writeScreen.clearToEndOfRow(); this.outputDataUpdate(); }, cc_RU: function cc_RU(nrRows) { //Roll-Up Captions-2,3,or 4 Rows logger.log("INFO", "RU(" + nrRows + ") - Roll Up"); this.writeScreen = this.displayedMemory; this.setMode("MODE_ROLL-UP"); this.writeScreen.setRollUpRows(nrRows); }, cc_FON: function cc_FON() { //Flash On logger.log("INFO", "FON - Flash On"); this.writeScreen.setPen({ flash: true }); }, cc_RDC: function cc_RDC() { // Resume Direct Captioning (switch mode to PaintOn) logger.log("INFO", "RDC - Resume Direct Captioning"); this.setMode("MODE_PAINT-ON"); }, cc_TR: function cc_TR() { // Text Restart in text mode (not supported, however) logger.log("INFO", "TR"); this.setMode("MODE_TEXT"); }, cc_RTD: function cc_RTD() { // Resume Text Display in Text mode (not supported, however) logger.log("INFO", "RTD"); this.setMode("MODE_TEXT"); }, cc_EDM: function cc_EDM() { // Erase Displayed Memory logger.log("INFO", "EDM - Erase Displayed Memory"); this.displayedMemory.reset(); this.outputDataUpdate(); }, cc_CR: function cc_CR() { // Carriage Return logger.log("CR - Carriage Return"); this.writeScreen.rollUp(); this.outputDataUpdate(); }, cc_ENM: function cc_ENM() { //Erase Non-Displayed Memory logger.log("INFO", "ENM - Erase Non-displayed Memory"); this.nonDisplayedMemory.reset(); }, cc_EOC: function cc_EOC() { //End of Caption (Flip Memories) logger.log("INFO", "EOC - End Of Caption"); if (this.mode === "MODE_POP-ON") { var tmp = this.displayedMemory; this.displayedMemory = this.nonDisplayedMemory; this.nonDisplayedMemory = tmp; this.writeScreen = this.nonDisplayedMemory; logger.log("TEXT", "DISP: " + this.displayedMemory.getDisplayText()); } this.outputDataUpdate(); }, cc_TO: function cc_TO(nrCols) { // Tab Offset 1,2, or 3 columns logger.log("INFO", "TO(" + nrCols + ") - Tab Offset"); this.writeScreen.moveCursor(nrCols); }, cc_MIDROW: function cc_MIDROW(secondByte) { // Parse MIDROW command var styles = { flash: false }; styles.underline = secondByte % 2 === 1; styles.italics = secondByte >= 0x2e; if (!styles.italics) { var colorIndex = Math.floor(secondByte / 2) - 0x10; var colors = ["white", "green", "blue", "cyan", "red", "yellow", "magenta"]; styles.foreground = colors[colorIndex]; } else { styles.foreground = "white"; } logger.log("INFO", "MIDROW: " + JSON.stringify(styles)); this.writeScreen.setPen(styles); }, outputDataUpdate: function outputDataUpdate() { var t = logger.time; if (t === null) { return; } if (this.outputFilter) { if (this.outputFilter.updateData) { this.outputFilter.updateData(t, this.displayedMemory); } if (this.cueStartTime === null && !this.displayedMemory.isEmpty()) { // Start of a new cue this.cueStartTime = t; } else { if (!this.displayedMemory.equals(this.lastOutputScreen)) { if (this.outputFilter.newCue) { this.outputFilter.newCue(this.cueStartTime, t, this.lastOutputScreen); } this.cueStartTime = this.displayedMemory.isEmpty() ? null : t; } } this.lastOutputScreen.copy(this.displayedMemory); } }, cueSplitAtTime: function cueSplitAtTime(t) { if (this.outputFilter) { if (!this.displayedMemory.isEmpty()) { if (this.outputFilter.newCue) { this.outputFilter.newCue(this.cueStartTime, t, this.displayedMemory); } this.cueStartTime = t; } } } }; /** * Parse CEA-608 data and send decoded data to out1 and out2. * @constructor * @param {Number} field CEA-608 field (1 or 2) * @param {CueHandler} out1 Output from channel1 newCue(startTime, endTime, captionScreen) * @param {CueHandler} out2 Output from channel2 newCue(startTime, endTime, captionScreen) */ var Cea608Parser = function Cea608Parser(field, out1, out2) { this.field = field || 1; this.outputs = [out1, out2]; this.channels = [new Cea608Channel(1, out1), new Cea608Channel(2, out2)]; this.currChNr = -1; // Will be 1 or 2 this.lastCmdA = null; // First byte of last command this.lastCmdB = null; // Second byte of last command this.bufferedData = []; this.startTime = null; this.lastTime = null; this.dataCounters = { 'padding': 0, 'char': 0, 'cmd': 0, 'other': 0 }; }; Cea608Parser.prototype = { getHandler: function getHandler(index) { return this.channels[index].getHandler(); }, setHandler: function setHandler(index, newHandler) { this.channels[index].setHandler(newHandler); }, /** * Add data for time t in forms of list of bytes (unsigned ints). The bytes are treated as pairs. */ addData: function addData(t, byteList) { var cmdFound, a, b, charsFound = false; this.lastTime = t; logger.setTime(t); for (var i = 0; i < byteList.length; i += 2) { a = byteList[i] & 0x7f; b = byteList[i + 1] & 0x7f; if (a >= 0x10 && a <= 0x1f && a === this.lastCmdA && b === this.lastCmdB) { this.lastCmdA = null; this.lastCmdB = null; logger.log("DEBUG", "Repeated command (" + numArrayToHexArray([a, b]) + ") is dropped"); continue; // Repeated commands are dropped (once) } if (a === 0 && b === 0) { this.dataCounters.padding += 2; continue; } else { logger.log("DATA", "[" + numArrayToHexArray([byteList[i], byteList[i + 1]]) + "] -> (" + numArrayToHexArray([a, b]) + ")"); } cmdFound = this.parseCmd(a, b); if (!cmdFound) { cmdFound = this.parseMidrow(a, b); } if (!cmdFound) { cmdFound = this.parsePAC(a, b); } if (!cmdFound) { cmdFound = this.parseBackgroundAttributes(a, b); } if (!cmdFound) { charsFound = this.parseChars(a, b); if (charsFound) { if (this.currChNr && this.currChNr >= 0) { var channel = this.channels[this.currChNr - 1]; channel.insertChars(charsFound); } else { logger.log("WARNING", "No channel found yet. TEXT-MODE?"); } } } if (cmdFound) { this.dataCounters.cmd += 2; } else if (charsFound) { this.dataCounters["char"] += 2; } else { this.dataCounters.other += 2; logger.log("WARNING", "Couldn't parse cleaned data " + numArrayToHexArray([a, b]) + " orig: " + numArrayToHexArray([byteList[i], byteList[i + 1]])); } } }, /** * Parse Command. * @returns {Boolean} Tells if a command was found */ parseCmd: function parseCmd(a, b) { var chNr = null; var cond1 = (a === 0x14 || a === 0x15 || a === 0x1C || a === 0x1D) && 0x20 <= b && b <= 0x2F; var cond2 = (a === 0x17 || a === 0x1F) && 0x21 <= b && b <= 0x23; if (!(cond1 || cond2)) { return false; } if (a === 0x14 || a === 0x15 || a === 0x17) { chNr = 1; } else { chNr = 2; // (a === 0x1C || a === 0x1D || a=== 0x1f) } var channel = this.channels[chNr - 1]; if (a === 0x14 || a === 0x15 || a === 0x1C || a === 0x1D) { if (b === 0x20) { channel.cc_RCL(); } else if (b === 0x21) { channel.cc_BS(); } else if (b === 0x22) { channel.cc_AOF(); } else if (b === 0x23) { channel.cc_AON(); } else if (b === 0x24) { channel.cc_DER(); } else if (b === 0x25) { channel.cc_RU(2); } else if (b === 0x26) { channel.cc_RU(3); } else if (b === 0x27) { channel.cc_RU(4); } else if (b === 0x28) { channel.cc_FON(); } else if (b === 0x29) { channel.cc_RDC(); } else if (b === 0x2A) { channel.cc_TR(); } else if (b === 0x2B) { channel.cc_RTD(); } else if (b === 0x2C) { channel.cc_EDM(); } else if (b === 0x2D) { channel.cc_CR(); } else if (b === 0x2E) { channel.cc_ENM(); } else if (b === 0x2F) { channel.cc_EOC(); } } else { //a == 0x17 || a == 0x1F channel.cc_TO(b - 0x20); } this.lastCmdA = a; this.lastCmdB = b; this.currChNr = chNr; return true; }, /** * Parse midrow styling command * @returns {Boolean} */ parseMidrow: function parseMidrow(a, b) { var chNr = null; if ((a === 0x11 || a === 0x19) && 0x20 <= b && b <= 0x2f) { if (a === 0x11) { chNr = 1; } else { chNr = 2; } if (chNr !== this.currChNr) { logger.log("ERROR", "Mismatch channel in midrow parsing"); return false; } var channel = this.channels[chNr - 1]; // cea608 spec says midrow codes should inject a space channel.insertChars([0x20]); channel.cc_MIDROW(b); logger.log("DEBUG", "MIDROW (" + numArrayToHexArray([a, b]) + ")"); this.lastCmdA = a; this.lastCmdB = b; return true; } return false; }, /** * Parse Preable Access Codes (Table 53). * @returns {Boolean} Tells if PAC found */ parsePAC: function parsePAC(a, b) { var chNr = null; var row = null; var case1 = (0x11 <= a && a <= 0x17 || 0x19 <= a && a <= 0x1F) && 0x40 <= b && b <= 0x7F; var case2 = (a === 0x10 || a === 0x18) && 0x40 <= b && b <= 0x5F; if (!(case1 || case2)) { return false; } chNr = a <= 0x17 ? 1 : 2; if (0x40 <= b && b <= 0x5F) { row = chNr === 1 ? rowsLowCh1[a] : rowsLowCh2[a]; } else { // 0x60 <= b <= 0x7F row = chNr === 1 ? rowsHighCh1[a] : rowsHighCh2[a]; } var pacData = this.interpretPAC(row, b); var channel = this.channels[chNr - 1]; channel.setPAC(pacData); this.lastCmdA = a; this.lastCmdB = b; this.currChNr = chNr; return true; }, /** * Interpret the second byte of the pac, and return the information. * @returns {Object} pacData with style parameters. */ interpretPAC: function interpretPAC(row, _byte3) { var pacIndex = _byte3; var pacData = { color: null, italics: false, indent: null, underline: false, row: row }; if (_byte3 > 0x5F) { pacIndex = _byte3 - 0x60; } else { pacIndex = _byte3 - 0x40; } pacData.underline = (pacIndex & 1) === 1; if (pacIndex <= 0xd) { pacData.color = ['white', 'green', 'blue', 'cyan', 'red', 'yellow', 'magenta', 'white'][Math.floor(pacIndex / 2)]; } else if (pacIndex <= 0xf) { pacData.italics = true; pacData.color = 'white'; } else { pacData.indent = Math.floor((pacIndex - 0x10) / 2) * 4; } return pacData; // Note that row has zero offset. The spec uses 1. }, /** * Parse characters. * @returns An array with 1 to 2 codes corresponding to chars, if found. null otherwise. */ parseChars: function parseChars(a, b) { var channelNr = null, charCodes = null, charCode1 = null; if (a >= 0x19) { channelNr = 2; charCode1 = a - 8; } else { channelNr = 1; charCode1 = a; } if (0x11 <= charCode1 && charCode1 <= 0x13) { // Special character var oneCode = b; if (charCode1 === 0x11) { oneCode = b + 0x50; } else if (charCode1 === 0x12) { oneCode = b + 0x70; } else { oneCode = b + 0x90; } logger.log("INFO", "Special char '" + getCharForByte(oneCode) + "' in channel " + channelNr); charCodes = [oneCode]; this.lastCmdA = a; this.lastCmdB = b; } else if (0x20 <= a && a <= 0x7f) { charCodes = b === 0 ? [a] : [a, b]; this.lastCmdA = null; this.lastCmdB = null; } if (charCodes) { var hexCodes = numArrayToHexArray(charCodes); logger.log("DEBUG", "Char codes = " + hexCodes.join(",")); } return charCodes; }, /** * Parse extended background attributes as well as new foreground color black. * @returns{Boolean} Tells if background attributes are found */ parseBackgroundAttributes: function parseBackgroundAttributes(a, b) { var bkgData, index, chNr, channel; var case1 = (a === 0x10 || a === 0x18) && 0x20 <= b && b <= 0x2f; var case2 = (a === 0x17 || a === 0x1f) && 0x2d <= b && b <= 0x2f; if (!(case1 || case2)) { return false; } bkgData = {}; if (a === 0x10 || a === 0x18) { index = Math.floor((b - 0x20) / 2); bkgData.background = backgroundColors[index]; if (b % 2 === 1) { bkgData.background = bkgData.background + "_semi"; } } else if (b === 0x2d) { bkgData.background = "transparent"; } else { bkgData.foreground = "black"; if (b === 0x2f) { bkgData.underline = true; } } chNr = a < 0x18 ? 1 : 2; channel = this.channels[chNr - 1]; channel.setBkgData(bkgData); this.lastCmdA = a; this.lastCmdB = b; return true; }, /** * Reset state of parser and its channels. */ reset: function reset() { for (var i = 0; i < this.channels.length; i++) { if (this.channels[i]) { this.channels[i].reset(); } } this.lastCmdA = null; this.lastCmdB = null; }, /** * Trigger the generation of a cue, and the start of a new one if displayScreens are not empty. */ cueSplitAtTime: function cueSplitAtTime(t) { for (var i = 0; i < this.channels.length; i++) { if (this.channels[i]) { this.channels[i].cueSplitAtTime(t); } } } }; /** * Find ranges corresponding to SEA CEA-608 NALUS in sizeprepended NALU array. * @param {raw} dataView of binary data * @param {startPos} start position in raw * @param {size} total size of data in raw to consider * @returns */ var findCea608Nalus = function findCea608Nalus(raw, startPos, size) { var nalSize = 0, cursor = startPos, nalType = 0, cea608NaluRanges = [], // Check SEI data according to ANSI-SCTE 128 isCEA608SEI = function isCEA608SEI(payloadType, payloadSize, raw, pos) { if (payloadType !== 4 || payloadSize < 8) { return null; } var countryCode = raw.getUint8(pos); var providerCode = raw.getUint16(pos + 1); var userIdentifier = raw.getUint32(pos + 3); var userDataTypeCode = raw.getUint8(pos + 7); return countryCode == 0xB5 && providerCode == 0x31 &&