Commit 5ce2f176 by tonihei Committed by Oliver Woodman

Check if source has been prepared before releasing it.

In ConcatenatingMediaSource, the source may be removed before it started
preparing (this may happen if lazyPreparation=true). In this case, we
shouldn't call releaseSource as the preparation didn't start.

Issue:#4986

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=218141658
parent ea49d39a
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
* IMA extension: * IMA extension:
* For preroll to live stream transitions, project forward the loading position * For preroll to live stream transitions, project forward the loading position
to avoid being behind the live window. to avoid being behind the live window.
* Fix issue where a `NullPointerException` is thrown when removing an unprepared
media source from a `ConcatenatingMediaSource` with the `useLazyPreparation`
option enabled ([#4986](https://github.com/google/ExoPlayer/issues/4986)).
### 2.9.0 ### ### 2.9.0 ###
......
...@@ -502,9 +502,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -502,9 +502,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
Assertions.checkNotNull(mediaSourceByMediaPeriod.remove(mediaPeriod)); Assertions.checkNotNull(mediaSourceByMediaPeriod.remove(mediaPeriod));
((DeferredMediaPeriod) mediaPeriod).releasePeriod(); ((DeferredMediaPeriod) mediaPeriod).releasePeriod();
holder.activeMediaPeriods.remove(mediaPeriod); holder.activeMediaPeriods.remove(mediaPeriod);
if (holder.activeMediaPeriods.isEmpty() && holder.isRemoved) { maybeReleaseChildSource(holder);
releaseChildSource(holder);
}
} }
@Override @Override
...@@ -747,9 +745,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -747,9 +745,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
-oldTimeline.getWindowCount(), -oldTimeline.getWindowCount(),
-oldTimeline.getPeriodCount()); -oldTimeline.getPeriodCount());
holder.isRemoved = true; holder.isRemoved = true;
if (holder.activeMediaPeriods.isEmpty()) { maybeReleaseChildSource(holder);
releaseChildSource(holder);
}
} }
private void moveMediaSourceInternal(int currentIndex, int newIndex) { private void moveMediaSourceInternal(int currentIndex, int newIndex) {
...@@ -778,6 +774,16 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo ...@@ -778,6 +774,16 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
} }
} }
private void maybeReleaseChildSource(MediaSourceHolder mediaSourceHolder) {
// Release if the source has been removed from the playlist, but only if it has been previously
// prepared and only if we are not waiting for an existing media period to be released.
if (mediaSourceHolder.isRemoved
&& mediaSourceHolder.hasStartedPreparing
&& mediaSourceHolder.activeMediaPeriods.isEmpty()) {
releaseChildSource(mediaSourceHolder);
}
}
/** Return uid of media source holder from period uid of concatenated source. */ /** Return uid of media source holder from period uid of concatenated source. */
private static Object getMediaSourceHolderUid(Object periodUid) { private static Object getMediaSourceHolderUid(Object periodUid) {
return ConcatenatedTimeline.getChildTimelineUidFromConcatenatedUid(periodUid); return ConcatenatedTimeline.getChildTimelineUidFromConcatenatedUid(periodUid);
......
...@@ -926,6 +926,22 @@ public final class ConcatenatingMediaSourceTest { ...@@ -926,6 +926,22 @@ public final class ConcatenatingMediaSourceTest {
} }
@Test @Test
public void testRemoveUnpreparedChildSourceWithLazyPreparation() throws IOException {
FakeMediaSource[] childSources = createMediaSources(/* count= */ 2);
mediaSource =
new ConcatenatingMediaSource(
/* isAtomic= */ false,
/* useLazyPreparation= */ true,
new DefaultShuffleOrder(0),
childSources);
testRunner = new MediaSourceTestRunner(mediaSource, /* allocator= */ null);
testRunner.prepareSource();
// Check that removal doesn't throw even though the child sources are unprepared.
mediaSource.removeMediaSource(0);
}
@Test
public void testSetShuffleOrderBeforePreparation() throws Exception { public void testSetShuffleOrderBeforePreparation() throws Exception {
mediaSource.setShuffleOrder(new ShuffleOrder.UnshuffledShuffleOrder(/* length= */ 0)); mediaSource.setShuffleOrder(new ShuffleOrder.UnshuffledShuffleOrder(/* length= */ 0));
mediaSource.addMediaSources( mediaSource.addMediaSources(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment