Fix potential media source release before media period release.

This could happen when a media source is removed from a
DynamicConcatenatingMediaSource and one of its media periods is still active.
This media period is only removed by the player after the player received
a timeline update and thus we shouldn't release the removed child source
as long as it has active media periods.

Issue:#3796

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=184522836
This commit is contained in:
tonihei 2018-02-05 06:48:48 -08:00 committed by Oliver Woodman
parent 7b19de2e99
commit fe98477045
2 changed files with 27 additions and 6 deletions

View File

@ -627,6 +627,18 @@ public final class DynamicConcatenatingMediaSourceTest extends TestCase {
mediaSourceWithAds.assertMediaPeriodCreated(new MediaPeriodId(1, 0, 0));
}
public void testRemoveChildSourceWithActiveMediaPeriod() throws IOException {
FakeMediaSource childSource = createFakeMediaSource();
mediaSource.addMediaSource(childSource);
testRunner.prepareSource();
MediaPeriod mediaPeriod = testRunner.createPeriod(new MediaPeriodId(/* periodIndex= */ 0));
mediaSource.removeMediaSource(/* index= */ 0);
testRunner.assertTimelineChangeBlocking();
testRunner.releasePeriod(mediaPeriod);
childSource.assertReleased();
testRunner.releaseSource();
}
private static FakeMediaSource[] createMediaSources(int count) {
FakeMediaSource[] sources = new FakeMediaSource[count];
for (int i = 0; i < count; i++) {

View File

@ -56,7 +56,7 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
// Accessed on the playback thread.
private final List<MediaSourceHolder> mediaSourceHolders;
private final MediaSourceHolder query;
private final Map<MediaPeriod, MediaSource> mediaSourceByMediaPeriod;
private final Map<MediaPeriod, MediaSourceHolder> mediaSourceByMediaPeriod;
private final List<DeferredMediaPeriod> deferredMediaPeriods;
private ExoPlayer player;
@ -355,19 +355,23 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
} else {
mediaPeriod = holder.mediaSource.createPeriod(idInSource, allocator);
}
mediaSourceByMediaPeriod.put(mediaPeriod, holder.mediaSource);
mediaSourceByMediaPeriod.put(mediaPeriod, holder);
holder.activeMediaPeriods++;
return mediaPeriod;
}
@Override
public void releasePeriod(MediaPeriod mediaPeriod) {
MediaSource mediaSource = mediaSourceByMediaPeriod.get(mediaPeriod);
mediaSourceByMediaPeriod.remove(mediaPeriod);
MediaSourceHolder holder = mediaSourceByMediaPeriod.remove(mediaPeriod);
if (mediaPeriod instanceof DeferredMediaPeriod) {
deferredMediaPeriods.remove(mediaPeriod);
((DeferredMediaPeriod) mediaPeriod).releasePeriod();
} else {
mediaSource.releasePeriod(mediaPeriod);
holder.mediaSource.releasePeriod(mediaPeriod);
}
holder.activeMediaPeriods--;
if (holder.activeMediaPeriods == 0 && holder.isRemoved) {
releaseChildSource(holder);
}
}
@ -520,7 +524,10 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
/* childIndexUpdate= */ -1,
-oldTimeline.getWindowCount(),
-oldTimeline.getPeriodCount());
releaseChildSource(holder);
holder.isRemoved = true;
if (holder.activeMediaPeriods == 0) {
releaseChildSource(holder);
}
}
private void moveMediaSourceInternal(int currentIndex, int newIndex) {
@ -573,6 +580,8 @@ public final class DynamicConcatenatingMediaSource extends CompositeMediaSource<
public int firstWindowIndexInChild;
public int firstPeriodIndexInChild;
public boolean isPrepared;
public boolean isRemoved;
public int activeMediaPeriods;
public MediaSourceHolder(
MediaSource mediaSource,