From 1e79d6eb849a7e404e7682f24bbdcbd720ab6eda Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 18 Oct 2017 05:59:14 -0700 Subject: [PATCH] Fix seeking with repeated periods newPlayingPeriodHolder could be set then updated if seeking to a repeated period that was loaded more than once. This led to MediaPeriodHolders leaking. Only set newPlayingPeriodHolder once so that any later holders with the same period identifier get released. Also add a regression test. FakeMediaSource checks that all created MediaPeriods were released when it is released. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=172591937 --- .../google/android/exoplayer2/ExoPlayerTest.java | 16 ++++++++++++++++ .../exoplayer2/ExoPlayerImplInternal.java | 3 ++- .../exoplayer2/testutil/FakeMediaSource.java | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java index 2971aaf779..eb9dc6f9d8 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -261,6 +261,22 @@ public final class ExoPlayerTest extends TestCase { assertTrue(renderer.isEnded); } + public void testPeriodHoldersReleasedAfterSeekWithRepeatModeAll() throws Exception { + Timeline fakeTimeline = new FakeTimeline(new TimelineWindowDefinition(true, false, 100000)); + FakeRenderer renderer = new FakeRenderer(Builder.VIDEO_FORMAT); + ActionSchedule actionSchedule = new ActionSchedule.Builder("testPeriodHoldersReleased") + .setRepeatMode(Player.REPEAT_MODE_ALL) + .waitForPositionDiscontinuity() + .seek(0) // Seek with repeat mode set to REPEAT_MODE_ALL. + .waitForPositionDiscontinuity() + .setRepeatMode(Player.REPEAT_MODE_OFF) // Turn off repeat so that playback can finish. + .build(); + new ExoPlayerTestRunner.Builder() + .setTimeline(fakeTimeline).setRenderers(renderer).setActionSchedule(actionSchedule) + .build().start().blockUntilEnded(TIMEOUT_MS); + assertTrue(renderer.isEnded); + } + public void testSeekProcessedCallback() throws Exception { Timeline timeline = new FakeTimeline( new TimelineWindowDefinition(true, false, 100000), diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index a0ca448de7..79c92aeb67 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -753,7 +753,8 @@ import java.io.IOException; // Clear the timeline, but keep the requested period if it is already prepared. MediaPeriodHolder periodHolder = playingPeriodHolder; while (periodHolder != null) { - if (shouldKeepPeriodHolder(periodId, periodPositionUs, periodHolder)) { + if (newPlayingPeriodHolder == null + && shouldKeepPeriodHolder(periodId, periodPositionUs, periodHolder)) { newPlayingPeriodHolder = periodHolder; } else { periodHolder.release(); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java index 9e7b498269..a827fb80c6 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeMediaSource.java @@ -116,4 +116,5 @@ public class FakeMediaSource implements MediaSource { } return new TrackGroupArray(trackGroups); } + }