From 9911c11191e7df82998eaac377debb33724ac9c0 Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 17 Jan 2019 17:00:11 +0000 Subject: [PATCH] Add start position to MediaSource.createPeriod. That's the same position set in MediaPeriod.prepare (where it may be removed in the future). Having the position at an earlier point is necessary to fix an issue with lazy preparation in ConcatenatingMediaSource where the prepare position was assumed to be known but MediaPeriod.prepare hasn't been called yet. Issue:#5350 PiperOrigin-RevId: 229756637 --- RELEASENOTES.md | 8 +++-- .../exoplayer2/ext/ima/ImaAdsMediaSource.java | 4 +-- .../android/exoplayer2/MediaPeriodHolder.java | 2 +- .../source/ClippingMediaSource.java | 4 +-- .../source/ConcatenatingMediaSource.java | 8 +++-- .../source/DeferredMediaPeriod.java | 36 ++++++++++--------- .../source/ExtractorMediaSource.java | 2 +- .../exoplayer2/source/LoopingMediaSource.java | 7 ++-- .../exoplayer2/source/MediaSource.java | 7 ++-- .../exoplayer2/source/MergingMediaSource.java | 4 +-- .../source/SingleSampleMediaSource.java | 2 +- .../exoplayer2/source/ads/AdsMediaSource.java | 8 +++-- .../source/dash/DashMediaSource.java | 3 +- .../exoplayer2/source/hls/HlsMediaSource.java | 2 +- .../source/smoothstreaming/SsMediaSource.java | 2 +- .../exoplayer2/testutil/FakeMediaSource.java | 2 +- .../testutil/MediaSourceTestRunner.java | 19 ++++++++-- 17 files changed, 74 insertions(+), 46 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7fb10727cc..28d7fb5597 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -16,8 +16,12 @@ ([#5351](https://github.com/google/ExoPlayer/issues/5351)). * Fix issue where uneven track durations in MP4 streams can cause OOM problems ([#3670](https://github.com/google/ExoPlayer/issues/3670)). -* Add the sub text to the MediaDescriptionAdapter of the - PlayerNotificationManager. +* Add `startPositionUs` to `MediaSource.createPeriod`. This fixes an issue where + using lazy preparation in `ConcatenatingMediaSource` with an + `ExtractorMediaSource` overrides initial seek positions + ([#5350](https://github.com/google/ExoPlayer/issues/5350)). +* Add subtext to the `MediaDescriptionAdapter` of the + `PlayerNotificationManager`. ### 2.9.3 ### diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java index 85042c4354..0978ee401c 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/ImaAdsMediaSource.java @@ -97,8 +97,8 @@ public final class ImaAdsMediaSource extends BaseMediaSource implements SourceIn } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { - return adsMediaSource.createPeriod(id, allocator); + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { + return adsMediaSource.createPeriod(id, allocator, startPositionUs); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java index 5925c8f383..8e51740c56 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaPeriodHolder.java @@ -79,7 +79,7 @@ import com.google.android.exoplayer2.util.Log; this.info = info; sampleStreams = new SampleStream[rendererCapabilities.length]; mayRetainStreamFlags = new boolean[rendererCapabilities.length]; - MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator); + MediaPeriod mediaPeriod = mediaSource.createPeriod(info.id, allocator, info.startPositionUs); if (info.id.endPositionUs != C.TIME_END_OF_SOURCE) { mediaPeriod = new ClippingMediaPeriod( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index 3ed18049bf..fce1c4b877 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -240,10 +240,10 @@ public final class ClippingMediaSource extends CompositeMediaSource { } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { ClippingMediaPeriod mediaPeriod = new ClippingMediaPeriod( - mediaSource.createPeriod(id, allocator), + mediaSource.createPeriod(id, allocator, startPositionUs), enableInitialDiscontinuity, periodStartUs, periodEndUs); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java index 72ecd2c767..c93afdb249 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ConcatenatingMediaSource.java @@ -476,7 +476,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource { } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { if (loopCount == Integer.MAX_VALUE) { - return childSource.createPeriod(id, allocator); + return childSource.createPeriod(id, allocator, startPositionUs); } Object childPeriodUid = LoopingTimeline.getChildPeriodUidFromConcatenatedUid(id.periodUid); MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(childPeriodUid); childMediaPeriodIdToMediaPeriodId.put(childMediaPeriodId, id); - MediaPeriod mediaPeriod = childSource.createPeriod(childMediaPeriodId, allocator); + MediaPeriod mediaPeriod = + childSource.createPeriod(childMediaPeriodId, allocator, startPositionUs); mediaPeriodToChildMediaPeriodId.put(mediaPeriod, childMediaPeriodId); return mediaPeriod; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 74449ba16b..801737faef 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -35,8 +35,8 @@ import java.io.IOException; * on the {@link SourceInfoRefreshListener}s passed to {@link #prepareSource(ExoPlayer, * boolean, SourceInfoRefreshListener, TransferListener)}. *
  • To provide {@link MediaPeriod} instances for the periods in its timeline. MediaPeriods are - * obtained by calling {@link #createPeriod(MediaPeriodId, Allocator)}, and provide a way for - * the player to load and read the media. + * obtained by calling {@link #createPeriod(MediaPeriodId, Allocator, long)}, and provide a + * way for the player to load and read the media. * * * All methods are called on the player's internal playback thread, as described in the {@link @@ -274,9 +274,10 @@ public interface MediaSource { * * @param id The identifier of the period. * @param allocator An {@link Allocator} from which to obtain media buffer allocations. + * @param startPositionUs The expected start position, in microseconds. * @return A new {@link MediaPeriod}. */ - MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator); + MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs); /** * Releases the period. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java index 573e97cb13..cc7202f9b2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java @@ -124,13 +124,13 @@ public final class MergingMediaSource extends CompositeMediaSource { } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { MediaPeriod[] periods = new MediaPeriod[mediaSources.length]; int periodIndex = timelines[0].getIndexOfPeriod(id.periodUid); for (int i = 0; i < periods.length; i++) { MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(timelines[i].getUidOfPeriod(periodIndex)); - periods[i] = mediaSources[i].createPeriod(childMediaPeriodId, allocator); + periods[i] = mediaSources[i].createPeriod(childMediaPeriodId, allocator, startPositionUs); } return new MergingMediaPeriod(compositeSequenceableLoaderFactory, periods); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java index 66097970c7..046672bb77 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaSource.java @@ -318,7 +318,7 @@ public final class SingleSampleMediaSource extends BaseMediaSource { } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { return new SingleSampleMediaPeriod( dataSpec, dataSourceFactory, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java index 19ddbd2c54..4bf661ddc0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java @@ -341,7 +341,7 @@ public final class AdsMediaSource extends CompositeMediaSource { } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { if (adPlaybackState.adGroupCount > 0 && id.isAd()) { int adGroupIndex = id.adGroupIndex; int adIndexInAdGroup = id.adIndexInAdGroup; @@ -360,7 +360,8 @@ public final class AdsMediaSource extends CompositeMediaSource { prepareChildSource(id, adMediaSource); } MediaSource mediaSource = adGroupMediaSources[adGroupIndex][adIndexInAdGroup]; - DeferredMediaPeriod deferredMediaPeriod = new DeferredMediaPeriod(mediaSource, id, allocator); + DeferredMediaPeriod deferredMediaPeriod = + new DeferredMediaPeriod(mediaSource, id, allocator, startPositionUs); deferredMediaPeriod.setPrepareErrorListener( new AdPrepareErrorListener(adUri, adGroupIndex, adIndexInAdGroup)); List mediaPeriods = deferredMediaPeriodByAdMediaSource.get(mediaSource); @@ -376,7 +377,8 @@ public final class AdsMediaSource extends CompositeMediaSource { } return deferredMediaPeriod; } else { - DeferredMediaPeriod mediaPeriod = new DeferredMediaPeriod(contentMediaSource, id, allocator); + DeferredMediaPeriod mediaPeriod = + new DeferredMediaPeriod(contentMediaSource, id, allocator, startPositionUs); mediaPeriod.createPeriod(id); return mediaPeriod; } diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index c8de8f02b1..c65bfceb39 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -635,7 +635,8 @@ public final class DashMediaSource extends BaseMediaSource { } @Override - public MediaPeriod createPeriod(MediaPeriodId periodId, Allocator allocator) { + public MediaPeriod createPeriod( + MediaPeriodId periodId, Allocator allocator, long startPositionUs) { int periodIndex = (Integer) periodId.periodUid - firstPeriodId; EventDispatcher periodEventDispatcher = createEventDispatcher(periodId, manifest.getPeriod(periodIndex).startMs); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index a9b0c579ac..2afd041631 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -412,7 +412,7 @@ public final class HlsMediaSource extends BaseMediaSource } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { EventDispatcher eventDispatcher = createEventDispatcher(id); return new HlsMediaPeriod( extractorFactory, diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java index 103a52a55a..d025f8fa3a 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaSource.java @@ -533,7 +533,7 @@ public final class SsMediaSource extends BaseMediaSource } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { EventDispatcher eventDispatcher = createEventDispatcher(id); SsMediaPeriod period = new SsMediaPeriod( 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 1f0c0c1a40..999372b90a 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,7 +116,7 @@ public class FakeMediaSource extends BaseMediaSource { } @Override - public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) { + public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) { assertThat(preparedSource).isTrue(); assertThat(releasedSource).isFalse(); int periodIndex = timeline.getIndexOfPeriod(id.periodUid); diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java index 70e7669dfb..e6fb5bc5f3 100644 --- a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java +++ b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/MediaSourceTestRunner.java @@ -142,15 +142,28 @@ public class MediaSourceTestRunner { } /** - * Calls {@link MediaSource#createPeriod(MediaSource.MediaPeriodId, Allocator)} on the playback - * thread, asserting that a non-null {@link MediaPeriod} is returned. + * Calls {@link MediaSource#createPeriod(MediaSource.MediaPeriodId, Allocator, long)} with a zero + * start position on the playback thread, asserting that a non-null {@link MediaPeriod} is + * returned. * * @param periodId The id of the period to create. * @return The created {@link MediaPeriod}. */ public MediaPeriod createPeriod(final MediaPeriodId periodId) { + return createPeriod(periodId, /* startPositionUs= */ 0); + } + + /** + * Calls {@link MediaSource#createPeriod(MediaSource.MediaPeriodId, Allocator, long)} on the + * playback thread, asserting that a non-null {@link MediaPeriod} is returned. + * + * @param periodId The id of the period to create. + * @return The created {@link MediaPeriod}. + */ + public MediaPeriod createPeriod(final MediaPeriodId periodId, long startPositionUs) { final MediaPeriod[] holder = new MediaPeriod[1]; - runOnPlaybackThread(() -> holder[0] = mediaSource.createPeriod(periodId, allocator)); + runOnPlaybackThread( + () -> holder[0] = mediaSource.createPeriod(periodId, allocator, startPositionUs)); assertThat(holder[0]).isNotNull(); return holder[0]; }