Commit 943de70a by aquilescanta Committed by Oliver Woodman

Pass HTTP DataSource's response headers to HlsExtractorFactory

Issue:#2025

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=200212344
parent 37516d31
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
bandwidth estimates in the future. Always null at the moment. bandwidth estimates in the future. Always null at the moment.
* HLS: * HLS:
* Allow injection of custom playlist trackers. * Allow injection of custom playlist trackers.
* Pass HTTP response headers to `HlsExtractorFactory.createExtractor`.
* DRM: * DRM:
* Allow DrmInitData to carry a license server URL * Allow DrmInitData to carry a license server URL
([#3393](https://github.com/google/ExoPlayer/issues/3393)). ([#3393](https://github.com/google/ExoPlayer/issues/3393)).
......
...@@ -31,6 +31,7 @@ import com.google.android.exoplayer2.util.MimeTypes; ...@@ -31,6 +31,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.TimestampAdjuster;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Default {@link HlsExtractorFactory} implementation. * Default {@link HlsExtractorFactory} implementation.
...@@ -48,9 +49,14 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { ...@@ -48,9 +49,14 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
public static final String WEBVTT_FILE_EXTENSION = ".webvtt"; public static final String WEBVTT_FILE_EXTENSION = ".webvtt";
@Override @Override
public Pair<Extractor, Boolean> createExtractor(Extractor previousExtractor, Uri uri, public Pair<Extractor, Boolean> createExtractor(
Format format, List<Format> muxedCaptionFormats, DrmInitData drmInitData, Extractor previousExtractor,
TimestampAdjuster timestampAdjuster) { Uri uri,
Format format,
List<Format> muxedCaptionFormats,
DrmInitData drmInitData,
TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders) {
String lastPathSegment = uri.getLastPathSegment(); String lastPathSegment = uri.getLastPathSegment();
if (lastPathSegment == null) { if (lastPathSegment == null) {
lastPathSegment = ""; lastPathSegment = "";
......
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.drm.DrmInitData; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.util.TimestampAdjuster; import com.google.android.exoplayer2.util.TimestampAdjuster;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Factory for HLS media chunk extractors. * Factory for HLS media chunk extractors.
...@@ -42,12 +43,18 @@ public interface HlsExtractorFactory { ...@@ -42,12 +43,18 @@ public interface HlsExtractorFactory {
* information is available in the master playlist. * information is available in the master playlist.
* @param drmInitData {@link DrmInitData} associated with the chunk. * @param drmInitData {@link DrmInitData} associated with the chunk.
* @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number. * @param timestampAdjuster Adjuster corresponding to the provided discontinuity sequence number.
* @param responseHeaders The HTTP response headers associated with the media segment or
* initialization section to extract.
* @return A pair containing the {@link Extractor} and a boolean that indicates whether it is a * @return A pair containing the {@link Extractor} and a boolean that indicates whether it is a
* packed audio extractor. The first element may be {@code previousExtractor} if the factory * packed audio extractor. The first element may be {@code previousExtractor} if the factory
* has determined it can be re-used. * has determined it can be re-used.
*/ */
Pair<Extractor, Boolean> createExtractor(Extractor previousExtractor, Uri uri, Format format, Pair<Extractor, Boolean> createExtractor(
List<Format> muxedCaptionFormats, DrmInitData drmInitData, Extractor previousExtractor,
TimestampAdjuster timestampAdjuster); Uri uri,
Format format,
List<Format> muxedCaptionFormats,
DrmInitData drmInitData,
TimestampAdjuster timestampAdjuster,
Map<String, List<String>> responseHeaders);
} }
...@@ -69,12 +69,15 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -69,12 +69,15 @@ import java.util.concurrent.atomic.AtomicInteger;
private final boolean hasGapTag; private final boolean hasGapTag;
private final TimestampAdjuster timestampAdjuster; private final TimestampAdjuster timestampAdjuster;
private final boolean shouldSpliceIn; private final boolean shouldSpliceIn;
private final Extractor extractor; private final HlsExtractorFactory extractorFactory;
private final boolean isPackedAudioExtractor; private final List<Format> muxedCaptionFormats;
private final boolean reusingExtractor; private final DrmInitData drmInitData;
private final Id3Decoder id3Decoder; private final Extractor previousExtractor;
private final ParsableByteArray id3Data;
private Extractor extractor;
private boolean isPackedAudioExtractor;
private Id3Decoder id3Decoder;
private ParsableByteArray id3Data;
private HlsSampleStreamWrapper output; private HlsSampleStreamWrapper output;
private int initSegmentBytesLoaded; private int initSegmentBytesLoaded;
private int bytesLoaded; private int bytesLoaded;
...@@ -145,32 +148,20 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -145,32 +148,20 @@ import java.util.concurrent.atomic.AtomicInteger;
// Note: this.dataSource and dataSource may be different. // Note: this.dataSource and dataSource may be different.
this.isEncrypted = this.dataSource instanceof Aes128DataSource; this.isEncrypted = this.dataSource instanceof Aes128DataSource;
this.hasGapTag = hasGapTag; this.hasGapTag = hasGapTag;
this.extractorFactory = extractorFactory;
this.muxedCaptionFormats = muxedCaptionFormats;
this.drmInitData = drmInitData;
Extractor previousExtractor = null; Extractor previousExtractor = null;
if (previousChunk != null) { if (previousChunk != null) {
id3Decoder = previousChunk.id3Decoder;
id3Data = previousChunk.id3Data;
shouldSpliceIn = previousChunk.hlsUrl != hlsUrl; shouldSpliceIn = previousChunk.hlsUrl != hlsUrl;
previousExtractor = previousChunk.discontinuitySequenceNumber != discontinuitySequenceNumber previousExtractor = previousChunk.discontinuitySequenceNumber != discontinuitySequenceNumber
|| shouldSpliceIn ? null : previousChunk.extractor; || shouldSpliceIn ? null : previousChunk.extractor;
} else { } else {
shouldSpliceIn = false; shouldSpliceIn = false;
} }
Pair<Extractor, Boolean> extractorData = extractorFactory.createExtractor(previousExtractor, this.previousExtractor = previousExtractor;
dataSpec.uri, trackFormat, muxedCaptionFormats, drmInitData, timestampAdjuster);
extractor = extractorData.first;
isPackedAudioExtractor = extractorData.second;
reusingExtractor = extractor == previousExtractor;
initLoadCompleted = reusingExtractor && initDataSpec != null;
if (isPackedAudioExtractor) {
if (previousChunk != null && previousChunk.id3Data != null) {
id3Decoder = previousChunk.id3Decoder;
id3Data = previousChunk.id3Data;
} else {
id3Decoder = new Id3Decoder();
id3Data = new ParsableByteArray(Id3Decoder.ID3_HEADER_LENGTH);
}
} else {
id3Decoder = null;
id3Data = null;
}
initDataSource = dataSource; initDataSource = dataSource;
uid = uidSource.getAndIncrement(); uid = uidSource.getAndIncrement();
} }
...@@ -183,10 +174,6 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -183,10 +174,6 @@ import java.util.concurrent.atomic.AtomicInteger;
*/ */
public void init(HlsSampleStreamWrapper output) { public void init(HlsSampleStreamWrapper output) {
this.output = output; this.output = output;
output.init(uid, shouldSpliceIn, reusingExtractor);
if (!reusingExtractor) {
extractor.init(output);
}
} }
@Override @Override
...@@ -217,7 +204,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -217,7 +204,7 @@ import java.util.concurrent.atomic.AtomicInteger;
} }
} }
// Internal loading methods. // Internal methods.
private void maybeLoadInitData() throws IOException, InterruptedException { private void maybeLoadInitData() throws IOException, InterruptedException {
if (initLoadCompleted || initDataSpec == null) { if (initLoadCompleted || initDataSpec == null) {
...@@ -226,8 +213,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -226,8 +213,7 @@ import java.util.concurrent.atomic.AtomicInteger;
} }
DataSpec initSegmentDataSpec = initDataSpec.subrange(initSegmentBytesLoaded); DataSpec initSegmentDataSpec = initDataSpec.subrange(initSegmentBytesLoaded);
try { try {
ExtractorInput input = new DefaultExtractorInput(initDataSource, DefaultExtractorInput input = prepareExtraction(initDataSource, initSegmentDataSpec);
initSegmentDataSpec.absoluteStreamPosition, initDataSource.open(initSegmentDataSpec));
try { try {
int result = Extractor.RESULT_CONTINUE; int result = Extractor.RESULT_CONTINUE;
while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { while (result == Extractor.RESULT_CONTINUE && !loadCanceled) {
...@@ -263,8 +249,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -263,8 +249,7 @@ import java.util.concurrent.atomic.AtomicInteger;
timestampAdjuster.setFirstSampleTimestampUs(startTimeUs); timestampAdjuster.setFirstSampleTimestampUs(startTimeUs);
} }
try { try {
ExtractorInput input = new DefaultExtractorInput(dataSource, ExtractorInput input = prepareExtraction(dataSource, loadDataSpec);
loadDataSpec.absoluteStreamPosition, dataSource.open(loadDataSpec));
if (isPackedAudioExtractor && !id3TimestampPeeked) { if (isPackedAudioExtractor && !id3TimestampPeeked) {
long id3Timestamp = peekId3PrivTimestamp(input); long id3Timestamp = peekId3PrivTimestamp(input);
id3TimestampPeeked = true; id3TimestampPeeked = true;
...@@ -287,6 +272,37 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -287,6 +272,37 @@ import java.util.concurrent.atomic.AtomicInteger;
} }
} }
private DefaultExtractorInput prepareExtraction(DataSource dataSource, DataSpec dataSpec)
throws IOException {
long bytesToRead = dataSource.open(dataSpec);
if (extractor == null) {
Pair<Extractor, Boolean> extractorData =
extractorFactory.createExtractor(
previousExtractor,
dataSpec.uri,
trackFormat,
muxedCaptionFormats,
drmInitData,
timestampAdjuster,
dataSource.getResponseHeaders());
extractor = extractorData.first;
isPackedAudioExtractor = extractorData.second;
boolean reusingExtractor = extractor == previousExtractor;
initLoadCompleted = reusingExtractor && initDataSpec != null;
if (isPackedAudioExtractor && id3Data == null) {
id3Decoder = new Id3Decoder();
id3Data = new ParsableByteArray(Id3Decoder.ID3_HEADER_LENGTH);
}
output.init(uid, shouldSpliceIn, reusingExtractor);
if (!reusingExtractor) {
extractor.init(output);
}
}
return new DefaultExtractorInput(dataSource, dataSpec.absoluteStreamPosition, bytesToRead);
}
/** /**
* Peek the presentation timestamp of the first sample in the chunk from an ID3 PRIV as defined * Peek the presentation timestamp of the first sample in the chunk from an ID3 PRIV as defined
* in the HLS spec, version 20, Section 3.4. Returns {@link C#TIME_UNSET} if the frame is not * in the HLS spec, version 20, Section 3.4. Returns {@link C#TIME_UNSET} if the frame is not
......
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