From ef1d797681c6559b63faded7a6d715f3ca249792 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Mon, 1 Mar 2021 14:40:48 +0000 Subject: [PATCH] Introduce ChunkExtractor.Factory for dependency injection PiperOrigin-RevId: 360175031 --- .../source/chunk/BundledChunkExtractor.java | 39 ++++++++++ .../source/chunk/ChunkExtractor.java | 22 ++++++ .../chunk/MediaParserChunkExtractor.java | 20 +++++ .../source/dash/DefaultDashChunkSource.java | 73 ++----------------- 4 files changed, 89 insertions(+), 65 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BundledChunkExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BundledChunkExtractor.java index f02329d5d5..ff19ee1d26 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BundledChunkExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BundledChunkExtractor.java @@ -29,8 +29,12 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; +import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.extractor.rawcc.RawCcExtractor; import com.google.android.exoplayer2.upstream.DataReader; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.ParsableByteArray; import java.io.IOException; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -41,6 +45,41 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; */ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtractor { + /** {@link ChunkExtractor.Factory} for instances of this class. */ + public static final ChunkExtractor.Factory FACTORY = + (primaryTrackType, + format, + enableEventMessageTrack, + closedCaptionFormats, + playerEmsgTrackOutput) -> { + @Nullable String containerMimeType = format.containerMimeType; + Extractor extractor; + if (MimeTypes.isText(containerMimeType)) { + if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) { + // RawCC is special because it's a text specific container format. + extractor = new RawCcExtractor(format); + } else { + // All other text types are raw formats that do not need an extractor. + return null; + } + } else if (MimeTypes.isMatroska(containerMimeType)) { + extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES); + } else { + int flags = 0; + if (enableEventMessageTrack) { + flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK; + } + extractor = + new FragmentedMp4Extractor( + flags, + /* timestampAdjuster= */ null, + /* sideloadedTrack= */ null, + closedCaptionFormats, + playerEmsgTrackOutput); + } + return new BundledChunkExtractor(extractor, primaryTrackType, format); + }; + private static final PositionHolder POSITION_HOLDER = new PositionHolder(); private final Extractor extractor; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractor.java index 6bfe9590db..60774c3ea6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractor.java @@ -22,6 +22,7 @@ import com.google.android.exoplayer2.extractor.ChunkIndex; import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.TrackOutput; import java.io.IOException; +import java.util.List; /** * Extracts samples and track {@link Format Formats} from chunks. @@ -31,6 +32,27 @@ import java.io.IOException; */ public interface ChunkExtractor { + /** Creates {@link ChunkExtractor} instances. */ + interface Factory { + + /** + * Returns a new {@link ChunkExtractor} instance. + * + * @param primaryTrackType The type of the primary track. One of {@link C C.TRACK_TYPE_*}. + * @param representationFormat The format of the representation to extract from. + * @param enableEventMessageTrack Whether to enable the event message track. + * @param closedCaptionFormats The {@link Format Formats} of the Closed-Caption tracks. + * @return A new {@link ChunkExtractor} instance, or null if not applicable. + */ + @Nullable + ChunkExtractor createProgressiveMediaExtractor( + int primaryTrackType, + Format representationFormat, + boolean enableEventMessageTrack, + List closedCaptionFormats, + @Nullable TrackOutput playerEmsgTrackOutput); + } + /** Provides {@link TrackOutput} instances to be written to during extraction. */ interface TrackOutputProvider { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.java index 7c440b46d7..ffedb4b1ff 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/MediaParserChunkExtractor.java @@ -26,6 +26,7 @@ import static com.google.android.exoplayer2.source.mediaparser.MediaParserUtil.P import android.annotation.SuppressLint; import android.media.MediaFormat; import android.media.MediaParser; +import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import com.google.android.exoplayer2.C; @@ -49,6 +50,25 @@ import java.util.List; @RequiresApi(30) public final class MediaParserChunkExtractor implements ChunkExtractor { + // Maximum TAG length is 23 characters. + private static final String TAG = "MediaPrsrChunkExtractor"; + + public static final ChunkExtractor.Factory FACTORY = + (primaryTrackType, + format, + enableEventMessageTrack, + closedCaptionFormats, + playerEmsgTrackOutput) -> { + if (!MimeTypes.isText(format.containerMimeType)) { + // Container is either Matroska or Fragmented MP4. + return new MediaParserChunkExtractor(primaryTrackType, format, closedCaptionFormats); + } else { + // This is either RAWCC (unsupported) or a text track that does not require an extractor. + Log.w(TAG, "Ignoring an unsupported text track."); + return null; + } + }; + private final OutputConsumerAdapterV30 outputConsumerAdapter; private final InputReaderAdapterV30 inputReaderAdapter; private final MediaParser mediaParser; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index 2225589950..809f0d10c3 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -26,11 +26,6 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.extractor.ChunkIndex; -import com.google.android.exoplayer2.extractor.Extractor; -import com.google.android.exoplayer2.extractor.TrackOutput; -import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; -import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import com.google.android.exoplayer2.extractor.rawcc.RawCcExtractor; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor; @@ -53,7 +48,6 @@ import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException; import com.google.android.exoplayer2.upstream.LoaderErrorThrower; import com.google.android.exoplayer2.upstream.TransferListener; -import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; import java.io.IOException; import java.util.ArrayList; @@ -180,11 +174,15 @@ public class DefaultDashChunkSource implements DashChunkSource { representationHolders[i] = new RepresentationHolder( periodDurationUs, - trackType, representation, - enableEventMessageTrack, - closedCaptionFormats, - playerTrackEmsgHandler); + BundledChunkExtractor.FACTORY.createProgressiveMediaExtractor( + trackType, + representation.format, + enableEventMessageTrack, + closedCaptionFormats, + playerTrackEmsgHandler), + /* segmentNumShift= */ 0, + representation.getIndex()); } } @@ -665,26 +663,6 @@ public class DefaultDashChunkSource implements DashChunkSource { private final long segmentNumShift; /* package */ RepresentationHolder( - long periodDurationUs, - int trackType, - Representation representation, - boolean enableEventMessageTrack, - List closedCaptionFormats, - @Nullable TrackOutput playerEmsgTrackOutput) { - this( - periodDurationUs, - representation, - createChunkExtractor( - trackType, - representation, - enableEventMessageTrack, - closedCaptionFormats, - playerEmsgTrackOutput), - /* segmentNumShift= */ 0, - representation.getIndex()); - } - - private RepresentationHolder( long periodDurationUs, Representation representation, @Nullable ChunkExtractor chunkExtractor, @@ -800,40 +778,5 @@ public class DefaultDashChunkSource implements DashChunkSource { public boolean isSegmentAvailableAtFullNetworkSpeed(long segmentNum, long nowPeriodTimeUs) { return nowPeriodTimeUs == C.TIME_UNSET || getSegmentEndTimeUs(segmentNum) <= nowPeriodTimeUs; } - - @Nullable - private static ChunkExtractor createChunkExtractor( - int trackType, - Representation representation, - boolean enableEventMessageTrack, - List closedCaptionFormats, - @Nullable TrackOutput playerEmsgTrackOutput) { - String containerMimeType = representation.format.containerMimeType; - Extractor extractor; - if (MimeTypes.isText(containerMimeType)) { - if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) { - // RawCC is special because it's a text specific container format. - extractor = new RawCcExtractor(representation.format); - } else { - // All other text types are raw formats that do not need an extractor. - return null; - } - } else if (MimeTypes.isMatroska(containerMimeType)) { - extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES); - } else { - int flags = 0; - if (enableEventMessageTrack) { - flags |= FragmentedMp4Extractor.FLAG_ENABLE_EMSG_TRACK; - } - extractor = - new FragmentedMp4Extractor( - flags, - /* timestampAdjuster= */ null, - /* sideloadedTrack= */ null, - closedCaptionFormats, - playerEmsgTrackOutput); - } - return new BundledChunkExtractor(extractor, trackType, representation.format); - } } }