diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java
index 8d7bd768bb..997f94bbfe 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaPeriod.java
@@ -67,7 +67,7 @@ public interface MediaPeriod extends SequenceableLoader {
* Throws an error that's preventing the period from becoming prepared. Does nothing if no such
* error exists.
*
- *
This method should only be called before the period has completed preparation.
+ *
This method is only called before the period has completed preparation.
*
* @throws IOException The underlying error.
*/
@@ -76,7 +76,7 @@ public interface MediaPeriod extends SequenceableLoader {
/**
* Returns the {@link TrackGroup}s exposed by the period.
*
- *
This method should only be called after the period has been prepared.
+ *
This method is only called after the period has been prepared.
*
* @return The {@link TrackGroup}s.
*/
@@ -93,7 +93,7 @@ public interface MediaPeriod extends SequenceableLoader {
* corresponding flag in {@code streamResetFlags} will be set to true. This flag will also be set
* if a new sample stream is created.
*
- *
This method should only be called after the period has been prepared.
+ *
This method is only called after the period has been prepared.
*
* @param selections The renderer track selections.
* @param mayRetainStreamFlags Flags indicating whether the existing sample stream can be retained
@@ -117,7 +117,7 @@ public interface MediaPeriod extends SequenceableLoader {
/**
* Discards buffered media up to the specified position.
*
- *
This method should only be called after the period has been prepared.
+ *
This method is only called after the period has been prepared.
*
* @param positionUs The position in microseconds.
* @param toKeyframe If true then for each track discards samples up to the keyframe before or at
@@ -131,8 +131,8 @@ public interface MediaPeriod extends SequenceableLoader {
*
After this method has returned a value other than {@link C#TIME_UNSET}, all {@link
* SampleStream}s provided by the period are guaranteed to start from a key frame.
*
- *
This method should only be called after the period has been prepared. It must be called
- * before attempting to read from any {@link SampleStream}s provided by the period.
+ *
This method is only called after the period has been prepared and before reading from any
+ * {@link SampleStream}s provided by the period.
*
* @return If a discontinuity was read then the playback position in microseconds after the
* discontinuity. Else {@link C#TIME_UNSET}.
@@ -145,7 +145,7 @@ public interface MediaPeriod extends SequenceableLoader {
*
After this method has been called, all {@link SampleStream}s provided by the period are
* guaranteed to start from a key frame.
*
- *
This method should only be called when at least one track is selected.
+ *
This method is only called when at least one track is selected.
*
* @param positionUs The seek position in microseconds.
* @return The actual position to which the period was seeked, in microseconds.
@@ -156,7 +156,7 @@ public interface MediaPeriod extends SequenceableLoader {
* Returns the position to which a seek will be performed, given the specified seek position and
* {@link SeekParameters}.
*
- *
This method should only be called after the period has been prepared.
+ *
This method is only called after the period has been prepared.
*
* @param positionUs The seek position in microseconds.
* @param seekParameters Parameters that control how the seek is performed. Implementations may
@@ -170,7 +170,7 @@ public interface MediaPeriod extends SequenceableLoader {
/**
* Returns an estimate of the position up to which data is buffered for the enabled tracks.
*
- *
This method should only be called when at least one track is selected.
+ *
This method is only called when at least one track is selected.
*
* @return An estimate of the absolute position in microseconds up to which data is buffered, or
* {@link C#TIME_END_OF_SOURCE} if the track is fully buffered.
@@ -181,8 +181,8 @@ public interface MediaPeriod extends SequenceableLoader {
/**
* Returns the next load time, or {@link C#TIME_END_OF_SOURCE} if loading has finished.
*
- *
This method should only be called after the period has been prepared. It may be called when
- * no tracks are selected.
+ *
This method is only called after the period has been prepared. It may be called when no
+ * tracks are selected.
*/
@Override
long getNextLoadPositionUs();
@@ -209,7 +209,7 @@ public interface MediaPeriod extends SequenceableLoader {
/**
* Re-evaluates the buffer given the playback position.
*
- *
This method should only be called after the period has been prepared.
+ *
This method is only called after the period has been prepared.
*
*
A period may choose to discard buffered media so that it can be re-buffered in a different
* quality.
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java
index d8b64fff7e..a4fc8c6b00 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java
@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.IdentityHashMap;
/**
@@ -32,9 +33,9 @@ import java.util.IdentityHashMap;
private final IdentityHashMap streamPeriodIndices;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
+ private final ArrayList childrenPendingPreparation;
private Callback callback;
- private int pendingChildPrepareCount;
private TrackGroupArray trackGroups;
private MediaPeriod[] enabledPeriods;
@@ -44,13 +45,16 @@ import java.util.IdentityHashMap;
MediaPeriod... periods) {
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
this.periods = periods;
+ childrenPendingPreparation = new ArrayList<>();
+ compositeSequenceableLoader =
+ compositeSequenceableLoaderFactory.createCompositeSequenceableLoader();
streamPeriodIndices = new IdentityHashMap<>();
}
@Override
public void prepare(Callback callback, long positionUs) {
this.callback = callback;
- pendingChildPrepareCount = periods.length;
+ Collections.addAll(childrenPendingPreparation, periods);
for (MediaPeriod period : periods) {
period.prepare(this, positionUs);
}
@@ -147,7 +151,16 @@ import java.util.IdentityHashMap;
@Override
public boolean continueLoading(long positionUs) {
- return compositeSequenceableLoader.continueLoading(positionUs);
+ if (!childrenPendingPreparation.isEmpty()) {
+ // Preparation is still going on.
+ int childrenPendingPreparationSize = childrenPendingPreparation.size();
+ for (int i = 0; i < childrenPendingPreparationSize; i++) {
+ childrenPendingPreparation.get(i).continueLoading(positionUs);
+ }
+ return false;
+ } else {
+ return compositeSequenceableLoader.continueLoading(positionUs);
+ }
}
@Override
@@ -201,8 +214,9 @@ import java.util.IdentityHashMap;
// MediaPeriod.Callback implementation
@Override
- public void onPrepared(MediaPeriod ignored) {
- if (--pendingChildPrepareCount > 0) {
+ public void onPrepared(MediaPeriod preparedPeriod) {
+ childrenPendingPreparation.remove(preparedPeriod);
+ if (!childrenPendingPreparation.isEmpty()) {
return;
}
int totalTrackGroupCount = 0;
@@ -224,10 +238,6 @@ import java.util.IdentityHashMap;
@Override
public void onContinueLoadingRequested(MediaPeriod ignored) {
- if (trackGroups == null) {
- // Still preparing.
- return;
- }
callback.onContinueLoadingRequested(this);
}
diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
index 8076fd8359..01b042e7a5 100644
--- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
+++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java
@@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer2.source.hls;
-import android.os.Handler;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.SeekParameters;
@@ -55,7 +54,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
private final Allocator allocator;
private final IdentityHashMap streamWrapperIndices;
private final TimestampAdjusterProvider timestampAdjusterProvider;
- private final Handler continueLoadingHandler;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private final boolean allowChunklessPreparation;
@@ -84,9 +82,10 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
this.allocator = allocator;
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
this.allowChunklessPreparation = allowChunklessPreparation;
+ compositeSequenceableLoader =
+ compositeSequenceableLoaderFactory.createCompositeSequenceableLoader();
streamWrapperIndices = new IdentityHashMap<>();
timestampAdjusterProvider = new TimestampAdjusterProvider();
- continueLoadingHandler = new Handler();
sampleStreamWrappers = new HlsSampleStreamWrapper[0];
enabledSampleStreamWrappers = new HlsSampleStreamWrapper[0];
eventDispatcher.mediaPeriodCreated();
@@ -94,7 +93,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
public void release() {
playlistTracker.removeListener(this);
- continueLoadingHandler.removeCallbacksAndMessages(null);
for (HlsSampleStreamWrapper sampleStreamWrapper : sampleStreamWrappers) {
sampleStreamWrapper.release();
}
@@ -214,7 +212,15 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
@Override
public boolean continueLoading(long positionUs) {
- return compositeSequenceableLoader.continueLoading(positionUs);
+ if (trackGroups == null) {
+ // Preparation is still going on.
+ for (HlsSampleStreamWrapper wrapper : sampleStreamWrappers) {
+ wrapper.continuePreparing();
+ }
+ return false;
+ } else {
+ return compositeSequenceableLoader.continueLoading(positionUs);
+ }
}
@Override
@@ -288,10 +294,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
@Override
public void onContinueLoadingRequested(HlsSampleStreamWrapper sampleStreamWrapper) {
- if (trackGroups == null) {
- // Still preparing.
- return;
- }
callback.onContinueLoadingRequested(this);
}
@@ -299,7 +301,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
@Override
public void onPlaylistChanged() {
- continuePreparingOrLoading();
+ callback.onContinueLoadingRequested(this);
}
@Override
@@ -307,7 +309,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
for (HlsSampleStreamWrapper streamWrapper : sampleStreamWrappers) {
streamWrapper.onPlaylistBlacklisted(url, blacklistMs);
}
- continuePreparingOrLoading();
+ callback.onContinueLoadingRequested(this);
}
// Internal methods.
@@ -475,17 +477,6 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
muxedAudioFormat, minLoadableRetryCount, eventDispatcher);
}
- private void continuePreparingOrLoading() {
- if (trackGroups != null) {
- callback.onContinueLoadingRequested(this);
- } else {
- // Some of the wrappers were waiting for their media playlist to prepare.
- for (HlsSampleStreamWrapper wrapper : sampleStreamWrappers) {
- wrapper.continuePreparing();
- }
- }
- }
-
private static Format deriveVideoFormat(Format variantFormat) {
String codecs = Util.getCodecsOfType(variantFormat.codecs, C.TRACK_TYPE_VIDEO);
String mimeType = MimeTypes.getMediaMimeType(codecs);
diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java
index 40d9b1ef9f..a251bd5ef0 100644
--- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java
+++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaPeriod.java
@@ -219,7 +219,6 @@ public class FakeMediaPeriod implements MediaPeriod {
@Override
public boolean continueLoading(long positionUs) {
- assertThat(prepared).isTrue();
return false;
}