Introduce ChunkExtractor.Factory for dependency injection

PiperOrigin-RevId: 360175031
This commit is contained in:
aquilescanta 2021-03-01 14:40:48 +00:00 committed by Oliver Woodman
parent aa2dc4c511
commit ef1d797681
4 changed files with 89 additions and 65 deletions

View file

@ -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;

View file

@ -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<Format> closedCaptionFormats,
@Nullable TrackOutput playerEmsgTrackOutput);
}
/** Provides {@link TrackOutput} instances to be written to during extraction. */
interface TrackOutputProvider {

View file

@ -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;

View file

@ -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<Format> 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<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);
}
}
}