Create the SectionPayloadReader interface
SectionPayloadReaders are provided to a SectionReader to get whole sections(crc checked). This allows the injection of custom section readers. E.G: SCTE35 messages. Issue:#726 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=136816612
This commit is contained in:
parent
a0fe258e8d
commit
eeb37d73e7
@ -78,8 +78,7 @@ public final class PesReader implements TsPayloadReader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void consume(ParsableByteArray data, boolean payloadUnitStartIndicator,
|
||||
ExtractorOutput output) {
|
||||
public final void consume(ParsableByteArray data, boolean payloadUnitStartIndicator) {
|
||||
if (payloadUnitStartIndicator) {
|
||||
switch (state) {
|
||||
case STATE_FINDING_HEADER:
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
|
||||
/**
|
||||
* Reads section data.
|
||||
*/
|
||||
public interface SectionPayloadReader {
|
||||
|
||||
/**
|
||||
* Called by a {@link SectionReader} when a full section is received.
|
||||
*
|
||||
* @param sectionData The data belonging to a section, including the section header but excluding
|
||||
* the CRC_32 field.
|
||||
*/
|
||||
void consume(ParsableByteArray sectionData);
|
||||
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.extractor.ts;
|
||||
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
import com.google.android.exoplayer2.extractor.TimestampAdjuster;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/**
|
||||
* Reads section data packets and feeds the whole sections to a given {@link SectionPayloadReader}.
|
||||
*/
|
||||
public final class SectionReader implements TsPayloadReader {
|
||||
|
||||
private static final int SECTION_HEADER_LENGTH = 3;
|
||||
|
||||
private final ParsableByteArray sectionData;
|
||||
private final ParsableBitArray headerScratch;
|
||||
private final SectionPayloadReader reader;
|
||||
private int sectionLength;
|
||||
private int sectionBytesRead;
|
||||
|
||||
public SectionReader(SectionPayloadReader reader) {
|
||||
this.reader = reader;
|
||||
sectionData = new ParsableByteArray();
|
||||
headerScratch = new ParsableBitArray(new byte[SECTION_HEADER_LENGTH]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(TimestampAdjuster timestampAdjuster, ExtractorOutput extractorOutput,
|
||||
TrackIdGenerator idGenerator) {
|
||||
// TODO: Injectable section readers might want to generate metadata tracks.
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data, boolean payloadUnitStartIndicator) {
|
||||
// Skip pointer.
|
||||
if (payloadUnitStartIndicator) {
|
||||
int pointerField = data.readUnsignedByte();
|
||||
data.skipBytes(pointerField);
|
||||
|
||||
// Note: see ISO/IEC 13818-1, section 2.4.4.3 for detailed information on the format of
|
||||
// the header.
|
||||
data.readBytes(headerScratch, SECTION_HEADER_LENGTH);
|
||||
data.setPosition(data.getPosition() - SECTION_HEADER_LENGTH);
|
||||
headerScratch.skipBits(12); // table_id (8), section_syntax_indicator (1), 0 (1), reserved (2)
|
||||
sectionLength = headerScratch.readBits(12) + SECTION_HEADER_LENGTH;
|
||||
sectionBytesRead = 0;
|
||||
|
||||
sectionData.reset(sectionLength);
|
||||
}
|
||||
|
||||
int bytesToRead = Math.min(data.bytesLeft(), sectionLength - sectionBytesRead);
|
||||
data.readBytes(sectionData.data, sectionBytesRead, bytesToRead);
|
||||
sectionBytesRead += bytesToRead;
|
||||
if (sectionBytesRead < sectionLength) {
|
||||
// Not yet fully read.
|
||||
return;
|
||||
}
|
||||
|
||||
if (Util.crc(sectionData.data, 0, sectionLength, 0xFFFFFFFF) != 0) {
|
||||
// CRC Invalid. The section gets discarded.
|
||||
return;
|
||||
}
|
||||
sectionData.setLimit(sectionData.limit() - 4); // Exclude the CRC_32 field.
|
||||
reader.consume(sectionData);
|
||||
}
|
||||
|
||||
}
|
@ -27,6 +27,8 @@ import com.google.android.exoplayer2.extractor.PositionHolder;
|
||||
import com.google.android.exoplayer2.extractor.SeekMap;
|
||||
import com.google.android.exoplayer2.extractor.TimestampAdjuster;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo;
|
||||
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.TrackIdGenerator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.ParsableBitArray;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
@ -236,7 +238,7 @@ public final class TsExtractor implements Extractor {
|
||||
payloadReader.seek();
|
||||
}
|
||||
tsPacketBuffer.setLimit(endOfPacket);
|
||||
payloadReader.consume(tsPacketBuffer, payloadUnitStartIndicator, output);
|
||||
payloadReader.consume(tsPacketBuffer, payloadUnitStartIndicator);
|
||||
Assertions.checkState(tsPacketBuffer.getPosition() <= endOfPacket);
|
||||
tsPacketBuffer.setLimit(limit);
|
||||
}
|
||||
@ -251,75 +253,29 @@ public final class TsExtractor implements Extractor {
|
||||
private void resetPayloadReaders() {
|
||||
trackIds.clear();
|
||||
tsPayloadReaders.clear();
|
||||
tsPayloadReaders.put(TS_PAT_PID, new PatReader());
|
||||
tsPayloadReaders.put(TS_PAT_PID, new SectionReader(new PatReader()));
|
||||
id3Reader = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses Program Association Table data.
|
||||
*/
|
||||
private class PatReader implements TsPayloadReader {
|
||||
private class PatReader implements SectionPayloadReader {
|
||||
|
||||
private final ParsableByteArray sectionData;
|
||||
private final ParsableBitArray patScratch;
|
||||
|
||||
private int sectionLength;
|
||||
private int sectionBytesRead;
|
||||
private int crc;
|
||||
|
||||
public PatReader() {
|
||||
sectionData = new ParsableByteArray();
|
||||
patScratch = new ParsableBitArray(new byte[4]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(TimestampAdjuster timestampAdjuster, ExtractorOutput extractorOutput,
|
||||
TrackIdGenerator idGenerator) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data, boolean payloadUnitStartIndicator,
|
||||
ExtractorOutput output) {
|
||||
// Skip pointer.
|
||||
if (payloadUnitStartIndicator) {
|
||||
int pointerField = data.readUnsignedByte();
|
||||
data.skipBytes(pointerField);
|
||||
|
||||
// Note: see ISO/IEC 13818-1, section 2.4.4.3 for detailed information on the format of
|
||||
// the header.
|
||||
data.readBytes(patScratch, 3);
|
||||
patScratch.skipBits(12); // table_id (8), section_syntax_indicator (1), 0 (1), reserved (2)
|
||||
sectionLength = patScratch.readBits(12);
|
||||
sectionBytesRead = 0;
|
||||
crc = Util.crc(patScratch.data, 0, 3, 0xFFFFFFFF);
|
||||
|
||||
sectionData.reset(sectionLength);
|
||||
}
|
||||
|
||||
int bytesToRead = Math.min(data.bytesLeft(), sectionLength - sectionBytesRead);
|
||||
data.readBytes(sectionData.data, sectionBytesRead, bytesToRead);
|
||||
sectionBytesRead += bytesToRead;
|
||||
if (sectionBytesRead < sectionLength) {
|
||||
// Not yet fully read.
|
||||
return;
|
||||
}
|
||||
|
||||
if (Util.crc(sectionData.data, 0, sectionLength, crc) != 0) {
|
||||
// CRC Invalid. The section gets discarded.
|
||||
return;
|
||||
}
|
||||
|
||||
public void consume(ParsableByteArray sectionData) {
|
||||
// table_id(8), section_syntax_indicator(1), '0'(1), reserved(2), section_length(12),
|
||||
// transport_stream_id (16), reserved (2), version_number (5), current_next_indicator (1),
|
||||
// section_number (8), last_section_number (8)
|
||||
sectionData.skipBytes(5);
|
||||
sectionData.skipBytes(8);
|
||||
|
||||
int programCount = (sectionLength - 9) / 4;
|
||||
int programCount = sectionData.bytesLeft() / 4;
|
||||
for (int i = 0; i < programCount; i++) {
|
||||
sectionData.readBytes(patScratch, 4);
|
||||
int programNumber = patScratch.readBits(16);
|
||||
@ -328,7 +284,7 @@ public final class TsExtractor implements Extractor {
|
||||
patScratch.skipBits(13); // network_PID (13)
|
||||
} else {
|
||||
int pid = patScratch.readBits(13);
|
||||
tsPayloadReaders.put(pid, new PmtReader(pid));
|
||||
tsPayloadReaders.put(pid, new SectionReader(new PmtReader(pid)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -338,7 +294,7 @@ public final class TsExtractor implements Extractor {
|
||||
/**
|
||||
* Parses Program Map Table.
|
||||
*/
|
||||
private class PmtReader implements TsPayloadReader {
|
||||
private class PmtReader implements SectionPayloadReader {
|
||||
|
||||
private static final int TS_PMT_DESC_REGISTRATION = 0x05;
|
||||
private static final int TS_PMT_DESC_ISO639_LANG = 0x0A;
|
||||
@ -347,66 +303,20 @@ public final class TsExtractor implements Extractor {
|
||||
private static final int TS_PMT_DESC_DTS = 0x7B;
|
||||
|
||||
private final ParsableBitArray pmtScratch;
|
||||
private final ParsableByteArray sectionData;
|
||||
private final int pid;
|
||||
|
||||
private int sectionLength;
|
||||
private int sectionBytesRead;
|
||||
private int crc;
|
||||
|
||||
public PmtReader(int pid) {
|
||||
pmtScratch = new ParsableBitArray(new byte[5]);
|
||||
sectionData = new ParsableByteArray();
|
||||
this.pid = pid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(TimestampAdjuster timestampAdjuster, ExtractorOutput extractorOutput,
|
||||
TrackIdGenerator idGenerator) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(ParsableByteArray data, boolean payloadUnitStartIndicator,
|
||||
ExtractorOutput output) {
|
||||
if (payloadUnitStartIndicator) {
|
||||
// Skip pointer.
|
||||
int pointerField = data.readUnsignedByte();
|
||||
data.skipBytes(pointerField);
|
||||
|
||||
// Note: see ISO/IEC 13818-1, section 2.4.4.8 for detailed information on the format of
|
||||
// the header.
|
||||
data.readBytes(pmtScratch, 3);
|
||||
pmtScratch.skipBits(12); // table_id (8), section_syntax_indicator (1), 0 (1), reserved (2)
|
||||
sectionLength = pmtScratch.readBits(12);
|
||||
sectionBytesRead = 0;
|
||||
crc = Util.crc(pmtScratch.data, 0, 3, 0xFFFFFFFF);
|
||||
|
||||
sectionData.reset(sectionLength);
|
||||
}
|
||||
|
||||
int bytesToRead = Math.min(data.bytesLeft(), sectionLength - sectionBytesRead);
|
||||
data.readBytes(sectionData.data, sectionBytesRead, bytesToRead);
|
||||
sectionBytesRead += bytesToRead;
|
||||
if (sectionBytesRead < sectionLength) {
|
||||
// Not yet fully read.
|
||||
return;
|
||||
}
|
||||
|
||||
if (Util.crc(sectionData.data, 0, sectionLength, crc) != 0) {
|
||||
// CRC Invalid. The section gets discarded.
|
||||
return;
|
||||
}
|
||||
|
||||
public void consume(ParsableByteArray sectionData) {
|
||||
// table_id(8), section_syntax_indicator(1), '0'(1), reserved(2), section_length(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.
|
||||
sectionData.skipBytes(7);
|
||||
sectionData.skipBytes(10);
|
||||
|
||||
// Read program_info_length.
|
||||
sectionData.readBytes(pmtScratch, 2);
|
||||
@ -425,8 +335,7 @@ public final class TsExtractor implements Extractor {
|
||||
new TrackIdGenerator(TS_STREAM_TYPE_ID3, MAX_PID_PLUS_ONE));
|
||||
}
|
||||
|
||||
int remainingEntriesLength = sectionLength - 9 /* Length of fields before descriptors */
|
||||
- programInfoLength - 4 /* CRC length */;
|
||||
int remainingEntriesLength = sectionData.bytesLeft();
|
||||
while (remainingEntriesLength > 0) {
|
||||
sectionData.readBytes(pmtScratch, 5);
|
||||
int streamType = pmtScratch.readBits(8);
|
||||
@ -513,7 +422,7 @@ public final class TsExtractor implements Extractor {
|
||||
}
|
||||
data.setPosition(descriptorsEndPosition);
|
||||
return new EsInfo(streamType, language,
|
||||
Arrays.copyOfRange(sectionData.data, descriptorsStartPosition, descriptorsEndPosition));
|
||||
Arrays.copyOfRange(data.data, descriptorsStartPosition, descriptorsEndPosition));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -100,8 +100,8 @@ public interface TsPayloadReader {
|
||||
* Notifies the reader that a seek has occurred.
|
||||
* <p>
|
||||
* Following a call to this method, the data passed to the next invocation of
|
||||
* {@link #consume(ParsableByteArray, boolean, ExtractorOutput)} will not be a continuation of
|
||||
* the data that was previously passed. Hence the reader should reset any internal state.
|
||||
* {@link #consume(ParsableByteArray, boolean)} will not be a continuation of the data that was
|
||||
* previously passed. Hence the reader should reset any internal state.
|
||||
*/
|
||||
void seek();
|
||||
|
||||
@ -110,8 +110,7 @@ public interface TsPayloadReader {
|
||||
*
|
||||
* @param data The TS packet. The position will be set to the start of the payload.
|
||||
* @param payloadUnitStartIndicator Whether payloadUnitStartIndicator was set on the TS packet.
|
||||
* @param output The output to which parsed data should be written.
|
||||
*/
|
||||
void consume(ParsableByteArray data, boolean payloadUnitStartIndicator, ExtractorOutput output);
|
||||
void consume(ParsableByteArray data, boolean payloadUnitStartIndicator);
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user