Skip to content

Commit

Permalink
Fix 608 parser handling of redundant special chars and cue timing aft…
Browse files Browse the repository at this point in the history
…er seek (#6439)

* Fix 608 parser handling of redundant control codes
Fixes #6427

* Fix 608 caption TextTrack Cue seek/discontinuity timing regression introduced in v1.5.0 with #5557
  • Loading branch information
robwalch authored May 24, 2024
1 parent ee3abcd commit a49da64
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 65 deletions.
21 changes: 9 additions & 12 deletions src/controller/timeline-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,20 +466,17 @@ export class TimelineController implements ComponentAPI {
// if this frag isn't contiguous, clear the parser so cues with bad start/end times aren't added to the textTrack
if (this.enabled && data.frag.type === PlaylistLevelType.MAIN) {
const { cea608Parser1, cea608Parser2, lastSn } = this;
if (!cea608Parser1 || !cea608Parser2) {
return;
}
const { cc, sn } = data.frag;
const partIndex = data.part?.index ?? -1;
if (
!(
sn === lastSn + 1 ||
(sn === lastSn && partIndex === this.lastPartIndex + 1) ||
cc === this.lastCc
)
) {
cea608Parser1.reset();
cea608Parser2.reset();
if (cea608Parser1 && cea608Parser2) {
if (
sn !== lastSn + 1 ||
(sn === lastSn && partIndex !== this.lastPartIndex + 1) ||
cc !== this.lastCc
) {
cea608Parser1.reset();
cea608Parser2.reset();
}
}
this.lastCc = cc as number;
this.lastSn = sn as number;
Expand Down
98 changes: 45 additions & 53 deletions src/utils/cea-608-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,8 @@ const specialCea608CharsCodes = {
/**
* Utils
*/
const getCharForByte = function (byte: number) {
let charCode = byte;
if (specialCea608CharsCodes.hasOwnProperty(byte)) {
charCode = specialCea608CharsCodes[byte];
}

return String.fromCharCode(charCode);
};
const getCharForByte = (byte: number) =>
String.fromCharCode(specialCea608CharsCodes[byte] || byte);

const NR_ROWS = 15;
const NR_COLS = 100;
Expand Down Expand Up @@ -1046,43 +1040,60 @@ class Cea608Parser {
* Add data for time t in forms of list of bytes (unsigned ints). The bytes are treated as pairs.
*/
addData(time: number | null, byteList: number[]) {
let cmdFound: boolean;
let a: number;
let b: number;
let charsFound: number[] | boolean | null = false;

this.logger.time = time;

for (let i = 0; i < byteList.length; i += 2) {
a = byteList[i] & 0x7f;
b = byteList[i + 1] & 0x7f;
const a = byteList[i] & 0x7f;
const b = byteList[i + 1] & 0x7f;
let cmdFound: boolean = false;
let charsFound: number[] | null = null;

if (a === 0 && b === 0) {
continue;
} else {
this.logger.log(
VerboseLevel.DATA,
'[' +
() =>
'[' +
numArrayToHexArray([byteList[i], byteList[i + 1]]) +
'] -> (' +
numArrayToHexArray([a, b]) +
')',
);
}

cmdFound = this.parseCmd(a, b);
const cmdHistory = this.cmdHistory;
const isControlCode = a >= 0x10 && a <= 0x1f;
if (isControlCode) {
// Skip redundant control codes
if (hasCmdRepeated(a, b, cmdHistory)) {
setLastCmd(null, null, cmdHistory);
this.logger.log(
VerboseLevel.DEBUG,
() =>
'Repeated command (' +
numArrayToHexArray([a, b]) +
') is dropped',
);
continue;
}
setLastCmd(a, b, this.cmdHistory);

if (!cmdFound) {
cmdFound = this.parseMidrow(a, b);
}
cmdFound = this.parseCmd(a, b);

if (!cmdFound) {
cmdFound = this.parsePAC(a, b);
}
if (!cmdFound) {
cmdFound = this.parseMidrow(a, b);
}

if (!cmdFound) {
cmdFound = this.parseBackgroundAttributes(a, b);
}
if (!cmdFound) {
cmdFound = this.parsePAC(a, b);
}

if (!cmdFound) {
cmdFound = this.parseBackgroundAttributes(a, b);
}
} else {
setLastCmd(null, null, cmdHistory);
}
if (!cmdFound) {
charsFound = this.parseChars(a, b);
if (charsFound) {
Expand All @@ -1101,7 +1112,8 @@ class Cea608Parser {
if (!cmdFound && !charsFound) {
this.logger.log(
VerboseLevel.WARNING,
"Couldn't parse cleaned data " +
() =>
"Couldn't parse cleaned data " +
numArrayToHexArray([a, b]) +
' orig: ' +
numArrayToHexArray([byteList[i], byteList[i + 1]]),
Expand All @@ -1115,7 +1127,6 @@ class Cea608Parser {
* @returns True if a command was found
*/
parseCmd(a: number, b: number): boolean {
const { cmdHistory } = this;
const cond1 =
(a === 0x14 || a === 0x1c || a === 0x15 || a === 0x1d) &&
b >= 0x20 &&
Expand All @@ -1125,15 +1136,6 @@ class Cea608Parser {
return false;
}

if (hasCmdRepeated(a, b, cmdHistory)) {
setLastCmd(null, null, cmdHistory);
this.logger.log(
VerboseLevel.DEBUG,
'Repeated command (' + numArrayToHexArray([a, b]) + ') is dropped',
);
return true;
}

const chNr = a === 0x14 || a === 0x15 || a === 0x17 ? 1 : 2;
const channel = this.channels[chNr] as Cea608Channel;

Expand Down Expand Up @@ -1175,7 +1177,6 @@ class Cea608Parser {
// a == 0x17 || a == 0x1F
channel.ccTO(b - 0x20);
}
setLastCmd(a, b, cmdHistory);
this.currentChannel = chNr;
return true;
}
Expand Down Expand Up @@ -1207,7 +1208,7 @@ class Cea608Parser {
channel.ccMIDROW(b);
this.logger.log(
VerboseLevel.DEBUG,
'MIDROW (' + numArrayToHexArray([a, b]) + ')',
() => 'MIDROW (' + numArrayToHexArray([a, b]) + ')',
);
return true;
}
Expand All @@ -1220,7 +1221,6 @@ class Cea608Parser {
*/
parsePAC(a: number, b: number): boolean {
let row: number;
const cmdHistory = this.cmdHistory;

const case1 =
((a >= 0x11 && a <= 0x17) || (a >= 0x19 && a <= 0x1f)) &&
Expand All @@ -1231,11 +1231,6 @@ class Cea608Parser {
return false;
}

if (hasCmdRepeated(a, b, cmdHistory)) {
setLastCmd(null, null, cmdHistory);
return true; // Repeated commands are dropped (once)
}

const chNr: Channels = a <= 0x17 ? 1 : 2;

if (b >= 0x40 && b <= 0x5f) {
Expand All @@ -1249,7 +1244,6 @@ class Cea608Parser {
return false;
}
channel.setPAC(this.interpretPAC(row, b));
setLastCmd(a, b, cmdHistory);
this.currentChannel = chNr;
return true;
}
Expand Down Expand Up @@ -1324,7 +1318,8 @@ class Cea608Parser {

this.logger.log(
VerboseLevel.INFO,
"Special char '" +
() =>
"Special char '" +
getCharForByte(oneCode) +
"' in channel " +
channelNr,
Expand All @@ -1334,12 +1329,10 @@ class Cea608Parser {
charCodes = b === 0 ? [a] : [a, b];
}
if (charCodes) {
const hexCodes = numArrayToHexArray(charCodes);
this.logger.log(
VerboseLevel.DEBUG,
'Char codes = ' + hexCodes.join(','),
() => 'Char codes = ' + numArrayToHexArray(charCodes).join(','),
);
setLastCmd(a, b, this.cmdHistory);
}
return charCodes;
}
Expand Down Expand Up @@ -1373,7 +1366,6 @@ class Cea608Parser {
const chNr: Channels = a <= 0x17 ? 1 : 2;
const channel: Cea608Channel = this.channels[chNr] as Cea608Channel;
channel.setBkgData(bkgData);
setLastCmd(a, b, this.cmdHistory);
return true;
}

Expand All @@ -1387,7 +1379,7 @@ class Cea608Parser {
channel.reset();
}
}
this.cmdHistory = createCmdHistory();
setLastCmd(null, null, this.cmdHistory);
}

/**
Expand Down

0 comments on commit a49da64

Please sign in to comment.