Optimize extractors sniffing order

Issue: #6410
PiperOrigin-RevId: 305436352
This commit is contained in:
kimvde 2020-04-08 10:20:36 +01:00 committed by Oliver Woodman
parent 4e2a0f6032
commit 703fb777c4
3 changed files with 77 additions and 58 deletions

View File

@ -109,6 +109,9 @@
* Cast extension: Implement playlist API and deprecate the old queue
manipulation API.
* Demo app: Retain previous position in list of samples.
* Change the order of extractors for sniffing to reduce start-up latency in
`DefaultExtractorsFactory` and `DefaultHlsExtractorsFactory`
([#6410](https://github.com/google/ExoPlayer/issues/6410)).
### 2.11.4 (2020-04-08)

View File

@ -241,44 +241,46 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory {
@Override
public synchronized Extractor[] createExtractors() {
Extractor[] extractors = new Extractor[14];
extractors[0] = new MatroskaExtractor(matroskaFlags);
extractors[1] = new FragmentedMp4Extractor(fragmentedMp4Flags);
extractors[2] = new Mp4Extractor(mp4Flags);
extractors[3] =
new Mp3Extractor(
mp3Flags
| (constantBitrateSeekingEnabled
? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
extractors[4] =
new AdtsExtractor(
adtsFlags
| (constantBitrateSeekingEnabled
? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
extractors[5] = new Ac3Extractor();
extractors[6] = new TsExtractor(tsMode, tsFlags);
extractors[7] = new FlvExtractor();
extractors[8] = new OggExtractor();
extractors[9] = new PsExtractor();
extractors[10] = new WavExtractor();
extractors[11] =
new AmrExtractor(
amrFlags
| (constantBitrateSeekingEnabled
? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
extractors[12] = new Ac4Extractor();
// Extractors order is optimized according to
// https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ.
extractors[0] = new FlvExtractor();
if (FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR != null) {
try {
extractors[13] = FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR.newInstance();
extractors[1] = FLAC_EXTENSION_EXTRACTOR_CONSTRUCTOR.newInstance();
} catch (Exception e) {
// Should never happen.
throw new IllegalStateException("Unexpected error creating FLAC extractor", e);
}
} else {
extractors[13] = new FlacExtractor(coreFlacFlags);
extractors[1] = new FlacExtractor(coreFlacFlags);
}
extractors[2] = new WavExtractor();
extractors[3] = new FragmentedMp4Extractor(fragmentedMp4Flags);
extractors[4] = new Mp4Extractor(mp4Flags);
extractors[5] =
new AmrExtractor(
amrFlags
| (constantBitrateSeekingEnabled
? AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
extractors[6] = new PsExtractor();
extractors[7] = new OggExtractor();
extractors[8] = new TsExtractor(tsMode, tsFlags);
extractors[9] = new MatroskaExtractor(matroskaFlags);
extractors[10] =
new AdtsExtractor(
adtsFlags
| (constantBitrateSeekingEnabled
? AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
extractors[11] = new Ac3Extractor();
extractors[12] = new Ac4Extractor();
extractors[13] =
new Mp3Extractor(
mp3Flags
| (constantBitrateSeekingEnabled
? Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING
: 0));
return extractors;
}

View File

@ -29,6 +29,7 @@ import com.google.android.exoplayer2.extractor.ts.AdtsExtractor;
import com.google.android.exoplayer2.extractor.ts.DefaultTsPayloadReaderFactory;
import com.google.android.exoplayer2.extractor.ts.TsExtractor;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.TimestampAdjuster;
import java.io.EOFException;
@ -51,6 +52,8 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
public static final String M4_FILE_EXTENSION_PREFIX = ".m4";
public static final String MP4_FILE_EXTENSION_PREFIX = ".mp4";
public static final String CMF_FILE_EXTENSION_PREFIX = ".cmf";
public static final String TS_FILE_EXTENSION = ".ts";
public static final String TS_FILE_EXTENSION_PREFIX = ".ts";
public static final String VTT_FILE_EXTENSION = ".vtt";
public static final String WEBVTT_FILE_EXTENSION = ".webvtt";
@ -94,7 +97,7 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
throws IOException {
if (previousExtractor != null) {
// A extractor has already been successfully used. Return one of the same type.
// An extractor has already been successfully used. Return one of the same type.
if (isReusable(previousExtractor)) {
return buildResult(previousExtractor);
} else {
@ -108,15 +111,29 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
}
// Try selecting the extractor by the file extension.
@Nullable
Extractor extractorByFileExtension =
createExtractorByFileExtension(uri, format, muxedCaptionFormats, timestampAdjuster);
extractorInput.resetPeekPosition();
if (sniffQuietly(extractorByFileExtension, extractorInput)) {
if (extractorByFileExtension != null
&& sniffQuietly(extractorByFileExtension, extractorInput)) {
return buildResult(extractorByFileExtension);
}
// We need to manually sniff each known type, without retrying the one selected by file
// extension.
// extension. Extractors order is optimized according to
// https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ.
// Extractor to be used if the type is not recognized.
@Nullable Extractor fallBackExtractor = extractorByFileExtension;
if (!(extractorByFileExtension instanceof FragmentedMp4Extractor)) {
FragmentedMp4Extractor fragmentedMp4Extractor =
createFragmentedMp4Extractor(timestampAdjuster, format, muxedCaptionFormats);
if (sniffQuietly(fragmentedMp4Extractor, extractorInput)) {
return buildResult(fragmentedMp4Extractor);
}
}
if (!(extractorByFileExtension instanceof WebvttExtractor)) {
WebvttExtractor webvttExtractor = new WebvttExtractor(format.language, timestampAdjuster);
@ -125,6 +142,22 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
}
}
if (!(extractorByFileExtension instanceof TsExtractor)) {
TsExtractor tsExtractor =
createTsExtractor(
payloadReaderFactoryFlags,
exposeCea608WhenMissingDeclarations,
format,
muxedCaptionFormats,
timestampAdjuster);
if (sniffQuietly(tsExtractor, extractorInput)) {
return buildResult(tsExtractor);
}
if (fallBackExtractor == null) {
fallBackExtractor = tsExtractor;
}
}
if (!(extractorByFileExtension instanceof AdtsExtractor)) {
AdtsExtractor adtsExtractor = new AdtsExtractor();
if (sniffQuietly(adtsExtractor, extractorInput)) {
@ -154,31 +187,10 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
}
}
if (!(extractorByFileExtension instanceof FragmentedMp4Extractor)) {
FragmentedMp4Extractor fragmentedMp4Extractor =
createFragmentedMp4Extractor(timestampAdjuster, format, muxedCaptionFormats);
if (sniffQuietly(fragmentedMp4Extractor, extractorInput)) {
return buildResult(fragmentedMp4Extractor);
}
}
if (!(extractorByFileExtension instanceof TsExtractor)) {
TsExtractor tsExtractor =
createTsExtractor(
payloadReaderFactoryFlags,
exposeCea608WhenMissingDeclarations,
format,
muxedCaptionFormats,
timestampAdjuster);
if (sniffQuietly(tsExtractor, extractorInput)) {
return buildResult(tsExtractor);
}
}
// Fall back on the extractor created by file extension.
return buildResult(extractorByFileExtension);
return buildResult(Assertions.checkNotNull(fallBackExtractor));
}
@Nullable
private Extractor createExtractorByFileExtension(
Uri uri,
Format format,
@ -206,14 +218,16 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|| lastPathSegment.startsWith(MP4_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 5)
|| lastPathSegment.startsWith(CMF_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 5)) {
return createFragmentedMp4Extractor(timestampAdjuster, format, muxedCaptionFormats);
} else {
// For any other file extension, we assume TS format.
} else if (lastPathSegment.endsWith(TS_FILE_EXTENSION)
|| lastPathSegment.startsWith(TS_FILE_EXTENSION_PREFIX, lastPathSegment.length() - 4)) {
return createTsExtractor(
payloadReaderFactoryFlags,
exposeCea608WhenMissingDeclarations,
format,
muxedCaptionFormats,
timestampAdjuster);
} else {
return null;
}
}