From 32c356177f2c4d420293e9c6e6abcee63c2cccbe Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Wed, 27 May 2020 12:57:11 +0100 Subject: [PATCH] Extract a ChunkExtractor interface A future implementation will depend on MediaParser. PiperOrigin-RevId: 313367998 --- .../source/chunk/BaseMediaChunkOutput.java | 2 +- ...rapper.java => BundledChunkExtractor.java} | 70 +++++---------- .../source/chunk/ChunkExtractor.java | 86 +++++++++++++++++++ .../source/chunk/ContainerMediaChunk.java | 18 ++-- .../source/chunk/InitializationChunk.java | 18 ++-- .../exoplayer2/source/dash/DashUtil.java | 48 ++++++----- .../source/dash/DefaultDashChunkSource.java | 45 ++++++---- .../smoothstreaming/DefaultSsChunkSource.java | 19 ++-- 8 files changed, 187 insertions(+), 119 deletions(-) rename library/core/src/main/java/com/google/android/exoplayer2/source/chunk/{ChunkExtractorWrapper.java => BundledChunkExtractor.java} (75%) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractor.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java index 50c37f8b31..961d1f8db6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BaseMediaChunkOutput.java @@ -18,7 +18,7 @@ package com.google.android.exoplayer2.source.chunk; import com.google.android.exoplayer2.extractor.DummyTrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.source.SampleQueue; -import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider; +import com.google.android.exoplayer2.source.chunk.ChunkExtractor.TrackOutputProvider; import com.google.android.exoplayer2.util.Log; /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BundledChunkExtractor.java similarity index 75% rename from library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java rename to library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BundledChunkExtractor.java index f2362f2eb1..6038ad2040 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/BundledChunkExtractor.java @@ -23,7 +23,9 @@ import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.DummyTrackOutput; import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; 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.upstream.DataReader; @@ -33,34 +35,14 @@ import java.io.IOException; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** - * An {@link Extractor} wrapper for loading chunks that contain a single primary track, and possibly - * additional embedded tracks. - *

