From 177092d9352e15978c1b4ffab394d97db3dbca3b Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 11 Apr 2025 12:43:21 -0700 Subject: [PATCH] Fix getChildPeriod logic if the child is a TimeOffsetMediaPeriod The current instanceof check accidentally unpacks the child, returning the inner period instead of the one passed to the source. PiperOrigin-RevId: 746556825 (cherry picked from commit 68538029c926642da42a7ebf40543f480c38146e) --- .../exoplayer/source/MergingMediaPeriod.java | 5 ++- .../source/MergingMediaPeriodTest.java | 35 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java index 8912f5c8df..48b94c2040 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/MergingMediaPeriod.java @@ -41,6 +41,7 @@ import java.util.List; /* package */ final class MergingMediaPeriod implements MediaPeriod, MediaPeriod.Callback { private final MediaPeriod[] periods; + private final boolean[] periodsWithTimeOffsets; private final IdentityHashMap streamPeriodIndices; private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private final ArrayList childrenPendingPreparation; @@ -62,8 +63,10 @@ import java.util.List; compositeSequenceableLoader = compositeSequenceableLoaderFactory.empty(); streamPeriodIndices = new IdentityHashMap<>(); enabledPeriods = new MediaPeriod[0]; + periodsWithTimeOffsets = new boolean[periods.length]; for (int i = 0; i < periods.length; i++) { if (periodTimeOffsetsUs[i] != 0) { + periodsWithTimeOffsets[i] = true; this.periods[i] = new TimeOffsetMediaPeriod(periods[i], periodTimeOffsetsUs[i]); } } @@ -75,7 +78,7 @@ import java.util.List; * specified index. */ public MediaPeriod getChildPeriod(int index) { - return periods[index] instanceof TimeOffsetMediaPeriod + return periodsWithTimeOffsets[index] ? ((TimeOffsetMediaPeriod) periods[index]).getWrappedMediaPeriod() : periods[index]; } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java index 3f3278f654..c558ee5be3 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/source/MergingMediaPeriodTest.java @@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat; import androidx.media3.common.C; import androidx.media3.common.Format; +import androidx.media3.common.MimeTypes; import androidx.media3.common.TrackGroup; import androidx.media3.common.util.NullableType; import androidx.media3.decoder.DecoderInputBuffer; @@ -33,6 +34,7 @@ import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId; import androidx.media3.exoplayer.source.MediaSourceEventListener.EventDispatcher; import androidx.media3.exoplayer.trackselection.ExoTrackSelection; import androidx.media3.exoplayer.trackselection.FixedTrackSelection; +import androidx.media3.exoplayer.upstream.Allocator; import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.test.utils.FakeMediaPeriod; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -270,6 +272,39 @@ public final class MergingMediaPeriodTest { assertThat(inputBuffer.timeUs).isEqualTo(456_000 - 3000); } + @Test + public void + getChildPeriod_withTimeOffsetsAndTimeOffsetPeriodChildren_returnsCorrectChildPeriod() { + TrackGroupArray trackGroupArray = + new TrackGroupArray( + new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.VIDEO_AV1).build())); + Allocator allocator = + new DefaultAllocator(/* trimOnReset= */ false, /* individualAllocationSize= */ 1024); + MediaPeriod childPeriod0 = + new FakeMediaPeriod( + trackGroupArray, allocator, /* singleSampleTimeUs= */ 0, new EventDispatcher()); + MediaPeriod childPeriod1 = + new TimeOffsetMediaPeriod( + new FakeMediaPeriod( + trackGroupArray, allocator, /* singleSampleTimeUs= */ 300, new EventDispatcher()), + /* timeOffsetUs= */ -300); + MediaPeriod childPeriod2 = + new FakeMediaPeriod( + trackGroupArray, allocator, /* singleSampleTimeUs= */ -500, new EventDispatcher()); + + MergingMediaPeriod mergingMediaPeriod = + new MergingMediaPeriod( + new DefaultCompositeSequenceableLoaderFactory(), + /* periodTimeOffsetsUs= */ new long[] {0, 0, 500}, + childPeriod0, + childPeriod1, + childPeriod2); + + assertThat(mergingMediaPeriod.getChildPeriod(0)).isEqualTo(childPeriod0); + assertThat(mergingMediaPeriod.getChildPeriod(1)).isEqualTo(childPeriod1); + assertThat(mergingMediaPeriod.getChildPeriod(2)).isEqualTo(childPeriod2); + } + private MergingMediaPeriod prepareMergingPeriod(MergingPeriodDefinition... definitions) throws Exception { return prepareMergingPeriod(/* singleTrackGroup= */ false, definitions);