Files
shaka-player/lib/cea/cea608_memory.js
T

374 lines
9.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*! @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],
]);