- * The wrapper allows switching of the {@link TrackOutput}s that receive parsed data. + * {@link ChunkExtractor} implementation that uses ExoPlayer app-bundled {@link Extractor + * Extractors}. */ -public final class ChunkExtractorWrapper implements ExtractorOutput { +public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtractor { - /** - * Provides {@link TrackOutput} instances to be written to by the wrapper. - */ - public interface TrackOutputProvider { - - /** - * Called to get the {@link TrackOutput} for a specific track. - *

- * The same {@link TrackOutput} is returned if multiple calls are made with the same {@code id}. - * - * @param id A track identifier. - * @param type The type of the track. Typically one of the - * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. - * @return The {@link TrackOutput} for the given track identifier. - */ - TrackOutput track(int id, int type); - - } - - public final Extractor extractor; + private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder(); + private final Extractor extractor; private final int primaryTrackType; private final Format primaryTrackManifestFormat; private final SparseArray bindingTrackOutputs; @@ -72,48 +54,37 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { private Format @MonotonicNonNull [] sampleFormats; /** + * Creates an instance. + * * @param extractor The extractor to wrap. - * @param primaryTrackType The type of the primary track. Typically one of the - * {@link com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. + * @param primaryTrackType The type of the primary track. Typically one of the {@link + * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param primaryTrackManifestFormat A manifest defined {@link Format} whose data should be merged * into any sample {@link Format} output from the {@link Extractor} for the primary track. */ - public ChunkExtractorWrapper(Extractor extractor, int primaryTrackType, - Format primaryTrackManifestFormat) { + public BundledChunkExtractor( + Extractor extractor, int primaryTrackType, Format primaryTrackManifestFormat) { this.extractor = extractor; this.primaryTrackType = primaryTrackType; this.primaryTrackManifestFormat = primaryTrackManifestFormat; bindingTrackOutputs = new SparseArray<>(); } - /** - * Returns the {@link SeekMap} most recently output by the extractor, or null if the extractor has - * not output a {@link SeekMap}. - */ + // ChunkExtractor implementation. + + @Override @Nullable public SeekMap getSeekMap() { return seekMap; } - /** - * Returns the sample {@link Format}s for the tracks identified by the extractor, or null if the - * extractor has not finished identifying tracks. - */ + @Override @Nullable public Format[] getSampleFormats() { return sampleFormats; } - /** - * Initializes the wrapper to output to {@link TrackOutput}s provided by the specified {@link - * TrackOutputProvider}, and configures the extractor to receive data from a new chunk. - * - * @param trackOutputProvider The provider of {@link TrackOutput}s that will receive sample data. - * @param startTimeUs The start position in the new chunk, or {@link C#TIME_UNSET} to output - * samples from the start of the chunk. - * @param endTimeUs The end position in the new chunk, or {@link C#TIME_UNSET} to output samples - * to the end of the chunk. - */ + @Override public void init( @Nullable TrackOutputProvider trackOutputProvider, long startTimeUs, long endTimeUs) { this.trackOutputProvider = trackOutputProvider; @@ -132,6 +103,11 @@ public final class ChunkExtractorWrapper implements ExtractorOutput { } } + @Override + public int read(ExtractorInput input) throws IOException { + return extractor.read(input, DUMMY_POSITION_HOLDER); + } + // ExtractorOutput implementation. @Override 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 new file mode 100644 index 0000000000..ee4daea725 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractor.java @@ -0,0 +1,86 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source.chunk; + +import androidx.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import java.io.IOException; + +/** + * Extracts samples and track {@link Format Formats} from chunks. + * + *

The {@link TrackOutputProvider} passed to {@link #init} provides the {@link TrackOutput + * TrackOutputs} that receive the extracted data. + */ +public interface ChunkExtractor { + + /** Provides {@link TrackOutput} instances to be written to during extraction. */ + interface TrackOutputProvider { + + /** + * Called to get the {@link TrackOutput} for a specific track. + * + *

The same {@link TrackOutput} is returned if multiple calls are made with the same {@code + * id}. + * + * @param id A track identifier. + * @param type The type of the track. Typically one of the {@link C} {@code TRACK_TYPE_*} + * constants. + * @return The {@link TrackOutput} for the given track identifier. + */ + TrackOutput track(int id, int type); + } + + /** + * Returns the {@link SeekMap} most recently output by the extractor, or null if the extractor has + * not output a {@link SeekMap}. + */ + @Nullable + SeekMap getSeekMap(); + + /** + * Returns the sample {@link Format}s for the tracks identified by the extractor, or null if the + * extractor has not finished identifying tracks. + */ + @Nullable + Format[] getSampleFormats(); + + /** + * Initializes the wrapper to output to {@link TrackOutput}s provided by the specified {@link + * TrackOutputProvider}, and configures the extractor to receive data from a new chunk. + * + * @param trackOutputProvider The provider of {@link TrackOutput}s that will receive sample data. + * @param startTimeUs The start position in the new chunk, or {@link C#TIME_UNSET} to output + * samples from the start of the chunk. + * @param endTimeUs The end position in the new chunk, or {@link C#TIME_UNSET} to output samples + * to the end of the chunk. + */ + void init(@Nullable TrackOutputProvider trackOutputProvider, long startTimeUs, long endTimeUs); + + /** + * Reads from the given {@link ExtractorInput}. + * + * @param input The input to read from. + * @return One of the {@link Extractor}{@code .RESULT_*} values. + * @throws IOException If an error occurred reading from or parsing the input. + */ + int read(ExtractorInput input) throws IOException; +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java index 1b43af2084..d0daaf0839 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ContainerMediaChunk.java @@ -21,8 +21,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; -import com.google.android.exoplayer2.extractor.PositionHolder; -import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider; +import com.google.android.exoplayer2.source.chunk.ChunkExtractor.TrackOutputProvider; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; @@ -34,11 +33,9 @@ import java.io.IOException; */ public class ContainerMediaChunk extends BaseMediaChunk { - private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder(); - private final int chunkCount; private final long sampleOffsetUs; - private final ChunkExtractorWrapper extractorWrapper; + private final ChunkExtractor chunkExtractor; private long nextLoadPosition; private volatile boolean loadCanceled; @@ -61,7 +58,7 @@ public class ContainerMediaChunk extends BaseMediaChunk { * instance. Normally equal to one, but may be larger if multiple chunks as defined by the * underlying media are being merged into a single load. * @param sampleOffsetUs An offset to add to the sample timestamps parsed by the extractor. - * @param extractorWrapper A wrapped extractor to use for parsing the data. + * @param chunkExtractor A wrapped extractor to use for parsing the data. */ public ContainerMediaChunk( DataSource dataSource, @@ -76,7 +73,7 @@ public class ContainerMediaChunk extends BaseMediaChunk { long chunkIndex, int chunkCount, long sampleOffsetUs, - ChunkExtractorWrapper extractorWrapper) { + ChunkExtractor chunkExtractor) { super( dataSource, dataSpec, @@ -90,7 +87,7 @@ public class ContainerMediaChunk extends BaseMediaChunk { chunkIndex); this.chunkCount = chunkCount; this.sampleOffsetUs = sampleOffsetUs; - this.extractorWrapper = extractorWrapper; + this.chunkExtractor = chunkExtractor; } @Override @@ -117,7 +114,7 @@ public class ContainerMediaChunk extends BaseMediaChunk { // Configure the output and set it as the target for the extractor wrapper. BaseMediaChunkOutput output = getOutput(); output.setSampleOffsetUs(sampleOffsetUs); - extractorWrapper.init( + chunkExtractor.init( getTrackOutputProvider(output), clippedStartTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedStartTimeUs - sampleOffsetUs), clippedEndTimeUs == C.TIME_UNSET ? C.TIME_UNSET : (clippedEndTimeUs - sampleOffsetUs)); @@ -130,10 +127,9 @@ public class ContainerMediaChunk extends BaseMediaChunk { dataSource, loadDataSpec.position, dataSource.open(loadDataSpec)); // Load and decode the sample data. try { - Extractor extractor = extractorWrapper.extractor; int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { - result = extractor.read(input, DUMMY_POSITION_HOLDER); + result = chunkExtractor.read(input); } Assertions.checkState(result != Extractor.RESULT_SEEK); } finally { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java index 8b954af2f8..fb33e940f2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/InitializationChunk.java @@ -21,8 +21,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.DefaultExtractorInput; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.ExtractorInput; -import com.google.android.exoplayer2.extractor.PositionHolder; -import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper.TrackOutputProvider; +import com.google.android.exoplayer2.source.chunk.ChunkExtractor.TrackOutputProvider; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.util.Assertions; @@ -35,9 +34,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; */ public final class InitializationChunk extends Chunk { - private static final PositionHolder DUMMY_POSITION_HOLDER = new PositionHolder(); - - private final ChunkExtractorWrapper extractorWrapper; + private final ChunkExtractor chunkExtractor; private @MonotonicNonNull TrackOutputProvider trackOutputProvider; private long nextLoadPosition; @@ -49,7 +46,7 @@ public final class InitializationChunk extends Chunk { * @param trackFormat See {@link #trackFormat}. * @param trackSelectionReason See {@link #trackSelectionReason}. * @param trackSelectionData See {@link #trackSelectionData}. - * @param extractorWrapper A wrapped extractor to use for parsing the initialization data. + * @param chunkExtractor A wrapped extractor to use for parsing the initialization data. */ public InitializationChunk( DataSource dataSource, @@ -57,10 +54,10 @@ public final class InitializationChunk extends Chunk { Format trackFormat, int trackSelectionReason, @Nullable Object trackSelectionData, - ChunkExtractorWrapper extractorWrapper) { + ChunkExtractor chunkExtractor) { super(dataSource, dataSpec, C.DATA_TYPE_MEDIA_INITIALIZATION, trackFormat, trackSelectionReason, trackSelectionData, C.TIME_UNSET, C.TIME_UNSET); - this.extractorWrapper = extractorWrapper; + this.chunkExtractor = chunkExtractor; } /** @@ -85,7 +82,7 @@ public final class InitializationChunk extends Chunk { @Override public void load() throws IOException { if (nextLoadPosition == 0) { - extractorWrapper.init( + chunkExtractor.init( trackOutputProvider, /* startTimeUs= */ C.TIME_UNSET, /* endTimeUs= */ C.TIME_UNSET); } try { @@ -96,10 +93,9 @@ public final class InitializationChunk extends Chunk { dataSource, loadDataSpec.position, dataSource.open(loadDataSpec)); // Load and decode the initialization data. try { - Extractor extractor = extractorWrapper.extractor; int result = Extractor.RESULT_CONTINUE; while (result == Extractor.RESULT_CONTINUE && !loadCanceled) { - result = extractor.read(input, DUMMY_POSITION_HOLDER); + result = chunkExtractor.read(input); } Assertions.checkState(result != Extractor.RESULT_SEEK); } finally { diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java index 6d440b96df..474902dd5b 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashUtil.java @@ -24,7 +24,8 @@ import com.google.android.exoplayer2.extractor.ChunkIndex; import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; -import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper; +import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor; +import com.google.android.exoplayer2.source.chunk.ChunkExtractor; import com.google.android.exoplayer2.source.chunk.InitializationChunk; import com.google.android.exoplayer2.source.dash.manifest.DashManifest; import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser; @@ -113,11 +114,11 @@ public final class DashUtil { @Nullable public static Format loadSampleFormat( DataSource dataSource, int trackType, Representation representation) throws IOException { - ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, - representation, false); - return extractorWrapper == null + ChunkExtractor chunkExtractor = + loadInitializationData(dataSource, trackType, representation, false); + return chunkExtractor == null ? null - : Assertions.checkStateNotNull(extractorWrapper.getSampleFormats())[0]; + : Assertions.checkStateNotNull(chunkExtractor.getSampleFormats())[0]; } /** @@ -135,33 +136,33 @@ public final class DashUtil { @Nullable public static ChunkIndex loadChunkIndex( DataSource dataSource, int trackType, Representation representation) throws IOException { - ChunkExtractorWrapper extractorWrapper = loadInitializationData(dataSource, trackType, - representation, true); - return extractorWrapper == null ? null : (ChunkIndex) extractorWrapper.getSeekMap(); + ChunkExtractor chunkExtractor = + loadInitializationData(dataSource, trackType, representation, true); + return chunkExtractor == null ? null : (ChunkIndex) chunkExtractor.getSeekMap(); } /** * Loads initialization data for the {@code representation} and optionally index data then returns - * a {@link ChunkExtractorWrapper} which contains the output. + * a {@link BundledChunkExtractor} which contains the output. * * @param dataSource The source from which the data should be loaded. * @param trackType The type of the representation. Typically one of the {@link * com.google.android.exoplayer2.C} {@code TRACK_TYPE_*} constants. * @param representation The representation which initialization chunk belongs to. * @param loadIndex Whether to load index data too. - * @return A {@link ChunkExtractorWrapper} for the {@code representation}, or null if no + * @return A {@link BundledChunkExtractor} for the {@code representation}, or null if no * initialization or (if requested) index data exists. * @throws IOException Thrown when there is an error while loading. */ @Nullable - private static ChunkExtractorWrapper loadInitializationData( + private static ChunkExtractor loadInitializationData( DataSource dataSource, int trackType, Representation representation, boolean loadIndex) throws IOException { RangedUri initializationUri = representation.getInitializationUri(); if (initializationUri == null) { return null; } - ChunkExtractorWrapper extractorWrapper = newWrappedExtractor(trackType, representation.format); + ChunkExtractor chunkExtractor = newChunkExtractor(trackType, representation.format); RangedUri requestUri; if (loadIndex) { RangedUri indexUri = representation.getIndexUri(); @@ -172,37 +173,42 @@ public final class DashUtil { // the two requests together to request both at once. requestUri = initializationUri.attemptMerge(indexUri, representation.baseUrl); if (requestUri == null) { - loadInitializationData(dataSource, representation, extractorWrapper, initializationUri); + loadInitializationData(dataSource, representation, chunkExtractor, initializationUri); requestUri = indexUri; } } else { requestUri = initializationUri; } - loadInitializationData(dataSource, representation, extractorWrapper, requestUri); - return extractorWrapper; + loadInitializationData(dataSource, representation, chunkExtractor, requestUri); + return chunkExtractor; } private static void loadInitializationData( DataSource dataSource, Representation representation, - ChunkExtractorWrapper extractorWrapper, + ChunkExtractor chunkExtractor, RangedUri requestUri) throws IOException { DataSpec dataSpec = DashUtil.buildDataSpec(representation, requestUri); - InitializationChunk initializationChunk = new InitializationChunk(dataSource, dataSpec, - representation.format, C.SELECTION_REASON_UNKNOWN, null /* trackSelectionData */, - extractorWrapper); + InitializationChunk initializationChunk = + new InitializationChunk( + dataSource, + dataSpec, + representation.format, + C.SELECTION_REASON_UNKNOWN, + null /* trackSelectionData */, + chunkExtractor); initializationChunk.load(); } - private static ChunkExtractorWrapper newWrappedExtractor(int trackType, Format format) { + private static ChunkExtractor newChunkExtractor(int trackType, Format format) { String mimeType = format.containerMimeType; boolean isWebm = mimeType != null && (mimeType.startsWith(MimeTypes.VIDEO_WEBM) || mimeType.startsWith(MimeTypes.AUDIO_WEBM)); Extractor extractor = isWebm ? new MatroskaExtractor() : new FragmentedMp4Extractor(); - return new ChunkExtractorWrapper(extractor, trackType, format); + return new BundledChunkExtractor(extractor, trackType, format); } @Nullable 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 e03ade2d48..29f62f0aca 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 @@ -31,8 +31,9 @@ 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; import com.google.android.exoplayer2.source.chunk.Chunk; -import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper; +import com.google.android.exoplayer2.source.chunk.ChunkExtractor; import com.google.android.exoplayer2.source.chunk.ChunkHolder; import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk; import com.google.android.exoplayer2.source.chunk.InitializationChunk; @@ -302,11 +303,11 @@ public class DefaultDashChunkSource implements DashChunkSource { RepresentationHolder representationHolder = representationHolders[trackSelection.getSelectedIndex()]; - if (representationHolder.extractorWrapper != null) { + if (representationHolder.chunkExtractor != null) { Representation selectedRepresentation = representationHolder.representation; RangedUri pendingInitializationUri = null; RangedUri pendingIndexUri = null; - if (representationHolder.extractorWrapper.getSampleFormats() == null) { + if (representationHolder.chunkExtractor.getSampleFormats() == null) { pendingInitializationUri = selectedRepresentation.getInitializationUri(); } if (representationHolder.segmentIndex == null) { @@ -399,7 +400,7 @@ public class DefaultDashChunkSource implements DashChunkSource { // from the stream. If the manifest defines an index then the stream shouldn't, but in cases // where it does we should ignore it. if (representationHolder.segmentIndex == null) { - SeekMap seekMap = representationHolder.extractorWrapper.getSeekMap(); + SeekMap seekMap = representationHolder.chunkExtractor.getSeekMap(); if (seekMap != null) { representationHolders[trackIndex] = representationHolder.copyWithNewSegmentIndex( @@ -500,8 +501,13 @@ public class DefaultDashChunkSource implements DashChunkSource { requestUri = indexUri; } DataSpec dataSpec = DashUtil.buildDataSpec(representation, requestUri); - return new InitializationChunk(dataSource, dataSpec, trackFormat, - trackSelectionReason, trackSelectionData, representationHolder.extractorWrapper); + return new InitializationChunk( + dataSource, + dataSpec, + trackFormat, + trackSelectionReason, + trackSelectionData, + representationHolder.chunkExtractor); } protected Chunk newMediaChunk( @@ -518,7 +524,7 @@ public class DefaultDashChunkSource implements DashChunkSource { long startTimeUs = representationHolder.getSegmentStartTimeUs(firstSegmentNum); RangedUri segmentUri = representationHolder.getSegmentUrl(firstSegmentNum); String baseUrl = representation.baseUrl; - if (representationHolder.extractorWrapper == null) { + if (representationHolder.chunkExtractor == null) { long endTimeUs = representationHolder.getSegmentEndTimeUs(firstSegmentNum); DataSpec dataSpec = DashUtil.buildDataSpec(representation, segmentUri); return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, @@ -556,7 +562,7 @@ public class DefaultDashChunkSource implements DashChunkSource { firstSegmentNum, segmentCount, sampleOffsetUs, - representationHolder.extractorWrapper); + representationHolder.chunkExtractor); } } @@ -605,7 +611,7 @@ public class DefaultDashChunkSource implements DashChunkSource { /** Holds information about a snapshot of a single {@link Representation}. */ protected static final class RepresentationHolder { - /* package */ final @Nullable ChunkExtractorWrapper extractorWrapper; + @Nullable /* package */ final ChunkExtractor chunkExtractor; public final Representation representation; @Nullable public final DashSegmentIndex segmentIndex; @@ -623,7 +629,7 @@ public class DefaultDashChunkSource implements DashChunkSource { this( periodDurationUs, representation, - createExtractorWrapper( + createChunkExtractor( trackType, representation, enableEventMessageTrack, @@ -636,13 +642,13 @@ public class DefaultDashChunkSource implements DashChunkSource { private RepresentationHolder( long periodDurationUs, Representation representation, - @Nullable ChunkExtractorWrapper extractorWrapper, + @Nullable ChunkExtractor chunkExtractor, long segmentNumShift, @Nullable DashSegmentIndex segmentIndex) { this.periodDurationUs = periodDurationUs; this.representation = representation; this.segmentNumShift = segmentNumShift; - this.extractorWrapper = extractorWrapper; + this.chunkExtractor = chunkExtractor; this.segmentIndex = segmentIndex; } @@ -656,20 +662,20 @@ public class DefaultDashChunkSource implements DashChunkSource { if (oldIndex == null) { // Segment numbers cannot shift if the index isn't defined by the manifest. return new RepresentationHolder( - newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, oldIndex); + newPeriodDurationUs, newRepresentation, chunkExtractor, segmentNumShift, oldIndex); } if (!oldIndex.isExplicit()) { // Segment numbers cannot shift if the index isn't explicit. return new RepresentationHolder( - newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, newIndex); + newPeriodDurationUs, newRepresentation, chunkExtractor, segmentNumShift, newIndex); } int oldIndexSegmentCount = oldIndex.getSegmentCount(newPeriodDurationUs); if (oldIndexSegmentCount == 0) { // Segment numbers cannot shift if the old index was empty. return new RepresentationHolder( - newPeriodDurationUs, newRepresentation, extractorWrapper, segmentNumShift, newIndex); + newPeriodDurationUs, newRepresentation, chunkExtractor, segmentNumShift, newIndex); } long oldIndexFirstSegmentNum = oldIndex.getFirstSegmentNum(); @@ -701,13 +707,13 @@ public class DefaultDashChunkSource implements DashChunkSource { - newIndexFirstSegmentNum; } return new RepresentationHolder( - newPeriodDurationUs, newRepresentation, extractorWrapper, newSegmentNumShift, newIndex); + newPeriodDurationUs, newRepresentation, chunkExtractor, newSegmentNumShift, newIndex); } @CheckResult /* package */ RepresentationHolder copyWithNewSegmentIndex(DashSegmentIndex segmentIndex) { return new RepresentationHolder( - periodDurationUs, representation, extractorWrapper, segmentNumShift, segmentIndex); + periodDurationUs, representation, chunkExtractor, segmentNumShift, segmentIndex); } public long getFirstSegmentNum() { @@ -772,7 +778,8 @@ public class DefaultDashChunkSource implements DashChunkSource { || mimeType.startsWith(MimeTypes.APPLICATION_WEBM); } - private static @Nullable ChunkExtractorWrapper createExtractorWrapper( + @Nullable + private static ChunkExtractor createChunkExtractor( int trackType, Representation representation, boolean enableEventMessageTrack, @@ -803,7 +810,7 @@ public class DefaultDashChunkSource implements DashChunkSource { closedCaptionFormats, playerEmsgTrackOutput); } - return new ChunkExtractorWrapper(extractor, trackType, representation.format); + return new BundledChunkExtractor(extractor, trackType, representation.format); } } } diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java index 5ce2e6a1c5..10e725fb58 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/DefaultSsChunkSource.java @@ -25,8 +25,9 @@ import com.google.android.exoplayer2.extractor.mp4.Track; import com.google.android.exoplayer2.extractor.mp4.TrackEncryptionBox; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.chunk.BaseMediaChunkIterator; +import com.google.android.exoplayer2.source.chunk.BundledChunkExtractor; import com.google.android.exoplayer2.source.chunk.Chunk; -import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper; +import com.google.android.exoplayer2.source.chunk.ChunkExtractor; import com.google.android.exoplayer2.source.chunk.ChunkHolder; import com.google.android.exoplayer2.source.chunk.ContainerMediaChunk; import com.google.android.exoplayer2.source.chunk.MediaChunk; @@ -74,7 +75,7 @@ public class DefaultSsChunkSource implements SsChunkSource { private final LoaderErrorThrower manifestLoaderErrorThrower; private final int streamElementIndex; - private final ChunkExtractorWrapper[] extractorWrappers; + private final ChunkExtractor[] chunkExtractors; private final DataSource dataSource; private TrackSelection trackSelection; @@ -103,8 +104,8 @@ public class DefaultSsChunkSource implements SsChunkSource { this.dataSource = dataSource; StreamElement streamElement = manifest.streamElements[streamElementIndex]; - extractorWrappers = new ChunkExtractorWrapper[trackSelection.length()]; - for (int i = 0; i < extractorWrappers.length; i++) { + chunkExtractors = new ChunkExtractor[trackSelection.length()]; + for (int i = 0; i < chunkExtractors.length; i++) { int manifestTrackIndex = trackSelection.getIndexInTrackGroup(i); Format format = streamElement.formats[manifestTrackIndex]; @Nullable @@ -122,7 +123,7 @@ public class DefaultSsChunkSource implements SsChunkSource { | FragmentedMp4Extractor.FLAG_WORKAROUND_IGNORE_TFDT_BOX, /* timestampAdjuster= */ null, track); - extractorWrappers[i] = new ChunkExtractorWrapper(extractor, streamElement.type, format); + chunkExtractors[i] = new BundledChunkExtractor(extractor, streamElement.type, format); } } @@ -238,7 +239,7 @@ public class DefaultSsChunkSource implements SsChunkSource { int currentAbsoluteChunkIndex = chunkIndex + currentManifestChunkOffset; int trackSelectionIndex = trackSelection.getSelectedIndex(); - ChunkExtractorWrapper extractorWrapper = extractorWrappers[trackSelectionIndex]; + ChunkExtractor chunkExtractor = chunkExtractors[trackSelectionIndex]; int manifestTrackIndex = trackSelection.getIndexInTrackGroup(trackSelectionIndex); Uri uri = streamElement.buildRequestUri(manifestTrackIndex, chunkIndex); @@ -254,7 +255,7 @@ public class DefaultSsChunkSource implements SsChunkSource { chunkSeekTimeUs, trackSelection.getSelectionReason(), trackSelection.getSelectionData(), - extractorWrapper); + chunkExtractor); } @Override @@ -282,7 +283,7 @@ public class DefaultSsChunkSource implements SsChunkSource { long chunkSeekTimeUs, int trackSelectionReason, @Nullable Object trackSelectionData, - ChunkExtractorWrapper extractorWrapper) { + ChunkExtractor chunkExtractor) { DataSpec dataSpec = new DataSpec(uri); // In SmoothStreaming each chunk contains sample timestamps relative to the start of the chunk. // To convert them the absolute timestamps, we need to set sampleOffsetUs to chunkStartTimeUs. @@ -300,7 +301,7 @@ public class DefaultSsChunkSource implements SsChunkSource { chunkIndex, /* chunkCount= */ 1, sampleOffsetUs, - extractorWrapper); + chunkExtractor); } private long resolveTimeToLiveEdgeUs(long playbackPositionUs) {