Commit 1809836c by aquilescanta Committed by Oliver Woodman

Provide a method for creating a reader for a particular PID

This allows the user to create section readers(usually) for reserved pids,
like SDT, EIT, CAT, etc.

Issue:#726

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=137150853
parent 8b3025d4
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.extractor.ts;
import android.test.InstrumentationTestCase;
import android.util.SparseArray;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorOutput;
......@@ -73,7 +74,7 @@ public final class TsExtractorTest extends InstrumentationTestCase {
}
public void testCustomPesReader() throws Exception {
CustomEsReaderFactory factory = new CustomEsReaderFactory();
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false);
TsExtractor tsExtractor = new TsExtractor(new TimestampAdjuster(0), factory, false);
FakeExtractorInput input = new FakeExtractorInput.Builder()
.setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample.ts"))
......@@ -82,13 +83,12 @@ public final class TsExtractorTest extends InstrumentationTestCase {
.setSimulatePartialReads(false).build();
FakeExtractorOutput output = new FakeExtractorOutput();
tsExtractor.init(output);
tsExtractor.seek(input.getPosition());
PositionHolder seekPositionHolder = new PositionHolder();
int readResult = Extractor.RESULT_CONTINUE;
while (readResult != Extractor.RESULT_END_OF_INPUT) {
readResult = tsExtractor.read(input, seekPositionHolder);
}
CustomEsReader reader = factory.reader;
CustomEsReader reader = factory.esReader;
assertEquals(2, reader.packetsRead);
TrackOutput trackOutput = reader.getTrackOutput();
assertTrue(trackOutput == output.trackOutputs.get(257 /* PID of audio track. */));
......@@ -97,6 +97,23 @@ public final class TsExtractorTest extends InstrumentationTestCase {
((FakeTrackOutput) trackOutput).format);
}
public void testCustomInitialSectionReader() throws Exception {
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true);
TsExtractor tsExtractor = new TsExtractor(new TimestampAdjuster(0), factory, false);
FakeExtractorInput input = new FakeExtractorInput.Builder()
.setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample_with_sdt.ts"))
.setSimulateIOErrors(false)
.setSimulateUnknownLength(false)
.setSimulatePartialReads(false).build();
tsExtractor.init(new FakeExtractorOutput());
PositionHolder seekPositionHolder = new PositionHolder();
int readResult = Extractor.RESULT_CONTINUE;
while (readResult != Extractor.RESULT_END_OF_INPUT) {
readResult = tsExtractor.read(input, seekPositionHolder);
}
assertEquals(1, factory.sdtReader.consumedSdts);
}
private static void writeJunkData(ByteArrayOutputStream out, int length) throws IOException {
for (int i = 0; i < length; i++) {
if (((byte) i) == TS_SYNC_BYTE) {
......@@ -107,6 +124,45 @@ public final class TsExtractorTest extends InstrumentationTestCase {
}
}
private static final class CustomTsPayloadReaderFactory implements TsPayloadReader.Factory {
private final boolean provideSdtReader;
private final boolean provideCustomEsReader;
private final TsPayloadReader.Factory defaultFactory;
private CustomEsReader esReader;
private SdtSectionReader sdtReader;
public CustomTsPayloadReaderFactory(boolean provideCustomEsReader, boolean provideSdtReader) {
this.provideCustomEsReader = provideCustomEsReader;
this.provideSdtReader = provideSdtReader;
defaultFactory = new DefaultTsPayloadReaderFactory();
}
@Override
public SparseArray<TsPayloadReader> createInitialPayloadReaders() {
if (provideSdtReader) {
assertNull(sdtReader);
SparseArray<TsPayloadReader> mapping = new SparseArray<>();
sdtReader = new SdtSectionReader();
mapping.put(17, new SectionReader(sdtReader));
return mapping;
} else {
return defaultFactory.createInitialPayloadReaders();
}
}
@Override
public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) {
if (provideCustomEsReader && streamType == 3) {
esReader = new CustomEsReader(esInfo.language);
return new PesReader(esReader);
} else {
return defaultFactory.createPayloadReader(streamType, esInfo);
}
}
}
private static final class CustomEsReader implements ElementaryStreamReader {
private final String language;
......@@ -147,23 +203,38 @@ public final class TsExtractorTest extends InstrumentationTestCase {
}
private static final class CustomEsReaderFactory implements TsPayloadReader.Factory {
private static final class SdtSectionReader implements SectionPayloadReader {
private final TsPayloadReader.Factory defaultFactory;
private CustomEsReader reader;
public CustomEsReaderFactory() {
defaultFactory = new DefaultTsPayloadReaderFactory();
}
private int consumedSdts;
@Override
public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) {
if (streamType == 3) {
reader = new CustomEsReader(esInfo.language);
return new PesReader(reader);
} else {
return defaultFactory.createPayloadReader(streamType, esInfo);
public void consume(ParsableByteArray sectionData) {
// table_id(8), section_syntax_indicator(1), reserved_future_use(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),
// original_network_id(16), reserved_future_use(8)
sectionData.skipBytes(11);
// Start of the service loop.
assertEquals(0x5566 /* arbitrary service id */, sectionData.readUnsignedShort());
// reserved_future_use(6), EIT_schedule_flag(1), EIT_present_following_flag(1)
sectionData.skipBytes(1);
// Assert there is only one service.
// Remove running_status(3), free_CA_mode(1) from the descriptors_loop_length with the mask.
assertEquals(sectionData.readUnsignedShort() & 0xFFF, sectionData.bytesLeft());
while (sectionData.bytesLeft() > 0) {
int descriptorTag = sectionData.readUnsignedByte();
int descriptorLength = sectionData.readUnsignedByte();
if (descriptorTag == 72 /* service descriptor */) {
assertEquals(1, sectionData.readUnsignedByte()); // Service type: Digital TV.
int serviceProviderNameLength = sectionData.readUnsignedByte();
assertEquals("Some provider", sectionData.readString(serviceProviderNameLength));
int serviceNameLength = sectionData.readUnsignedByte();
assertEquals("Some Channel", sectionData.readString(serviceNameLength));
} else {
sectionData.skipBytes(descriptorLength);
}
}
consumedSdts++;
}
}
......
......@@ -16,6 +16,7 @@
package com.google.android.exoplayer2.extractor.ts;
import android.support.annotation.IntDef;
import android.util.SparseArray;
import com.google.android.exoplayer2.extractor.ts.TsPayloadReader.EsInfo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
......@@ -50,6 +51,11 @@ public final class DefaultTsPayloadReaderFactory implements TsPayloadReader.Fact
}
@Override
public SparseArray<TsPayloadReader> createInitialPayloadReaders() {
return new SparseArray<>();
}
@Override
public TsPayloadReader createPayloadReader(int streamType, EsInfo esInfo) {
switch (streamType) {
case TsExtractor.TS_STREAM_TYPE_MPA:
......
......@@ -253,6 +253,12 @@ public final class TsExtractor implements Extractor {
private void resetPayloadReaders() {
trackIds.clear();
tsPayloadReaders.clear();
SparseArray<TsPayloadReader> initialPayloadReaders =
payloadReaderFactory.createInitialPayloadReaders();
int initialPayloadReadersSize = initialPayloadReaders.size();
for (int i = 0; i < initialPayloadReadersSize; i++) {
tsPayloadReaders.put(initialPayloadReaders.keyAt(i), initialPayloadReaders.valueAt(i));
}
tsPayloadReaders.put(TS_PAT_PID, new SectionReader(new PatReader()));
id3Reader = null;
}
......
......@@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.extractor.ts;
import android.util.SparseArray;
import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.TimestampAdjuster;
import com.google.android.exoplayer2.extractor.TrackOutput;
......@@ -31,6 +32,15 @@ public interface TsPayloadReader {
interface Factory {
/**
* Returns the initial mapping from PIDs to payload readers.
* <p>
* This method allows the injection of payload readers for reserved PIDs, excluding PID 0.
*
* @return A {@link SparseArray} that maps PIDs to payload readers.
*/
SparseArray<TsPayloadReader> createInitialPayloadReaders();
/**
* Returns a {@link TsPayloadReader} for a given stream type and elementary stream information.
* May return null if the stream type is not supported.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment