@Override public void consume(ParsableByteArray data, boolean payloadUnitStartIndicator) { // Skip pointer. if (payloadUnitStartIndicator) { int pointerField = data.readUnsignedByte(); data.skip(pointerField); } data.readBytes(patScratch, 3); patScratch.skipBits(12); // table_id (8), section_syntax_indicator (1), '0' (1), reserved (2) int sectionLength = patScratch.readBits(12); // transport_stream_id (16), reserved (2), version_number (5), current_next_indicator (1), // section_number (8), last_section_number (8) data.skip(5); int programCount = (sectionLength - 9) / 4; for (int i = 0; i < programCount; i++) { data.readBytes(patScratch, 4); patScratch.skipBits(19); // program_number (16), reserved (3) int pid = patScratch.readBits(13); tsPayloadReaders.put(pid, new PmtReader()); } // Skip CRC_32. }
@Override public int read(DataSource dataSource) throws IOException { int bytesRead = dataSource.read(tsPacketBuffer.data, tsPacketBytesRead, TS_PACKET_SIZE - tsPacketBytesRead); if (bytesRead == -1) { return -1; } tsPacketBytesRead += bytesRead; if (tsPacketBytesRead < TS_PACKET_SIZE) { // We haven't read the whole packet yet. return bytesRead; } // Reset before reading the packet. tsPacketBytesRead = 0; tsPacketBuffer.setPosition(0); tsPacketBuffer.setLimit(TS_PACKET_SIZE); int syncByte = tsPacketBuffer.readUnsignedByte(); if (syncByte != TS_SYNC_BYTE) { return bytesRead; } tsPacketBuffer.readBytes(tsScratch, 3); tsScratch.skipBits(1); // transport_error_indicator boolean payloadUnitStartIndicator = tsScratch.readBit(); tsScratch.skipBits(1); // transport_priority int pid = tsScratch.readBits(13); tsScratch.skipBits(2); // transport_scrambling_control boolean adaptationFieldExists = tsScratch.readBit(); boolean payloadExists = tsScratch.readBit(); // Last 4 bits of scratch are skipped: continuity_counter // Skip the adaptation field. if (adaptationFieldExists) { int adaptationFieldLength = tsPacketBuffer.readUnsignedByte(); tsPacketBuffer.skip(adaptationFieldLength); } // Read the payload. if (payloadExists) { TsPayloadReader payloadReader = tsPayloadReaders.get(pid); if (payloadReader != null) { payloadReader.consume(tsPacketBuffer, payloadUnitStartIndicator); } } if (!prepared) { prepared = checkPrepared(); } return bytesRead; }
/** * Continues a read from the provided {@code source} into a given {@code target}. It's assumed * that the data should be written into {@code target} starting from an offset of zero. * * @param source The source from which to read. * @param target The target into which data is to be read, or {@code null} to skip. * @param targetLength The target length of the read. * @return Whether the target length has been reached. */ private boolean continueRead(ParsableByteArray source, byte[] target, int targetLength) { int bytesToRead = Math.min(source.bytesLeft(), targetLength - bytesRead); if (bytesToRead <= 0) { return true; } else if (target == null) { source.skip(bytesToRead); } else { source.readBytes(target, bytesRead, bytesToRead); } bytesRead += bytesToRead; return bytesRead == targetLength; }
@Override public void consume(ParsableByteArray data, boolean payloadUnitStartIndicator) { if (payloadUnitStartIndicator) { switch (state) { case STATE_FINDING_HEADER: case STATE_READING_HEADER: // Expected. break; case STATE_READING_HEADER_EXTENSION: Log.w(TAG, "Unexpected start indicator reading extended header"); break; case STATE_READING_BODY: // If payloadSize == -1 then the length of the previous packet was unspecified, and so // we only know that it's finished now that we've seen the start of the next one. This // is expected. If payloadSize != -1, then the length of the previous packet was known, // but we didn't receive that amount of data. This is not expected. if (payloadSize != -1) { Log.w(TAG, "Unexpected start indicator: expected " + payloadSize + " more bytes"); } // Either way, if the body was started, notify the reader that it has now finished. if (bodyStarted) { pesPayloadReader.packetFinished(); } break; } setState(STATE_READING_HEADER); } while (data.bytesLeft() > 0) { switch (state) { case STATE_FINDING_HEADER: data.skip(data.bytesLeft()); break; case STATE_READING_HEADER: if (continueRead(data, pesScratch.getData(), HEADER_SIZE)) { setState(parseHeader() ? STATE_READING_HEADER_EXTENSION : STATE_FINDING_HEADER); } break; case STATE_READING_HEADER_EXTENSION: int readLength = Math.min(MAX_HEADER_EXTENSION_SIZE, extendedHeaderLength); // Read as much of the extended header as we're interested in, and skip the rest. if (continueRead(data, pesScratch.getData(), readLength) && continueRead(data, null, extendedHeaderLength)) { parseHeaderExtension(); bodyStarted = false; setState(STATE_READING_BODY); } break; case STATE_READING_BODY: readLength = data.bytesLeft(); int padding = payloadSize == -1 ? 0 : readLength - payloadSize; if (padding > 0) { readLength -= padding; data.setLimit(data.getPosition() + readLength); } pesPayloadReader.consume(data, timeUs, !bodyStarted); bodyStarted = true; if (payloadSize != -1) { payloadSize -= readLength; if (payloadSize == 0) { pesPayloadReader.packetFinished(); setState(STATE_READING_HEADER); } } break; } } }
@Override public void consume(ParsableByteArray data, boolean payloadUnitStartIndicator) { // Skip pointer. if (payloadUnitStartIndicator) { int pointerField = data.readUnsignedByte(); data.skip(pointerField); } data.readBytes(pmtScratch, 3); pmtScratch.skipBits(12); // table_id (8), section_syntax_indicator (1), '0' (1), reserved (2) int sectionLength = pmtScratch.readBits(12); // program_number (16), reserved (2), version_number (5), current_next_indicator (1), // section_number (8), last_section_number (8), reserved (3), PCR_PID (13) // Skip the rest of the PMT header. data.skip(7); data.readBytes(pmtScratch, 2); pmtScratch.skipBits(4); int programInfoLength = pmtScratch.readBits(12); // Skip the descriptors. data.skip(programInfoLength); int entriesSize = sectionLength - 9 /* Size of the rest of the fields before descriptors */ - programInfoLength - 4 /* CRC size */; while (entriesSize > 0) { data.readBytes(pmtScratch, 5); int streamType = pmtScratch.readBits(8); pmtScratch.skipBits(3); // reserved int elementaryPid = pmtScratch.readBits(13); pmtScratch.skipBits(4); // reserved int esInfoLength = pmtScratch.readBits(12); // Skip the descriptors. data.skip(esInfoLength); entriesSize -= esInfoLength + 5; if (sampleQueues.get(streamType) != null) { continue; } ElementaryStreamReader pesPayloadReader = null; switch (streamType) { case TS_STREAM_TYPE_AAC: pesPayloadReader = new AdtsReader(bufferPool); break; case TS_STREAM_TYPE_H264: SeiReader seiReader = new SeiReader(bufferPool); sampleQueues.put(TS_STREAM_TYPE_EIA608, seiReader); pesPayloadReader = new H264Reader(bufferPool, seiReader); break; case TS_STREAM_TYPE_ID3: pesPayloadReader = new Id3Reader(bufferPool); break; } if (pesPayloadReader != null) { sampleQueues.put(streamType, pesPayloadReader); tsPayloadReaders.put(elementaryPid, new PesReader(pesPayloadReader)); } } // Skip CRC_32. }