Fallback to inferred file types when sniffing fails
If none of the extractors successfully sniff the content then we will fall back to inferred file types in the following order: - Webvtt if the media comes from a SUBTITLE EXT-X-MEDIA. - The type of media declared in the HTTP "Content-Type" header. - The type of the media according to the file extension. - Transport stream. Issue: #8700 PiperOrigin-RevId: 362519769
This commit is contained in:
parent
3dae045487
commit
21326e67e3
@ -125,9 +125,13 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory {
|
|||||||
if (sniffQuietly(extractor, extractorInput)) {
|
if (sniffQuietly(extractor, extractorInput)) {
|
||||||
return new BundledHlsMediaChunkExtractor(extractor, format, timestampAdjuster);
|
return new BundledHlsMediaChunkExtractor(extractor, format, timestampAdjuster);
|
||||||
}
|
}
|
||||||
if (fileType == FileTypes.TS) {
|
if (fallBackExtractor == null
|
||||||
// Fall back on TsExtractor to handle TS streams with an EXT-X-MAP tag. See
|
&& (fileType == formatInferredFileType
|
||||||
// https://github.com/google/ExoPlayer/issues/8219.
|
|| fileType == responseHeadersInferredFileType
|
||||||
|
|| fileType == uriInferredFileType
|
||||||
|
|| fileType == FileTypes.TS)) {
|
||||||
|
// If sniffing fails, fallback to the file types inferred from context. If all else fails,
|
||||||
|
// fallback to Transport Stream. See https://github.com/google/ExoPlayer/issues/8219.
|
||||||
fallBackExtractor = extractor;
|
fallBackExtractor = extractor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,14 @@ import com.google.android.exoplayer2.Format;
|
|||||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||||
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
import com.google.android.exoplayer2.extractor.ExtractorInput;
|
||||||
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
|
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
|
||||||
|
import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor;
|
||||||
import com.google.android.exoplayer2.extractor.ts.Ac3Extractor;
|
import com.google.android.exoplayer2.extractor.ts.Ac3Extractor;
|
||||||
import com.google.android.exoplayer2.extractor.ts.TsExtractor;
|
import com.google.android.exoplayer2.extractor.ts.TsExtractor;
|
||||||
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
import com.google.android.exoplayer2.testutil.FakeExtractorInput;
|
||||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
import com.google.android.exoplayer2.util.TimestampAdjuster;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -42,14 +44,15 @@ import org.junit.runner.RunWith;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class DefaultHlsExtractorFactoryTest {
|
public class DefaultHlsExtractorFactoryTest {
|
||||||
|
|
||||||
private Uri tsUri;
|
private static final Uri URI_WITH_TS_EXTENSION = Uri.parse("http://path/filename.ts");
|
||||||
|
private static final Uri URI_WITH_MP4_EXTENSION = Uri.parse("http://path/filename.mp4");
|
||||||
|
|
||||||
private Format webVttFormat;
|
private Format webVttFormat;
|
||||||
private TimestampAdjuster timestampAdjuster;
|
private TimestampAdjuster timestampAdjuster;
|
||||||
private Map<String, List<String>> ac3ResponseHeaders;
|
private Map<String, List<String>> ac3ResponseHeaders;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
tsUri = Uri.parse("http://path/filename.ts");
|
|
||||||
webVttFormat = new Format.Builder().setSampleMimeType(MimeTypes.TEXT_VTT).build();
|
webVttFormat = new Format.Builder().setSampleMimeType(MimeTypes.TEXT_VTT).build();
|
||||||
timestampAdjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0);
|
timestampAdjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0);
|
||||||
ac3ResponseHeaders = new HashMap<>();
|
ac3ResponseHeaders = new HashMap<>();
|
||||||
@ -69,7 +72,7 @@ public class DefaultHlsExtractorFactoryTest {
|
|||||||
BundledHlsMediaChunkExtractor result =
|
BundledHlsMediaChunkExtractor result =
|
||||||
new DefaultHlsExtractorFactory()
|
new DefaultHlsExtractorFactory()
|
||||||
.createExtractor(
|
.createExtractor(
|
||||||
tsUri,
|
URI_WITH_TS_EXTENSION,
|
||||||
webVttFormat,
|
webVttFormat,
|
||||||
/* muxedCaptionFormats= */ null,
|
/* muxedCaptionFormats= */ null,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
@ -93,7 +96,7 @@ public class DefaultHlsExtractorFactoryTest {
|
|||||||
BundledHlsMediaChunkExtractor result =
|
BundledHlsMediaChunkExtractor result =
|
||||||
new DefaultHlsExtractorFactory()
|
new DefaultHlsExtractorFactory()
|
||||||
.createExtractor(
|
.createExtractor(
|
||||||
tsUri,
|
URI_WITH_TS_EXTENSION,
|
||||||
webVttFormat,
|
webVttFormat,
|
||||||
/* muxedCaptionFormats= */ null,
|
/* muxedCaptionFormats= */ null,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
@ -115,7 +118,7 @@ public class DefaultHlsExtractorFactoryTest {
|
|||||||
BundledHlsMediaChunkExtractor result =
|
BundledHlsMediaChunkExtractor result =
|
||||||
new DefaultHlsExtractorFactory()
|
new DefaultHlsExtractorFactory()
|
||||||
.createExtractor(
|
.createExtractor(
|
||||||
tsUri,
|
URI_WITH_TS_EXTENSION,
|
||||||
webVttFormat,
|
webVttFormat,
|
||||||
/* muxedCaptionFormats= */ null,
|
/* muxedCaptionFormats= */ null,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
@ -138,7 +141,7 @@ public class DefaultHlsExtractorFactoryTest {
|
|||||||
BundledHlsMediaChunkExtractor result =
|
BundledHlsMediaChunkExtractor result =
|
||||||
new DefaultHlsExtractorFactory()
|
new DefaultHlsExtractorFactory()
|
||||||
.createExtractor(
|
.createExtractor(
|
||||||
tsUri,
|
URI_WITH_TS_EXTENSION,
|
||||||
webVttFormat,
|
webVttFormat,
|
||||||
/* muxedCaptionFormats= */ null,
|
/* muxedCaptionFormats= */ null,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
@ -149,19 +152,75 @@ public class DefaultHlsExtractorFactoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void createExtractor_withNoMatchingExtractor_fallsBackOnTsExtractor() throws Exception {
|
public void createExtractor_onFailedSniff_fallsBackOnFormatInferred() throws Exception {
|
||||||
ExtractorInput emptyExtractorInput = new FakeExtractorInput.Builder().build();
|
ExtractorInput emptyExtractorInput = new FakeExtractorInput.Builder().build();
|
||||||
|
|
||||||
BundledHlsMediaChunkExtractor result =
|
BundledHlsMediaChunkExtractor result =
|
||||||
new DefaultHlsExtractorFactory()
|
new DefaultHlsExtractorFactory()
|
||||||
.createExtractor(
|
.createExtractor(
|
||||||
tsUri,
|
URI_WITH_MP4_EXTENSION,
|
||||||
webVttFormat,
|
webVttFormat,
|
||||||
/* muxedCaptionFormats= */ null,
|
/* muxedCaptionFormats= */ null,
|
||||||
timestampAdjuster,
|
timestampAdjuster,
|
||||||
ac3ResponseHeaders,
|
ac3ResponseHeaders,
|
||||||
emptyExtractorInput);
|
emptyExtractorInput);
|
||||||
|
|
||||||
|
// The format indicates WebVTT so we expect a WebVTT extractor.
|
||||||
|
assertThat(result.extractor.getClass()).isEqualTo(WebvttExtractor.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createExtractor_onFailedSniff_fallsBackOnHttpContentType() throws Exception {
|
||||||
|
ExtractorInput emptyExtractorInput = new FakeExtractorInput.Builder().build();
|
||||||
|
|
||||||
|
BundledHlsMediaChunkExtractor result =
|
||||||
|
new DefaultHlsExtractorFactory()
|
||||||
|
.createExtractor(
|
||||||
|
URI_WITH_MP4_EXTENSION,
|
||||||
|
new Format.Builder().build(),
|
||||||
|
/* muxedCaptionFormats= */ null,
|
||||||
|
timestampAdjuster,
|
||||||
|
ac3ResponseHeaders,
|
||||||
|
emptyExtractorInput);
|
||||||
|
|
||||||
|
// No format info, so we expect an AC-3 Extractor, as per HTTP Content-Type header.
|
||||||
|
assertThat(result.extractor.getClass()).isEqualTo(Ac3Extractor.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createExtractor_onFailedSniff_fallsBackOnFileExtension() throws Exception {
|
||||||
|
ExtractorInput emptyExtractorInput = new FakeExtractorInput.Builder().build();
|
||||||
|
|
||||||
|
BundledHlsMediaChunkExtractor result =
|
||||||
|
new DefaultHlsExtractorFactory()
|
||||||
|
.createExtractor(
|
||||||
|
URI_WITH_MP4_EXTENSION,
|
||||||
|
new Format.Builder().build(),
|
||||||
|
/* muxedCaptionFormats= */ null,
|
||||||
|
timestampAdjuster,
|
||||||
|
/* responseHeaders= */ ImmutableMap.of(),
|
||||||
|
emptyExtractorInput);
|
||||||
|
|
||||||
|
// No format info, and no HTTP headers, so we expect an fMP4 extractor, as per file extension.
|
||||||
|
assertThat(result.extractor.getClass()).isEqualTo(FragmentedMp4Extractor.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createExtractor_onFailedSniff_fallsBackOnTsExtractor() throws Exception {
|
||||||
|
ExtractorInput emptyExtractorInput = new FakeExtractorInput.Builder().build();
|
||||||
|
|
||||||
|
BundledHlsMediaChunkExtractor result =
|
||||||
|
new DefaultHlsExtractorFactory()
|
||||||
|
.createExtractor(
|
||||||
|
Uri.parse("http://path/no_extension"),
|
||||||
|
new Format.Builder().build(),
|
||||||
|
/* muxedCaptionFormats= */ null,
|
||||||
|
timestampAdjuster,
|
||||||
|
/* responseHeaders= */ ImmutableMap.of(),
|
||||||
|
emptyExtractorInput);
|
||||||
|
|
||||||
|
// There's no information for inferring the file type, we expect the factory to fall back on
|
||||||
|
// Transport Stream.
|
||||||
assertThat(result.extractor.getClass()).isEqualTo(TsExtractor.class);
|
assertThat(result.extractor.getClass()).isEqualTo(TsExtractor.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user