Fix to remove CEA-608 caption stuck on screen with timeout

This changes fixes issue #7181.  Removing CEA-608 captions that timeout after 16 seconds without a
clear.
This commit is contained in:
Sadashiva Neelavara 2020-04-01 18:34:37 -07:00 committed by Ian Baker
parent 9dac400734
commit 59b8552ac0
3 changed files with 44 additions and 2 deletions

View File

@ -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<>();
@ -310,6 +320,7 @@ public final class Cea608Decoder extends CeaDecoder {
repeatableControlCc2 = 0;
currentChannel = NTSC_CC_CHANNEL_1;
isInCaptionService = true;
ccTimeOutCounter = C.TIME_UNSET;
}
@Override
@ -334,6 +345,7 @@ public final class Cea608Decoder extends CeaDecoder {
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();
@ -343,7 +355,6 @@ public final class Cea608Decoder extends CeaDecoder {
// 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;
@ -353,7 +364,6 @@ public final class Cea608Decoder extends CeaDecoder {
// 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);
@ -423,6 +433,9 @@ public final class Cea608Decoder extends CeaDecoder {
if (captionDataProcessed) {
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
cues = getDisplayCues();
if (!captionEraseCommandSeen) {
ccTimeOutCounter = System.currentTimeMillis();
}
}
}
}
@ -541,14 +554,17 @@ public final class Cea608Decoder extends CeaDecoder {
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
@ -1018,4 +1034,15 @@ public final class Cea608Decoder extends CeaDecoder {
}
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();
}
}
}
}

View File

@ -1296,6 +1296,14 @@ public final class Cea708Decoder extends CeaDecoder {
}
}
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 {

View File

@ -97,6 +97,8 @@ import java.util.PriorityQueue;
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
@ -213,4 +215,9 @@ import java.util.PriorityQueue;
owner.releaseOutputBuffer(this);
}
}
/**
* Implements CEA-608 Annex C.9 automatic Caption Erase Logic
*/
protected abstract void clearStuckCaptions();
}