mirror of
https://github.com/androidx/media.git
synced 2025-05-13 18:50:02 +08:00
Cea708Decoder: Handle multiple service blocks
When a asset contains multiple cc embedded tracks, current Cea708Decoder service block parsing logic is discarding all the data in that frame. For example, a manifest with 2 embedded CEA-708 close captions tracks: <Accessibility schemeIdUri="urn:scte:dash:cc:cea-708:2015" value="1=lang:eng;2=lang:spa"/> when the spanish track is selected (service number 2), when processing the following CEA-708 frame: FC9420FD2062FF0829FE8CFCFE9818FEE332FE731FFE1042FE2062FE0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000FA0000 the frame can be descomposed as: FF0829 FE8CFC FE9818 FEE332 FE731F FE1042 FE2062 FE0000 08 (00 001000) 0 (sequence) 8 (frame size) 298CFC9818E332731F10 422062 0000 ===== 29 (001 01001) 1 (service number) 9 (service block length) 8CFC9818E332731F10 42 (010 00010) 2 (service number) 2 (service block length) 2062 0000 Null block service The current processCurrentPacket logic will discard the whole frame is discarded because the first service number found in the frame belongs to service number 1, which is not the one we are currently looking for. This commit modifies the processCurrentPacket decoding logic, to take into account all service blocks available in the frame, by iteraring over the full frame data and skipping those service blocks we are not interesting in. Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
This commit is contained in:
parent
86afae9c3e
commit
9ceba909da
@ -297,71 +297,87 @@ public final class Cea708Decoder extends CeaDecoder {
|
||||
// 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
|
||||
// processing the service block any text has been added to the buffer. See CEA-708-B Section
|
||||
// 8.10.4 for more details.
|
||||
boolean cuesNeedUpdate = false;
|
||||
|
||||
int blockEndBitPosition = serviceBlockPacket.getPosition() + (blockSize * 8);
|
||||
while (serviceBlockPacket.bitsLeft() > 0
|
||||
&& serviceBlockPacket.getPosition() < blockEndBitPosition) {
|
||||
int command = serviceBlockPacket.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);
|
||||
// Streams with multiple embedded cc tracks (different language tracks) can be delivered
|
||||
// in the same frame packet, so current serviceBlockPacket buffer can contain information
|
||||
// for different service numbers.
|
||||
// xe: consider the following service block 298CFC9818E332731F104220620000. This service
|
||||
// block must be split into 3 different blocks
|
||||
// 298CFC9818E332731F10: Information for service number 1
|
||||
// 422062: Information for service number 2
|
||||
// 0000: Null data
|
||||
//
|
||||
// So here we iterate over the full buffer until we found a null block service or untll
|
||||
// buffer is emptied, and, on each iteration, process only the block related to that
|
||||
// service block. if the specific service number is not the selected one, then just skip
|
||||
// it and continue with next service block.
|
||||
serviceBlockPacket.reset(currentDtvCcPacket.packetData, currentDtvCcPacket.currentIndex);
|
||||
while (serviceBlockPacket.bitsLeft() > 0) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
// Read the extended command
|
||||
command = serviceBlockPacket.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;
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (serviceNumber != selectedServiceNumber) {
|
||||
serviceBlockPacket.skipBytes(blockSize);
|
||||
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 = serviceBlockPacket.getPosition() + (blockSize * 8);
|
||||
while (serviceBlockPacket.getPosition() < endBlockPosition) {
|
||||
int command = serviceBlockPacket.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 {
|
||||
Log.w(TAG, "Invalid extended command: " + command);
|
||||
// Read the extended command
|
||||
command = serviceBlockPacket.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user