From ac3501dd84394bafe9dc14ec2e0a6c04fbfa04a6 Mon Sep 17 00:00:00 2001 From: Drew Hill Date: Thu, 12 Oct 2017 08:39:06 -0400 Subject: [PATCH 1/6] make videoframereleasetimehelper get refresh rate when it's enabled, so we can reuse video renderer for multiple clips with different frame rates --- .../video/MediaCodecVideoRenderer.java | 2 +- .../video/VideoFrameReleaseTimeHelper.java | 36 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 4c1f4c0eb2..f8c3eace24 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -236,7 +236,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { tunnelingAudioSessionId = getConfiguration().tunnelingAudioSessionId; tunneling = tunnelingAudioSessionId != C.AUDIO_SESSION_ID_UNSET; eventDispatcher.enabled(decoderCounters); - frameReleaseTimeHelper.enable(); + frameReleaseTimeHelper.enable(context); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index ad489c2312..96693a1bd2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -38,10 +38,10 @@ public final class VideoFrameReleaseTimeHelper { private static final long VSYNC_OFFSET_PERCENTAGE = 80; private static final int MIN_FRAMES_FOR_ADJUSTMENT = 6; - private final VSyncSampler vsyncSampler; - private final boolean useDefaultDisplayVsync; - private final long vsyncDurationNs; - private final long vsyncOffsetNs; + private VSyncSampler vsyncSampler; + private boolean useDefaultDisplayVsync; + private long vsyncDurationNs; + private long vsyncOffsetNs; private long lastFramePresentationTimeUs; private long adjustedLastFrameTimeNs; @@ -71,24 +71,16 @@ public final class VideoFrameReleaseTimeHelper { } private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate) { - useDefaultDisplayVsync = defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN; - if (useDefaultDisplayVsync) { - vsyncSampler = VSyncSampler.getInstance(); - vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); - vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; - } else { - vsyncSampler = null; - vsyncDurationNs = -1; // Value unused. - vsyncOffsetNs = -1; // Value unused. - } + setSync(defaultDisplayRefreshRate); } /** * Enables the helper. */ - public void enable() { + public void enable(Context context) { haveSync = false; if (useDefaultDisplayVsync) { + setSync(getDefaultDisplayRefreshRate(context)); vsyncSampler.addObserver(); } } @@ -102,6 +94,20 @@ public final class VideoFrameReleaseTimeHelper { } } + private void setSync(double defaultDisplayRefreshRate) { + + useDefaultDisplayVsync = defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN; + if (useDefaultDisplayVsync) { + vsyncSampler = VSyncSampler.getInstance(); + vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); + vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; + } else { + vsyncSampler = null; + vsyncDurationNs = -1; // Value unused. + vsyncOffsetNs = -1; // Value unused. + } + } + /** * Adjusts a frame release timestamp. * From 3a1a032fa81e184c5467ec105838d425a5a7a82e Mon Sep 17 00:00:00 2001 From: Drew Hill Date: Thu, 12 Oct 2017 14:52:14 -0400 Subject: [PATCH 2/6] change to use displaymanager listener for refresh rate updating --- .../video/MediaCodecVideoRenderer.java | 2 +- .../video/VideoFrameReleaseTimeHelper.java | 71 +++++++++++++++++-- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index f8c3eace24..4c1f4c0eb2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -236,7 +236,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { tunnelingAudioSessionId = getConfiguration().tunnelingAudioSessionId; tunneling = tunnelingAudioSessionId != C.AUDIO_SESSION_ID_UNSET; eventDispatcher.enabled(decoderCounters); - frameReleaseTimeHelper.enable(context); + frameReleaseTimeHelper.enable(); } @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index 96693a1bd2..af06432261 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -17,6 +17,8 @@ package com.google.android.exoplayer2.video; import android.annotation.TargetApi; import android.content.Context; +import android.hardware.display.DisplayManager; +import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -31,6 +33,7 @@ import com.google.android.exoplayer2.C; @TargetApi(16) public final class VideoFrameReleaseTimeHelper { + private static final int DISPLAY_ID_UNKNOWN = -1; private static final double DISPLAY_REFRESH_RATE_UNKNOWN = -1; private static final long CHOREOGRAPHER_SAMPLE_DELAY_MILLIS = 500; private static final long MAX_ALLOWED_DRIFT_NS = 20000000; @@ -38,6 +41,9 @@ public final class VideoFrameReleaseTimeHelper { private static final long VSYNC_OFFSET_PERCENTAGE = 80; private static final int MIN_FRAMES_FOR_ADJUSTMENT = 6; + private DisplayManager.DisplayListener displayListener = null; + private Context context = null; + private VSyncSampler vsyncSampler; private boolean useDefaultDisplayVsync; private long vsyncDurationNs; @@ -68,6 +74,8 @@ public final class VideoFrameReleaseTimeHelper { */ public VideoFrameReleaseTimeHelper(Context context) { this(getDefaultDisplayRefreshRate(context)); + this.context = context; + registerDisplayListener(); } private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate) { @@ -77,12 +85,12 @@ public final class VideoFrameReleaseTimeHelper { /** * Enables the helper. */ - public void enable(Context context) { + public void enable() { haveSync = false; if (useDefaultDisplayVsync) { - setSync(getDefaultDisplayRefreshRate(context)); vsyncSampler.addObserver(); } + registerDisplayListener(); } /** @@ -92,6 +100,29 @@ public final class VideoFrameReleaseTimeHelper { if (useDefaultDisplayVsync) { vsyncSampler.removeObserver(); } + unregisterDisplayListener(); + } + + private void registerDisplayListener() { + if (displayListener == null && context != null && + Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + DisplayManager displayManager = context.getSystemService(DisplayManager.class); + if (displayManager != null) { + displayListener = new DefaultDisplayListener(context); + displayManager.registerDisplayListener(displayListener, null); + } + } + } + + private void unregisterDisplayListener() { + if (context != null && displayListener != null && + Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + DisplayManager displayManager = context.getSystemService(DisplayManager.class); + if (displayManager != null) { + displayManager.unregisterDisplayListener(displayListener); + displayListener = null; + } + } } private void setSync(double defaultDisplayRefreshRate) { @@ -206,10 +237,16 @@ public final class VideoFrameReleaseTimeHelper { return snappedAfterDiff < snappedBeforeDiff ? snappedAfterNs : snappedBeforeNs; } + private static int getDefaultDisplayId(Context context) { + WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + return manager != null && manager.getDefaultDisplay() != null ? + manager.getDefaultDisplay().getDisplayId() : DISPLAY_ID_UNKNOWN; + } + private static double getDefaultDisplayRefreshRate(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - return manager.getDefaultDisplay() != null ? manager.getDefaultDisplay().getRefreshRate() - : DISPLAY_REFRESH_RATE_UNKNOWN; + return manager != null && manager.getDefaultDisplay() != null ? + manager.getDefaultDisplay().getRefreshRate() : DISPLAY_REFRESH_RATE_UNKNOWN; } /** @@ -307,4 +344,30 @@ public final class VideoFrameReleaseTimeHelper { } + @TargetApi(17) + private class DefaultDisplayListener implements DisplayManager.DisplayListener { + + private final Context context; + DefaultDisplayListener(Context context) { + this.context = context; + } + + @Override + public void onDisplayAdded(int displayId) { + } + + @Override + public void onDisplayRemoved(int displayId) { + } + + @Override + public void onDisplayChanged(int displayId) { + final int defaultDisplayId = getDefaultDisplayId(context); + if (displayId == defaultDisplayId || defaultDisplayId == DISPLAY_ID_UNKNOWN) { + setSync(getDefaultDisplayRefreshRate(context)); + } + } + + } + } From feff4d3e0272a9c3594fbb3144ed4453202192ac Mon Sep 17 00:00:00 2001 From: Drew Hill Date: Thu, 19 Oct 2017 12:49:09 -0400 Subject: [PATCH 3/6] fix missing cause of display refresh rate changing between videoframereleasetimehelper constructor and enable being called --- .../exoplayer2/video/VideoFrameReleaseTimeHelper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index af06432261..596e1046d1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -74,7 +74,7 @@ public final class VideoFrameReleaseTimeHelper { */ public VideoFrameReleaseTimeHelper(Context context) { this(getDefaultDisplayRefreshRate(context)); - this.context = context; + this.context = context.getApplicationContext(); registerDisplayListener(); } @@ -89,8 +89,9 @@ public final class VideoFrameReleaseTimeHelper { haveSync = false; if (useDefaultDisplayVsync) { vsyncSampler.addObserver(); + setSync(getDefaultDisplayRefreshRate(context)); + registerDisplayListener(); } - registerDisplayListener(); } /** From 84afad0748125142b3612c5fcd24e31b8d59f2a0 Mon Sep 17 00:00:00 2001 From: Drew Hill Date: Thu, 19 Oct 2017 16:24:07 -0400 Subject: [PATCH 4/6] adjustments --- .../video/VideoFrameReleaseTimeHelper.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index 596e1046d1..408cd1a09a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -44,10 +44,10 @@ public final class VideoFrameReleaseTimeHelper { private DisplayManager.DisplayListener displayListener = null; private Context context = null; - private VSyncSampler vsyncSampler; - private boolean useDefaultDisplayVsync; - private long vsyncDurationNs; - private long vsyncOffsetNs; + private VSyncSampler vsyncSampler = null; + private final boolean useDefaultDisplayVsync; + private long vsyncDurationNs = -1; // Value unused. + private long vsyncOffsetNs = -1; // Value unused. private long lastFramePresentationTimeUs; private long adjustedLastFrameTimeNs; @@ -75,11 +75,10 @@ public final class VideoFrameReleaseTimeHelper { public VideoFrameReleaseTimeHelper(Context context) { this(getDefaultDisplayRefreshRate(context)); this.context = context.getApplicationContext(); - registerDisplayListener(); } private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate) { - setSync(defaultDisplayRefreshRate); + useDefaultDisplayVsync = defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN; } /** @@ -100,8 +99,8 @@ public final class VideoFrameReleaseTimeHelper { public void disable() { if (useDefaultDisplayVsync) { vsyncSampler.removeObserver(); + unregisterDisplayListener(); } - unregisterDisplayListener(); } private void registerDisplayListener() { @@ -128,15 +127,10 @@ public final class VideoFrameReleaseTimeHelper { private void setSync(double defaultDisplayRefreshRate) { - useDefaultDisplayVsync = defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN; if (useDefaultDisplayVsync) { vsyncSampler = VSyncSampler.getInstance(); vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; - } else { - vsyncSampler = null; - vsyncDurationNs = -1; // Value unused. - vsyncOffsetNs = -1; // Value unused. } } From 3830307cd3c012ed4e6e5a764793b640ead00e2b Mon Sep 17 00:00:00 2001 From: Drew Hill Date: Thu, 19 Oct 2017 20:28:17 -0400 Subject: [PATCH 5/6] fix not initialized error --- .../android/exoplayer2/video/VideoFrameReleaseTimeHelper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index 408cd1a09a..b3ce65daa4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -79,6 +79,9 @@ public final class VideoFrameReleaseTimeHelper { private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate) { useDefaultDisplayVsync = defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN; + if (useDefaultDisplayVsync) { + vsyncSampler = VSyncSampler.getInstance(); + } } /** @@ -128,7 +131,6 @@ public final class VideoFrameReleaseTimeHelper { private void setSync(double defaultDisplayRefreshRate) { if (useDefaultDisplayVsync) { - vsyncSampler = VSyncSampler.getInstance(); vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; } From 208166759124075727fa5fc319b860f1be4561cd Mon Sep 17 00:00:00 2001 From: Drew Hill Date: Tue, 24 Oct 2017 11:19:26 -0400 Subject: [PATCH 6/6] cleanups for videoframereleasetimehelper --- .../video/VideoFrameReleaseTimeHelper.java | 84 ++++++++----------- 1 file changed, 35 insertions(+), 49 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java index b3ce65daa4..c5ca212a36 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java @@ -24,6 +24,7 @@ import android.os.HandlerThread; import android.os.Message; import android.view.Choreographer; import android.view.Choreographer.FrameCallback; +import android.view.Display; import android.view.WindowManager; import com.google.android.exoplayer2.C; @@ -33,7 +34,6 @@ import com.google.android.exoplayer2.C; @TargetApi(16) public final class VideoFrameReleaseTimeHelper { - private static final int DISPLAY_ID_UNKNOWN = -1; private static final double DISPLAY_REFRESH_RATE_UNKNOWN = -1; private static final long CHOREOGRAPHER_SAMPLE_DELAY_MILLIS = 500; private static final long MAX_ALLOWED_DRIFT_NS = 20000000; @@ -41,10 +41,10 @@ public final class VideoFrameReleaseTimeHelper { private static final long VSYNC_OFFSET_PERCENTAGE = 80; private static final int MIN_FRAMES_FOR_ADJUSTMENT = 6; - private DisplayManager.DisplayListener displayListener = null; private Context context = null; - private VSyncSampler vsyncSampler = null; + private final DefaultDisplayListener defaultDisplayListener; + private final VSyncSampler vsyncSampler; private final boolean useDefaultDisplayVsync; private long vsyncDurationNs = -1; // Value unused. private long vsyncOffsetNs = -1; // Value unused. @@ -63,7 +63,10 @@ public final class VideoFrameReleaseTimeHelper { * the default display's vsync signal. */ public VideoFrameReleaseTimeHelper() { - this(DISPLAY_REFRESH_RATE_UNKNOWN); + defaultDisplayListener = null; + useDefaultDisplayVsync = false; + vsyncSampler = null; + context = null; } /** @@ -73,16 +76,13 @@ public final class VideoFrameReleaseTimeHelper { * @param context A context from which information about the default display can be retrieved. */ public VideoFrameReleaseTimeHelper(Context context) { - this(getDefaultDisplayRefreshRate(context)); this.context = context.getApplicationContext(); + defaultDisplayListener = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 ? + new DefaultDisplayListener(context) : null; + useDefaultDisplayVsync = true; + vsyncSampler = VSyncSampler.getInstance(); } - private VideoFrameReleaseTimeHelper(double defaultDisplayRefreshRate) { - useDefaultDisplayVsync = defaultDisplayRefreshRate != DISPLAY_REFRESH_RATE_UNKNOWN; - if (useDefaultDisplayVsync) { - vsyncSampler = VSyncSampler.getInstance(); - } - } /** * Enables the helper. @@ -92,7 +92,8 @@ public final class VideoFrameReleaseTimeHelper { if (useDefaultDisplayVsync) { vsyncSampler.addObserver(); setSync(getDefaultDisplayRefreshRate(context)); - registerDisplayListener(); + if (defaultDisplayListener != null) + defaultDisplayListener.register(); } } @@ -102,38 +103,14 @@ public final class VideoFrameReleaseTimeHelper { public void disable() { if (useDefaultDisplayVsync) { vsyncSampler.removeObserver(); - unregisterDisplayListener(); - } - } - - private void registerDisplayListener() { - if (displayListener == null && context != null && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - DisplayManager displayManager = context.getSystemService(DisplayManager.class); - if (displayManager != null) { - displayListener = new DefaultDisplayListener(context); - displayManager.registerDisplayListener(displayListener, null); - } - } - } - - private void unregisterDisplayListener() { - if (context != null && displayListener != null && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - DisplayManager displayManager = context.getSystemService(DisplayManager.class); - if (displayManager != null) { - displayManager.unregisterDisplayListener(displayListener); - displayListener = null; - } + if (defaultDisplayListener != null) + defaultDisplayListener.unregister(); } } private void setSync(double defaultDisplayRefreshRate) { - - if (useDefaultDisplayVsync) { - vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); - vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; - } + vsyncDurationNs = (long) (C.NANOS_PER_SECOND / defaultDisplayRefreshRate); + vsyncOffsetNs = (vsyncDurationNs * VSYNC_OFFSET_PERCENTAGE) / 100; } /** @@ -234,12 +211,6 @@ public final class VideoFrameReleaseTimeHelper { return snappedAfterDiff < snappedBeforeDiff ? snappedAfterNs : snappedBeforeNs; } - private static int getDefaultDisplayId(Context context) { - WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - return manager != null && manager.getDefaultDisplay() != null ? - manager.getDefaultDisplay().getDisplayId() : DISPLAY_ID_UNKNOWN; - } - private static double getDefaultDisplayRefreshRate(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); return manager != null && manager.getDefaultDisplay() != null ? @@ -341,12 +312,16 @@ public final class VideoFrameReleaseTimeHelper { } - @TargetApi(17) + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private class DefaultDisplayListener implements DisplayManager.DisplayListener { private final Context context; + private final DisplayManager displayManager; + DefaultDisplayListener(Context context) { this.context = context; + displayManager = context != null ? + (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE) : null; } @Override @@ -359,12 +334,23 @@ public final class VideoFrameReleaseTimeHelper { @Override public void onDisplayChanged(int displayId) { - final int defaultDisplayId = getDefaultDisplayId(context); - if (displayId == defaultDisplayId || defaultDisplayId == DISPLAY_ID_UNKNOWN) { + if (displayId == Display.DEFAULT_DISPLAY) { setSync(getDefaultDisplayRefreshRate(context)); } } + public void register() { + if (displayManager != null && context != null) { // context is used on callback + displayManager.registerDisplayListener(this, null); + } + } + + public void unregister() { + if (displayManager != null) { + displayManager.unregisterDisplayListener(this); + } + } + } }