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 f5b05db047..f02329d5d5 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 @@ -104,6 +104,11 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac } } + @Override + public void release() { + extractor.release(); + } + @Override public boolean read(ExtractorInput input) throws IOException { int result = extractor.read(input, POSITION_HOLDER); 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 215e965ca0..6bfe9590db 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 @@ -74,6 +74,9 @@ public interface ChunkExtractor { */ void init(@Nullable TrackOutputProvider trackOutputProvider, long startTimeUs, long endTimeUs); + /** Releases any held resources. */ + void release(); + /** * Reads from the given {@link ExtractorInput}. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java index 9238ef1c7c..bff7c7870b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSampleStream.java @@ -355,6 +355,7 @@ public class ChunkSampleStream implements SampleStream, S for (SampleQueue embeddedSampleQueue : embeddedSampleQueues) { embeddedSampleQueue.release(); } + chunkSource.release(); if (releaseCallback != null) { releaseCallback.onSampleStreamReleased(this); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSource.java index e05dab69d3..32ac6fee7a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkSource.java @@ -104,4 +104,7 @@ public interface ChunkSource { * chunk. */ boolean onChunkLoadError(Chunk chunk, boolean cancelable, Exception e, long exclusionDurationMs); + + /** Releases any held resources. */ + void release(); } 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 10c69ce65c..b0c892de03 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 @@ -114,11 +114,16 @@ public final class DashUtil { @Nullable public static Format loadSampleFormat( DataSource dataSource, int trackType, Representation representation) throws IOException { - ChunkExtractor chunkExtractor = - loadInitializationData(dataSource, trackType, representation, false); - return chunkExtractor == null - ? null - : Assertions.checkStateNotNull(chunkExtractor.getSampleFormats())[0]; + if (representation.getInitializationUri() == null) { + return null; + } + ChunkExtractor chunkExtractor = newChunkExtractor(trackType, representation.format); + try { + loadInitializationData(chunkExtractor, dataSource, representation, /* loadIndex= */ false); + } finally { + chunkExtractor.release(); + } + return Assertions.checkStateNotNull(chunkExtractor.getSampleFormats())[0]; } /** @@ -136,39 +141,40 @@ public final class DashUtil { @Nullable public static ChunkIndex loadChunkIndex( DataSource dataSource, int trackType, Representation representation) throws IOException { - @Nullable - ChunkExtractor chunkExtractor = - loadInitializationData(dataSource, trackType, representation, true); - return chunkExtractor == null ? null : chunkExtractor.getChunkIndex(); + if (representation.getInitializationUri() == null) { + return null; + } + ChunkExtractor chunkExtractor = newChunkExtractor(trackType, representation.format); + try { + loadInitializationData(chunkExtractor, dataSource, representation, /* loadIndex= */ true); + } finally { + chunkExtractor.release(); + } + return chunkExtractor.getChunkIndex(); } /** * Loads initialization data for the {@code representation} and optionally index data then returns * a {@link BundledChunkExtractor} which contains the output. * + * @param chunkExtractor The {@link ChunkExtractor} to use. * @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 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 ChunkExtractor loadInitializationData( - DataSource dataSource, int trackType, Representation representation, boolean loadIndex) + private static void loadInitializationData( + ChunkExtractor chunkExtractor, + DataSource dataSource, + Representation representation, + boolean loadIndex) throws IOException { - RangedUri initializationUri = representation.getInitializationUri(); - if (initializationUri == null) { - return null; - } - ChunkExtractor chunkExtractor = newChunkExtractor(trackType, representation.format); + RangedUri initializationUri = Assertions.checkNotNull(representation.getInitializationUri()); RangedUri requestUri; if (loadIndex) { RangedUri indexUri = representation.getIndexUri(); if (indexUri == null) { - return null; + return; } // It's common for initialization and index data to be stored adjacently. Attempt to merge // the two requests together to request both at once. @@ -181,7 +187,6 @@ public final class DashUtil { requestUri = initializationUri; } loadInitializationData(dataSource, representation, chunkExtractor, requestUri); - return chunkExtractor; } private static void loadInitializationData( 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 ff62aabef2..366a507b4a 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 @@ -442,6 +442,16 @@ public class DefaultDashChunkSource implements DashChunkSource { && trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), exclusionDurationMs); } + @Override + public void release() { + for (RepresentationHolder representationHolder : representationHolders) { + @Nullable ChunkExtractor chunkExtractor = representationHolder.chunkExtractor; + if (chunkExtractor != null) { + chunkExtractor.release(); + } + } + } + // Internal methods. private long getSegmentNum( 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 c7df39033b..3760a5337d 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 @@ -271,6 +271,13 @@ public class DefaultSsChunkSource implements SsChunkSource { && trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), exclusionDurationMs); } + @Override + public void release() { + for (ChunkExtractor chunkExtractor : chunkExtractors) { + chunkExtractor.release(); + } + } + // Private methods. private static MediaChunk newMediaChunk( diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java index 844823205a..c703cf0bc3 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeChunkSource.java @@ -150,4 +150,8 @@ public final class FakeChunkSource implements ChunkSource { return false; } + @Override + public void release() { + // Do nothing. + } }