From 8337991be3f57c942c95fe172f4b4d754b43e0fe Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Thu, 18 Mar 2021 13:08:11 +0000 Subject: [PATCH] Avoid invalid extractors in DefaultHlsExtractorFactory This change fixes playback of playlists where segments have the extension and Content-Type of JPEG pictures (although in reality) they are transport streams. File inferrence before this change will cause an exception when assuming the inferred file type is one of the allowed HLS containers. #minor-release Issue: #8733 PiperOrigin-RevId: 363641277 --- RELEASENOTES.md | 3 +++ .../hls/DefaultHlsExtractorFactory.java | 13 +++++----- .../hls/DefaultHlsExtractorFactoryTest.java | 26 ++++++++++++++++++- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 23ba7ca161..46364e50f7 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -39,6 +39,9 @@ `EXT-X-DISCONTINUITY` tags in different media playlists occur at different positions in time ([#8372](https://github.com/google/ExoPlayer/issues/8372)). + * Fix container type detection for segments with incorrect file extension + or HTTP Content-Type + ([#8733](https://github.com/google/ExoPlayer/issues/8733)). * Remove deprecated symbols: * Remove `Player.DefaultEventListener`. Use `Player.EventListener` instead. diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java index 4c7b5629ba..77333fd4cb 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactory.java @@ -35,6 +35,7 @@ import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.util.FileTypes; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.TimestampAdjuster; +import com.google.common.primitives.Ints; import java.io.EOFException; import java.io.IOException; import java.util.ArrayList; @@ -107,11 +108,11 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { // Defines the order in which to try the extractors. List fileTypeOrder = new ArrayList<>(/* initialCapacity= */ DEFAULT_EXTRACTOR_ORDER.length); - addFileTypeIfNotPresent(formatInferredFileType, fileTypeOrder); - addFileTypeIfNotPresent(responseHeadersInferredFileType, fileTypeOrder); - addFileTypeIfNotPresent(uriInferredFileType, fileTypeOrder); + addFileTypeIfValidAndNotPresent(formatInferredFileType, fileTypeOrder); + addFileTypeIfValidAndNotPresent(responseHeadersInferredFileType, fileTypeOrder); + addFileTypeIfValidAndNotPresent(uriInferredFileType, fileTypeOrder); for (int fileType : DEFAULT_EXTRACTOR_ORDER) { - addFileTypeIfNotPresent(fileType, fileTypeOrder); + addFileTypeIfValidAndNotPresent(fileType, fileTypeOrder); } // Extractor to be used if the type is not recognized. @@ -140,9 +141,9 @@ public final class DefaultHlsExtractorFactory implements HlsExtractorFactory { checkNotNull(fallBackExtractor), format, timestampAdjuster); } - private static void addFileTypeIfNotPresent( + private static void addFileTypeIfValidAndNotPresent( @FileTypes.Type int fileType, List fileTypes) { - if (fileType == FileTypes.UNKNOWN || fileTypes.contains(fileType)) { + if (Ints.indexOf(DEFAULT_EXTRACTOR_ORDER, fileType) == -1 || fileTypes.contains(fileType)) { return; } fileTypes.add(fileType); diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java index 2bbc5bb0f9..7055bc1ba4 100644 --- a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/DefaultHlsExtractorFactoryTest.java @@ -31,6 +31,7 @@ import com.google.android.exoplayer2.testutil.FakeExtractorInput; import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.TimestampAdjuster; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.util.Collections; import java.util.HashMap; @@ -44,8 +45,9 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class DefaultHlsExtractorFactoryTest { - private static final Uri URI_WITH_TS_EXTENSION = Uri.parse("http://path/filename.ts"); + private static final Uri URI_WITH_JPEG_EXTENSION = Uri.parse("http://path/filename.jpg"); private static final Uri URI_WITH_MP4_EXTENSION = Uri.parse("http://path/filename.mp4"); + private static final Uri URI_WITH_TS_EXTENSION = Uri.parse("http://path/filename.ts"); private Format webVttFormat; private TimestampAdjuster timestampAdjuster; @@ -151,6 +153,28 @@ public class DefaultHlsExtractorFactoryTest { assertThat(result.extractor.getClass()).isEqualTo(Mp3Extractor.class); } + @Test + public void createExtractor_withInvalidFileTypeInUri_returnsSniffedType() throws Exception { + ExtractorInput tsExtractorInput = + new FakeExtractorInput.Builder() + .setData( + TestUtil.getByteArray( + ApplicationProvider.getApplicationContext(), "media/ts/sample_ac3.ts")) + .build(); + + BundledHlsMediaChunkExtractor result = + new DefaultHlsExtractorFactory() + .createExtractor( + URI_WITH_JPEG_EXTENSION, + webVttFormat, + /* muxedCaptionFormats= */ null, + timestampAdjuster, + ImmutableMap.of("Content-Type", ImmutableList.of(MimeTypes.IMAGE_JPEG)), + tsExtractorInput); + + assertThat(result.extractor.getClass()).isEqualTo(TsExtractor.class); + } + @Test public void createExtractor_onFailedSniff_fallsBackOnFormatInferred() throws Exception { ExtractorInput emptyExtractorInput = new FakeExtractorInput.Builder().build();