Skip to content

Commit

Permalink
Fix to remove CEA-608 caption stuck on screen with timeout
Browse files Browse the repository at this point in the history
This changes fixes issue google#7181.  Removing CEA-608 captions that timeout after 16 seconds without a
clear.
  • Loading branch information
sneelavara authored and stevemayhew committed Apr 7, 2020
1 parent 8991586 commit 61b0d74
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ public final class Cea608Decoder extends CeaDecoder {
// service bytes and drops the rest.
private boolean isInCaptionService;

// Static counter to keep track of last CC rendered. This is used to force erase the caption when
// the stream does not explicitly send control codes to remove caption as specified by
// CEA-608 Annex C.9
private long ccTimeOutCounter = C.TIME_UNSET;
private boolean captionEraseCommandSeen = false;
// CEA-608 Annex C.9 propose that if no data are received for the selected caption channel within
// a given time, the decoder should automatically erase the caption. The time limit should be no
// less than 16 seconds
public static final int VALID_DATA_CHANNEL_TIMEOUT_MS = 16000;

public Cea608Decoder(String mimeType, int accessibilityChannel) {
ccData = new ParsableByteArray();
cueBuilders = new ArrayList<>();
Expand Down Expand Up @@ -310,6 +320,7 @@ public void flush() {
repeatableControlCc2 = 0;
currentChannel = NTSC_CC_CHANNEL_1;
isInCaptionService = true;
ccTimeOutCounter = C.TIME_UNSET;
}

@Override
Expand All @@ -334,6 +345,7 @@ protected void decode(SubtitleInputBuffer inputBuffer) {
ByteBuffer subtitleData = Assertions.checkNotNull(inputBuffer.data);
ccData.reset(subtitleData.array(), subtitleData.limit());
boolean captionDataProcessed = false;
captionEraseCommandSeen = false;
while (ccData.bytesLeft() >= packetLength) {
byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
: (byte) ccData.readUnsignedByte();
Expand All @@ -343,7 +355,6 @@ protected void decode(SubtitleInputBuffer inputBuffer) {
// TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
// to the CEA-608 specification. We need to determine if the data should be handled
// differently when that is not the case.

if ((ccHeader & CC_TYPE_FLAG) != 0) {
// Do not process anything that is not part of the 608 byte stream.
continue;
Expand All @@ -353,7 +364,6 @@ protected void decode(SubtitleInputBuffer inputBuffer) {
// Do not process packets not within the selected field.
continue;
}

// Strip the parity bit from each byte to get CC data.
byte ccData1 = (byte) (ccByte1 & 0x7F);
byte ccData2 = (byte) (ccByte2 & 0x7F);
Expand Down Expand Up @@ -423,6 +433,9 @@ protected void decode(SubtitleInputBuffer inputBuffer) {
if (captionDataProcessed) {
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
cues = getDisplayCues();
if (!captionEraseCommandSeen) {
ccTimeOutCounter = System.currentTimeMillis();
}
}
}
}
Expand Down Expand Up @@ -541,14 +554,17 @@ private void handleMiscCode(byte cc2) {
cues = Collections.emptyList();
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
resetCueBuilders();
captionEraseCommandSeen = true;
}
break;
case CTRL_ERASE_NON_DISPLAYED_MEMORY:
resetCueBuilders();
captionEraseCommandSeen = true;
break;
case CTRL_END_OF_CAPTION:
cues = getDisplayCues();
resetCueBuilders();
captionEraseCommandSeen = true;
break;
case CTRL_CARRIAGE_RETURN:
// carriage returns only apply to rollup captions; don't bother if we don't have anything
Expand Down Expand Up @@ -1018,4 +1034,15 @@ public CueStyle(int style, boolean underline, int start) {

}

protected void clearStuckCaptions()
{
if (ccTimeOutCounter != C.TIME_UNSET) {
long timeElapsed = System.currentTimeMillis() - ccTimeOutCounter;
if (timeElapsed >= VALID_DATA_CHANNEL_TIMEOUT_MS) {
// Force erase captions. There might be stale captions stuck on screen.
// (CEA-608 Annex C.9)
flush();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,14 @@ public static int getArgbColorFromCeaColor(int red, int green, int blue, int opa
}
}

protected void clearStuckCaptions()
{
// Do nothing for CEA-708.
// As per spec CEA-708 Caption text sequences shall be terminated by either the start of a new
// DTVCC Command, or with an ASCII ETX (End of Text) (0x03) character when no other DTVCC
// Commands follow.
}

/** A {@link Cue} for CEA-708. */
private static final class Cea708CueInfo {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ public SubtitleOutputBuffer dequeueOutputBuffer() throws SubtitleDecoderExceptio
if (availableOutputBuffers.isEmpty()) {
return null;
}
// check if 608 decoder needs to clean up the stale caption
clearStuckCaptions();
// iterate through all available input buffers whose timestamps are less than or equal
// to the current playback position; processing input buffers for future content should
// be deferred until they would be applicable
Expand Down Expand Up @@ -213,4 +215,9 @@ public final void release() {
owner.releaseOutputBuffer(this);
}
}

/**
* Implements CEA-608 Annex C.9 automatic Caption Erase Logic
*/
protected abstract void clearStuckCaptions();
}

0 comments on commit 61b0d74

Please sign in to comment.