mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Introduce ChunkExtractor.Factory for dependency injection
PiperOrigin-RevId: 360175031
This commit is contained in:
parent
aa2dc4c511
commit
ef1d797681
4 changed files with 89 additions and 65 deletions
|
|
@ -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;
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
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;
|
||||||
*/
|
*/
|
||||||
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
|
||||||
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;
|
||||||
@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;
|
||||||
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;
|
||||||
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 {
|
||||||
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -665,26 +663,6 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
private final long segmentNumShift;
|
private final long segmentNumShift;
|
||||||
|
|
||||||
/* package */ RepresentationHolder(
|
/* 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,
|
long periodDurationUs,
|
||||||
Representation representation,
|
Representation representation,
|
||||||
@Nullable ChunkExtractor chunkExtractor,
|
@Nullable ChunkExtractor chunkExtractor,
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue