Remove 1 track per type limitation in TsExtractor

Mainly, this allows the extractor to expose multiple audio tracks.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=130928152
This commit is contained in:
aquilescanta 2016-08-22 05:07:42 -07:00 committed by Oliver Woodman
parent d5607cfc47
commit abdb8ddb6e
3 changed files with 31 additions and 46 deletions

View File

@ -2,8 +2,8 @@ seekMap:
isSeekable = false isSeekable = false
duration = UNSET TIME duration = UNSET TIME
getPosition(0) = 0 getPosition(0) = 0
numberOfTracks = 3 numberOfTracks = 2
track 2: track 256:
format: format:
bitrate = -1 bitrate = -1
id = null id = null
@ -35,7 +35,7 @@ track 2:
time = 66733 time = 66733
flags = 0 flags = 0
data = length 18112, hash EC44B35B data = length 18112, hash EC44B35B
track 3: track 257:
format: format:
bitrate = -1 bitrate = -1
id = null id = null
@ -74,27 +74,4 @@ track 3:
time = 100822 time = 100822
flags = 1 flags = 1
data = length 1254, hash 73FB07B8 data = length 1254, hash 73FB07B8
track 21:
format:
bitrate = -1
id = null
containerMimeType = null
sampleMimeType = application/id3
maxInputSize = -1
width = -1
height = -1
frameRate = -1.0
rotationDegrees = -1
pixelWidthHeightRatio = -1.0
channelCount = -1
sampleRate = -1
pcmEncoding = -1
encoderDelay = -1
encoderPadding = -1
subsampleOffsetUs = 9223372036854775807
selectionFlags = 0
language = null
drmInitData = -
initializationData:
sample count = 0
tracksEnded = true tracksEnded = true

View File

@ -53,6 +53,7 @@ public final class TsExtractor implements Extractor {
public static final int WORKAROUND_IGNORE_AAC_STREAM = 2; public static final int WORKAROUND_IGNORE_AAC_STREAM = 2;
public static final int WORKAROUND_IGNORE_H264_STREAM = 4; public static final int WORKAROUND_IGNORE_H264_STREAM = 4;
public static final int WORKAROUND_DETECT_ACCESS_UNITS = 8; public static final int WORKAROUND_DETECT_ACCESS_UNITS = 8;
public static final int WORKAROUND_MAP_BY_TYPE = 16;
private static final String TAG = "TsExtractor"; private static final String TAG = "TsExtractor";
@ -71,7 +72,7 @@ public final class TsExtractor implements Extractor {
private static final int TS_STREAM_TYPE_H264 = 0x1B; private static final int TS_STREAM_TYPE_H264 = 0x1B;
private static final int TS_STREAM_TYPE_H265 = 0x24; private static final int TS_STREAM_TYPE_H265 = 0x24;
private static final int TS_STREAM_TYPE_ID3 = 0x15; private static final int TS_STREAM_TYPE_ID3 = 0x15;
private static final int TS_STREAM_TYPE_EIA608 = 0x100; // 0xFF + 1 private static final int BASE_EMBEDDED_TRACK_ID = 0x2000; // 0xFF + 1
private static final long AC3_FORMAT_IDENTIFIER = Util.getIntegerCodeForString("AC-3"); private static final long AC3_FORMAT_IDENTIFIER = Util.getIntegerCodeForString("AC-3");
private static final long E_AC3_FORMAT_IDENTIFIER = Util.getIntegerCodeForString("EAC3"); private static final long E_AC3_FORMAT_IDENTIFIER = Util.getIntegerCodeForString("EAC3");
@ -85,10 +86,11 @@ public final class TsExtractor implements Extractor {
private final ParsableByteArray tsPacketBuffer; private final ParsableByteArray tsPacketBuffer;
private final ParsableBitArray tsScratch; private final ParsableBitArray tsScratch;
/* package */ final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid /* package */ final SparseArray<TsPayloadReader> tsPayloadReaders; // Indexed by pid
/* package */ final SparseBooleanArray streamTypes; /* package */ final SparseBooleanArray trackIds;
// Accessed only by the loading thread. // Accessed only by the loading thread.
private ExtractorOutput output; private ExtractorOutput output;
private int nextEmbeddedTrackId;
/* package */ Id3Reader id3Reader; /* package */ Id3Reader id3Reader;
public TsExtractor() { public TsExtractor() {
@ -106,7 +108,8 @@ public final class TsExtractor implements Extractor {
tsScratch = new ParsableBitArray(new byte[3]); tsScratch = new ParsableBitArray(new byte[3]);
tsPayloadReaders = new SparseArray<>(); tsPayloadReaders = new SparseArray<>();
tsPayloadReaders.put(TS_PAT_PID, new PatReader()); tsPayloadReaders.put(TS_PAT_PID, new PatReader());
streamTypes = new SparseBooleanArray(); trackIds = new SparseBooleanArray();
nextEmbeddedTrackId = BASE_EMBEDDED_TRACK_ID;
} }
// Extractor implementation. // Extractor implementation.
@ -359,7 +362,7 @@ public final class TsExtractor implements Extractor {
// Skip the descriptors. // Skip the descriptors.
sectionData.skipBytes(programInfoLength); sectionData.skipBytes(programInfoLength);
if (id3Reader == null) { if ((workaroundFlags & WORKAROUND_MAP_BY_TYPE) != 0 && 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 b/20261500. // appears intermittently during playback. See b/20261500.
id3Reader = new Id3Reader(output.track(TS_STREAM_TYPE_ID3)); id3Reader = new Id3Reader(output.track(TS_STREAM_TYPE_ID3));
@ -381,48 +384,52 @@ public final class TsExtractor implements Extractor {
sectionData.skipBytes(esInfoLength); sectionData.skipBytes(esInfoLength);
} }
remainingEntriesLength -= esInfoLength + 5; remainingEntriesLength -= esInfoLength + 5;
if (streamTypes.get(streamType)) { int trackId = (workaroundFlags & WORKAROUND_MAP_BY_TYPE) != 0 ? streamType : elementaryPid;
if (trackIds.get(trackId)) {
continue; continue;
} }
ElementaryStreamReader pesPayloadReader; ElementaryStreamReader pesPayloadReader;
switch (streamType) { switch (streamType) {
case TS_STREAM_TYPE_MPA: case TS_STREAM_TYPE_MPA:
pesPayloadReader = new MpegAudioReader(output.track(TS_STREAM_TYPE_MPA)); pesPayloadReader = new MpegAudioReader(output.track(trackId));
break; break;
case TS_STREAM_TYPE_MPA_LSF: case TS_STREAM_TYPE_MPA_LSF:
pesPayloadReader = new MpegAudioReader(output.track(TS_STREAM_TYPE_MPA_LSF)); pesPayloadReader = new MpegAudioReader(output.track(trackId));
break; break;
case TS_STREAM_TYPE_AAC: case TS_STREAM_TYPE_AAC:
pesPayloadReader = (workaroundFlags & WORKAROUND_IGNORE_AAC_STREAM) != 0 ? null pesPayloadReader = (workaroundFlags & WORKAROUND_IGNORE_AAC_STREAM) != 0 ? null
: new AdtsReader(output.track(TS_STREAM_TYPE_AAC), new DummyTrackOutput()); : new AdtsReader(output.track(trackId), new DummyTrackOutput());
break; break;
case TS_STREAM_TYPE_AC3: case TS_STREAM_TYPE_AC3:
pesPayloadReader = new Ac3Reader(output.track(TS_STREAM_TYPE_AC3), false); pesPayloadReader = new Ac3Reader(output.track(trackId), false);
break; break;
case TS_STREAM_TYPE_E_AC3: case TS_STREAM_TYPE_E_AC3:
pesPayloadReader = new Ac3Reader(output.track(TS_STREAM_TYPE_E_AC3), true); pesPayloadReader = new Ac3Reader(output.track(trackId), true);
break; break;
case TS_STREAM_TYPE_DTS: case TS_STREAM_TYPE_DTS:
case TS_STREAM_TYPE_HDMV_DTS: case TS_STREAM_TYPE_HDMV_DTS:
pesPayloadReader = new DtsReader(output.track(TS_STREAM_TYPE_DTS)); pesPayloadReader = new DtsReader(output.track(trackId));
break; break;
case TS_STREAM_TYPE_H262: case TS_STREAM_TYPE_H262:
pesPayloadReader = new H262Reader(output.track(TS_STREAM_TYPE_H262)); pesPayloadReader = new H262Reader(output.track(trackId));
break; break;
case TS_STREAM_TYPE_H264: case TS_STREAM_TYPE_H264:
pesPayloadReader = (workaroundFlags & WORKAROUND_IGNORE_H264_STREAM) != 0 ? null pesPayloadReader = (workaroundFlags & WORKAROUND_IGNORE_H264_STREAM) != 0 ? null
: new H264Reader(output.track(TS_STREAM_TYPE_H264), : new H264Reader(output.track(trackId),
new SeiReader(output.track(TS_STREAM_TYPE_EIA608)), new SeiReader(output.track(nextEmbeddedTrackId++)),
(workaroundFlags & WORKAROUND_ALLOW_NON_IDR_KEYFRAMES) != 0, (workaroundFlags & WORKAROUND_ALLOW_NON_IDR_KEYFRAMES) != 0,
(workaroundFlags & WORKAROUND_DETECT_ACCESS_UNITS) != 0); (workaroundFlags & WORKAROUND_DETECT_ACCESS_UNITS) != 0);
break; break;
case TS_STREAM_TYPE_H265: case TS_STREAM_TYPE_H265:
pesPayloadReader = new H265Reader(output.track(TS_STREAM_TYPE_H265), pesPayloadReader = new H265Reader(output.track(trackId),
new SeiReader(output.track(TS_STREAM_TYPE_EIA608))); new SeiReader(output.track(nextEmbeddedTrackId++)));
break; break;
case TS_STREAM_TYPE_ID3: case TS_STREAM_TYPE_ID3:
if ((workaroundFlags & WORKAROUND_MAP_BY_TYPE) != 0) {
pesPayloadReader = id3Reader; pesPayloadReader = id3Reader;
} else {
pesPayloadReader = new Id3Reader(output.track(nextEmbeddedTrackId++));
}
break; break;
default: default:
pesPayloadReader = null; pesPayloadReader = null;
@ -430,7 +437,7 @@ public final class TsExtractor implements Extractor {
} }
if (pesPayloadReader != null) { if (pesPayloadReader != null) {
streamTypes.put(streamType, true); trackIds.put(trackId, true);
tsPayloadReaders.put(elementaryPid, tsPayloadReaders.put(elementaryPid,
new PesReader(pesPayloadReader, ptsTimestampAdjuster)); new PesReader(pesPayloadReader, ptsTimestampAdjuster));
} }

View File

@ -309,7 +309,8 @@ public class HlsChunkSource {
// The master source has yet to instantiate an adjuster for the discontinuity sequence. // The master source has yet to instantiate an adjuster for the discontinuity sequence.
return; return;
} }
int workaroundFlags = 0; // This flag ensures the change of pid between streams does not affect the sample queues.
int workaroundFlags = TsExtractor.WORKAROUND_MAP_BY_TYPE;
String codecs = variants[newVariantIndex].codecs; String codecs = variants[newVariantIndex].codecs;
if (!TextUtils.isEmpty(codecs)) { if (!TextUtils.isEmpty(codecs)) {
// Sometimes AAC and H264 streams are declared in TS chunks even though they don't really // Sometimes AAC and H264 streams are declared in TS chunks even though they don't really