Extend support of 608 captions in SEI messages
Issue:#3816 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=185124378
This commit is contained in:
parent
6aad066d51
commit
d274ca6750
@ -19,18 +19,19 @@ import android.util.Log;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/**
|
||||
* Utility methods for handling CEA-608/708 messages.
|
||||
*/
|
||||
/** Utility methods for handling CEA-608/708 messages. Defined in A/53 Part 4:2009. */
|
||||
public final class CeaUtil {
|
||||
|
||||
private static final String TAG = "CeaUtil";
|
||||
|
||||
private static final int PAYLOAD_TYPE_CC = 4;
|
||||
private static final int COUNTRY_CODE = 0xB5;
|
||||
private static final int PROVIDER_CODE = 0x31;
|
||||
private static final int USER_ID = 0x47413934; // "GA94"
|
||||
private static final int PROVIDER_CODE_ATSC = 0x31;
|
||||
private static final int PROVIDER_CODE_DIRECTV = 0x2F;
|
||||
private static final int USER_ID_GA94 = Util.getIntegerCodeForString("GA94");
|
||||
private static final int USER_ID_DTG1 = Util.getIntegerCodeForString("DTG1");
|
||||
private static final int USER_DATA_TYPE_CODE = 0x3;
|
||||
|
||||
/**
|
||||
@ -46,33 +47,49 @@ public final class CeaUtil {
|
||||
while (seiBuffer.bytesLeft() > 1 /* last byte will be rbsp_trailing_bits */) {
|
||||
int payloadType = readNon255TerminatedValue(seiBuffer);
|
||||
int payloadSize = readNon255TerminatedValue(seiBuffer);
|
||||
int nextPayloadPosition = seiBuffer.getPosition() + payloadSize;
|
||||
// Process the payload.
|
||||
if (payloadSize == -1 || payloadSize > seiBuffer.bytesLeft()) {
|
||||
// This might occur if we're trying to read an encrypted SEI NAL unit.
|
||||
Log.w(TAG, "Skipping remainder of malformed SEI NAL unit.");
|
||||
seiBuffer.setPosition(seiBuffer.limit());
|
||||
} else if (isSeiMessageCea608(payloadType, payloadSize, seiBuffer)) {
|
||||
// Ignore country_code (1) + provider_code (2) + user_identifier (4)
|
||||
// + user_data_type_code (1).
|
||||
seiBuffer.skipBytes(8);
|
||||
// Ignore first three bits: reserved (1) + process_cc_data_flag (1) + zero_bit (1).
|
||||
int ccCount = seiBuffer.readUnsignedByte() & 0x1F;
|
||||
// Ignore em_data (1)
|
||||
seiBuffer.skipBytes(1);
|
||||
// Each data packet consists of 24 bits: marker bits (5) + cc_valid (1) + cc_type (2)
|
||||
// + cc_data_1 (8) + cc_data_2 (8).
|
||||
int sampleLength = ccCount * 3;
|
||||
int sampleStartPosition = seiBuffer.getPosition();
|
||||
for (TrackOutput output : outputs) {
|
||||
seiBuffer.setPosition(sampleStartPosition);
|
||||
output.sampleData(seiBuffer, sampleLength);
|
||||
output.sampleMetadata(presentationTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleLength, 0, null);
|
||||
} else if (payloadType == PAYLOAD_TYPE_CC && payloadSize >= 8) {
|
||||
int countryCode = seiBuffer.readUnsignedByte();
|
||||
int providerCode = seiBuffer.readUnsignedShort();
|
||||
int userIdentifier = 0;
|
||||
if (providerCode == PROVIDER_CODE_ATSC) {
|
||||
userIdentifier = seiBuffer.readInt();
|
||||
}
|
||||
int userDataTypeCode = seiBuffer.readUnsignedByte();
|
||||
if (providerCode == PROVIDER_CODE_DIRECTV) {
|
||||
seiBuffer.skipBytes(1); // user_data_length.
|
||||
}
|
||||
boolean messageIsSupportedCeaCaption =
|
||||
countryCode == COUNTRY_CODE
|
||||
&& (providerCode == PROVIDER_CODE_ATSC || providerCode == PROVIDER_CODE_DIRECTV)
|
||||
&& userDataTypeCode == USER_DATA_TYPE_CODE;
|
||||
if (providerCode == PROVIDER_CODE_ATSC) {
|
||||
messageIsSupportedCeaCaption &=
|
||||
userIdentifier == USER_ID_GA94 || userIdentifier == USER_ID_DTG1;
|
||||
}
|
||||
if (messageIsSupportedCeaCaption) {
|
||||
// Ignore first three bits: reserved (1) + process_cc_data_flag (1) + zero_bit (1).
|
||||
int ccCount = seiBuffer.readUnsignedByte() & 0x1F;
|
||||
// Ignore em_data (1)
|
||||
seiBuffer.skipBytes(1);
|
||||
// Each data packet consists of 24 bits: marker bits (5) + cc_valid (1) + cc_type (2)
|
||||
// + cc_data_1 (8) + cc_data_2 (8).
|
||||
int sampleLength = ccCount * 3;
|
||||
int sampleStartPosition = seiBuffer.getPosition();
|
||||
for (TrackOutput output : outputs) {
|
||||
seiBuffer.setPosition(sampleStartPosition);
|
||||
output.sampleData(seiBuffer, sampleLength);
|
||||
output.sampleMetadata(
|
||||
presentationTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleLength, 0, null);
|
||||
}
|
||||
}
|
||||
// Ignore trailing information in SEI, if any.
|
||||
seiBuffer.skipBytes(payloadSize - (10 + ccCount * 3));
|
||||
} else {
|
||||
seiBuffer.skipBytes(payloadSize);
|
||||
}
|
||||
seiBuffer.setPosition(nextPayloadPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,31 +114,6 @@ public final class CeaUtil {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inspects an sei message to determine whether it contains CEA-608.
|
||||
* <p>
|
||||
* The position of {@code payload} is left unchanged.
|
||||
*
|
||||
* @param payloadType The payload type of the message.
|
||||
* @param payloadLength The length of the payload.
|
||||
* @param payload A {@link ParsableByteArray} containing the payload.
|
||||
* @return Whether the sei message contains CEA-608.
|
||||
*/
|
||||
private static boolean isSeiMessageCea608(int payloadType, int payloadLength,
|
||||
ParsableByteArray payload) {
|
||||
if (payloadType != PAYLOAD_TYPE_CC || payloadLength < 8) {
|
||||
return false;
|
||||
}
|
||||
int startPosition = payload.getPosition();
|
||||
int countryCode = payload.readUnsignedByte();
|
||||
int providerCode = payload.readUnsignedShort();
|
||||
int userIdentifier = payload.readInt();
|
||||
int userDataTypeCode = payload.readUnsignedByte();
|
||||
payload.setPosition(startPosition);
|
||||
return countryCode == COUNTRY_CODE && providerCode == PROVIDER_CODE
|
||||
&& userIdentifier == USER_ID && userDataTypeCode == USER_DATA_TYPE_CODE;
|
||||
}
|
||||
|
||||
private CeaUtil() {}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user