mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
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
This commit is contained in:
parent
35988395d2
commit
e26723cdc7
3 changed files with 47 additions and 21 deletions
|
|
@ -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 {
|
||||||
|
|
||||||
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 @@
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
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 {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
// 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 {
|
||||||
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 {
|
||||||
}
|
}
|
||||||
// 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 {
|
||||||
// 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 {
|
||||||
}
|
}
|
||||||
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 {
|
||||||
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 {
|
||||||
}
|
}
|
||||||
} 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;
|
||||||
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);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue