mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Pass HTTP DataSource's response headers to HlsExtractorFactory
Issue:#2025 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=200212344
This commit is contained in:
parent
37516d3126
commit
943de70a15
4 changed files with 69 additions and 39 deletions
|
|
@ -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;
|
||||||
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 {
|
||||||
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;
|
||||||
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 {
|
||||||
* 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;
|
||||||
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;
|
||||||
// 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;
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
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;
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue