Commit e26723cd by aquilescanta Committed by Oliver Woodman

Add MODE_SINGLE_PMT to TsExtractor

This mode allows the extractor to support streams with multiple
programs declared in the PAT, but only one PMT. This is necessary
to support tuner-obtained media.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=148636312
parent 35988395
...@@ -75,7 +75,8 @@ public final class TsExtractorTest extends InstrumentationTestCase { ...@@ -75,7 +75,8 @@ public final class TsExtractorTest extends InstrumentationTestCase {
public void testCustomPesReader() throws Exception { public void testCustomPesReader() throws Exception {
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false); CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false);
TsExtractor tsExtractor = new TsExtractor(new TimestampAdjuster(0), factory, false); TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_NORMAL, new TimestampAdjuster(0),
factory);
FakeExtractorInput input = new FakeExtractorInput.Builder() FakeExtractorInput input = new FakeExtractorInput.Builder()
.setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample.ts")) .setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample.ts"))
.setSimulateIOErrors(false) .setSimulateIOErrors(false)
...@@ -99,7 +100,8 @@ public final class TsExtractorTest extends InstrumentationTestCase { ...@@ -99,7 +100,8 @@ public final class TsExtractorTest extends InstrumentationTestCase {
public void testCustomInitialSectionReader() throws Exception { public void testCustomInitialSectionReader() throws Exception {
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true); CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true);
TsExtractor tsExtractor = new TsExtractor(new TimestampAdjuster(0), factory, false); TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_NORMAL, new TimestampAdjuster(0),
factory);
FakeExtractorInput input = new FakeExtractorInput.Builder() FakeExtractorInput input = new FakeExtractorInput.Builder()
.setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample_with_sdt.ts")) .setData(TestUtil.getByteArray(getInstrumentation(), "ts/sample_with_sdt.ts"))
.setSimulateIOErrors(false) .setSimulateIOErrors(false)
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.extractor.ts; package com.google.android.exoplayer2.extractor.ts;
import android.support.annotation.IntDef;
import android.util.SparseArray; import android.util.SparseArray;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import android.util.SparseIntArray; import android.util.SparseIntArray;
...@@ -34,6 +35,8 @@ import com.google.android.exoplayer2.util.ParsableByteArray; ...@@ -34,6 +35,8 @@ import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.TimestampAdjuster;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
...@@ -56,6 +59,27 @@ public final class TsExtractor implements Extractor { ...@@ -56,6 +59,27 @@ public final class TsExtractor implements Extractor {
}; };
/**
* Modes for the extractor.
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({MODE_NORMAL, MODE_SINGLE_PMT, MODE_HLS})
public @interface Mode {}
/**
* Behave as defined in ISO/IEC 13818-1.
*/
public static final int MODE_NORMAL = 0;
/**
* Assume only one PMT will be contained in the stream, even if more are declared by the PAT.
*/
public static final int MODE_SINGLE_PMT = 1;
/**
* Enable single PMT mode, map {@link TrackOutput}s by their type (instead of PID) and ignore
* continuity counters.
*/
public static final int MODE_HLS = 2;
public static final int TS_STREAM_TYPE_MPA = 0x03; public static final int TS_STREAM_TYPE_MPA = 0x03;
public static final int TS_STREAM_TYPE_MPA_LSF = 0x04; public static final int TS_STREAM_TYPE_MPA_LSF = 0x04;
public static final int TS_STREAM_TYPE_AAC = 0x0F; public static final int TS_STREAM_TYPE_AAC = 0x0F;
...@@ -81,7 +105,7 @@ public final class TsExtractor implements Extractor { ...@@ -81,7 +105,7 @@ public final class TsExtractor implements Extractor {
private static final int BUFFER_PACKET_COUNT = 5; // Should be at least 2 private static final int BUFFER_PACKET_COUNT = 5; // Should be at least 2
private static final int BUFFER_SIZE = TS_PACKET_SIZE * BUFFER_PACKET_COUNT; private static final int BUFFER_SIZE = TS_PACKET_SIZE * BUFFER_PACKET_COUNT;
private final boolean hlsMode; @Mode private final int mode;
private final List<TimestampAdjuster> timestampAdjusters; private final List<TimestampAdjuster> timestampAdjusters;
private final ParsableByteArray tsPacketBuffer; private final ParsableByteArray tsPacketBuffer;
private final ParsableBitArray tsScratch; private final ParsableBitArray tsScratch;
...@@ -97,25 +121,25 @@ public final class TsExtractor implements Extractor { ...@@ -97,25 +121,25 @@ public final class TsExtractor implements Extractor {
private TsPayloadReader id3Reader; private TsPayloadReader id3Reader;
public TsExtractor() { public TsExtractor() {
this(new TimestampAdjuster(0), new DefaultTsPayloadReaderFactory(), false); this(MODE_NORMAL, new TimestampAdjuster(0), new DefaultTsPayloadReaderFactory());
} }
/** /**
* @param mode Mode for the extractor. One of {@link #MODE_NORMAL}, {@link #MODE_SINGLE_PMT}
* and {@link #MODE_HLS}.
* @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps. * @param timestampAdjuster A timestamp adjuster for offsetting and scaling sample timestamps.
* @param payloadReaderFactory Factory for injecting a custom set of payload readers. * @param payloadReaderFactory Factory for injecting a custom set of payload readers.
* @param hlsMode Whether the extractor should be used in HLS mode. If true, {@link TrackOutput}s
* are mapped by their type (instead of PID) and continuity counters are ignored.
*/ */
public TsExtractor(TimestampAdjuster timestampAdjuster, public TsExtractor(@Mode int mode, TimestampAdjuster timestampAdjuster,
TsPayloadReader.Factory payloadReaderFactory, boolean hlsMode) { TsPayloadReader.Factory payloadReaderFactory) {
if (hlsMode) { this.payloadReaderFactory = Assertions.checkNotNull(payloadReaderFactory);
this.mode = mode;
if (mode == MODE_SINGLE_PMT || mode == MODE_HLS) {
timestampAdjusters = Collections.singletonList(timestampAdjuster); timestampAdjusters = Collections.singletonList(timestampAdjuster);
} else { } else {
timestampAdjusters = new ArrayList<>(); timestampAdjusters = new ArrayList<>();
timestampAdjusters.add(timestampAdjuster); timestampAdjusters.add(timestampAdjuster);
} }
this.payloadReaderFactory = Assertions.checkNotNull(payloadReaderFactory);
this.hlsMode = hlsMode;
tsPacketBuffer = new ParsableByteArray(BUFFER_SIZE); tsPacketBuffer = new ParsableByteArray(BUFFER_SIZE);
tsScratch = new ParsableBitArray(new byte[3]); tsScratch = new ParsableBitArray(new byte[3]);
trackIds = new SparseBooleanArray(); trackIds = new SparseBooleanArray();
...@@ -220,7 +244,7 @@ public final class TsExtractor implements Extractor { ...@@ -220,7 +244,7 @@ public final class TsExtractor implements Extractor {
// Discontinuity check. // Discontinuity check.
boolean discontinuityFound = false; boolean discontinuityFound = false;
int continuityCounter = tsScratch.readBits(4); int continuityCounter = tsScratch.readBits(4);
if (!hlsMode) { if (mode != MODE_HLS) {
int previousCounter = continuityCounters.get(pid, continuityCounter - 1); int previousCounter = continuityCounters.get(pid, continuityCounter - 1);
continuityCounters.put(pid, continuityCounter); continuityCounters.put(pid, continuityCounter);
if (previousCounter == continuityCounter) { if (previousCounter == continuityCounter) {
...@@ -315,7 +339,7 @@ public final class TsExtractor implements Extractor { ...@@ -315,7 +339,7 @@ public final class TsExtractor implements Extractor {
remainingPmts++; remainingPmts++;
} }
} }
if (!hlsMode) { if (mode != MODE_HLS) {
tsPayloadReaders.remove(TS_PAT_PID); tsPayloadReaders.remove(TS_PAT_PID);
} }
} }
...@@ -356,7 +380,7 @@ public final class TsExtractor implements Extractor { ...@@ -356,7 +380,7 @@ public final class TsExtractor implements Extractor {
} }
// TimestampAdjuster assignment. // TimestampAdjuster assignment.
TimestampAdjuster timestampAdjuster; TimestampAdjuster timestampAdjuster;
if (hlsMode || remainingPmts == 1) { if (mode == MODE_SINGLE_PMT || mode == MODE_HLS || remainingPmts == 1) {
timestampAdjuster = timestampAdjusters.get(0); timestampAdjuster = timestampAdjusters.get(0);
} else { } else {
timestampAdjuster = new TimestampAdjuster(timestampAdjusters.get(0).firstSampleTimestampUs); timestampAdjuster = new TimestampAdjuster(timestampAdjusters.get(0).firstSampleTimestampUs);
...@@ -378,7 +402,7 @@ public final class TsExtractor implements Extractor { ...@@ -378,7 +402,7 @@ public final class TsExtractor implements Extractor {
// Skip the descriptors. // Skip the descriptors.
sectionData.skipBytes(programInfoLength); sectionData.skipBytes(programInfoLength);
if (hlsMode && id3Reader == null) { if (mode == MODE_HLS && id3Reader == null) {
// Setup an ID3 track regardless of whether there's a corresponding entry, in case one // Setup an ID3 track regardless of whether there's a corresponding entry, in case one
// appears intermittently during playback. See [Internal: b/20261500]. // appears intermittently during playback. See [Internal: b/20261500].
EsInfo dummyEsInfo = new EsInfo(TS_STREAM_TYPE_ID3, null, new byte[0]); EsInfo dummyEsInfo = new EsInfo(TS_STREAM_TYPE_ID3, null, new byte[0]);
...@@ -401,14 +425,14 @@ public final class TsExtractor implements Extractor { ...@@ -401,14 +425,14 @@ public final class TsExtractor implements Extractor {
} }
remainingEntriesLength -= esInfoLength + 5; remainingEntriesLength -= esInfoLength + 5;
int trackId = hlsMode ? streamType : elementaryPid; int trackId = mode == MODE_HLS ? streamType : elementaryPid;
if (trackIds.get(trackId)) { if (trackIds.get(trackId)) {
continue; continue;
} }
trackIds.put(trackId, true); trackIds.put(trackId, true);
TsPayloadReader reader; TsPayloadReader reader;
if (hlsMode && streamType == TS_STREAM_TYPE_ID3) { if (mode == MODE_HLS && streamType == TS_STREAM_TYPE_ID3) {
reader = id3Reader; reader = id3Reader;
} else { } else {
reader = payloadReaderFactory.createPayloadReader(streamType, esInfo); reader = payloadReaderFactory.createPayloadReader(streamType, esInfo);
...@@ -422,7 +446,7 @@ public final class TsExtractor implements Extractor { ...@@ -422,7 +446,7 @@ public final class TsExtractor implements Extractor {
tsPayloadReaders.put(elementaryPid, reader); tsPayloadReaders.put(elementaryPid, reader);
} }
} }
if (hlsMode) { if (mode == MODE_HLS) {
if (!tracksEnded) { if (!tracksEnded) {
output.endTracks(); output.endTracks();
remainingPmts = 0; remainingPmts = 0;
...@@ -430,7 +454,7 @@ public final class TsExtractor implements Extractor { ...@@ -430,7 +454,7 @@ public final class TsExtractor implements Extractor {
} }
} else { } else {
tsPayloadReaders.remove(pid); tsPayloadReaders.remove(pid);
remainingPmts--; remainingPmts = mode == MODE_SINGLE_PMT ? 0 : remainingPmts - 1;
if (remainingPmts == 0) { if (remainingPmts == 0) {
output.endTracks(); output.endTracks();
tracksEnded = true; tracksEnded = true;
......
...@@ -372,8 +372,8 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -372,8 +372,8 @@ import java.util.concurrent.atomic.AtomicInteger;
esReaderFactoryFlags |= DefaultTsPayloadReaderFactory.FLAG_IGNORE_H264_STREAM; esReaderFactoryFlags |= DefaultTsPayloadReaderFactory.FLAG_IGNORE_H264_STREAM;
} }
} }
extractor = new TsExtractor(timestampAdjuster, extractor = new TsExtractor(TsExtractor.MODE_HLS, timestampAdjuster,
new DefaultTsPayloadReaderFactory(esReaderFactoryFlags, muxedCaptionFormats), true); new DefaultTsPayloadReaderFactory(esReaderFactoryFlags, muxedCaptionFormats));
} }
if (usingNewExtractor) { if (usingNewExtractor) {
extractor.init(extractorOutput); extractor.init(extractorOutput);
......
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