From 3f17f5d44198fc66d24758131e3f9fa4aac5de6e Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 1 Mar 2021 18:53:21 +0000 Subject: [PATCH] 1) Adds new csi ticks: exp (ExoPlayer prepare) ffr (First Frame Rendered) psr (Player State Ready). 2) Modifies aci/acc vci/vcc to report timing from ExoPlayer Playback thread. 3) Fix to report pvri and pari for every playback. and other minor bug fixes. PiperOrigin-RevId: 360228206 --- .../android/exoplayer2/SimpleExoPlayer.java | 4 +-- .../analytics/AnalyticsCollector.java | 12 +++++++-- .../analytics/AnalyticsListener.java | 27 +++++++++++++++++++ .../video/VideoRendererEventListener.java | 15 +++++++++-- .../analytics/AnalyticsCollectorTest.java | 19 ++++++++----- 5 files changed, 65 insertions(+), 12 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index cea132c296..320f4825ba 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -2020,8 +2020,8 @@ public class SimpleExoPlayer extends BasePlayer } @Override - public void onRenderedFirstFrame(@Nullable Surface surface) { - analyticsCollector.onRenderedFirstFrame(surface); + public void onRenderedFirstFrame(@Nullable Surface surface, long renderTimeMs) { + analyticsCollector.onRenderedFirstFrame(surface, renderTimeMs); if (SimpleExoPlayer.this.surface == surface) { for (VideoListener videoListener : videoListeners) { videoListener.onRenderedFirstFrame(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index 2690214567..92f4ff78ff 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -231,6 +231,8 @@ public class AnalyticsCollector AnalyticsListener.EVENT_AUDIO_DECODER_INITIALIZED, listener -> { listener.onAudioDecoderInitialized(eventTime, decoderName, initializationDurationMs); + listener.onAudioDecoderInitialized( + eventTime, decoderName, initializedTimestampMs, initializationDurationMs); listener.onDecoderInitialized( eventTime, C.TRACK_TYPE_AUDIO, decoderName, initializationDurationMs); }); @@ -386,6 +388,8 @@ public class AnalyticsCollector AnalyticsListener.EVENT_VIDEO_DECODER_INITIALIZED, listener -> { listener.onVideoDecoderInitialized(eventTime, decoderName, initializationDurationMs); + listener.onVideoDecoderInitialized( + eventTime, decoderName, initializedTimestampMs, initializationDurationMs); listener.onDecoderInitialized( eventTime, C.TRACK_TYPE_VIDEO, decoderName, initializationDurationMs); }); @@ -449,13 +453,17 @@ public class AnalyticsCollector eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio)); } + @SuppressWarnings("deprecation") // Calling deprecated listener method. @Override - public final void onRenderedFirstFrame(@Nullable Surface surface) { + public final void onRenderedFirstFrame(@Nullable Surface surface, long renderTimeMs) { EventTime eventTime = generateReadingMediaPeriodEventTime(); sendEvent( eventTime, AnalyticsListener.EVENT_RENDERED_FIRST_FRAME, - listener -> listener.onRenderedFirstFrame(eventTime, surface)); + listener -> { + listener.onRenderedFirstFrame(eventTime, surface); + listener.onRenderedFirstFrame(eventTime, surface, renderTimeMs); + }); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java index 62cce20a3b..d9978ed6a4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java @@ -20,6 +20,7 @@ import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import android.media.MediaCodec; import android.media.MediaCodec.CodecException; import android.os.Looper; +import android.os.SystemClock; import android.util.SparseArray; import android.view.Surface; import androidx.annotation.IntDef; @@ -753,8 +754,18 @@ public interface AnalyticsListener { * * @param eventTime The event time. * @param decoderName The decoder that was created. + * @param initializedTimestampMs {@link SystemClock#elapsedRealtime()} when initialization + * finished. * @param initializationDurationMs The time taken to initialize the decoder in milliseconds. */ + default void onAudioDecoderInitialized( + EventTime eventTime, + String decoderName, + long initializedTimestampMs, + long initializationDurationMs) {} + + /** @deprecated Use {@link #onAudioDecoderInitialized(EventTime, String, long, long)}. */ + @Deprecated default void onAudioDecoderInitialized( EventTime eventTime, String decoderName, long initializationDurationMs) {} @@ -895,8 +906,18 @@ public interface AnalyticsListener { * * @param eventTime The event time. * @param decoderName The decoder that was created. + * @param initializedTimestampMs {@link SystemClock#elapsedRealtime()} when initialization + * finished. * @param initializationDurationMs The time taken to initialize the decoder in milliseconds. */ + default void onVideoDecoderInitialized( + EventTime eventTime, + String decoderName, + long initializedTimestampMs, + long initializationDurationMs) {} + + /** @deprecated Use {@link #onVideoDecoderInitialized(EventTime, String, long, long)}. */ + @Deprecated default void onVideoDecoderInitialized( EventTime eventTime, String decoderName, long initializationDurationMs) {} @@ -988,7 +1009,13 @@ public interface AnalyticsListener { * @param eventTime The event time. * @param surface The {@link Surface} to which a frame has been rendered, or {@code null} if the * renderer renders to something that isn't a {@link Surface}. + * @param renderTimeMs {@link SystemClock#elapsedRealtime()} when the first frame was rendered. */ + default void onRenderedFirstFrame( + EventTime eventTime, @Nullable Surface surface, long renderTimeMs) {} + + /** @deprecated Use {@link #onRenderedFirstFrame(EventTime, Surface, long)} instead. */ + @Deprecated default void onRenderedFirstFrame(EventTime eventTime, @Nullable Surface surface) {} /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java index 1d7fbf1133..78b1a72867 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java @@ -130,7 +130,12 @@ public interface VideoRendererEventListener { * * @param surface The {@link Surface} to which a first frame has been rendered, or {@code null} if * the renderer renders to something that isn't a {@link Surface}. + * @param renderTimeMs The {@link SystemClock#elapsedRealtime()} when the frame was rendered. */ + default void onRenderedFirstFrame(@Nullable Surface surface, long renderTimeMs) {} + + /** @deprecated Use {@link #onRenderedFirstFrame(Surface, long)}. */ + @Deprecated default void onRenderedFirstFrame(@Nullable Surface surface) {} /** @@ -246,10 +251,16 @@ public interface VideoRendererEventListener { } } - /** Invokes {@link VideoRendererEventListener#onRenderedFirstFrame(Surface)}. */ + /** Invokes {@link VideoRendererEventListener#onRenderedFirstFrame(Surface, long)}. */ public void renderedFirstFrame(@Nullable Surface surface) { if (handler != null) { - handler.post(() -> castNonNull(listener).onRenderedFirstFrame(surface)); + // TODO: Replace this timestamp with the actual frame release time. + long renderTimeMs = SystemClock.elapsedRealtime(); + handler.post( + () -> { + castNonNull(listener).onRenderedFirstFrame(surface); + castNonNull(listener).onRenderedFirstFrame(surface, renderTimeMs); + }); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java index ad813e891f..3a753d6e2b 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java @@ -1701,12 +1701,12 @@ public final class AnalyticsCollectorTest { ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); verify(listener, atLeastOnce()) .onVideoDecoderInitialized( - individualVideoDecoderInitializedEventTimes.capture(), any(), anyLong()); + individualVideoDecoderInitializedEventTimes.capture(), any(), anyLong(), anyLong()); ArgumentCaptor individualAudioDecoderInitializedEventTimes = ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); verify(listener, atLeastOnce()) .onAudioDecoderInitialized( - individualAudioDecoderInitializedEventTimes.capture(), any(), anyLong()); + individualAudioDecoderInitializedEventTimes.capture(), any(), anyLong(), anyLong()); ArgumentCaptor individualVideoDisabledEventTimes = ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); verify(listener, atLeastOnce()) @@ -1718,7 +1718,7 @@ public final class AnalyticsCollectorTest { ArgumentCaptor individualRenderedFirstFrameEventTimes = ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); verify(listener, atLeastOnce()) - .onRenderedFirstFrame(individualRenderedFirstFrameEventTimes.capture(), any()); + .onRenderedFirstFrame(individualRenderedFirstFrameEventTimes.capture(), any(), anyLong()); ArgumentCaptor individualVideoSizeChangedEventTimes = ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); verify(listener, atLeastOnce()) @@ -2184,7 +2184,10 @@ public final class AnalyticsCollectorTest { @Override public void onAudioDecoderInitialized( - EventTime eventTime, String decoderName, long initializationDurationMs) { + EventTime eventTime, + String decoderName, + long initializedTimestampMs, + long initializationDurationMs) { reportedEvents.add(new ReportedEvent(EVENT_AUDIO_DECODER_INITIALIZED, eventTime)); } @@ -2221,7 +2224,10 @@ public final class AnalyticsCollectorTest { @Override public void onVideoDecoderInitialized( - EventTime eventTime, String decoderName, long initializationDurationMs) { + EventTime eventTime, + String decoderName, + long initializedTimestampMs, + long initializationDurationMs) { reportedEvents.add(new ReportedEvent(EVENT_VIDEO_DECODER_INITIALIZED, eventTime)); } @@ -2247,7 +2253,8 @@ public final class AnalyticsCollectorTest { } @Override - public void onRenderedFirstFrame(EventTime eventTime, @Nullable Surface surface) { + public void onRenderedFirstFrame( + EventTime eventTime, @Nullable Surface surface, long renderTimeMs) { reportedEvents.add(new ReportedEvent(EVENT_RENDERED_FIRST_FRAME, eventTime)); }