SectionReader implements TsPayloadReader { @Override public void consume(ParsableByteArray data, @Flags int flags) { boolean payloadUnitStartIndicator = (flags & FLAG_PAYLOAD_UNIT_START_INDICATOR) != 0; int payloadStartPosition = C.POSITION_UNSET; if (payloadUnitStartIndicator) { int payloadStartOffset = data.readUnsignedByte(); payloadStartPosition = data.getPosition() + payloadStartOffset; } if (waitingForPayloadStart) { if (!payloadUnitStartIndicator) { return; } waitingForPayloadStart = false; data.setPosition(payloadStartPosition); bytesRead = 0; } while (data.bytesLeft() > 0) { if (bytesRead < SECTION_HEADER_LENGTH) { if (bytesRead == 0) { int tableId = data.readUnsignedByte(); data.setPosition(data.getPosition() - 1); if (tableId == 0xFF ) { waitingForPayloadStart = true; return; } } int headerBytesToRead = Math.min(data.bytesLeft(), SECTION_HEADER_LENGTH - bytesRead); data.readBytes(sectionData.data, bytesRead, headerBytesToRead); bytesRead += headerBytesToRead; if (bytesRead == SECTION_HEADER_LENGTH) { sectionData.reset(SECTION_HEADER_LENGTH); sectionData.skipBytes(1); int secondHeaderByte = sectionData.readUnsignedByte(); int thirdHeaderByte = sectionData.readUnsignedByte(); sectionSyntaxIndicator = (secondHeaderByte & 0x80) != 0; totalSectionLength = (((secondHeaderByte & 0x0F) << 8) | thirdHeaderByte) + SECTION_HEADER_LENGTH; if (sectionData.capacity() < totalSectionLength) { byte[] bytes = sectionData.data; sectionData.reset( Math.min(MAX_SECTION_LENGTH, Math.max(totalSectionLength, bytes.length * 2))); System.arraycopy(bytes, 0, sectionData.data, 0, SECTION_HEADER_LENGTH); } } } else { int bodyBytesToRead = Math.min(data.bytesLeft(), totalSectionLength - bytesRead); data.readBytes(sectionData.data, bytesRead, bodyBytesToRead); bytesRead += bodyBytesToRead; if (bytesRead == totalSectionLength) { if (sectionSyntaxIndicator) { if (Util.crc32(sectionData.data, 0, totalSectionLength, 0xFFFFFFFF) != 0) { waitingForPayloadStart = true; return; } sectionData.reset(totalSectionLength - 4); } else { sectionData.reset(totalSectionLength); } reader.consume(sectionData); bytesRead = 0; } } } } SectionReader(SectionPayloadReader reader); @Override void init(TimestampAdjuster timestampAdjuster, ExtractorOutput extractorOutput,
      TrackIdGenerator idGenerator); @Override void seek(); @Override void consume(ParsableByteArray data, @Flags int flags);  }
@Test public void testSingleOnePacketSection() { packetPayload[0] = 3; insertTableSection(4, (byte) 99, 3); reader.consume(new ParsableByteArray(packetPayload), FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEqualTo(singletonList(99)); }
@Test public void testHeaderSplitAcrossPackets() { packetPayload[0] = 3; insertTableSection(4, (byte) 100, 3); ParsableByteArray firstPacket = new ParsableByteArray(packetPayload, 5); reader.consume(firstPacket, FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEmpty(); ParsableByteArray secondPacket = new ParsableByteArray(packetPayload); secondPacket.setPosition(5); reader.consume(secondPacket, 0); assertThat(payloadReader.parsedTableIds).isEqualTo(singletonList(100)); }
@Test public void testFiveSectionsInTwoPackets() { packetPayload[0] = 0; insertTableSection(1, (byte) 101, 10); insertTableSection(14, (byte) 102, 10); insertTableSection(27, (byte) 103, 10); packetPayload[40] = 0; insertTableSection(41, (byte) 104, 10); insertTableSection(54, (byte) 105, 10); ParsableByteArray firstPacket = new ParsableByteArray(packetPayload, 40); reader.consume(firstPacket, FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEqualTo(asList(101, 102, 103)); ParsableByteArray secondPacket = new ParsableByteArray(packetPayload); secondPacket.setPosition(40); reader.consume(secondPacket, FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEqualTo(asList(101, 102, 103, 104, 105)); }
@Test public void testLongSectionAcrossFourPackets() { packetPayload[0] = 13; insertTableSection(1, (byte) 106, 10); insertTableSection(14, (byte) 107, 300); packetPayload[300] = 17; insertTableSection(318, (byte) 108, 10); ParsableByteArray firstPacket = new ParsableByteArray(packetPayload, 100); reader.consume(firstPacket, FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEmpty(); ParsableByteArray secondPacket = new ParsableByteArray(packetPayload, 200); secondPacket.setPosition(100); reader.consume(secondPacket, 0); assertThat(payloadReader.parsedTableIds).isEmpty(); ParsableByteArray thirdPacket = new ParsableByteArray(packetPayload, 300); thirdPacket.setPosition(200); reader.consume(thirdPacket, 0); assertThat(payloadReader.parsedTableIds).isEmpty(); ParsableByteArray fourthPacket = new ParsableByteArray(packetPayload); fourthPacket.setPosition(300); reader.consume(fourthPacket, FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEqualTo(asList(107, 108)); }
@Test public void testCrcChecks() { byte[] correctCrcPat = new byte[] { (byte) 0x0, (byte) 0x0, (byte) 0xb0, (byte) 0xd, (byte) 0x0, (byte) 0x1, (byte) 0xc1, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1, (byte) 0xe1, (byte) 0x0, (byte) 0xe8, (byte) 0xf9, (byte) 0x5e, (byte) 0x7d}; byte[] incorrectCrcPat = Arrays.copyOf(correctCrcPat, correctCrcPat.length); incorrectCrcPat[16]--; reader.consume(new ParsableByteArray(correctCrcPat), FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEqualTo(singletonList(0)); reader.consume(new ParsableByteArray(incorrectCrcPat), FLAG_PAYLOAD_UNIT_START_INDICATOR); assertThat(payloadReader.parsedTableIds).isEqualTo(singletonList(0)); }