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 b11e946e90..12eb1004e7 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/BaseRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/BaseRenderer.java @@ -24,6 +24,7 @@ import androidx.media3.common.C; import androidx.media3.common.Format; import androidx.media3.common.PlaybackException; import androidx.media3.common.util.Assertions; +import androidx.media3.common.util.Clock; import androidx.media3.common.util.UnstableApi; import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.decoder.DecoderInputBuffer.InsufficientCapacityException; @@ -45,6 +46,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { @Nullable private RendererConfiguration configuration; private int index; private @MonotonicNonNull PlayerId playerId; + private @MonotonicNonNull Clock clock; private int state; @Nullable private SampleStream stream; @Nullable private Format[] streamFormats; @@ -80,9 +82,10 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { } @Override - public final void init(int index, PlayerId playerId) { + public final void init(int index, PlayerId playerId, Clock clock) { this.index = index; this.playerId = playerId; + this.clock = clock; } @Override @@ -393,6 +396,15 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { return checkNotNull(playerId); } + /** + * Returns the {@link Clock}. + * + *
Must only be used after the renderer has been initialized by the player.
+ */
+ protected final Clock getClock() {
+ return checkNotNull(clock);
+ }
+
/**
* 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 305f91dfca..f3035b0683 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/ExoPlayerImplInternal.java
@@ -17,6 +17,7 @@ package androidx.media3.exoplayer;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.castNonNull;
+import static androidx.media3.common.util.Util.msToUs;
import static java.lang.Math.max;
import static java.lang.Math.min;
@@ -25,7 +26,6 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
-import android.os.SystemClock;
import android.util.Pair;
import androidx.annotation.CheckResult;
import androidx.annotation.Nullable;
@@ -277,7 +277,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
RendererCapabilities.Listener rendererCapabilitiesListener =
trackSelector.getRendererCapabilitiesListener();
for (int i = 0; i < renderers.length; i++) {
- renderers[i].init(/* index= */ i, playerId);
+ renderers[i].init(/* index= */ i, playerId, clock);
rendererCapabilities[i] = renderers[i].getCapabilities();
if (rendererCapabilitiesListener != null) {
rendererCapabilities[i].setListener(rendererCapabilitiesListener);
@@ -1056,7 +1056,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
boolean renderersEnded = true;
boolean renderersAllowPlayback = true;
if (playingPeriodHolder.prepared) {
- long rendererPositionElapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
+ long rendererPositionElapsedRealtimeUs = msToUs(clock.elapsedRealtime());
playingPeriodHolder.mediaPeriod.discardBuffer(
playbackInfo.positionUs - backBufferDurationUs, retainBackBufferFromKeyframe);
for (int i = 0; i < renderers.length; i++) {
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 c9cf750d62..3b33e06a2e 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/NoSampleRenderer.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/NoSampleRenderer.java
@@ -19,6 +19,7 @@ import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Format;
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.SampleStream;
@@ -49,7 +50,7 @@ public abstract class NoSampleRenderer implements Renderer, RendererCapabilities
}
@Override
- public final void init(int index, PlayerId playerId) {
+ public final void init(int index, PlayerId playerId, Clock clock) {
this.index = index;
}
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 e5de1f2eaf..ff994b1f8a 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/Renderer.java
@@ -27,6 +27,7 @@ import androidx.media3.common.C;
import androidx.media3.common.Effect;
import androidx.media3.common.Format;
import androidx.media3.common.Player;
+import androidx.media3.common.util.Clock;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util;
@@ -305,8 +306,9 @@ public interface Renderer extends PlayerMessage.Target {
*
* @param index The renderer index within the player.
* @param playerId The {@link PlayerId} of the player.
+ * @param clock The {@link Clock}.
*/
- void init(int index, PlayerId playerId);
+ void init(int index, PlayerId playerId, Clock clock);
/**
* If the renderer advances its own playback position then this method returns a corresponding
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 b02b6fd3c8..91a90f4502 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
@@ -573,7 +573,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
throws DecoderException {
if (frameMetadataListener != null) {
frameMetadataListener.onVideoFrameAboutToBeRendered(
- presentationTimeUs, System.nanoTime(), outputFormat, /* mediaFormat= */ null);
+ presentationTimeUs, getClock().nanoTime(), outputFormat, /* mediaFormat= */ null);
}
lastRenderTimeUs = Util.msToUs(SystemClock.elapsedRealtime() * 1000);
int bufferMode = outputBuffer.mode;
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
index 8aae18bbad..5900dc5067 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
@@ -19,6 +19,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
+import static androidx.media3.common.util.Util.msToUs;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_VIDEO_MAX_RESOLUTION_EXCEEDED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.REUSE_RESULT_NO;
@@ -59,6 +60,7 @@ import androidx.media3.common.SurfaceInfo;
import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.VideoSize;
+import androidx.media3.common.util.Clock;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.MediaFormatUtil;
import androidx.media3.common.util.Size;
@@ -644,7 +646,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
} else if (joiningDeadlineMs == C.TIME_UNSET) {
// Not joining.
return false;
- } else if (SystemClock.elapsedRealtime() < joiningDeadlineMs) {
+ } else if (getClock().elapsedRealtime() < joiningDeadlineMs) {
// Joining and still within the joining deadline.
return true;
} else {
@@ -658,8 +660,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
protected void onStarted() {
super.onStarted();
droppedFrames = 0;
- droppedFrameAccumulationStartTimeMs = SystemClock.elapsedRealtime();
- lastRenderRealtimeUs = SystemClock.elapsedRealtime() * 1000;
+ long elapsedRealtimeMs = getClock().elapsedRealtime();
+ droppedFrameAccumulationStartTimeMs = elapsedRealtimeMs;
+ lastRenderRealtimeUs = msToUs(elapsedRealtimeMs);
totalVideoFrameProcessingOffsetUs = 0;
videoFrameProcessingOffsetCount = 0;
frameReleaseHelper.onStarted();
@@ -1009,7 +1012,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@Override
protected void onReadyToInitializeCodec(Format format) throws ExoPlaybackException {
if (!videoFrameProcessorManager.isEnabled()) {
- videoFrameProcessorManager.maybeEnable(format, getOutputStreamOffsetUs());
+ videoFrameProcessorManager.maybeEnable(format, getOutputStreamOffsetUs(), getClock());
}
}
@@ -1202,7 +1205,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// Note: Use of double rather than float is intentional for accuracy in the calculations below.
boolean isStarted = getState() == STATE_STARTED;
- long elapsedRealtimeNowUs = SystemClock.elapsedRealtime() * 1000;
+ long elapsedRealtimeNowUs = msToUs(getClock().elapsedRealtime());
long earlyUs =
calculateEarlyTimeUs(
positionUs,
@@ -1244,7 +1247,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
// Compute the buffer's desired release time in nanoseconds.
- long systemTimeNs = System.nanoTime();
+ long systemTimeNs = getClock().nanoTime();
long unadjustedFrameReleaseTimeNs = systemTimeNs + (earlyUs * 1000);
// Apply a timestamp adjustment, if there is one.
@@ -1330,7 +1333,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
!renderedFirstFrameAfterEnable
? (isStarted || mayRenderFirstFrameAfterEnableIfNotStarted)
: !renderedFirstFrameAfterReset;
- long elapsedSinceLastRenderUs = SystemClock.elapsedRealtime() * 1000 - lastRenderRealtimeUs;
+ long elapsedSinceLastRenderUs = msToUs(getClock().elapsedRealtime()) - lastRenderRealtimeUs;
// Don't force output until we joined and the position reached the current stream.
return joiningDeadlineMs == C.TIME_UNSET
&& positionUs >= getOutputStreamOffsetUs()
@@ -1597,7 +1600,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
? videoFrameProcessorManager.getCorrectedFramePresentationTimeUs(
presentationTimeUs, getOutputStreamOffsetUs())
* 1000
- : System.nanoTime();
+ : getClock().nanoTime();
if (notifyFrameMetadataListener) {
notifyFrameMetadataListener(presentationTimeUs, releaseTimeNs, format);
}
@@ -1627,7 +1630,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
if (!videoFrameProcessorManager.isEnabled()) {
- lastRenderRealtimeUs = SystemClock.elapsedRealtime() * 1000;
+ lastRenderRealtimeUs = msToUs(getClock().elapsedRealtime());
maybeNotifyVideoSizeChanged(decodedVideoSize);
maybeNotifyRenderedFirstFrame();
}
@@ -1655,7 +1658,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
if (!videoFrameProcessorManager.isEnabled()) {
- lastRenderRealtimeUs = SystemClock.elapsedRealtime() * 1000;
+ lastRenderRealtimeUs = msToUs(getClock().elapsedRealtime());
maybeNotifyVideoSizeChanged(decodedVideoSize);
maybeNotifyRenderedFirstFrame();
}
@@ -1680,7 +1683,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private void setJoiningDeadlineMs() {
joiningDeadlineMs =
allowedJoiningTimeMs > 0
- ? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs)
+ ? (getClock().elapsedRealtime() + allowedJoiningTimeMs)
: C.TIME_UNSET;
}
@@ -1734,7 +1737,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private void maybeNotifyDroppedFrames() {
if (droppedFrames > 0) {
- long now = SystemClock.elapsedRealtime();
+ long now = getClock().elapsedRealtime();
long elapsedMs = now - droppedFrameAccumulationStartTimeMs;
eventDispatcher.droppedFrames(droppedFrames, elapsedMs);
droppedFrames = 0;
@@ -1936,6 +1939,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
*/
private @MonotonicNonNull Pair