Source: lib/cea/cea608_data_channel.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.cea.Cea608DataChannel');
  7. goog.require('shaka.cea.Cea608Memory');
  8. goog.require('shaka.cea.CeaUtils');
  9. goog.require('shaka.log');
  10. /**
  11. * 608 closed captions channel.
  12. */
  13. shaka.cea.Cea608DataChannel = class {
  14. /**
  15. * @param {number} fieldNum Field number.
  16. * @param {number} channelNum Channel number.
  17. */
  18. constructor(fieldNum, channelNum) {
  19. /**
  20. * Current Caption Type.
  21. * @public {!shaka.cea.Cea608DataChannel.CaptionType}
  22. */
  23. this.type_ = shaka.cea.Cea608DataChannel.CaptionType.NONE;
  24. /**
  25. * Text buffer for CEA-608 "text mode". Although, we don't emit text mode.
  26. * So, this buffer serves as a no-op placeholder, just in case we receive
  27. * captions that toggle text mode.
  28. * @private @const {!shaka.cea.Cea608Memory}
  29. */
  30. this.text_ =
  31. new shaka.cea.Cea608Memory(fieldNum, channelNum);
  32. /**
  33. * Displayed memory.
  34. * @private {!shaka.cea.Cea608Memory}
  35. */
  36. this.displayedMemory_ =
  37. new shaka.cea.Cea608Memory(fieldNum, channelNum);
  38. /**
  39. * Non-displayed memory.
  40. * @private {!shaka.cea.Cea608Memory}
  41. */
  42. this.nonDisplayedMemory_ =
  43. new shaka.cea.Cea608Memory(fieldNum, channelNum);
  44. /**
  45. * Points to current buffer.
  46. * @private {!shaka.cea.Cea608Memory}
  47. */
  48. this.curbuf_ = this.nonDisplayedMemory_;
  49. /**
  50. * End time of the previous caption, serves as start time of next caption.
  51. * @private {number}
  52. */
  53. this.prevEndTime_ = 0;
  54. /**
  55. * Last control pair, 16 bits representing byte 1 and byte 2
  56. * @private {?number}
  57. */
  58. this.lastcp_ = null;
  59. }
  60. /**
  61. * Resets channel state.
  62. */
  63. reset() {
  64. this.type_ = shaka.cea.Cea608DataChannel.CaptionType.NONE;
  65. this.curbuf_ = this.nonDisplayedMemory_;
  66. this.lastcp_ = null;
  67. this.displayedMemory_.reset();
  68. this.nonDisplayedMemory_.reset();
  69. this.text_.reset();
  70. }
  71. /**
  72. * Set the initial PTS, which may not be 0 if we start decoding at a later
  73. * point in the stream. Without this, the first cue's startTime can be way
  74. * off.
  75. *
  76. * @param {number} pts
  77. */
  78. firstPts(pts) {
  79. this.prevEndTime_ = pts;
  80. }
  81. /**
  82. * Gets the row index from a Preamble Address Code byte pair.
  83. * @param {number} b1 Byte 1.
  84. * @param {number} b2 Byte 2.
  85. * @return {number} Row index.
  86. * @private
  87. */
  88. pacToRow_(b1, b2) {
  89. const ccrowtab = [
  90. 11, 11, // 0x00 or 0x01
  91. 1, 2, // 0x02 -> 0x03
  92. 3, 4, // 0x04 -> 0x05
  93. 12, 13, // 0x06 -> 0x07
  94. 14, 15, // 0x08 -> 0x09
  95. 5, 6, // 0x0A -> 0x0B
  96. 7, 8, // 0x0C -> 0x0D
  97. 9, 10, // 0x0E -> 0x0F
  98. ];
  99. return ccrowtab[((b1 & 0x07) << 1) | ((b2 >> 5) & 0x01)];
  100. }
  101. /**
  102. * PAC - Preamble Address Code.
  103. * b1 is of the form |P|0|0|1|C|0|ROW|
  104. * b2 is of the form |P|1|N|ATTRIBUTE|U|
  105. * @param {number} b1 Byte 1.
  106. * @param {number} b2 Byte 2.
  107. * @private
  108. */
  109. controlPac_(b1, b2) {
  110. const row = this.pacToRow_(b1, b2);
  111. // Get attribute bits (4 bits)
  112. const attr = (b2 & 0x1E) >> 1;
  113. // Set up the defaults.
  114. let textColor = shaka.cea.CeaUtils.DEFAULT_TXT_COLOR;
  115. let italics = false;
  116. // Attributes < 7 are colors, = 7 is white w/ italics, and >7 are indents
  117. if (attr < 7) {
  118. textColor = shaka.cea.Cea608DataChannel.TEXT_COLORS[attr];
  119. } else if (attr === 7) {
  120. italics = true; // color stays white
  121. }
  122. // PACs toggle underline on the last bit of b2.
  123. const underline = (b2 & 0x01) === 0x01;
  124. if (this.type_ === shaka.cea.Cea608DataChannel.CaptionType.TEXT) {
  125. // Don't execute the PAC if in text mode.
  126. return;
  127. }
  128. // Execute the PAC.
  129. const buf = this.curbuf_;
  130. // Move entire scroll window to a new base in rollup mode.
  131. if (this.type_ === shaka.cea.Cea608DataChannel.CaptionType.ROLLUP &&
  132. row !== buf.getRow()) {
  133. const oldTopRow = 1 + buf.getRow() - buf.getScrollSize();
  134. const newTopRow = 1 + row - buf.getScrollSize();
  135. // Shift up the scroll window.
  136. buf.moveRows(newTopRow, oldTopRow, buf.getScrollSize());
  137. // Clear everything outside of the new scroll window.
  138. buf.resetRows(0, newTopRow - 1);
  139. buf.resetRows(row + 1,
  140. shaka.cea.Cea608Memory.CC_ROWS - row);
  141. }
  142. buf.setRow(row);
  143. buf.setUnderline(underline);
  144. buf.setItalics(italics);
  145. buf.setTextColor(textColor);
  146. // Clear the background color, since new row (PAC) should reset ALL styles.
  147. buf.setBackgroundColor(shaka.cea.CeaUtils.DEFAULT_BG_COLOR);
  148. }
  149. /**
  150. * Mid-Row control code handler.
  151. * @param {number} b2 Byte #2.
  152. * @private
  153. */
  154. controlMidrow_(b2) {
  155. // Clear all pre-existing midrow style attributes.
  156. this.curbuf_.setUnderline(false);
  157. this.curbuf_.setItalics(false);
  158. this.curbuf_.setTextColor(shaka.cea.CeaUtils.DEFAULT_TXT_COLOR);
  159. // Mid-row attrs use a space.
  160. this.curbuf_.addChar(
  161. shaka.cea.Cea608Memory.CharSet.BASIC_NORTH_AMERICAN, ' '.charCodeAt(0));
  162. let textColor = shaka.cea.CeaUtils.DEFAULT_TXT_COLOR;
  163. let italics = false;
  164. // Midrow codes set underline on last (LSB) bit.
  165. const underline = (b2 & 0x01) === 0x01;
  166. // b2 has the form |P|0|1|0|STYLE|U|
  167. textColor = shaka.cea.Cea608DataChannel.TEXT_COLORS[(b2 & 0xe) >> 1];
  168. if (textColor === 'white_italics') {
  169. textColor = 'white';
  170. italics = true;
  171. }
  172. this.curbuf_.setUnderline(underline);
  173. this.curbuf_.setItalics(italics);
  174. this.curbuf_.setTextColor(textColor);
  175. }
  176. /**
  177. * Background attribute control code handler.
  178. * @param {number} b1 Byte #1
  179. * @param {number} b2 Byte #2.
  180. * @private
  181. */
  182. controlBackgroundAttribute_(b1, b2) {
  183. let backgroundColor = shaka.cea.CeaUtils.DEFAULT_BG_COLOR;
  184. if ((b1 & 0x07) === 0x0) {
  185. // If background provided, last 3 bits of b1 are |0|0|0|. Color is in b2.
  186. backgroundColor = shaka.cea.Cea608DataChannel.BG_COLORS[(b2 & 0xe) >> 1];
  187. }
  188. this.curbuf_.setBackgroundColor(backgroundColor);
  189. }
  190. /**
  191. * The Cea608DataChannel control methods implement all CC control operations.
  192. * @param {!shaka.cea.Cea608DataChannel.Cea608Packet} ccPacket
  193. * @return {?shaka.extern.ICaptionDecoder.ClosedCaption}
  194. * @private
  195. */
  196. controlMiscellaneous_(ccPacket) {
  197. const MiscCmd = shaka.cea.Cea608DataChannel.MiscCmd_;
  198. const b2 = ccPacket.ccData2;
  199. const pts = ccPacket.pts;
  200. let parsedClosedCaption = null;
  201. switch (b2) {
  202. case MiscCmd.RCL:
  203. this.controlRcl_();
  204. break;
  205. case MiscCmd.BS:
  206. this.controlBs_();
  207. break;
  208. // unused (alarm off and alarm on)
  209. case MiscCmd.AOD:
  210. case MiscCmd.AON:
  211. break;
  212. case MiscCmd.DER:
  213. // Delete to End of Row. Not implemented since position not supported.
  214. break;
  215. case MiscCmd.RU2:
  216. parsedClosedCaption = this.controlRu_(2, pts);
  217. break;
  218. case MiscCmd.RU3:
  219. parsedClosedCaption = this.controlRu_(3, pts);
  220. break;
  221. case MiscCmd.RU4:
  222. parsedClosedCaption = this.controlRu_(4, pts);
  223. break;
  224. case MiscCmd.FON:
  225. this.controlFon_();
  226. break;
  227. case MiscCmd.RDC:
  228. this.controlRdc_(pts);
  229. break;
  230. case MiscCmd.TR:
  231. this.controlTr_();
  232. break;
  233. case MiscCmd.RTD:
  234. this.controlRtd_();
  235. break;
  236. case MiscCmd.EDM:
  237. parsedClosedCaption = this.controlEdm_(pts);
  238. break;
  239. case MiscCmd.CR:
  240. parsedClosedCaption = this.controlCr_(pts);
  241. break;
  242. case MiscCmd.ENM:
  243. this.controlEnm_();
  244. break;
  245. case MiscCmd.EOC:
  246. parsedClosedCaption = this.controlEoc_(pts);
  247. break;
  248. }
  249. return parsedClosedCaption;
  250. }
  251. /**
  252. * Handles CR - Carriage Return (Start new row).
  253. * CR only affects scroll windows (Rollup and Text modes).
  254. * Any currently buffered line needs to be emitted, along
  255. * with a window scroll action.
  256. * @param {number} pts in seconds.
  257. * @return {?shaka.extern.ICaptionDecoder.ClosedCaption}
  258. * @private
  259. */
  260. controlCr_(pts) {
  261. const buf = this.curbuf_;
  262. // Only rollup and text mode is affected, but we don't emit text mode.
  263. if (this.type_ !== shaka.cea.Cea608DataChannel.CaptionType.ROLLUP) {
  264. return null;
  265. }
  266. // Force out the scroll window since the top row will cleared.
  267. const parsedClosedCaption = buf.forceEmit(this.prevEndTime_, pts);
  268. // Calculate the top of the scroll window.
  269. const toprow = (buf.getRow() - buf.getScrollSize()) + 1;
  270. // Shift up the window one row higher.
  271. buf.moveRows(toprow - 1, toprow, buf.getScrollSize());
  272. // Clear out anything that's outside of our current scroll window.
  273. buf.resetRows(0, toprow - 1);
  274. buf.resetRows(buf.getRow(), shaka.cea.Cea608Memory.CC_ROWS - buf.getRow());
  275. // Update the end time so the next caption emits starting at this time.
  276. this.prevEndTime_ = pts;
  277. return parsedClosedCaption;
  278. }
  279. /**
  280. * Handles RU2, RU3, RU4 - Roll-Up, N rows.
  281. * If in TEXT, POPON or PAINTON, any displayed captions are erased.
  282. * This means must force emit entire display buffer.
  283. * @param {number} scrollSize New scroll window size.
  284. * @param {number} pts
  285. * @return {?shaka.extern.ICaptionDecoder.ClosedCaption}
  286. * @private
  287. */
  288. controlRu_(scrollSize, pts) {
  289. this.curbuf_ = this.displayedMemory_; // Point to displayed memory
  290. const buf = this.curbuf_;
  291. let parsedClosedCaption = null;
  292. // For any type except rollup and text mode, it should be emitted,
  293. // and memories cleared.
  294. if (this.type_ !== shaka.cea.Cea608DataChannel.CaptionType.ROLLUP &&
  295. this.type_ !== shaka.cea.Cea608DataChannel.CaptionType.TEXT) {
  296. parsedClosedCaption = buf.forceEmit(this.prevEndTime_, pts);
  297. // Clear both memories.
  298. this.displayedMemory_.eraseBuffer();
  299. this.nonDisplayedMemory_.eraseBuffer();
  300. // Rollup base row defaults to the last row (15).
  301. buf.setRow(shaka.cea.Cea608Memory.CC_ROWS);
  302. }
  303. this.type_ = shaka.cea.Cea608DataChannel.CaptionType.ROLLUP;
  304. // Set the new rollup window size.
  305. buf.setScrollSize(scrollSize);
  306. return parsedClosedCaption;
  307. }
  308. /**
  309. * Handles flash on.
  310. * @private
  311. */
  312. controlFon_() {
  313. this.curbuf_.addChar(
  314. shaka.cea.Cea608Memory.CharSet.BASIC_NORTH_AMERICAN,
  315. ' '.charCodeAt(0));
  316. }
  317. /**
  318. * Handles EDM - Erase Displayed Mem
  319. * Mode check:
  320. * EDM affects all captioning modes (but not Text mode);
  321. * @param {number} pts
  322. * @return {?shaka.extern.ICaptionDecoder.ClosedCaption}
  323. * @private
  324. */
  325. controlEdm_(pts) {
  326. const buf = this.displayedMemory_;
  327. let parsedClosedCaption = null;
  328. if (this.type_ !== shaka.cea.Cea608DataChannel.CaptionType.TEXT) {
  329. // Clearing displayed memory means we now know how long
  330. // its contents were displayed, so force it out.
  331. parsedClosedCaption = buf.forceEmit(this.prevEndTime_, pts);
  332. }
  333. buf.resetAllRows();
  334. return parsedClosedCaption;
  335. }
  336. /**
  337. * Handles RDC - Resume Direct Captions. Initiates Paint-On captioning mode.
  338. * RDC does not affect current display, so nothing needs to be forced out yet.
  339. * @param {number} pts in seconds
  340. * @private
  341. */
  342. controlRdc_(pts) {
  343. this.type_ = shaka.cea.Cea608DataChannel.CaptionType.PAINTON;
  344. // Point to displayed memory.
  345. this.curbuf_ = this.displayedMemory_;
  346. // No scroll window now.
  347. this.curbuf_.setScrollSize(0);
  348. // The next paint-on caption needs this time as the start time.
  349. this.prevEndTime_ = pts;
  350. }
  351. /**
  352. * Handles ENM - Erase Nondisplayed Mem
  353. * @private
  354. */
  355. controlEnm_() {
  356. this.nonDisplayedMemory_.resetAllRows();
  357. }
  358. /**
  359. * Handles EOC - End Of Caption (flip mem)
  360. * This forces Pop-On mode, and swaps the displayed and nondisplayed memories.
  361. * @private
  362. * @param {number} pts
  363. * @return {?shaka.extern.ICaptionDecoder.ClosedCaption}
  364. */
  365. controlEoc_(pts) {
  366. let parsedClosedCaption = null;
  367. if (this.type_ !== shaka.cea.Cea608DataChannel.CaptionType.TEXT) {
  368. parsedClosedCaption =
  369. this.displayedMemory_.forceEmit(this.prevEndTime_, pts);
  370. }
  371. // Swap memories
  372. const buf = this.nonDisplayedMemory_;
  373. this.nonDisplayedMemory_ = this.displayedMemory_; // Swap buffers
  374. this.displayedMemory_ = buf;
  375. // Enter Pop-On mode.
  376. this.controlRcl_();
  377. // The caption ended, and so the previous end time should be updated.
  378. this.prevEndTime_ = pts;
  379. return parsedClosedCaption;
  380. }
  381. /**
  382. * Handles RCL - Resume Caption Loading
  383. * Initiates Pop-On style captioning. No need to force anything out upon
  384. * entering Pop-On mode because it does not affect the current display.
  385. * @private
  386. */
  387. controlRcl_() {
  388. this.type_ = shaka.cea.Cea608DataChannel.CaptionType.POPON;
  389. this.curbuf_ = this.nonDisplayedMemory_;
  390. // No scroll window now
  391. this.curbuf_.setScrollSize(0);
  392. }
  393. /**
  394. * Handles BS - BackSpace.
  395. * @private
  396. */
  397. controlBs_() {
  398. this.curbuf_.eraseChar();
  399. }
  400. /**
  401. * Handles TR - Text Restart.
  402. * Clears text buffer and resumes Text Mode.
  403. * @private
  404. */
  405. controlTr_() {
  406. this.text_.reset();
  407. this.controlRtd_(); // Put into text mode.
  408. }
  409. /**
  410. * Handles RTD - Resume Text Display.
  411. * Resumes text mode. No need to force anything out, because Text Mode doesn't
  412. * affect current display. Also, this decoder does not emit Text Mode anyway.
  413. * @private
  414. */
  415. controlRtd_() {
  416. shaka.log.warnOnce('Cea608DataChannel',
  417. 'CEA-608 text mode entered, but is unsupported');
  418. this.curbuf_ = this.text_;
  419. this.type_ = shaka.cea.Cea608DataChannel.CaptionType.TEXT;
  420. }
  421. /**
  422. * Handles a Basic North American byte pair.
  423. * @param {number} b1 Byte 1.
  424. * @param {number} b2 Byte 2.
  425. */
  426. handleBasicNorthAmericanChar(b1, b2) {
  427. this.curbuf_.addChar(
  428. shaka.cea.Cea608Memory.CharSet.BASIC_NORTH_AMERICAN, b1);
  429. this.curbuf_.addChar(
  430. shaka.cea.Cea608Memory.CharSet.BASIC_NORTH_AMERICAN, b2);
  431. }
  432. /**
  433. * Handles an Extended Western European byte pair.
  434. * @param {number} b1 Byte 1.
  435. * @param {number} b2 Byte 2.
  436. * @private
  437. */
  438. handleExtendedWesternEuropeanChar_(b1, b2) {
  439. // Get the char set from the LSB, which is the char set toggle bit.
  440. const charSet = b1 & 0x01 ?
  441. shaka.cea.Cea608Memory.CharSet.PORTUGUESE_GERMAN:
  442. shaka.cea.Cea608Memory.CharSet.SPANISH_FRENCH;
  443. this.curbuf_.addChar(charSet, b2);
  444. }
  445. /**
  446. * Decodes control code.
  447. * Three types of control codes:
  448. * Preamble Address Codes, Mid-Row Codes, and Miscellaneous Control Codes.
  449. * @param {!shaka.cea.Cea608DataChannel.Cea608Packet} ccPacket
  450. * @return {?shaka.extern.ICaptionDecoder.ClosedCaption}
  451. */
  452. handleControlCode(ccPacket) {
  453. const b1 = ccPacket.ccData1;
  454. const b2 = ccPacket.ccData2;
  455. // FCC wants control codes transmitted twice, and that will often be
  456. // seen in broadcast captures. If the very next frame has a duplicate
  457. // control code, that duplicate is ignored. Note that this only applies
  458. // to the very next frame, and only for one match.
  459. if (this.lastcp_ === ((b1 << 8) | b2)) {
  460. this.lastcp_ = null;
  461. return null;
  462. }
  463. // Remember valid control code for checking in next frame!
  464. this.lastcp_ = (b1 << 8) | b2;
  465. if (this.isPAC_(b1, b2)) {
  466. this.controlPac_(b1, b2);
  467. } else if (this.isMidrowStyleChange_(b1, b2)) {
  468. this.controlMidrow_(b2);
  469. } else if (this.isBackgroundAttribute_(b1, b2)) {
  470. this.controlBackgroundAttribute_(b1, b2);
  471. } else if (this.isSpecialNorthAmericanChar_(b1, b2)) {
  472. this.curbuf_.addChar(
  473. shaka.cea.Cea608Memory.CharSet.SPECIAL_NORTH_AMERICAN, b2);
  474. } else if (this.isExtendedWesternEuropeanChar_(b1, b2)) {
  475. this.handleExtendedWesternEuropeanChar_(b1, b2);
  476. } else if (this.isMiscellaneous_(b1, b2)) {
  477. return this.controlMiscellaneous_(ccPacket);
  478. }
  479. return null;
  480. }
  481. /**
  482. * Checks if this is a Miscellaneous control code.
  483. * @param {number} b1 Byte 1.
  484. * @param {number} b2 Byte 2.
  485. * @return {boolean}
  486. * @private
  487. */
  488. isMiscellaneous_(b1, b2) {
  489. // For Miscellaneous Control Codes, the bytes take the following form:
  490. // b1 -> |0|0|0|1|C|1|0|F|
  491. // b2 -> |0|0|1|0|X|X|X|X|
  492. return ((b1 & 0xf6) === 0x14) && ((b2 & 0xf0) === 0x20);
  493. }
  494. /**
  495. * Checks if this is a PAC control code.
  496. * @param {number} b1 Byte 1.
  497. * @param {number} b2 Byte 2.
  498. * @return {boolean}
  499. * @private
  500. */
  501. isPAC_(b1, b2) {
  502. // For Preamble Address Codes, the bytes take the following form:
  503. // b1 -> |0|0|0|1|X|X|X|X|
  504. // b2 -> |0|1|X|X|X|X|X|X|
  505. return ((b1 & 0xf0) === 0x10) && ((b2 & 0xc0) === 0x40);
  506. }
  507. /**
  508. * Checks if this is a Midrow style change control code.
  509. * @param {number} b1 Byte 1.
  510. * @param {number} b2 Byte 2.
  511. * @return {boolean}
  512. * @private
  513. */
  514. isMidrowStyleChange_(b1, b2) {
  515. // For Midrow Control Codes, the bytes take the following form:
  516. // b1 -> |0|0|0|1|C|0|0|1|
  517. // b2 -> |0|0|1|0|X|X|X|X|
  518. return ((b1 & 0xf7) === 0x11) && ((b2 & 0xf0) === 0x20);
  519. }
  520. /**
  521. * Checks if this is a background attribute control code.
  522. * @param {number} b1 Byte 1.
  523. * @param {number} b2 Byte 2.
  524. * @return {boolean}
  525. * @private
  526. */
  527. isBackgroundAttribute_(b1, b2) {
  528. // For Background Attribute Codes, the bytes take the following form:
  529. // Bg provided: b1 -> |0|0|0|1|C|0|0|0| b2 -> |0|0|1|0|COLOR|T|
  530. // No Bg: b1 -> |0|0|0|1|C|1|1|1| b2 -> |0|0|1|0|1|1|0|1|
  531. return (((b1 & 0xf7) === 0x10) && ((b2 & 0xf0) === 0x20)) ||
  532. (((b1 & 0xf7) === 0x17) && ((b2 & 0xff) === 0x2D));
  533. }
  534. /**
  535. * Checks if the character is in the Special North American char. set.
  536. * @param {number} b1 Byte 1.
  537. * @param {number} b2 Byte 2.
  538. * @return {boolean}
  539. * @private
  540. */
  541. isSpecialNorthAmericanChar_(b1, b2) {
  542. // The bytes take the following form:
  543. // b1 -> |0|0|0|1|C|0|0|1|
  544. // b2 -> |0|0|1|1| CHAR |
  545. return ((b1 & 0xf7) === 0x11) && ((b2 & 0xf0) === 0x30);
  546. }
  547. /**
  548. * Checks if the character is in the Extended Western European char. set.
  549. * @param {number} b1 Byte 1.
  550. * @param {number} b2 Byte 2.
  551. * @return {boolean}
  552. * @private
  553. */
  554. isExtendedWesternEuropeanChar_(b1, b2) {
  555. // The bytes take the following form:
  556. // b1 -> |0|0|0|1|C|0|1|S|
  557. // b2 -> |0|0|1|CHARACTER|
  558. return ((b1 & 0xf6) === 0x12) && ((b2 & 0xe0) === 0x20);
  559. }
  560. /**
  561. * Checks if the data contains a control code.
  562. * @param {number} b1 Byte 1.
  563. * @return {boolean}
  564. */
  565. static isControlCode(b1) {
  566. // For control codes, the first byte takes the following form:
  567. // b1 -> |P|0|0|1|X|X|X|X|
  568. return (b1 & 0x70) === 0x10;
  569. }
  570. /**
  571. * Checks if the data contains a XDS control code.
  572. * @param {number} b1 Byte 1.
  573. * @return {boolean}
  574. */
  575. static isXdsControlCode(b1) {
  576. return b1 >= 0x01 && b1 <= 0x0F;
  577. }
  578. };
  579. /**
  580. * Command codes.
  581. * @enum {number}
  582. * @private
  583. */
  584. shaka.cea.Cea608DataChannel.MiscCmd_ = {
  585. // "RCL - Resume Caption Loading"
  586. RCL: 0x20,
  587. // "BS - BackSpace"
  588. BS: 0x21,
  589. // "AOD - Unused (alarm off)"
  590. AOD: 0x22,
  591. // "AON - Unused (alarm on)"
  592. AON: 0x23,
  593. // "DER - Delete to End of Row"
  594. DER: 0x24,
  595. // "RU2 - Roll-Up, 2 rows"
  596. RU2: 0x25,
  597. // "RU3 - Roll-Up, 3 rows"
  598. RU3: 0x26,
  599. // "RU4 - Roll-Up, 4 rows"
  600. RU4: 0x27,
  601. // "FON - Flash On"
  602. FON: 0x28,
  603. // "RDC - Resume Direct Captions"
  604. RDC: 0x29,
  605. // "TR - Text Restart"
  606. TR: 0x2a,
  607. // "RTD - Resume Text Display"
  608. RTD: 0x2b,
  609. // "EDM - Erase Displayed Mem"
  610. EDM: 0x2c,
  611. // "CR - Carriage return"
  612. CR: 0x2d,
  613. // "ENM - Erase Nondisplayed Mem"
  614. ENM: 0x2e,
  615. // "EOC - End Of Caption (flip mem)"
  616. EOC: 0x2f,
  617. };
  618. /**
  619. * Caption type.
  620. * @private @const @enum {number}
  621. */
  622. shaka.cea.Cea608DataChannel.CaptionType = {
  623. NONE: 0,
  624. POPON: 1,
  625. PAINTON: 2,
  626. ROLLUP: 3,
  627. TEXT: 4,
  628. };
  629. /**
  630. * @const {!Array<string>}
  631. */
  632. shaka.cea.Cea608DataChannel.BG_COLORS = [
  633. 'black',
  634. 'green',
  635. 'blue',
  636. 'cyan',
  637. 'red',
  638. 'yellow',
  639. 'magenta',
  640. 'black',
  641. ];
  642. /**
  643. * @const {!Array<string>}
  644. */
  645. shaka.cea.Cea608DataChannel.TEXT_COLORS = [
  646. 'white',
  647. 'green',
  648. 'blue',
  649. 'cyan',
  650. 'red',
  651. 'yellow',
  652. 'magenta',
  653. 'white_italics',
  654. ];
  655. /**
  656. * Style associated with a cue.
  657. * @typedef {{
  658. * textColor: ?string,
  659. * backgroundColor: ?string,
  660. * italics: ?boolean,
  661. * underline: ?boolean
  662. * }}
  663. */
  664. shaka.cea.Cea608DataChannel.Style;
  665. /**
  666. * CEA closed captions packet.
  667. * @typedef {{
  668. * pts: number,
  669. * type: number,
  670. * ccData1: number,
  671. * ccData2: number,
  672. * order: number
  673. * }}
  674. *
  675. * @property {number} pts
  676. * Presentation timestamp (in second) at which this packet was received.
  677. * @property {number} type
  678. * Type of the packet. Either 0 or 1, representing the CEA-608 field.
  679. * @property {number} ccData1 CEA-608 byte 1.
  680. * @property {number} ccData2 CEA-608 byte 2.
  681. * @property {number} order
  682. * A number indicating the order this packet was received in a sequence
  683. * of packets. Used to break ties in a stable sorting algorithm
  684. */
  685. shaka.cea.Cea608DataChannel.Cea608Packet;