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
This commit is contained in:
tonihei 2018-10-22 03:31:38 -07:00 committed by Oliver Woodman
parent ea49d39a4d
commit 5ce2f1763d
3 changed files with 31 additions and 6 deletions

View file

@ -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 ###

View file

@ -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
-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
} }
} }
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);

View file

@ -925,6 +925,22 @@ public final class ConcatenatingMediaSourceTest {
testRunner.createPeriod(mediaPeriodId); testRunner.createPeriod(mediaPeriodId);
} }
@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 @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));