From 4afecc9099f2b1c91e9c7de867e9bc02df940442 Mon Sep 17 00:00:00 2001 From: christosts Date: Fri, 8 Sep 2023 04:37:23 -0700 Subject: [PATCH] Rollback of https://github.com/androidx/media/commit/51fd06482bee6b9edbf7aec4ae0f012901ed6055 PiperOrigin-RevId: 563714392 --- RELEASENOTES.md | 2 + .../media3/exoplayer/BaseRenderer.java | 55 +++++++++++-- .../exoplayer/ExoPlayerImplInternal.java | 9 ++- .../media3/exoplayer/MediaPeriodHolder.java | 4 +- .../media3/exoplayer/NoSampleRenderer.java | 18 ++++- .../androidx/media3/exoplayer/Renderer.java | 24 +++++- .../exoplayer/audio/DecoderAudioRenderer.java | 9 ++- .../media3/exoplayer/image/ImageRenderer.java | 9 ++- .../mediacodec/MediaCodecRenderer.java | 7 +- .../exoplayer/metadata/MetadataRenderer.java | 7 +- .../media3/exoplayer/text/TextRenderer.java | 7 +- .../exoplayer/video/DecoderVideoRenderer.java | 9 ++- .../video/spherical/CameraMotionRenderer.java | 7 +- .../media3/exoplayer/ExoPlayerTest.java | 79 ++++++++++++++++--- .../DefaultAnalyticsCollectorTest.java | 5 +- .../audio/DecoderAudioRendererTest.java | 14 +++- .../audio/MediaCodecAudioRendererTest.java | 45 +++++++---- .../exoplayer/image/ImageRendererTest.java | 4 +- .../mediacodec/MediaCodecRendererTest.java | 71 ++++++++++++++--- .../metadata/MetadataRendererTest.java | 24 ++++-- .../video/DecoderVideoRendererTest.java | 26 ++++-- .../video/MediaCodecVideoRendererTest.java | 65 +++++++++------ .../media3/test/utils/FakeVideoRenderer.java | 9 ++- .../ExoAssetLoaderBaseRenderer.java | 7 +- 24 files changed, 404 insertions(+), 112 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 44d7d535b2..d1ff1e1fdd 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -21,6 +21,8 @@ * Support `ClippingMediaSource` (and other sources with period/window time offsets) in `ConcatenatingMediaSource2` ([#11226](https://github.com/google/ExoPlayer/issues/11226)). + * Change `BaseRenderer.onStreamChanged()` to also receive a + `MediaPeriodId` argument. * Transformer: * Changed `frameRate` and `durationUs` parameters of `SampleConsumer.queueInputBitmap` to `TimestampIterator`. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/BaseRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/BaseRenderer.java index 2e89df6431..101dc6f258 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/BaseRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/BaseRenderer.java @@ -23,12 +23,16 @@ import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.PlaybackException; +import androidx.media3.common.Timeline; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Clock; import androidx.media3.common.util.UnstableApi; +import androidx.media3.common.util.Util; import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.decoder.DecoderInputBuffer.InsufficientCapacityException; import androidx.media3.exoplayer.analytics.PlayerId; +import androidx.media3.exoplayer.source.MediaPeriod; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.exoplayer.source.SampleStream.ReadFlags; @@ -55,6 +59,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { private long readingPositionUs; private boolean streamIsFinal; private boolean throwRendererExceptionIsExecuting; + private Timeline timeline; @GuardedBy("lock") @Nullable @@ -69,6 +74,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { this.trackType = trackType; formatHolder = new FormatHolder(); readingPositionUs = C.TIME_END_OF_SOURCE; + timeline = Timeline.EMPTY; } @Override @@ -108,13 +114,14 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { boolean joining, boolean mayRenderStartOfStream, long startPositionUs, - long offsetUs) + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { Assertions.checkState(state == STATE_DISABLED); this.configuration = configuration; state = STATE_ENABLED; onEnabled(joining, mayRenderStartOfStream); - replaceStream(formats, stream, startPositionUs, offsetUs); + replaceStream(formats, stream, startPositionUs, offsetUs, mediaPeriodId); resetPosition(startPositionUs, joining); } @@ -127,7 +134,11 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { @Override public final void replaceStream( - Format[] formats, SampleStream stream, long startPositionUs, long offsetUs) + Format[] formats, + SampleStream stream, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { Assertions.checkState(!streamIsFinal); this.stream = stream; @@ -136,7 +147,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { } streamFormats = formats; streamOffsetUs = offsetUs; - onStreamChanged(formats, startPositionUs, offsetUs); + onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); } @Override @@ -170,6 +181,14 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { Assertions.checkNotNull(stream).maybeThrowError(); } + @Override + public final void setTimeline(Timeline timeline) { + if (!Util.areEqual(this.timeline, timeline)) { + this.timeline = timeline; + onTimelineChanged(this.timeline); + } + } + @Override public final void resetPosition(long positionUs) throws ExoPlaybackException { resetPosition(positionUs, /* joining= */ false); @@ -270,17 +289,23 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { * @param startPositionUs The start position of the new stream in renderer time (microseconds). * @param offsetUs The offset that will be added to the timestamps of buffers read via {@link * #readSource} so that decoder input buffers have monotonically increasing timestamps. + * @param mediaPeriodId The {@link MediaSource.MediaPeriodId} of the {@link MediaPeriod} that + * produces the stream. * @throws ExoPlaybackException If an error occurs. */ - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { // Do nothing. } /** * Called when the position is reset. This occurs when the renderer is enabled after {@link - * #onStreamChanged(Format[], long, long)} has been called, and also when a position discontinuity - * is encountered. + * #onStreamChanged(Format[], long, long, MediaSource.MediaPeriodId)} has been called, and also + * when a position discontinuity is encountered. * *

After a position reset, the renderer's {@link SampleStream} is guaranteed to provide samples * starting from a key frame. @@ -342,6 +367,17 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { // Do nothing. } + /** + * Called when a new timeline is {@linkplain #setTimeline(Timeline) set}. + * + *

The default implementation is a no-op. + * + * @param timeline The new timeline, which can also be obtained from {@link #getTimeline()}. + */ + protected void onTimelineChanged(Timeline timeline) { + // Do nothing + } + // Methods to be called by subclasses. /** @@ -405,6 +441,11 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { return checkNotNull(clock); } + /** Returns the current {@link Timeline} containing the rendered stream. */ + protected final Timeline getTimeline() { + return timeline; + } + /** * Creates an {@link ExoPlaybackException} of type {@link ExoPlaybackException#TYPE_RENDERER} for * this renderer. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java index 489e77da17..c99c25940f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java @@ -1949,6 +1949,9 @@ import java.util.concurrent.atomic.AtomicBoolean; /* releaseMediaSourceList= */ false, /* resetError= */ true); } + for (Renderer renderer : renderers) { + renderer.setTimeline(timeline); + } if (!periodPositionChanged) { // We can keep the current playing period. Update the rest of the queued periods. if (!queue.updateQueuedPeriods( @@ -2246,7 +2249,8 @@ import java.util.concurrent.atomic.AtomicBoolean; formats, readingPeriodHolder.sampleStreams[i], readingPeriodHolder.getStartPositionRendererTime(), - readingPeriodHolder.getRendererOffset()); + readingPeriodHolder.getRendererOffset(), + readingPeriodHolder.info.id); } else if (renderer.isEnded()) { // The renderer has finished playback, so we can disable it now. disableRenderer(renderer); @@ -2624,7 +2628,8 @@ import java.util.concurrent.atomic.AtomicBoolean; joining, mayRenderStartOfStream, startPositionUs, - periodHolder.getRendererOffset()); + periodHolder.getRendererOffset(), + periodHolder.info.id); renderer.handleMessage( Renderer.MSG_SET_WAKEUP_LISTENER, new Renderer.WakeupListener() { diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java index 0d2427a48d..b4a95c4910 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/MediaPeriodHolder.java @@ -65,8 +65,8 @@ import androidx.media3.exoplayer.upstream.Allocator; * *

Renderers that are needed must have been enabled with the {@link #sampleStreams} for this * {@link #mediaPeriod}. This means either {@link Renderer#enable(RendererConfiguration, Format[], - * SampleStream, long, boolean, boolean, long, long)} or {@link Renderer#replaceStream(Format[], - * SampleStream, long, long)} has been called. + * SampleStream, long, boolean, boolean, long, long, MediaPeriodId)} or {@link + * Renderer#replaceStream(Format[], SampleStream, long, long, MediaPeriodId)} has been called. * *

Renderers that are not needed must have been {@link Renderer#disable() disabled}. */ diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/NoSampleRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/NoSampleRenderer.java index 3b33e06a2e..a67bfcf816 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/NoSampleRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/NoSampleRenderer.java @@ -18,10 +18,12 @@ package androidx.media3.exoplayer; import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.Format; +import androidx.media3.common.Timeline; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Clock; import androidx.media3.common.util.UnstableApi; import androidx.media3.exoplayer.analytics.PlayerId; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream; import java.io.IOException; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -74,13 +76,14 @@ public abstract class NoSampleRenderer implements Renderer, RendererCapabilities boolean joining, boolean mayRenderStartOfStream, long startPositionUs, - long offsetUs) + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { Assertions.checkState(state == STATE_DISABLED); this.configuration = configuration; state = STATE_ENABLED; onEnabled(joining); - replaceStream(formats, stream, startPositionUs, offsetUs); + replaceStream(formats, stream, startPositionUs, offsetUs, mediaPeriodId); onPositionReset(positionUs, joining); } @@ -93,7 +96,11 @@ public abstract class NoSampleRenderer implements Renderer, RendererCapabilities @Override public final void replaceStream( - Format[] formats, SampleStream stream, long startPositionUs, long offsetUs) + Format[] formats, + SampleStream stream, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { Assertions.checkState(!streamIsFinal); this.stream = stream; @@ -187,6 +194,11 @@ public abstract class NoSampleRenderer implements Renderer, RendererCapabilities // Do nothing. } + @Override + public void setTimeline(Timeline timeline) { + // Do nothing. + } + // Methods to be overridden by subclasses. /** diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java index 17311ca7d1..baa7019654 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java @@ -27,11 +27,14 @@ import androidx.media3.common.C; import androidx.media3.common.Effect; import androidx.media3.common.Format; import androidx.media3.common.Player; +import androidx.media3.common.Timeline; import androidx.media3.common.util.Clock; import androidx.media3.common.util.Size; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import androidx.media3.exoplayer.analytics.PlayerId; +import androidx.media3.exoplayer.source.MediaPeriod; +import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId; import androidx.media3.exoplayer.source.SampleStream; import androidx.media3.exoplayer.video.VideoDecoderOutputBufferRenderer; import androidx.media3.exoplayer.video.VideoFrameMetadataListener; @@ -346,6 +349,8 @@ public interface Renderer extends PlayerMessage.Target { * @param startPositionUs The start position of the stream in renderer time (microseconds). * @param offsetUs The offset to be added to timestamps of buffers read from {@code stream} before * they are rendered. + * @param mediaPeriodId The {@link MediaPeriodId} of the {@link MediaPeriod} producing the {@code + * stream}. * @throws ExoPlaybackException If an error occurs. */ void enable( @@ -356,7 +361,8 @@ public interface Renderer extends PlayerMessage.Target { boolean joining, boolean mayRenderStartOfStream, long startPositionUs, - long offsetUs) + long offsetUs, + MediaPeriodId mediaPeriodId) throws ExoPlaybackException; /** @@ -381,9 +387,16 @@ public interface Renderer extends PlayerMessage.Target { * @param startPositionUs The start position of the new stream in renderer time (microseconds). * @param offsetUs The offset to be added to timestamps of buffers read from {@code stream} before * they are rendered. + * @param mediaPeriodId The {@link MediaPeriodId} of the {@link MediaPeriod} producing the {@code + * stream}. * @throws ExoPlaybackException If an error occurs. */ - void replaceStream(Format[] formats, SampleStream stream, long startPositionUs, long offsetUs) + void replaceStream( + Format[] formats, + SampleStream stream, + long startPositionUs, + long offsetUs, + MediaPeriodId mediaPeriodId) throws ExoPlaybackException; /** Returns the {@link SampleStream} being consumed, or null if the renderer is disabled. */ @@ -471,6 +484,9 @@ public interface Renderer extends PlayerMessage.Target { */ default void enableMayRenderStartOfStream() {} + /** Sets the timeline that is currently being played. */ + void setTimeline(Timeline timeline); + /** * Incrementally renders the {@link SampleStream}. * @@ -482,8 +498,8 @@ public interface Renderer extends PlayerMessage.Target { *

The renderer may also render the very start of the media at the current position (e.g. the * first frame of a video stream) while still in the {@link #STATE_ENABLED} state, unless it's the * initial start of the media after calling {@link #enable(RendererConfiguration, Format[], - * SampleStream, long, boolean, boolean, long, long)} with {@code mayRenderStartOfStream} set to - * {@code false}. + * SampleStream, long, boolean, boolean, long, long, MediaPeriodId)} with {@code + * mayRenderStartOfStream} set to {@code false}. * *

This method should return quickly, and should not block if the renderer is unable to make * useful progress. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DecoderAudioRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DecoderAudioRenderer.java index 309c4aa323..959289b625 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DecoderAudioRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DecoderAudioRenderer.java @@ -62,6 +62,7 @@ import androidx.media3.exoplayer.audio.AudioRendererEventListener.EventDispatche import androidx.media3.exoplayer.audio.AudioSink.SinkFormatSupport; import androidx.media3.exoplayer.drm.DrmSession; import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import com.google.errorprone.annotations.ForOverride; import java.lang.annotation.Documented; @@ -649,9 +650,13 @@ public abstract class DecoderAudioRenderer< } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { - super.onStreamChanged(formats, startPositionUs, offsetUs); + super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); firstStreamSampleRead = false; if (outputStreamOffsetUs == C.TIME_UNSET) { setOutputStreamOffsetUs(offsetUs); diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/image/ImageRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/image/ImageRenderer.java index 4b75c61093..6d12c71260 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/image/ImageRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/image/ImageRenderer.java @@ -33,6 +33,7 @@ import androidx.media3.exoplayer.ExoPlaybackException; import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.Renderer; import androidx.media3.exoplayer.RendererCapabilities; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @@ -138,13 +139,17 @@ public final class ImageRenderer extends BaseRenderer { } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { // TODO(b/289989736): when the mediaPeriodId is signalled to the renders, collect and set // durationUs here. durationUs = 2 * C.MICROS_PER_SECOND; this.offsetUs = offsetUs; - super.onStreamChanged(formats, startPositionUs, offsetUs); + super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); } @Override diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index aed5233206..c749b49a1f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -74,6 +74,7 @@ import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException; import androidx.media3.exoplayer.drm.FrameworkCryptoConfig; import androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException; import androidx.media3.exoplayer.source.MediaPeriod; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.exoplayer.source.SampleStream.ReadFlags; @@ -708,7 +709,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET) { // This is the first stream. diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/metadata/MetadataRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/metadata/MetadataRenderer.java index 9ca0a1fee3..dfb868258e 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/metadata/MetadataRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/metadata/MetadataRenderer.java @@ -32,6 +32,7 @@ import androidx.media3.common.util.Util; import androidx.media3.exoplayer.BaseRenderer; import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.RendererCapabilities; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.extractor.metadata.MetadataDecoder; import androidx.media3.extractor.metadata.MetadataInputBuffer; @@ -140,7 +141,11 @@ public final class MetadataRenderer extends BaseRenderer implements Callback { } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) { + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) { decoder = decoderFactory.createDecoder(formats[0]); if (pendingMetadata != null) { pendingMetadata = diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java index de74671018..70756a3d4d 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java @@ -36,6 +36,7 @@ import androidx.media3.common.util.Util; import androidx.media3.exoplayer.BaseRenderer; import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.RendererCapabilities; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.extractor.text.Subtitle; import androidx.media3.extractor.text.SubtitleDecoder; @@ -177,7 +178,11 @@ public final class TextRenderer extends BaseRenderer implements Callback { } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) { + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) { outputStreamOffsetUs = offsetUs; streamFormat = formats[0]; if (decoder != null) { diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java index a6997b8788..c300010bd9 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/DecoderVideoRenderer.java @@ -54,6 +54,7 @@ import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.PlayerMessage; import androidx.media3.exoplayer.drm.DrmSession; import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import androidx.media3.exoplayer.video.VideoRendererEventListener.EventDispatcher; import java.lang.annotation.Documented; @@ -334,13 +335,17 @@ public abstract class DecoderVideoRenderer extends BaseRenderer { } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { // TODO: This shouldn't just update the output stream offset as long as there are still buffers // of the previous stream in the decoder. It should also make sure to render the first frame of // the next stream if the playback position reached the new stream. outputStreamOffsetUs = offsetUs; - super.onStreamChanged(formats, startPositionUs, offsetUs); + super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); } /** diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/CameraMotionRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/CameraMotionRenderer.java index b372d03481..c76e2d24a6 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/CameraMotionRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/spherical/CameraMotionRenderer.java @@ -28,6 +28,7 @@ import androidx.media3.exoplayer.ExoPlaybackException; import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.Renderer; import androidx.media3.exoplayer.RendererCapabilities; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import java.nio.ByteBuffer; @@ -75,7 +76,11 @@ public final class CameraMotionRenderer extends BaseRenderer { } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) { + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) { this.offsetUs = offsetUs; } diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java index 36c903f8a9..d3c3c2fbe1 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -49,7 +49,6 @@ import static androidx.media3.common.Player.COMMAND_SET_TRACK_SELECTION_PARAMETE import static androidx.media3.common.Player.COMMAND_SET_VIDEO_SURFACE; import static androidx.media3.common.Player.COMMAND_SET_VOLUME; import static androidx.media3.common.Player.COMMAND_STOP; -import static androidx.media3.common.Player.STATE_ENDED; import static androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState; import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM; import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample; @@ -410,7 +409,7 @@ public final class ExoPlayerTest { playerListenerOrder.verify(mockPlayerListener).onVideoSizeChanged(new VideoSize(1280, 720)); playerListenerOrder.verify(mockPlayerListener).onVideoSizeChanged(VideoSize.UNKNOWN); playerListenerOrder.verify(mockPlayerListener).onVideoSizeChanged(new VideoSize(1280, 720)); - playerListenerOrder.verify(mockPlayerListener).onPlaybackStateChanged(STATE_ENDED); + playerListenerOrder.verify(mockPlayerListener).onPlaybackStateChanged(Player.STATE_ENDED); verify(mockPlayerListener, times(3)).onVideoSizeChanged(any()); // Verify calls to analytics listener. verify(mockAnalyticsListener, times(2)).onVideoEnabled(any(), any()); @@ -3412,7 +3411,7 @@ public final class ExoPlayerTest { player.setMediaSource(new FakeMediaSource()); player.prepare(); player.play(); - TestPlayerRunHelper.runUntilPlaybackState(player, STATE_ENDED); + TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_ENDED); // Now the player, which had a playback error, was re-prepared causing the error to be cleared. // We expect the change to null to be notified, but not onPlayerError. verify(mockListener).onPlayerErrorChanged(ArgumentMatchers.isNull()); @@ -8904,7 +8903,8 @@ public final class ExoPlayerTest { boolean pendingFirstBufferTime = false; @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) { + protected void onStreamChanged( + Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId) { rendererStreamOffsetsUs.add(offsetUs); pendingFirstBufferTime = true; } @@ -10592,7 +10592,8 @@ public final class ExoPlayerTest { private long positionUs; @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) { + protected void onStreamChanged( + Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId) { this.positionUs = offsetUs; } @@ -12872,9 +12873,12 @@ public final class ExoPlayerTest { @Override protected void onStreamChanged( - Format[] formats, long startPositionUs, long offsetUs) + Format[] formats, + long startPositionUs, + long offsetUs, + MediaPeriodId mediaPeriodId) throws ExoPlaybackException { - super.onStreamChanged(formats, startPositionUs, offsetUs); + super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); streamChangeCount++; } @@ -13851,9 +13855,10 @@ public final class ExoPlayerTest { FakeRenderer newlyEnabledRenderer = new FakeRenderer(C.TRACK_TYPE_AUDIO) { @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + protected void onStreamChanged( + Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId) throws ExoPlaybackException { - super.onStreamChanged(formats, startPositionUs, offsetUs); + super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); startPositionInRendererUs.set(startPositionUs); rendererOffsetUs.set(offsetUs); } @@ -13882,7 +13887,7 @@ public final class ExoPlayerTest { .setTrackTypeDisabled(C.TRACK_TYPE_AUDIO, /* disabled= */ false) .build()); player.play(); - runUntilPlaybackState(player, STATE_ENDED); + runUntilPlaybackState(player, Player.STATE_ENDED); player.release(); long expectedStartPositionInRendererUs = @@ -13892,6 +13897,60 @@ public final class ExoPlayerTest { assertThat(startPositionInRendererUs.get()).isEqualTo(expectedStartPositionInRendererUs); } + @Test + public void newlyEnabledRenderer_timelineIsSetBeforeEnable() + throws TimeoutException, ExoPlaybackException { + MediaItem mediaItem = MediaItem.fromUri(SAMPLE_URI); + ArrayList timelineOnEnabled = new ArrayList<>(); + FakeRenderer videoRenderer = + new FakeRenderer(C.TRACK_TYPE_VIDEO) { + @Override + protected void onEnabled(boolean joining, boolean mayRenderStartOfStream) { + timelineOnEnabled.add(getTimeline()); + } + }; + ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(videoRenderer).build(); + player.addMediaItem(mediaItem); + player.prepare(); + + runUntilPlaybackState(player, Player.STATE_READY); + player.release(); + + assertThat(timelineOnEnabled).hasSize(1); + Timeline timeline = timelineOnEnabled.get(0); + assertThat(timeline.getWindowCount()).isEqualTo(1); + assertThat(timeline.getWindow(0, new Window()).mediaItem).isSameInstanceAs(mediaItem); + } + + @Test + public void changeMediaItemMidPlayback_rendererReceivesNewTimelineBeforeStreamChange() + throws TimeoutException { + MediaItem mediaItem1 = MediaItem.fromUri(SAMPLE_URI); + MediaItem mediaItem2 = MediaItem.fromUri(SAMPLE_URI); + ArrayList timelinesOnStreamChange = new ArrayList<>(); + FakeRenderer videoRenderer = + new FakeRenderer(C.TRACK_TYPE_VIDEO) { + @Override + protected void onStreamChanged( + Format[] formats, long startPositionUs, long offsetUs, MediaPeriodId mediaPeriodId) { + timelinesOnStreamChange.add(getTimeline()); + } + }; + ExoPlayer player = new TestExoPlayerBuilder(context).setRenderers(videoRenderer).build(); + player.addMediaItem(mediaItem1); + player.prepare(); + runUntilPlaybackState(player, Player.STATE_READY); + player.setMediaItem(mediaItem2); + runUntilPlaybackState(player, Player.STATE_READY); + player.release(); + + assertThat(timelinesOnStreamChange).hasSize(2); + assertThat(timelinesOnStreamChange.get(0).getWindow(0, new Window()).mediaItem) + .isSameInstanceAs(mediaItem1); + assertThat(timelinesOnStreamChange.get(1).getWindow(0, new Window()).mediaItem) + .isSameInstanceAs(mediaItem2); + } + // Internal methods. private void addWatchAsSystemFeature() { diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollectorTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollectorTest.java index 1173abb886..c1421266ba 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollectorTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/analytics/DefaultAnalyticsCollectorTest.java @@ -1576,7 +1576,10 @@ public final class DefaultAnalyticsCollectorTest { @Override protected void onStreamChanged( - Format[] formats, long startPositionUs, long offsetUs) + Format[] formats, + long startPositionUs, + long offsetUs, + MediaPeriodId mediaPeriodId) throws ExoPlaybackException { // Fail when changing streams for the second time. This will happen during the // period transition (as the first time is when enabling the stream initially). diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DecoderAudioRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DecoderAudioRendererTest.java index 4710314321..fc3dda6290 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DecoderAudioRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/DecoderAudioRendererTest.java @@ -45,6 +45,7 @@ import androidx.media3.exoplayer.RendererConfiguration; import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionManager; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.test.utils.FakeSampleStream; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -134,7 +135,8 @@ public class DecoderAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); audioRenderer.setCurrentStreamFinal(); when(mockAudioSink.isEnded()).thenReturn(true); while (!audioRenderer.isEnded()) { @@ -172,7 +174,8 @@ public class DecoderAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); audioRenderer.setCurrentStreamFinal(); while (!audioRenderer.isEnded()) { @@ -215,6 +218,7 @@ public class DecoderAudioRendererTest { oneByteSample(/* timeUs= */ 1_001_000), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object()); audioRenderer.enable( RendererConfiguration.DEFAULT, new Format[] {FORMAT}, @@ -223,7 +227,8 @@ public class DecoderAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId); while (!audioRenderer.hasReadStreamToEnd()) { audioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -232,7 +237,8 @@ public class DecoderAudioRendererTest { new Format[] {FORMAT}, fakeSampleStream2, /* startPositionUs= */ 1_000_000, - /* offsetUs= */ 1_000_000); + /* offsetUs= */ 1_000_000, + mediaPeriodId); audioRenderer.setCurrentStreamFinal(); while (!audioRenderer.isEnded()) { audioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/MediaCodecAudioRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/MediaCodecAudioRendererTest.java index b70bacf266..944cf7a0a1 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/MediaCodecAudioRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/audio/MediaCodecAudioRendererTest.java @@ -49,6 +49,7 @@ import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionManager; import androidx.media3.exoplayer.mediacodec.MediaCodecInfo; import androidx.media3.exoplayer.mediacodec.MediaCodecSelector; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.test.utils.FakeSampleStream; import androidx.media3.test.utils.TestUtil; @@ -191,7 +192,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecAudioRenderer.start(); mediaCodecAudioRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); @@ -248,7 +250,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecAudioRenderer.start(); mediaCodecAudioRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); @@ -312,7 +315,6 @@ public class MediaCodecAudioRendererTest { ImmutableList.of( oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM)); fakeSampleStream.writeData(/* startPositionUs= */ 0); - exceptionThrowingRenderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); exceptionThrowingRenderer.enable( RendererConfiguration.DEFAULT, @@ -322,7 +324,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); exceptionThrowingRenderer.start(); exceptionThrowingRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); @@ -403,6 +406,7 @@ public class MediaCodecAudioRendererTest { oneByteSample(/* timeUs= */ 1_001_000), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object()); mediaCodecAudioRenderer.enable( RendererConfiguration.DEFAULT, new Format[] {AUDIO_AAC}, @@ -411,7 +415,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId); mediaCodecAudioRenderer.start(); while (!mediaCodecAudioRenderer.hasReadStreamToEnd()) { @@ -421,7 +426,8 @@ public class MediaCodecAudioRendererTest { new Format[] {AUDIO_AAC}, fakeSampleStream2, /* startPositionUs= */ 1_000_000, - /* offsetUs= */ 1_000_000); + /* offsetUs= */ 1_000_000, + mediaPeriodId); mediaCodecAudioRenderer.setCurrentStreamFinal(); while (!mediaCodecAudioRenderer.isEnded()) { mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -487,7 +493,6 @@ public class MediaCodecAudioRendererTest { oneByteSample(/* timeUs= */ 1_000), END_OF_STREAM_ITEM)); fakeSampleStream.writeData(/* startPositionUs= */ 0); - mediaCodecAudioRenderer.enable( RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED, new Format[] {format}, @@ -496,7 +501,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecAudioRenderer.start(); mediaCodecAudioRenderer.setCurrentStreamFinal(); @@ -525,7 +531,6 @@ public class MediaCodecAudioRendererTest { oneByteSample(/* timeUs= */ 1_000), END_OF_STREAM_ITEM)); fakeSampleStream.writeData(/* startPositionUs= */ 0); - mediaCodecAudioRenderer.enable( RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED, new Format[] {format}, @@ -534,7 +539,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecAudioRenderer.start(); mediaCodecAudioRenderer.setCurrentStreamFinal(); @@ -575,6 +581,7 @@ public class MediaCodecAudioRendererTest { oneByteSample(/* timeUs= */ 1_001_000), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object()); mediaCodecAudioRenderer.enable( RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED, new Format[] {format1}, @@ -583,7 +590,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId); mediaCodecAudioRenderer.start(); while (!mediaCodecAudioRenderer.hasReadStreamToEnd()) { mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -593,7 +601,8 @@ public class MediaCodecAudioRendererTest { new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 1_000_000, - /* offsetUs= */ 1_000_000); + /* offsetUs= */ 1_000_000, + mediaPeriodId); mediaCodecAudioRenderer.setCurrentStreamFinal(); while (!mediaCodecAudioRenderer.isEnded()) { mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -634,6 +643,9 @@ public class MediaCodecAudioRendererTest { oneByteSample(/* timeUs= */ 1_001_000), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); + mediaCodecAudioRenderer.enable( RENDERER_CONFIGURATION_OFFLOAD_ENABLED_GAPLESS_REQUIRED, new Format[] {format1}, @@ -642,7 +654,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); mediaCodecAudioRenderer.start(); while (!mediaCodecAudioRenderer.hasReadStreamToEnd()) { mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -653,7 +666,8 @@ public class MediaCodecAudioRendererTest { new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 1_000_000, - /* offsetUs= */ 1_000_000); + /* offsetUs= */ 1_000_000, + mediaPeriodId2); mediaCodecAudioRenderer.setCurrentStreamFinal(); while (!mediaCodecAudioRenderer.isEnded()) { mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -693,7 +707,8 @@ public class MediaCodecAudioRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecAudioRenderer.setCurrentStreamFinal(); while (!mediaCodecAudioRenderer.isEnded()) { mediaCodecAudioRenderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/image/ImageRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/image/ImageRendererTest.java index 6e46b84812..70fc01b629 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/image/ImageRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/image/ImageRendererTest.java @@ -29,6 +29,7 @@ import androidx.media3.exoplayer.RendererConfiguration; import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionManager; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.test.utils.FakeSampleStream; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -93,7 +94,8 @@ public class ImageRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); renderer.setCurrentStreamFinal(); while (!renderer.isReady()) { diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java index 0050c7ade5..157bbd7bbc 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/mediacodec/MediaCodecRendererTest.java @@ -41,6 +41,7 @@ import androidx.media3.exoplayer.RendererConfiguration; import androidx.media3.exoplayer.analytics.PlayerId; import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionManager; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.test.utils.FakeSampleStream; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -66,6 +67,8 @@ public class MediaCodecRendererTest { createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300); FakeSampleStream fakeSampleStream2 = createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); MediaCodecRenderer renderer = spy(new TestRenderer()); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); @@ -77,7 +80,8 @@ public class MediaCodecRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); renderer.start(); long positionUs = 0; while (!renderer.hasReadStreamToEnd()) { @@ -85,7 +89,11 @@ public class MediaCodecRendererTest { positionUs += 100; } renderer.replaceStream( - new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 400); + new Format[] {format2}, + fakeSampleStream2, + /* startPositionUs= */ 400, + /* offsetUs= */ 400, + mediaPeriodId2); renderer.setCurrentStreamFinal(); while (!renderer.isEnded()) { renderer.render(positionUs, SystemClock.elapsedRealtime()); @@ -119,6 +127,8 @@ public class MediaCodecRendererTest { createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300, 400, 500, 600); FakeSampleStream fakeSampleStream2 = createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); MediaCodecRenderer renderer = spy(new TestRenderer()); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); @@ -130,7 +140,8 @@ public class MediaCodecRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); renderer.start(); long positionUs = 0; while (!renderer.hasReadStreamToEnd()) { @@ -138,7 +149,11 @@ public class MediaCodecRendererTest { positionUs += 100; } renderer.replaceStream( - new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 400); + new Format[] {format2}, + fakeSampleStream2, + /* startPositionUs= */ 400, + /* offsetUs= */ 400, + mediaPeriodId2); renderer.setCurrentStreamFinal(); while (!renderer.isEnded()) { renderer.render(positionUs, SystemClock.elapsedRealtime()); @@ -175,6 +190,8 @@ public class MediaCodecRendererTest { createFakeSampleStream(format1, /* sampleTimesUs...= */ 0, 100, 200, 300); FakeSampleStream fakeSampleStream2 = createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200, 300, 400); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); MediaCodecRenderer renderer = spy(new TestRenderer()); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); @@ -186,7 +203,8 @@ public class MediaCodecRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); renderer.start(); long positionUs = 0; while (!renderer.hasReadStreamToEnd()) { @@ -194,7 +212,11 @@ public class MediaCodecRendererTest { positionUs += 100; } renderer.replaceStream( - new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 400, /* offsetUs= */ 200); + new Format[] {format2}, + fakeSampleStream2, + /* startPositionUs= */ 400, + /* offsetUs= */ 200, + mediaPeriodId2); renderer.setCurrentStreamFinal(); while (!renderer.isEnded()) { renderer.render(positionUs, SystemClock.elapsedRealtime()); @@ -229,6 +251,8 @@ public class MediaCodecRendererTest { FakeSampleStream fakeSampleStream1 = createFakeSampleStream(format1 /* no samples */); FakeSampleStream fakeSampleStream2 = createFakeSampleStream(format2, /* sampleTimesUs...= */ 0, 100, 200); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); MediaCodecRenderer renderer = spy(new TestRenderer()); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); @@ -240,7 +264,8 @@ public class MediaCodecRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); renderer.start(); long positionUs = 0; while (!renderer.hasReadStreamToEnd()) { @@ -248,7 +273,11 @@ public class MediaCodecRendererTest { positionUs += 100; } renderer.replaceStream( - new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 0, /* offsetUs= */ 0); + new Format[] {format2}, + fakeSampleStream2, + /* startPositionUs= */ 0, + /* offsetUs= */ 0, + mediaPeriodId2); renderer.setCurrentStreamFinal(); while (!renderer.isEnded()) { renderer.render(positionUs, SystemClock.elapsedRealtime()); @@ -280,6 +309,9 @@ public class MediaCodecRendererTest { FakeSampleStream fakeSampleStream2 = createFakeSampleStream(format2 /* no samples */); FakeSampleStream fakeSampleStream3 = createFakeSampleStream(format3, /* sampleTimesUs...= */ 0, 100, 200); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId3 = new MediaSource.MediaPeriodId(new Object()); MediaCodecRenderer renderer = spy(new TestRenderer()); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); @@ -291,7 +323,8 @@ public class MediaCodecRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); renderer.start(); long positionUs = 0; while (!renderer.hasReadStreamToEnd()) { @@ -299,13 +332,21 @@ public class MediaCodecRendererTest { positionUs += 100; } renderer.replaceStream( - new Format[] {format2}, fakeSampleStream2, /* startPositionUs= */ 200, /* offsetUs= */ 200); + new Format[] {format2}, + fakeSampleStream2, + /* startPositionUs= */ 200, + /* offsetUs= */ 200, + mediaPeriodId2); while (!renderer.hasReadStreamToEnd()) { renderer.render(positionUs, SystemClock.elapsedRealtime()); positionUs += 100; } renderer.replaceStream( - new Format[] {format3}, fakeSampleStream3, /* startPositionUs= */ 200, /* offsetUs= */ 200); + new Format[] {format3}, + fakeSampleStream3, + /* startPositionUs= */ 200, + /* offsetUs= */ 200, + mediaPeriodId3); renderer.setCurrentStreamFinal(); while (!renderer.isEnded()) { renderer.render(positionUs, SystemClock.elapsedRealtime()); @@ -334,6 +375,7 @@ public class MediaCodecRendererTest { new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1000).build(); FakeSampleStream fakeSampleStream = createFakeSampleStream(format, /* sampleTimesUs...= */ 0, 100, 200, 300, 400, 500); + MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object()); MediaCodecRenderer renderer = spy(new TestRenderer()); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); @@ -345,7 +387,8 @@ public class MediaCodecRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 300, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId); renderer.start(); renderer.setCurrentStreamFinal(); long positionUs = 0; @@ -375,6 +418,7 @@ public class MediaCodecRendererTest { new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).setAverageBitrate(1000).build(); FakeSampleStream fakeSampleStream = createFakeSampleStream(format, /* sampleTimesUs...= */ 0, 100, 200, 300, 400, 500); + MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object()); MediaCodecRenderer renderer = spy(new TestRenderer()); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); renderer.enable( @@ -385,7 +429,8 @@ public class MediaCodecRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 400, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId); renderer.start(); renderer.resetPosition(/* positionUs= */ 200); diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/metadata/MetadataRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/metadata/MetadataRendererTest.java index 9e248def39..2a6bd2b2ce 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/metadata/MetadataRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/metadata/MetadataRendererTest.java @@ -29,6 +29,7 @@ import androidx.media3.common.util.Assertions; import androidx.media3.exoplayer.ExoPlaybackException; import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionManager; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.extractor.metadata.emsg.EventMessage; import androidx.media3.extractor.metadata.emsg.EventMessageEncoder; @@ -169,7 +170,8 @@ public class MetadataRendererTest { new Format[] {EMSG_FORMAT}, fakeSampleStream, /* startPositionUs= */ 0L, - /* offsetUs= */ 0L); + /* offsetUs= */ 0L, + new MediaSource.MediaPeriodId(new Object())); // Call render() twice, the first call is to read the format and the second call will read the // metadata. @@ -208,7 +210,8 @@ public class MetadataRendererTest { new Format[] {EMSG_FORMAT}, fakeSampleStream, /* startPositionUs= */ 0L, - /* offsetUs= */ 0L); + /* offsetUs= */ 0L, + new MediaSource.MediaPeriodId(new Object())); // Call render() twice, the first call is to read the format and the second call will read the // metadata. @@ -246,12 +249,14 @@ public class MetadataRendererTest { sample(/* timeUs= */ 200_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg), END_OF_STREAM_ITEM)); fakeSampleStream.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object()); // Start of the first reading period. renderer.replaceStream( new Format[] {EMSG_FORMAT}, fakeSampleStream, /* startPositionUs= */ 0L, - /* offsetUs= */ 0L); + /* offsetUs= */ 0L, + mediaPeriodId); // Read the format renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -268,7 +273,8 @@ public class MetadataRendererTest { new Format[] {EMSG_FORMAT}, fakeSampleStream, /* startPositionUs= */ 0L, - /* offsetUs= */ 100_000L); + /* offsetUs= */ 100_000L, + mediaPeriodId); renderer.render(/* positionUs= */ 199_999, /* elapsedRealtimeUs= */ 0); assertThat(metadataOutput).hasSize(1); @@ -304,12 +310,14 @@ public class MetadataRendererTest { sample(/* timeUs= */ 200_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg), END_OF_STREAM_ITEM)); fakeSampleStream.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId = new MediaSource.MediaPeriodId(new Object()); // Start of the first reading period. renderer.replaceStream( new Format[] {EMSG_FORMAT}, fakeSampleStream, /* startPositionUs= */ 0L, - /* offsetUs= */ 100_000L); + /* offsetUs= */ 100_000L, + mediaPeriodId); // Read the format renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); @@ -326,7 +334,8 @@ public class MetadataRendererTest { new Format[] {EMSG_FORMAT}, fakeSampleStream, /* startPositionUs= */ 0L, - /* offsetUs= */ 0L); + /* offsetUs= */ 0L, + mediaPeriodId); renderer.render(/* positionUs= */ 299_999, /* elapsedRealtimeUs= */ 0); assertThat(metadataOutput).hasSize(1); @@ -349,7 +358,8 @@ public class MetadataRendererTest { new Format[] {EMSG_FORMAT}, fakeSampleStream, /* startPositionUs= */ 0L, - /* offsetUs= */ 0L); + /* offsetUs= */ 0L, + new MediaSource.MediaPeriodId(new Object())); renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the format renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0); // Read the data diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/DecoderVideoRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/DecoderVideoRendererTest.java index 95a9a67b61..a411f8d1fe 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/DecoderVideoRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/DecoderVideoRendererTest.java @@ -41,6 +41,7 @@ import androidx.media3.exoplayer.RendererCapabilities; import androidx.media3.exoplayer.RendererConfiguration; import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionManager; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.upstream.DefaultAllocator; import androidx.media3.test.utils.FakeSampleStream; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -204,7 +205,8 @@ public final class DecoderVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0L, - /* offsetUs */ 0); + /* offsetUs */ 0, + new MediaSource.MediaPeriodId(new Object())); for (int i = 0; i < 10; i++) { renderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); // Ensure pending messages are delivered. @@ -235,7 +237,8 @@ public final class DecoderVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs */ 0); + /* offsetUs */ 0, + new MediaSource.MediaPeriodId(new Object())); for (int i = 0; i < 10; i++) { renderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); // Ensure pending messages are delivered. @@ -265,7 +268,8 @@ public final class DecoderVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs */ 0); + /* offsetUs */ 0, + new MediaSource.MediaPeriodId(new Object())); renderer.start(); for (int i = 0; i < 10; i++) { renderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); @@ -299,6 +303,8 @@ public final class DecoderVideoRendererTest { /* initialFormat= */ H264_FORMAT, ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); renderer.enable( RendererConfiguration.DEFAULT, new Format[] {H264_FORMAT}, @@ -307,7 +313,8 @@ public final class DecoderVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs */ 0); + /* offsetUs */ 0, + mediaPeriodId1); renderer.start(); boolean replacedStream = false; @@ -318,7 +325,8 @@ public final class DecoderVideoRendererTest { new Format[] {H264_FORMAT}, fakeSampleStream2, /* startPositionUs= */ 100, - /* offsetUs= */ 100); + /* offsetUs= */ 100, + mediaPeriodId2); replacedStream = true; } // Ensure pending messages are delivered. @@ -352,6 +360,8 @@ public final class DecoderVideoRendererTest { /* initialFormat= */ H264_FORMAT, ImmutableList.of(oneByteSample(/* timeUs= */ 0), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); renderer.enable( RendererConfiguration.DEFAULT, new Format[] {H264_FORMAT}, @@ -360,7 +370,8 @@ public final class DecoderVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs */ 0); + /* offsetUs */ 0, + mediaPeriodId1); boolean replacedStream = false; for (int i = 0; i < 10; i++) { @@ -370,7 +381,8 @@ public final class DecoderVideoRendererTest { new Format[] {H264_FORMAT}, fakeSampleStream2, /* startPositionUs= */ 100, - /* offsetUs= */ 100); + /* offsetUs= */ 100, + mediaPeriodId2); replacedStream = true; } // Ensure pending messages are delivered. diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java index 68f0087856..20a322b1d1 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java @@ -221,7 +221,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + /* mediaPeriodId= */ new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.start(); mediaCodecVideoRenderer.render(0, SystemClock.elapsedRealtime() * 1000); @@ -277,7 +278,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 30_000, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.start(); mediaCodecVideoRenderer.setCurrentStreamFinal(); @@ -304,15 +306,14 @@ public class MediaCodecVideoRendererTest { ArgumentCaptor argumentDecoderCounters = ArgumentCaptor.forClass(DecoderCounters.class); // Set up MediaPeriod with samples. + MediaSource.MediaPeriodId fakeMediaPeriodId = new MediaSource.MediaPeriodId(new Object()); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod( new TrackGroupArray(TRACK_GROUP_H264), new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024), /* trackDataFactory= */ (format, mediaPeriodId) -> ImmutableList.of(), new MediaSourceEventListener.EventDispatcher() - .withParameters( - /* windowIndex= */ 0, - new MediaSource.MediaPeriodId(/* periodUid= */ new Object())), + .withParameters(/* windowIndex= */ 0, fakeMediaPeriodId), DrmSessionManager.DRM_UNSUPPORTED, new DrmSessionEventListener.EventDispatcher(), /* deferOnPrepared= */ false) { @@ -388,7 +389,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 100, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + fakeMediaPeriodId); mediaCodecVideoRenderer.start(); // Call to render should have read all samples up before endUs. @@ -409,15 +411,14 @@ public class MediaCodecVideoRendererTest { ArgumentCaptor argumentDecoderCounters = ArgumentCaptor.forClass(DecoderCounters.class); // Set up MediaPeriod with samples. + MediaSource.MediaPeriodId fakeMediaPeriodId = new MediaSource.MediaPeriodId(new Object()); FakeMediaPeriod mediaPeriod = new FakeMediaPeriod( new TrackGroupArray(TRACK_GROUP_H264), new DefaultAllocator(/* trimOnReset= */ true, /* individualAllocationSize= */ 1024), /* trackDataFactory= */ (format, mediaPeriodId) -> ImmutableList.of(), new MediaSourceEventListener.EventDispatcher() - .withParameters( - /* windowIndex= */ 0, - new MediaSource.MediaPeriodId(/* periodUid= */ new Object())), + .withParameters(/* windowIndex= */ 0, fakeMediaPeriodId), DrmSessionManager.DRM_UNSUPPORTED, new DrmSessionEventListener.EventDispatcher(), /* deferOnPrepared= */ false) { @@ -493,7 +494,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 100, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + fakeMediaPeriodId); mediaCodecVideoRenderer.start(); mediaCodecVideoRenderer.setCurrentStreamFinal(); @@ -529,7 +531,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.setCurrentStreamFinal(); mediaCodecVideoRenderer.start(); @@ -575,7 +578,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.start(); mediaCodecVideoRenderer.render(/* positionUs= */ 0, msToUs(SystemClock.elapsedRealtime())); ShadowSystemClock.advanceBy(10, TimeUnit.MILLISECONDS); @@ -630,7 +634,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.start(); mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); @@ -670,7 +675,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); for (int i = 0; i < 10; i++) { mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); } @@ -700,7 +706,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); for (int i = 0; i < 10; i++) { mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); } @@ -729,7 +736,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ false, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.start(); for (int i = 0; i < 10; i++) { mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); @@ -762,7 +770,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 2000, - /* offsetUs= */ 1000); + /* offsetUs= */ 1000, + new MediaSource.MediaPeriodId(new Object())); for (int i = 0; i < 10; i++) { mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); } @@ -795,6 +804,8 @@ public class MediaCodecVideoRendererTest { oneByteSample(/* timeUs= */ 1_000_000, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); mediaCodecVideoRenderer.enable( RendererConfiguration.DEFAULT, new Format[] {VIDEO_H264}, @@ -803,7 +814,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); mediaCodecVideoRenderer.start(); boolean replacedStream = false; @@ -816,7 +828,8 @@ public class MediaCodecVideoRendererTest { new Format[] {VIDEO_H264}, fakeSampleStream2, /* startPositionUs= */ 100, - /* offsetUs= */ 50); + /* offsetUs= */ 50, + mediaPeriodId2); replacedStream = true; } } @@ -857,6 +870,8 @@ public class MediaCodecVideoRendererTest { ImmutableList.of( oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM)); fakeSampleStream2.writeData(/* startPositionUs= */ 0); + MediaSource.MediaPeriodId mediaPeriodId1 = new MediaSource.MediaPeriodId(new Object()); + MediaSource.MediaPeriodId mediaPeriodId2 = new MediaSource.MediaPeriodId(new Object()); mediaCodecVideoRenderer.enable( RendererConfiguration.DEFAULT, new Format[] {VIDEO_H264}, @@ -865,7 +880,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + mediaPeriodId1); boolean replacedStream = false; for (int i = 0; i < 10; i++) { @@ -876,7 +892,8 @@ public class MediaCodecVideoRendererTest { new Format[] {VIDEO_H264}, fakeSampleStream2, /* startPositionUs= */ 100, - /* offsetUs= */ 100); + /* offsetUs= */ 100, + mediaPeriodId2); replacedStream = true; } } @@ -912,7 +929,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 1000, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.start(); // Render at the original start position. for (int i = 0; i < 10; i++) { @@ -1267,7 +1285,8 @@ public class MediaCodecVideoRendererTest { /* joining= */ false, /* mayRenderStartOfStream= */ true, /* startPositionUs= */ 0, - /* offsetUs= */ 0); + /* offsetUs= */ 0, + new MediaSource.MediaPeriodId(new Object())); mediaCodecVideoRenderer.start(); mediaCodecVideoRenderer.render(/* positionUs= */ 0, SystemClock.elapsedRealtime() * 1000); diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeVideoRenderer.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeVideoRenderer.java index 99cdeaaa38..2e1ba578fd 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeVideoRenderer.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/FakeVideoRenderer.java @@ -27,6 +27,7 @@ import androidx.media3.common.util.UnstableApi; import androidx.media3.exoplayer.DecoderCounters; import androidx.media3.exoplayer.ExoPlaybackException; import androidx.media3.exoplayer.Renderer; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.video.VideoRendererEventListener; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; @@ -65,9 +66,13 @@ public class FakeVideoRenderer extends FakeRenderer { } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) throws ExoPlaybackException { - super.onStreamChanged(formats, startPositionUs, offsetUs); + super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId); streamOffsetUs = offsetUs; renderedFirstFrameAfterReset = false; } diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java index 920884aa8d..5f42ef4831 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/ExoAssetLoaderBaseRenderer.java @@ -32,6 +32,7 @@ import androidx.media3.exoplayer.BaseRenderer; import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.MediaClock; import androidx.media3.exoplayer.RendererCapabilities; +import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.SampleStream.ReadDataResult; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf; @@ -124,7 +125,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; } @Override - protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) { + protected void onStreamChanged( + Format[] formats, + long startPositionUs, + long offsetUs, + MediaSource.MediaPeriodId mediaPeriodId) { this.streamStartPositionUs = startPositionUs; this.streamOffsetUs = offsetUs; }