Merge pull request #9967 from jruesga:cea708-handle-multiple-service-blocks
PiperOrigin-RevId: 444816821
This commit is contained in:
commit
2898d41f4a
@ -30,6 +30,8 @@
|
|||||||
* SSA: Support `OutlineColour` style setting when `BorderStyle == 3` (i.e.
|
* SSA: Support `OutlineColour` style setting when `BorderStyle == 3` (i.e.
|
||||||
`OutlineColour` sets the background of the cue)
|
`OutlineColour` sets the background of the cue)
|
||||||
([#8435](https://github.com/google/ExoPlayer/issues/8435)).
|
([#8435](https://github.com/google/ExoPlayer/issues/8435)).
|
||||||
|
* CEA-708: Parse data into multiple service blocks and ignore blocks not
|
||||||
|
associated with the currently selected service number.
|
||||||
* Extractors:
|
* Extractors:
|
||||||
* Matroska: Parse `DiscardPadding` for Opus tracks.
|
* Matroska: Parse `DiscardPadding` for Opus tracks.
|
||||||
* Parse bitrates from `esds` boxes.
|
* Parse bitrates from `esds` boxes.
|
||||||
|
@ -145,7 +145,7 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
private static final int CHARACTER_UPPER_LEFT_BORDER = 0x7F;
|
private static final int CHARACTER_UPPER_LEFT_BORDER = 0x7F;
|
||||||
|
|
||||||
private final ParsableByteArray ccData;
|
private final ParsableByteArray ccData;
|
||||||
private final ParsableBitArray serviceBlockPacket;
|
private final ParsableBitArray captionChannelPacketData;
|
||||||
private int previousSequenceNumber;
|
private int previousSequenceNumber;
|
||||||
// TODO: Use isWideAspectRatio in decoding.
|
// TODO: Use isWideAspectRatio in decoding.
|
||||||
@SuppressWarnings({"unused", "FieldCanBeLocal"})
|
@SuppressWarnings({"unused", "FieldCanBeLocal"})
|
||||||
@ -163,7 +163,7 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
|
|
||||||
public Cea708Decoder(int accessibilityChannel, @Nullable List<byte[]> initializationData) {
|
public Cea708Decoder(int accessibilityChannel, @Nullable List<byte[]> initializationData) {
|
||||||
ccData = new ParsableByteArray();
|
ccData = new ParsableByteArray();
|
||||||
serviceBlockPacket = new ParsableBitArray();
|
captionChannelPacketData = new ParsableBitArray();
|
||||||
previousSequenceNumber = C.INDEX_UNSET;
|
previousSequenceNumber = C.INDEX_UNSET;
|
||||||
selectedServiceNumber = accessibilityChannel == Format.NO_VALUE ? 1 : accessibilityChannel;
|
selectedServiceNumber = accessibilityChannel == Format.NO_VALUE ? 1 : accessibilityChannel;
|
||||||
isWideAspectRatio =
|
isWideAspectRatio =
|
||||||
@ -299,71 +299,83 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
// we have received.
|
// we have received.
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceBlockPacket.reset(currentDtvCcPacket.packetData, currentDtvCcPacket.currentIndex);
|
|
||||||
|
|
||||||
int serviceNumber = serviceBlockPacket.readBits(3);
|
|
||||||
int blockSize = serviceBlockPacket.readBits(5);
|
|
||||||
if (serviceNumber == 7) {
|
|
||||||
// extended service numbers
|
|
||||||
serviceBlockPacket.skipBits(2);
|
|
||||||
serviceNumber = serviceBlockPacket.readBits(6);
|
|
||||||
if (serviceNumber < 7) {
|
|
||||||
Log.w(TAG, "Invalid extended service number: " + serviceNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore packets in which blockSize is 0
|
|
||||||
if (blockSize == 0) {
|
|
||||||
if (serviceNumber != 0) {
|
|
||||||
Log.w(TAG, "serviceNumber is non-zero (" + serviceNumber + ") when blockSize is 0");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serviceNumber != selectedServiceNumber) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The cues should be updated if we receive a C0 ETX command, any C1 command, or if after
|
// The cues should be updated if we receive a C0 ETX command, any C1 command, or if after
|
||||||
// processing the service block any text has been added to the buffer. See CEA-708-B Section
|
// processing the service block any text has been added to the buffer. See CEA-708-B Section
|
||||||
// 8.10.4 for more details.
|
// 8.10.4 for more details.
|
||||||
boolean cuesNeedUpdate = false;
|
boolean cuesNeedUpdate = false;
|
||||||
|
|
||||||
int blockEndBitPosition = serviceBlockPacket.getPosition() + (blockSize * 8);
|
// Streams with multiple embedded CC tracks (different language tracks) can be delivered
|
||||||
while (serviceBlockPacket.bitsLeft() > 0
|
// in the same frame packet, so captionChannelPacketData can contain service blocks with
|
||||||
&& serviceBlockPacket.getPosition() < blockEndBitPosition) {
|
// different service numbers.
|
||||||
int command = serviceBlockPacket.readBits(8);
|
//
|
||||||
if (command != COMMAND_EXT1) {
|
// We iterate over the full buffer until we find a null service block or until the buffer is
|
||||||
if (command <= GROUP_C0_END) {
|
// exhausted. On each iteration we process a single service block. If the block has a service
|
||||||
handleC0Command(command);
|
// number different to the currently selected service, then we skip it and continue with the
|
||||||
// If the C0 command was an ETX command, the cues are updated in handleC0Command.
|
// next service block.
|
||||||
} else if (command <= GROUP_G0_END) {
|
captionChannelPacketData.reset(currentDtvCcPacket.packetData, currentDtvCcPacket.currentIndex);
|
||||||
handleG0Character(command);
|
while (captionChannelPacketData.bitsLeft() > 0) {
|
||||||
cuesNeedUpdate = true;
|
// Parse the Standard Service Block Header (see CEA-708B 6.2.1)
|
||||||
} else if (command <= GROUP_C1_END) {
|
int serviceNumber = captionChannelPacketData.readBits(3);
|
||||||
handleC1Command(command);
|
int blockSize = captionChannelPacketData.readBits(5);
|
||||||
cuesNeedUpdate = true;
|
if (serviceNumber == 7) {
|
||||||
} else if (command <= GROUP_G1_END) {
|
// Parse the Extended Service Block Header (see CEA-708B 6.2.2)
|
||||||
handleG1Character(command);
|
captionChannelPacketData.skipBits(2);
|
||||||
cuesNeedUpdate = true;
|
serviceNumber = captionChannelPacketData.readBits(6);
|
||||||
} else {
|
if (serviceNumber < 7) {
|
||||||
Log.w(TAG, "Invalid base command: " + command);
|
Log.w(TAG, "Invalid extended service number: " + serviceNumber);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
// Read the extended command
|
|
||||||
command = serviceBlockPacket.readBits(8);
|
// Ignore packets with the Null Service Block Header (see CEA-708B 6.2.3)
|
||||||
if (command <= GROUP_C2_END) {
|
if (blockSize == 0) {
|
||||||
handleC2Command(command);
|
if (serviceNumber != 0) {
|
||||||
} else if (command <= GROUP_G2_END) {
|
Log.w(TAG, "serviceNumber is non-zero (" + serviceNumber + ") when blockSize is 0");
|
||||||
handleG2Character(command);
|
}
|
||||||
cuesNeedUpdate = true;
|
break;
|
||||||
} else if (command <= GROUP_C3_END) {
|
}
|
||||||
handleC3Command(command);
|
|
||||||
} else if (command <= GROUP_G3_END) {
|
if (serviceNumber != selectedServiceNumber) {
|
||||||
handleG3Character(command);
|
captionChannelPacketData.skipBytes(blockSize);
|
||||||
cuesNeedUpdate = true;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process only the information for the current service block (there could be
|
||||||
|
// more data in the buffer, but it is not part of the current service block).
|
||||||
|
int endBlockPosition = captionChannelPacketData.getPosition() + (blockSize * 8);
|
||||||
|
while (captionChannelPacketData.getPosition() < endBlockPosition) {
|
||||||
|
int command = captionChannelPacketData.readBits(8);
|
||||||
|
if (command != COMMAND_EXT1) {
|
||||||
|
if (command <= GROUP_C0_END) {
|
||||||
|
handleC0Command(command);
|
||||||
|
// If the C0 command was an ETX command, the cues are updated in handleC0Command.
|
||||||
|
} else if (command <= GROUP_G0_END) {
|
||||||
|
handleG0Character(command);
|
||||||
|
cuesNeedUpdate = true;
|
||||||
|
} else if (command <= GROUP_C1_END) {
|
||||||
|
handleC1Command(command);
|
||||||
|
cuesNeedUpdate = true;
|
||||||
|
} else if (command <= GROUP_G1_END) {
|
||||||
|
handleG1Character(command);
|
||||||
|
cuesNeedUpdate = true;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Invalid base command: " + command);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Invalid extended command: " + command);
|
// Read the extended command
|
||||||
|
command = captionChannelPacketData.readBits(8);
|
||||||
|
if (command <= GROUP_C2_END) {
|
||||||
|
handleC2Command(command);
|
||||||
|
} else if (command <= GROUP_G2_END) {
|
||||||
|
handleG2Character(command);
|
||||||
|
cuesNeedUpdate = true;
|
||||||
|
} else if (command <= GROUP_C3_END) {
|
||||||
|
handleC3Command(command);
|
||||||
|
} else if (command <= GROUP_G3_END) {
|
||||||
|
handleG3Character(command);
|
||||||
|
cuesNeedUpdate = true;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Invalid extended command: " + command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,10 +408,10 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
default:
|
default:
|
||||||
if (command >= COMMAND_EXT1_START && command <= COMMAND_EXT1_END) {
|
if (command >= COMMAND_EXT1_START && command <= COMMAND_EXT1_END) {
|
||||||
Log.w(TAG, "Currently unsupported COMMAND_EXT1 Command: " + command);
|
Log.w(TAG, "Currently unsupported COMMAND_EXT1 Command: " + command);
|
||||||
serviceBlockPacket.skipBits(8);
|
captionChannelPacketData.skipBits(8);
|
||||||
} else if (command >= COMMAND_P16_START && command <= COMMAND_P16_END) {
|
} else if (command >= COMMAND_P16_START && command <= COMMAND_P16_END) {
|
||||||
Log.w(TAG, "Currently unsupported COMMAND_P16 Command: " + command);
|
Log.w(TAG, "Currently unsupported COMMAND_P16 Command: " + command);
|
||||||
serviceBlockPacket.skipBits(16);
|
captionChannelPacketData.skipBits(16);
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "Invalid C0 command: " + command);
|
Log.w(TAG, "Invalid C0 command: " + command);
|
||||||
}
|
}
|
||||||
@ -425,28 +437,28 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
break;
|
break;
|
||||||
case COMMAND_CLW:
|
case COMMAND_CLW:
|
||||||
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
||||||
if (serviceBlockPacket.readBit()) {
|
if (captionChannelPacketData.readBit()) {
|
||||||
cueInfoBuilders[NUM_WINDOWS - i].clear();
|
cueInfoBuilders[NUM_WINDOWS - i].clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMAND_DSW:
|
case COMMAND_DSW:
|
||||||
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
||||||
if (serviceBlockPacket.readBit()) {
|
if (captionChannelPacketData.readBit()) {
|
||||||
cueInfoBuilders[NUM_WINDOWS - i].setVisibility(true);
|
cueInfoBuilders[NUM_WINDOWS - i].setVisibility(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMAND_HDW:
|
case COMMAND_HDW:
|
||||||
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
||||||
if (serviceBlockPacket.readBit()) {
|
if (captionChannelPacketData.readBit()) {
|
||||||
cueInfoBuilders[NUM_WINDOWS - i].setVisibility(false);
|
cueInfoBuilders[NUM_WINDOWS - i].setVisibility(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMAND_TGW:
|
case COMMAND_TGW:
|
||||||
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
||||||
if (serviceBlockPacket.readBit()) {
|
if (captionChannelPacketData.readBit()) {
|
||||||
CueInfoBuilder cueInfoBuilder = cueInfoBuilders[NUM_WINDOWS - i];
|
CueInfoBuilder cueInfoBuilder = cueInfoBuilders[NUM_WINDOWS - i];
|
||||||
cueInfoBuilder.setVisibility(!cueInfoBuilder.isVisible());
|
cueInfoBuilder.setVisibility(!cueInfoBuilder.isVisible());
|
||||||
}
|
}
|
||||||
@ -454,14 +466,14 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
break;
|
break;
|
||||||
case COMMAND_DLW:
|
case COMMAND_DLW:
|
||||||
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
for (int i = 1; i <= NUM_WINDOWS; i++) {
|
||||||
if (serviceBlockPacket.readBit()) {
|
if (captionChannelPacketData.readBit()) {
|
||||||
cueInfoBuilders[NUM_WINDOWS - i].reset();
|
cueInfoBuilders[NUM_WINDOWS - i].reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMMAND_DLY:
|
case COMMAND_DLY:
|
||||||
// TODO: Add support for delay commands.
|
// TODO: Add support for delay commands.
|
||||||
serviceBlockPacket.skipBits(8);
|
captionChannelPacketData.skipBits(8);
|
||||||
break;
|
break;
|
||||||
case COMMAND_DLC:
|
case COMMAND_DLC:
|
||||||
// TODO: Add support for delay commands.
|
// TODO: Add support for delay commands.
|
||||||
@ -472,7 +484,7 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
case COMMAND_SPA:
|
case COMMAND_SPA:
|
||||||
if (!currentCueInfoBuilder.isDefined()) {
|
if (!currentCueInfoBuilder.isDefined()) {
|
||||||
// ignore this command if the current window/cue isn't defined
|
// ignore this command if the current window/cue isn't defined
|
||||||
serviceBlockPacket.skipBits(16);
|
captionChannelPacketData.skipBits(16);
|
||||||
} else {
|
} else {
|
||||||
handleSetPenAttributes();
|
handleSetPenAttributes();
|
||||||
}
|
}
|
||||||
@ -480,7 +492,7 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
case COMMAND_SPC:
|
case COMMAND_SPC:
|
||||||
if (!currentCueInfoBuilder.isDefined()) {
|
if (!currentCueInfoBuilder.isDefined()) {
|
||||||
// ignore this command if the current window/cue isn't defined
|
// ignore this command if the current window/cue isn't defined
|
||||||
serviceBlockPacket.skipBits(24);
|
captionChannelPacketData.skipBits(24);
|
||||||
} else {
|
} else {
|
||||||
handleSetPenColor();
|
handleSetPenColor();
|
||||||
}
|
}
|
||||||
@ -488,7 +500,7 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
case COMMAND_SPL:
|
case COMMAND_SPL:
|
||||||
if (!currentCueInfoBuilder.isDefined()) {
|
if (!currentCueInfoBuilder.isDefined()) {
|
||||||
// ignore this command if the current window/cue isn't defined
|
// ignore this command if the current window/cue isn't defined
|
||||||
serviceBlockPacket.skipBits(16);
|
captionChannelPacketData.skipBits(16);
|
||||||
} else {
|
} else {
|
||||||
handleSetPenLocation();
|
handleSetPenLocation();
|
||||||
}
|
}
|
||||||
@ -496,7 +508,7 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
case COMMAND_SWA:
|
case COMMAND_SWA:
|
||||||
if (!currentCueInfoBuilder.isDefined()) {
|
if (!currentCueInfoBuilder.isDefined()) {
|
||||||
// ignore this command if the current window/cue isn't defined
|
// ignore this command if the current window/cue isn't defined
|
||||||
serviceBlockPacket.skipBits(32);
|
captionChannelPacketData.skipBits(32);
|
||||||
} else {
|
} else {
|
||||||
handleSetWindowAttributes();
|
handleSetWindowAttributes();
|
||||||
}
|
}
|
||||||
@ -527,27 +539,27 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
if (command <= 0x07) {
|
if (command <= 0x07) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
} else if (command <= 0x0F) {
|
} else if (command <= 0x0F) {
|
||||||
serviceBlockPacket.skipBits(8);
|
captionChannelPacketData.skipBits(8);
|
||||||
} else if (command <= 0x17) {
|
} else if (command <= 0x17) {
|
||||||
serviceBlockPacket.skipBits(16);
|
captionChannelPacketData.skipBits(16);
|
||||||
} else if (command <= 0x1F) {
|
} else if (command <= 0x1F) {
|
||||||
serviceBlockPacket.skipBits(24);
|
captionChannelPacketData.skipBits(24);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleC3Command(int command) {
|
private void handleC3Command(int command) {
|
||||||
// C3 Table doesn't contain any commands in CEA-708-B, but we do need to skip bytes
|
// C3 Table doesn't contain any commands in CEA-708-B, but we do need to skip bytes
|
||||||
if (command <= 0x87) {
|
if (command <= 0x87) {
|
||||||
serviceBlockPacket.skipBits(32);
|
captionChannelPacketData.skipBits(32);
|
||||||
} else if (command <= 0x8F) {
|
} else if (command <= 0x8F) {
|
||||||
serviceBlockPacket.skipBits(40);
|
captionChannelPacketData.skipBits(40);
|
||||||
} else if (command <= 0x9F) {
|
} else if (command <= 0x9F) {
|
||||||
// 90-9F are variable length codes; the first byte defines the header with the first
|
// 90-9F are variable length codes; the first byte defines the header with the first
|
||||||
// 2 bits specifying the type and the last 6 bits specifying the remaining length of the
|
// 2 bits specifying the type and the last 6 bits specifying the remaining length of the
|
||||||
// command in bytes
|
// command in bytes
|
||||||
serviceBlockPacket.skipBits(2);
|
captionChannelPacketData.skipBits(2);
|
||||||
int length = serviceBlockPacket.readBits(6);
|
int length = captionChannelPacketData.readBits(6);
|
||||||
serviceBlockPacket.skipBits(8 * length);
|
captionChannelPacketData.skipBits(8 * length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,14 +675,14 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
private void handleSetPenAttributes() {
|
private void handleSetPenAttributes() {
|
||||||
// the SetPenAttributes command contains 2 bytes of data
|
// the SetPenAttributes command contains 2 bytes of data
|
||||||
// first byte
|
// first byte
|
||||||
int textTag = serviceBlockPacket.readBits(4);
|
int textTag = captionChannelPacketData.readBits(4);
|
||||||
int offset = serviceBlockPacket.readBits(2);
|
int offset = captionChannelPacketData.readBits(2);
|
||||||
int penSize = serviceBlockPacket.readBits(2);
|
int penSize = captionChannelPacketData.readBits(2);
|
||||||
// second byte
|
// second byte
|
||||||
boolean italicsToggle = serviceBlockPacket.readBit();
|
boolean italicsToggle = captionChannelPacketData.readBit();
|
||||||
boolean underlineToggle = serviceBlockPacket.readBit();
|
boolean underlineToggle = captionChannelPacketData.readBit();
|
||||||
int edgeType = serviceBlockPacket.readBits(3);
|
int edgeType = captionChannelPacketData.readBits(3);
|
||||||
int fontStyle = serviceBlockPacket.readBits(3);
|
int fontStyle = captionChannelPacketData.readBits(3);
|
||||||
|
|
||||||
currentCueInfoBuilder.setPenAttributes(
|
currentCueInfoBuilder.setPenAttributes(
|
||||||
textTag, offset, penSize, italicsToggle, underlineToggle, edgeType, fontStyle);
|
textTag, offset, penSize, italicsToggle, underlineToggle, edgeType, fontStyle);
|
||||||
@ -679,24 +691,24 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
private void handleSetPenColor() {
|
private void handleSetPenColor() {
|
||||||
// the SetPenColor command contains 3 bytes of data
|
// the SetPenColor command contains 3 bytes of data
|
||||||
// first byte
|
// first byte
|
||||||
int foregroundO = serviceBlockPacket.readBits(2);
|
int foregroundO = captionChannelPacketData.readBits(2);
|
||||||
int foregroundR = serviceBlockPacket.readBits(2);
|
int foregroundR = captionChannelPacketData.readBits(2);
|
||||||
int foregroundG = serviceBlockPacket.readBits(2);
|
int foregroundG = captionChannelPacketData.readBits(2);
|
||||||
int foregroundB = serviceBlockPacket.readBits(2);
|
int foregroundB = captionChannelPacketData.readBits(2);
|
||||||
int foregroundColor =
|
int foregroundColor =
|
||||||
CueInfoBuilder.getArgbColorFromCeaColor(foregroundR, foregroundG, foregroundB, foregroundO);
|
CueInfoBuilder.getArgbColorFromCeaColor(foregroundR, foregroundG, foregroundB, foregroundO);
|
||||||
// second byte
|
// second byte
|
||||||
int backgroundO = serviceBlockPacket.readBits(2);
|
int backgroundO = captionChannelPacketData.readBits(2);
|
||||||
int backgroundR = serviceBlockPacket.readBits(2);
|
int backgroundR = captionChannelPacketData.readBits(2);
|
||||||
int backgroundG = serviceBlockPacket.readBits(2);
|
int backgroundG = captionChannelPacketData.readBits(2);
|
||||||
int backgroundB = serviceBlockPacket.readBits(2);
|
int backgroundB = captionChannelPacketData.readBits(2);
|
||||||
int backgroundColor =
|
int backgroundColor =
|
||||||
CueInfoBuilder.getArgbColorFromCeaColor(backgroundR, backgroundG, backgroundB, backgroundO);
|
CueInfoBuilder.getArgbColorFromCeaColor(backgroundR, backgroundG, backgroundB, backgroundO);
|
||||||
// third byte
|
// third byte
|
||||||
serviceBlockPacket.skipBits(2); // null padding
|
captionChannelPacketData.skipBits(2); // null padding
|
||||||
int edgeR = serviceBlockPacket.readBits(2);
|
int edgeR = captionChannelPacketData.readBits(2);
|
||||||
int edgeG = serviceBlockPacket.readBits(2);
|
int edgeG = captionChannelPacketData.readBits(2);
|
||||||
int edgeB = serviceBlockPacket.readBits(2);
|
int edgeB = captionChannelPacketData.readBits(2);
|
||||||
int edgeColor = CueInfoBuilder.getArgbColorFromCeaColor(edgeR, edgeG, edgeB);
|
int edgeColor = CueInfoBuilder.getArgbColorFromCeaColor(edgeR, edgeG, edgeB);
|
||||||
|
|
||||||
currentCueInfoBuilder.setPenColor(foregroundColor, backgroundColor, edgeColor);
|
currentCueInfoBuilder.setPenColor(foregroundColor, backgroundColor, edgeColor);
|
||||||
@ -705,11 +717,11 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
private void handleSetPenLocation() {
|
private void handleSetPenLocation() {
|
||||||
// the SetPenLocation command contains 2 bytes of data
|
// the SetPenLocation command contains 2 bytes of data
|
||||||
// first byte
|
// first byte
|
||||||
serviceBlockPacket.skipBits(4);
|
captionChannelPacketData.skipBits(4);
|
||||||
int row = serviceBlockPacket.readBits(4);
|
int row = captionChannelPacketData.readBits(4);
|
||||||
// second byte
|
// second byte
|
||||||
serviceBlockPacket.skipBits(2);
|
captionChannelPacketData.skipBits(2);
|
||||||
int column = serviceBlockPacket.readBits(6);
|
int column = captionChannelPacketData.readBits(6);
|
||||||
|
|
||||||
currentCueInfoBuilder.setPenLocation(row, column);
|
currentCueInfoBuilder.setPenLocation(row, column);
|
||||||
}
|
}
|
||||||
@ -717,28 +729,28 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
private void handleSetWindowAttributes() {
|
private void handleSetWindowAttributes() {
|
||||||
// the SetWindowAttributes command contains 4 bytes of data
|
// the SetWindowAttributes command contains 4 bytes of data
|
||||||
// first byte
|
// first byte
|
||||||
int fillO = serviceBlockPacket.readBits(2);
|
int fillO = captionChannelPacketData.readBits(2);
|
||||||
int fillR = serviceBlockPacket.readBits(2);
|
int fillR = captionChannelPacketData.readBits(2);
|
||||||
int fillG = serviceBlockPacket.readBits(2);
|
int fillG = captionChannelPacketData.readBits(2);
|
||||||
int fillB = serviceBlockPacket.readBits(2);
|
int fillB = captionChannelPacketData.readBits(2);
|
||||||
int fillColor = CueInfoBuilder.getArgbColorFromCeaColor(fillR, fillG, fillB, fillO);
|
int fillColor = CueInfoBuilder.getArgbColorFromCeaColor(fillR, fillG, fillB, fillO);
|
||||||
// second byte
|
// second byte
|
||||||
int borderType = serviceBlockPacket.readBits(2); // only the lower 2 bits of borderType
|
int borderType = captionChannelPacketData.readBits(2); // only the lower 2 bits of borderType
|
||||||
int borderR = serviceBlockPacket.readBits(2);
|
int borderR = captionChannelPacketData.readBits(2);
|
||||||
int borderG = serviceBlockPacket.readBits(2);
|
int borderG = captionChannelPacketData.readBits(2);
|
||||||
int borderB = serviceBlockPacket.readBits(2);
|
int borderB = captionChannelPacketData.readBits(2);
|
||||||
int borderColor = CueInfoBuilder.getArgbColorFromCeaColor(borderR, borderG, borderB);
|
int borderColor = CueInfoBuilder.getArgbColorFromCeaColor(borderR, borderG, borderB);
|
||||||
// third byte
|
// third byte
|
||||||
if (serviceBlockPacket.readBit()) {
|
if (captionChannelPacketData.readBit()) {
|
||||||
borderType |= 0x04; // set the top bit of the 3-bit borderType
|
borderType |= 0x04; // set the top bit of the 3-bit borderType
|
||||||
}
|
}
|
||||||
boolean wordWrapToggle = serviceBlockPacket.readBit();
|
boolean wordWrapToggle = captionChannelPacketData.readBit();
|
||||||
int printDirection = serviceBlockPacket.readBits(2);
|
int printDirection = captionChannelPacketData.readBits(2);
|
||||||
int scrollDirection = serviceBlockPacket.readBits(2);
|
int scrollDirection = captionChannelPacketData.readBits(2);
|
||||||
int justification = serviceBlockPacket.readBits(2);
|
int justification = captionChannelPacketData.readBits(2);
|
||||||
// fourth byte
|
// fourth byte
|
||||||
// Note that we don't intend to support display effects
|
// Note that we don't intend to support display effects
|
||||||
serviceBlockPacket.skipBits(8); // effectSpeed(4), effectDirection(2), displayEffect(2)
|
captionChannelPacketData.skipBits(8); // effectSpeed(4), effectDirection(2), displayEffect(2)
|
||||||
|
|
||||||
currentCueInfoBuilder.setWindowAttributes(
|
currentCueInfoBuilder.setWindowAttributes(
|
||||||
fillColor,
|
fillColor,
|
||||||
@ -755,26 +767,26 @@ public final class Cea708Decoder extends CeaDecoder {
|
|||||||
|
|
||||||
// the DefineWindow command contains 6 bytes of data
|
// the DefineWindow command contains 6 bytes of data
|
||||||
// first byte
|
// first byte
|
||||||
serviceBlockPacket.skipBits(2); // null padding
|
captionChannelPacketData.skipBits(2); // null padding
|
||||||
boolean visible = serviceBlockPacket.readBit();
|
boolean visible = captionChannelPacketData.readBit();
|
||||||
boolean rowLock = serviceBlockPacket.readBit();
|
boolean rowLock = captionChannelPacketData.readBit();
|
||||||
boolean columnLock = serviceBlockPacket.readBit();
|
boolean columnLock = captionChannelPacketData.readBit();
|
||||||
int priority = serviceBlockPacket.readBits(3);
|
int priority = captionChannelPacketData.readBits(3);
|
||||||
// second byte
|
// second byte
|
||||||
boolean relativePositioning = serviceBlockPacket.readBit();
|
boolean relativePositioning = captionChannelPacketData.readBit();
|
||||||
int verticalAnchor = serviceBlockPacket.readBits(7);
|
int verticalAnchor = captionChannelPacketData.readBits(7);
|
||||||
// third byte
|
// third byte
|
||||||
int horizontalAnchor = serviceBlockPacket.readBits(8);
|
int horizontalAnchor = captionChannelPacketData.readBits(8);
|
||||||
// fourth byte
|
// fourth byte
|
||||||
int anchorId = serviceBlockPacket.readBits(4);
|
int anchorId = captionChannelPacketData.readBits(4);
|
||||||
int rowCount = serviceBlockPacket.readBits(4);
|
int rowCount = captionChannelPacketData.readBits(4);
|
||||||
// fifth byte
|
// fifth byte
|
||||||
serviceBlockPacket.skipBits(2); // null padding
|
captionChannelPacketData.skipBits(2); // null padding
|
||||||
int columnCount = serviceBlockPacket.readBits(6);
|
int columnCount = captionChannelPacketData.readBits(6);
|
||||||
// sixth byte
|
// sixth byte
|
||||||
serviceBlockPacket.skipBits(2); // null padding
|
captionChannelPacketData.skipBits(2); // null padding
|
||||||
int windowStyle = serviceBlockPacket.readBits(3);
|
int windowStyle = captionChannelPacketData.readBits(3);
|
||||||
int penStyle = serviceBlockPacket.readBits(3);
|
int penStyle = captionChannelPacketData.readBits(3);
|
||||||
|
|
||||||
cueInfoBuilder.defineWindow(
|
cueInfoBuilder.defineWindow(
|
||||||
visible,
|
visible,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user