mirror of
https://github.com/androidx/media.git
synced 2025-05-09 00:20:45 +08:00
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:
parent
9dac400734
commit
59b8552ac0
@ -257,6 +257,16 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
// service bytes and drops the rest.
|
// service bytes and drops the rest.
|
||||||
private boolean isInCaptionService;
|
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) {
|
public Cea608Decoder(String mimeType, int accessibilityChannel) {
|
||||||
ccData = new ParsableByteArray();
|
ccData = new ParsableByteArray();
|
||||||
cueBuilders = new ArrayList<>();
|
cueBuilders = new ArrayList<>();
|
||||||
@ -310,6 +320,7 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
repeatableControlCc2 = 0;
|
repeatableControlCc2 = 0;
|
||||||
currentChannel = NTSC_CC_CHANNEL_1;
|
currentChannel = NTSC_CC_CHANNEL_1;
|
||||||
isInCaptionService = true;
|
isInCaptionService = true;
|
||||||
|
ccTimeOutCounter = C.TIME_UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -334,6 +345,7 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
ByteBuffer subtitleData = Assertions.checkNotNull(inputBuffer.data);
|
ByteBuffer subtitleData = Assertions.checkNotNull(inputBuffer.data);
|
||||||
ccData.reset(subtitleData.array(), subtitleData.limit());
|
ccData.reset(subtitleData.array(), subtitleData.limit());
|
||||||
boolean captionDataProcessed = false;
|
boolean captionDataProcessed = false;
|
||||||
|
captionEraseCommandSeen = false;
|
||||||
while (ccData.bytesLeft() >= packetLength) {
|
while (ccData.bytesLeft() >= packetLength) {
|
||||||
byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
|
byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
|
||||||
: (byte) ccData.readUnsignedByte();
|
: (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
|
// 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
|
// to the CEA-608 specification. We need to determine if the data should be handled
|
||||||
// differently when that is not the case.
|
// differently when that is not the case.
|
||||||
|
|
||||||
if ((ccHeader & CC_TYPE_FLAG) != 0) {
|
if ((ccHeader & CC_TYPE_FLAG) != 0) {
|
||||||
// Do not process anything that is not part of the 608 byte stream.
|
// Do not process anything that is not part of the 608 byte stream.
|
||||||
continue;
|
continue;
|
||||||
@ -353,7 +364,6 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
// Do not process packets not within the selected field.
|
// Do not process packets not within the selected field.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strip the parity bit from each byte to get CC data.
|
// Strip the parity bit from each byte to get CC data.
|
||||||
byte ccData1 = (byte) (ccByte1 & 0x7F);
|
byte ccData1 = (byte) (ccByte1 & 0x7F);
|
||||||
byte ccData2 = (byte) (ccByte2 & 0x7F);
|
byte ccData2 = (byte) (ccByte2 & 0x7F);
|
||||||
@ -423,6 +433,9 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
if (captionDataProcessed) {
|
if (captionDataProcessed) {
|
||||||
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
|
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
|
||||||
cues = getDisplayCues();
|
cues = getDisplayCues();
|
||||||
|
if (!captionEraseCommandSeen) {
|
||||||
|
ccTimeOutCounter = System.currentTimeMillis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,14 +554,17 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||||||
cues = Collections.emptyList();
|
cues = Collections.emptyList();
|
||||||
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
|
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
|
||||||
resetCueBuilders();
|
resetCueBuilders();
|
||||||
|
captionEraseCommandSeen = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CTRL_ERASE_NON_DISPLAYED_MEMORY:
|
case CTRL_ERASE_NON_DISPLAYED_MEMORY:
|
||||||
resetCueBuilders();
|
resetCueBuilders();
|
||||||
|
captionEraseCommandSeen = true;
|
||||||
break;
|
break;
|
||||||
case CTRL_END_OF_CAPTION:
|
case CTRL_END_OF_CAPTION:
|
||||||
cues = getDisplayCues();
|
cues = getDisplayCues();
|
||||||
resetCueBuilders();
|
resetCueBuilders();
|
||||||
|
captionEraseCommandSeen = true;
|
||||||
break;
|
break;
|
||||||
case CTRL_CARRIAGE_RETURN:
|
case CTRL_CARRIAGE_RETURN:
|
||||||
// carriage returns only apply to rollup captions; don't bother if we don't have anything
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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. */
|
/** A {@link Cue} for CEA-708. */
|
||||||
private static final class Cea708CueInfo {
|
private static final class Cea708CueInfo {
|
||||||
|
|
||||||
|
@ -97,6 +97,8 @@ import java.util.PriorityQueue;
|
|||||||
if (availableOutputBuffers.isEmpty()) {
|
if (availableOutputBuffers.isEmpty()) {
|
||||||
return null;
|
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
|
// 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
|
// to the current playback position; processing input buffers for future content should
|
||||||
// be deferred until they would be applicable
|
// be deferred until they would be applicable
|
||||||
@ -213,4 +215,9 @@ import java.util.PriorityQueue;
|
|||||||
owner.releaseOutputBuffer(this);
|
owner.releaseOutputBuffer(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements CEA-608 Annex C.9 automatic Caption Erase Logic
|
||||||
|
*/
|
||||||
|
protected abstract void clearStuckCaptions();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user