UNPKG

shaka-player

Version:
374 lines (330 loc) 9.45 kB
/*! @license * Shaka Player * Copyright 2016 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.cea.Cea608Memory'); goog.require('shaka.cea.CeaUtils'); goog.require('shaka.text.Cue'); /** * CEA-608 captions memory/buffer. */ shaka.cea.Cea608Memory = class { /** * @param {number} fieldNum Field number. * @param {number} channelNum Channel number. */ constructor(fieldNum, channelNum) { /** * Buffer for storing decoded characters. * @private @const {!Array<!Array<!shaka.cea.CeaUtils.StyledChar>>} */ this.rows_ = []; /** * Current row. * @private {number} */ this.row_ = 1; /** * Number of rows in the scroll window. Used for rollup mode. * @private {number} */ this.scrollRows_ = 0; /** * Field number. * @private {number} */ this.fieldNum_ = fieldNum; /** * Channel number. * @private {number} */ this.channelNum_ = channelNum; /** * @private {boolean} */ this.underline_ = false; /** * @private {boolean} */ this.italics_ = false; /** * @private {string} */ this.textColor_ = shaka.cea.CeaUtils.DEFAULT_TXT_COLOR; /** * @private {string} */ this.backgroundColor_ = shaka.cea.CeaUtils.DEFAULT_BG_COLOR; /** * @private {?number} */ this.offset_ = null; /** * @private {?number} */ this.indent_ = null; this.reset(); } /** * Emits a closed caption based on the state of the buffer. * @param {number} startTime Start time of the cue. * @param {number} endTime End time of the cue. * @return {?shaka.extern.ICaptionDecoder.ClosedCaption} */ forceEmit(startTime, endTime) { const Cea608Memory = shaka.cea.Cea608Memory; const stream = `CC${((this.fieldNum_<< 1) | this.channelNum_) + 1}`; const topLevelCue = new shaka.text.Cue( startTime, endTime, /* payload= */ ''); topLevelCue.lineInterpretation = shaka.text.Cue.lineInterpretation.PERCENTAGE; let line = Cea608Memory.ROW_TO_LINE_CONVERSION_.get(this.row_); if (line) { topLevelCue.line = line; } if (this.indent_ != null && this.offset_ != null) { topLevelCue.position = 10 + Math.min(70, this.indent_ * 10) + this.offset_ * 2.5; } const ret = shaka.cea.CeaUtils.getParsedCaption( topLevelCue, stream, this.rows_, startTime, endTime); // If the text and its lines are larger than what we can show on the // screen, we move the lines up so that the text does not come out of the // video. if (ret && (this.row_ + ret.cue.nestedCues.length - 3) > 15) { const newLinePosition = this.row_ + 3 - ret.cue.nestedCues.length; line = Cea608Memory.ROW_TO_LINE_CONVERSION_.get(newLinePosition); if (line) { topLevelCue.line = line; } } return ret; } /** * Resets the memory buffer. */ reset() { this.resetAllRows(); this.row_ = 1; } /** * @return {number} */ getRow() { return this.row_; } /** * @param {number} row */ setRow(row) { this.row_ = row; } /** * @return {number} */ getScrollSize() { return this.scrollRows_; } /** * @param {number} scrollRows */ setScrollSize(scrollRows) { this.scrollRows_ = scrollRows; } /** * Adds a character to the buffer. * @param {!shaka.cea.Cea608Memory.CharSet} set Character set. * @param {number} b CC byte to add. */ addChar(set, b) { // Valid chars are in the range [0x20, 0x7f] if (b < 0x20 || b > 0x7f) { return; } let char = ''; switch (set) { case shaka.cea.Cea608Memory.CharSet.BASIC_NORTH_AMERICAN: if (shaka.cea.Cea608Memory.CharSet.BasicNorthAmericanChars.has(b)) { char = shaka.cea.Cea608Memory.CharSet.BasicNorthAmericanChars.get(b); } else { // Regular ASCII char = String.fromCharCode(b); } break; case shaka.cea.Cea608Memory.CharSet.SPECIAL_NORTH_AMERICAN: char = shaka.cea.Cea608Memory.CharSet.SpecialNorthAmericanChars.get(b); break; case shaka.cea.Cea608Memory.CharSet.SPANISH_FRENCH: // Extended charset does a BS over preceding char, 6.4.2 EIA-608-B. this.eraseChar(); char = shaka.cea.Cea608Memory.CharSet.ExtendedSpanishFrench.get(b); break; case shaka.cea.Cea608Memory.CharSet.PORTUGUESE_GERMAN: this.eraseChar(); char = shaka.cea.Cea608Memory.CharSet.ExtendedPortugueseGerman.get(b); break; } if (char) { const styledChar = new shaka.cea.CeaUtils.StyledChar( char, this.underline_, this.italics_, this.backgroundColor_, this.textColor_); this.rows_[this.row_].push(styledChar); } } /** * Erases a character from the buffer. */ eraseChar() { this.rows_[this.row_].pop(); } /** * Moves rows of characters. * @param {number} dst Destination row index. * @param {number} src Source row index. * @param {number} count Count of rows to move. */ moveRows(dst, src, count) { if (src < 0 || dst < 0) { return; } if (dst >= src) { for (let i = count-1; i >= 0; i--) { this.rows_[dst + i] = this.rows_[src + i].map((e) => e); } } else { for (let i = 0; i < count; i++) { this.rows_[dst + i] = this.rows_[src + i].map((e) => e); } } } /** * Resets rows of characters. * @param {number} idx Starting index. * @param {number} count Count of rows to reset. */ resetRows(idx, count) { for (let i = 0; i <= count; i++) { this.rows_[idx + i] = []; } } /** * Resets the entire memory buffer. */ resetAllRows() { this.resetRows(0, shaka.cea.Cea608Memory.CC_ROWS); } /** * Erases entire memory buffer. * Doesn't change scroll state or number of rows. */ eraseBuffer() { this.row_ = (this.scrollRows_ > 0) ? this.scrollRows_ : 0; this.resetAllRows(); } /** * @param {boolean} underline */ setUnderline(underline) { this.underline_ = underline; } /** * @param {boolean} italics */ setItalics(italics) { this.italics_ = italics; } /** * @param {string} color */ setTextColor(color) { this.textColor_ = color; } /** * @param {string} color */ setBackgroundColor(color) { this.backgroundColor_ = color; } /** * @param {number} offset */ setOffset(offset) { this.offset_ = offset; } /** * @param {?number} indent */ setIndent(indent) { this.indent_ = indent; } }; /** * Maximum number of rows in the buffer. * @const {number} */ shaka.cea.Cea608Memory.CC_ROWS = 15; /** * Characters sets. * @const @enum {number} */ shaka.cea.Cea608Memory.CharSet = { BASIC_NORTH_AMERICAN: 0, SPECIAL_NORTH_AMERICAN: 1, SPANISH_FRENCH: 2, PORTUGUESE_GERMAN: 3, }; /** * Basic North American char set deviates from ASCII with these exceptions. * @private @const {!Map<number, string>} */ shaka.cea.Cea608Memory.CharSet.BasicNorthAmericanChars = new Map([ [0x27, '’'], [0x2a, 'á'], [0x5c, 'é'], [0x5c, 'é'], [0x5e, 'í'], [0x5f, 'ó'], [0x60, 'ú'], [0x7b, 'ç'], [0x7c, '÷'], [0x7d, 'Ñ'], [0x7e, 'ñ'], [0x7f, '█'], ]); /** * Special North American char set. * Note: Transparent Space is currently implemented as a regular space. * @private @const {!Map<number, string>} */ shaka.cea.Cea608Memory.CharSet.SpecialNorthAmericanChars = new Map([ [0x30, '®'], [0x31, '°'], [0x32, '½'], [0x33, '¿'], [0x34, '™'], [0x35, '¢'], [0x36, '£'], [0x37, '♪'], [0x38, 'à'], [0x39, ' '], [0x3a, 'è'], [0x3b, 'â'], [0x3c, 'ê'], [0x3d, 'î'], [0x3e, 'ô'], [0x3f, 'û'], ]); /** * Extended Spanish/Misc/French char set. * @private @const {!Map<number, string>} */ shaka.cea.Cea608Memory.CharSet.ExtendedSpanishFrench = new Map([ [0x20, 'Á'], [0x21, 'É'], [0x22, 'Ó'], [0x23, 'Ú'], [0x24, 'Ü'], [0x25, 'ü'], [0x26, '‘'], [0x27, '¡'], [0x28, '*'], [0x29, '\''], [0x2a, '─'], [0x2b, '©'], [0x2c, '℠'], [0x2d, '·'], [0x2e, '“'], [0x2f, '”'], [0x30, 'À'], [0x31, 'Â'], [0x32, 'Ç'], [0x33, 'È'], [0x34, 'Ê'], [0x35, 'Ë'], [0x36, 'ë'], [0x37, 'Î'], [0x38, 'Ï'], [0x39, 'ï'], [0x3a, 'Ô'], [0x3b, 'Ù'], [0x3c, 'ù'], [0x3d, 'Û'], [0x3e, '«'], [0x3f, '»'], ]); /** * Extended Portuguese/German/Danish char set. * @private @const {!Map<number, string>} */ shaka.cea.Cea608Memory.CharSet.ExtendedPortugueseGerman = new Map([ [0x20, 'Ã'], [0x21, 'ã'], [0x22, 'Í'], [0x23, 'Ì'], [0x24, 'ì'], [0x25, 'Ò'], [0x26, 'ò'], [0x27, 'Õ'], [0x28, 'õ'], [0x29, '{'], [0x2a, '}'], [0x2b, '\\'], [0x2c, '^'], [0x2d, '_'], [0x2e, '|'], [0x2f, '~'], [0x30, 'Ä'], [0x31, 'ä'], [0x32, 'Ö'], [0x33, 'ö'], [0x34, 'ß'], [0x35, '¥'], [0x36, '¤'], [0x37, '│'], [0x38, 'Å'], [0x39, 'å'], [0x3a, 'Ø'], [0x3b, 'ø'], [0x3c, '┌'], [0x3d, '┐'], [0x3e, '└'], [0x3f, '┘'], ]); /** * @private @const {!Map<number, number>} */ shaka.cea.Cea608Memory.ROW_TO_LINE_CONVERSION_ = new Map([ [1, 10], [2, 15.33], [3, 20.66], [4, 26], [5, 31.33], [6, 36.66], [7, 42], [8, 47.33], [9, 52.66], [10, 58], [11, 63.33], [12, 68.66], [13, 74], [14, 79.33], [15, 84.66], ]);