Commit ef1d7976 by aquilescanta Committed by Oliver Woodman

Introduce ChunkExtractor.Factory for dependency injection

PiperOrigin-RevId: 360175031
parent aa2dc4c5
...@@ -29,8 +29,12 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput; ...@@ -29,8 +29,12 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; 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.upstream.DataReader;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.ParsableByteArray;
import java.io.IOException; import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
...@@ -41,6 +45,41 @@ 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 { 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 static final PositionHolder POSITION_HOLDER = new PositionHolder();
private final Extractor extractor; private final Extractor extractor;
......
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.extractor.ChunkIndex; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.extractor.ChunkIndex;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import java.io.IOException; import java.io.IOException;
import java.util.List;
/** /**
* Extracts samples and track {@link Format Formats} from chunks. * Extracts samples and track {@link Format Formats} from chunks.
...@@ -31,6 +32,27 @@ import java.io.IOException; ...@@ -31,6 +32,27 @@ import java.io.IOException;
*/ */
public interface ChunkExtractor { 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<Format> closedCaptionFormats,
@Nullable TrackOutput playerEmsgTrackOutput);
}
/** Provides {@link TrackOutput} instances to be written to during extraction. */ /** Provides {@link TrackOutput} instances to be written to during extraction. */
interface TrackOutputProvider { interface TrackOutputProvider {
......
...@@ -26,6 +26,7 @@ import static com.google.android.exoplayer2.source.mediaparser.MediaParserUtil.P ...@@ -26,6 +26,7 @@ import static com.google.android.exoplayer2.source.mediaparser.MediaParserUtil.P
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.media.MediaFormat; import android.media.MediaFormat;
import android.media.MediaParser; import android.media.MediaParser;
import android.util.Log;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
...@@ -49,6 +50,25 @@ import java.util.List; ...@@ -49,6 +50,25 @@ import java.util.List;
@RequiresApi(30) @RequiresApi(30)
public final class MediaParserChunkExtractor implements ChunkExtractor { 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 OutputConsumerAdapterV30 outputConsumerAdapter;
private final InputReaderAdapterV30 inputReaderAdapter; private final InputReaderAdapterV30 inputReaderAdapter;
private final MediaParser mediaParser; private final MediaParser mediaParser;
......
...@@ -26,11 +26,6 @@ import com.google.android.exoplayer2.C; ...@@ -26,11 +26,6 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SeekParameters; import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.extractor.ChunkIndex; 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.BehindLiveWindowException;
import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator;
import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor; import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor;
...@@ -53,7 +48,6 @@ import com.google.android.exoplayer2.upstream.DataSpec; ...@@ -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.HttpDataSource.InvalidResponseCodeException;
import com.google.android.exoplayer2.upstream.LoaderErrorThrower; import com.google.android.exoplayer2.upstream.LoaderErrorThrower;
import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -180,11 +174,15 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -180,11 +174,15 @@ public class DefaultDashChunkSource implements DashChunkSource {
representationHolders[i] = representationHolders[i] =
new RepresentationHolder( new RepresentationHolder(
periodDurationUs, periodDurationUs,
trackType,
representation, representation,
enableEventMessageTrack, BundledChunkExtractor.FACTORY.createProgressiveMediaExtractor(
closedCaptionFormats, trackType,
playerTrackEmsgHandler); representation.format,
enableEventMessageTrack,
closedCaptionFormats,
playerTrackEmsgHandler),
/* segmentNumShift= */ 0,
representation.getIndex());
} }
} }
...@@ -666,26 +664,6 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -666,26 +664,6 @@ public class DefaultDashChunkSource implements DashChunkSource {
/* package */ RepresentationHolder( /* package */ RepresentationHolder(
long periodDurationUs, long periodDurationUs,
int trackType,
Representation representation,
boolean enableEventMessageTrack,
List<Format> closedCaptionFormats,
@Nullable TrackOutput playerEmsgTrackOutput) {
this(
periodDurationUs,
representation,
createChunkExtractor(
trackType,
representation,
enableEventMessageTrack,
closedCaptionFormats,
playerEmsgTrackOutput),
/* segmentNumShift= */ 0,
representation.getIndex());
}
private RepresentationHolder(
long periodDurationUs,
Representation representation, Representation representation,
@Nullable ChunkExtractor chunkExtractor, @Nullable ChunkExtractor chunkExtractor,
long segmentNumShift, long segmentNumShift,
...@@ -800,40 +778,5 @@ public class DefaultDashChunkSource implements DashChunkSource { ...@@ -800,40 +778,5 @@ public class DefaultDashChunkSource implements DashChunkSource {
public boolean isSegmentAvailableAtFullNetworkSpeed(long segmentNum, long nowPeriodTimeUs) { public boolean isSegmentAvailableAtFullNetworkSpeed(long segmentNum, long nowPeriodTimeUs) {
return nowPeriodTimeUs == C.TIME_UNSET || getSegmentEndTimeUs(segmentNum) <= nowPeriodTimeUs; return nowPeriodTimeUs == C.TIME_UNSET || getSegmentEndTimeUs(segmentNum) <= nowPeriodTimeUs;
} }
@Nullable
private static ChunkExtractor createChunkExtractor(
int trackType,
Representation representation,
boolean enableEventMessageTrack,
List<Format> 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);
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment