Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
SDK
/
exoplayer
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
d02e1df4
authored
Oct 27, 2017
by
Oliver Woodman
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Clean up VideoFrameReleaseTimeHelper
parent
eb54da59
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
88 additions
and
86 deletions
library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java
library/core/src/main/java/com/google/android/exoplayer2/video/VideoFrameReleaseTimeHelper.java
View file @
d02e1df4
...
@@ -18,15 +18,16 @@ package com.google.android.exoplayer2.video;
...
@@ -18,15 +18,16 @@ package com.google.android.exoplayer2.video;
import
android.annotation.TargetApi
;
import
android.annotation.TargetApi
;
import
android.content.Context
;
import
android.content.Context
;
import
android.hardware.display.DisplayManager
;
import
android.hardware.display.DisplayManager
;
import
android.os.Build
;
import
android.os.Handler
;
import
android.os.Handler
;
import
android.os.HandlerThread
;
import
android.os.HandlerThread
;
import
android.os.Message
;
import
android.os.Message
;
import
android.support.annotation.Nullable
;
import
android.view.Choreographer
;
import
android.view.Choreographer
;
import
android.view.Choreographer.FrameCallback
;
import
android.view.Choreographer.FrameCallback
;
import
android.view.Display
;
import
android.view.Display
;
import
android.view.WindowManager
;
import
android.view.WindowManager
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.util.Util
;
/**
/**
* Makes a best effort to adjust frame release timestamps for a smoother visual result.
* Makes a best effort to adjust frame release timestamps for a smoother visual result.
...
@@ -34,20 +35,18 @@ import com.google.android.exoplayer2.C;
...
@@ -34,20 +35,18 @@ import com.google.android.exoplayer2.C;
@TargetApi
(
16
)
@TargetApi
(
16
)
public
final
class
VideoFrameReleaseTimeHelper
{
public
final
class
VideoFrameReleaseTimeHelper
{
private
static
final
double
DISPLAY_REFRESH_RATE_UNKNOWN
=
-
1
;
private
static
final
long
CHOREOGRAPHER_SAMPLE_DELAY_MILLIS
=
500
;
private
static
final
long
CHOREOGRAPHER_SAMPLE_DELAY_MILLIS
=
500
;
private
static
final
long
MAX_ALLOWED_DRIFT_NS
=
20000000
;
private
static
final
long
MAX_ALLOWED_DRIFT_NS
=
20000000
;
private
static
final
long
VSYNC_OFFSET_PERCENTAGE
=
80
;
private
static
final
long
VSYNC_OFFSET_PERCENTAGE
=
80
;
private
static
final
int
MIN_FRAMES_FOR_ADJUSTMENT
=
6
;
private
static
final
int
MIN_FRAMES_FOR_ADJUSTMENT
=
6
;
private
Context
context
=
null
;
private
final
WindowManager
windowManager
;
private
final
DefaultDisplayListener
defaultDisplayListener
;
private
final
VSyncSampler
vsyncSampler
;
private
final
VSyncSampler
vsyncSampler
;
private
final
boolean
useDefaultDisplayVsync
;
private
final
DefaultDisplayListener
displayListener
;
private
long
vsyncDurationNs
=
-
1
;
// Value unused.
private
long
vsyncOffsetNs
=
-
1
;
// Value unused.
private
long
vsyncDurationNs
;
private
long
vsyncOffsetNs
;
private
long
lastFramePresentationTimeUs
;
private
long
lastFramePresentationTimeUs
;
private
long
adjustedLastFrameTimeNs
;
private
long
adjustedLastFrameTimeNs
;
...
@@ -63,10 +62,7 @@ public final class VideoFrameReleaseTimeHelper {
...
@@ -63,10 +62,7 @@ public final class VideoFrameReleaseTimeHelper {
* the default display's vsync signal.
* the default display's vsync signal.
*/
*/
public
VideoFrameReleaseTimeHelper
()
{
public
VideoFrameReleaseTimeHelper
()
{
defaultDisplayListener
=
null
;
this
(
null
);
useDefaultDisplayVsync
=
false
;
vsyncSampler
=
null
;
context
=
null
;
}
}
/**
/**
...
@@ -75,46 +71,48 @@ public final class VideoFrameReleaseTimeHelper {
...
@@ -75,46 +71,48 @@ public final class VideoFrameReleaseTimeHelper {
*
*
* @param context A context from which information about the default display can be retrieved.
* @param context A context from which information about the default display can be retrieved.
*/
*/
public
VideoFrameReleaseTimeHelper
(
Context
context
)
{
public
VideoFrameReleaseTimeHelper
(
@Nullable
Context
context
)
{
this
.
context
=
context
.
getApplicationContext
();
windowManager
=
context
==
null
?
null
defaultDisplayListener
=
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
JELLY_BEAN_MR1
?
:
(
WindowManager
)
context
.
getSystemService
(
Context
.
WINDOW_SERVICE
);
new
DefaultDisplayListener
(
context
)
:
null
;
if
(
windowManager
!=
null
)
{
useDefaultDisplayVsync
=
true
;
displayListener
=
Util
.
SDK_INT
>=
17
?
maybeBuildDefaultDisplayListenerV17
(
context
)
:
null
;
vsyncSampler
=
VSyncSampler
.
getInstance
();
vsyncSampler
=
VSyncSampler
.
getInstance
();
}
else
{
displayListener
=
null
;
vsyncSampler
=
null
;
}
vsyncDurationNs
=
C
.
TIME_UNSET
;
vsyncOffsetNs
=
C
.
TIME_UNSET
;
}
}
/**
/**
* Enables the helper.
* Enables the helper.
Must be called from the playback thread.
*/
*/
public
void
enable
()
{
public
void
enable
()
{
haveSync
=
false
;
haveSync
=
false
;
if
(
useDefaultDisplayVsync
)
{
if
(
windowManager
!=
null
)
{
vsyncSampler
.
addObserver
();
vsyncSampler
.
addObserver
();
setSync
(
getDefaultDisplayRefreshRate
(
context
));
if
(
displayListener
!=
null
)
{
if
(
defaultDisplayListener
!=
null
)
displayListener
.
register
();
defaultDisplayListener
.
register
();
}
updateDefaultDisplayRefreshRateParams
();
}
}
}
}
/**
/**
* Disables the helper.
* Disables the helper.
Must be called from the playback thread.
*/
*/
public
void
disable
()
{
public
void
disable
()
{
if
(
useDefaultDisplayVsync
)
{
if
(
windowManager
!=
null
)
{
if
(
displayListener
!=
null
)
{
displayListener
.
unregister
();
}
vsyncSampler
.
removeObserver
();
vsyncSampler
.
removeObserver
();
if
(
defaultDisplayListener
!=
null
)
defaultDisplayListener
.
unregister
();
}
}
}
}
private
void
setSync
(
double
defaultDisplayRefreshRate
)
{
vsyncDurationNs
=
(
long
)
(
C
.
NANOS_PER_SECOND
/
defaultDisplayRefreshRate
);
vsyncOffsetNs
=
(
vsyncDurationNs
*
VSYNC_OFFSET_PERCENTAGE
)
/
100
;
}
/**
/**
* Adjusts a frame release timestamp.
* Adjusts a frame release timestamp.
Must be called from the playback thread.
*
*
* @param framePresentationTimeUs The frame's presentation time, in microseconds.
* @param framePresentationTimeUs The frame's presentation time, in microseconds.
* @param unadjustedReleaseTimeNs The frame's unadjusted release time, in nanoseconds and in
* @param unadjustedReleaseTimeNs The frame's unadjusted release time, in nanoseconds and in
...
@@ -167,25 +165,39 @@ public final class VideoFrameReleaseTimeHelper {
...
@@ -167,25 +165,39 @@ public final class VideoFrameReleaseTimeHelper {
syncUnadjustedReleaseTimeNs
=
unadjustedReleaseTimeNs
;
syncUnadjustedReleaseTimeNs
=
unadjustedReleaseTimeNs
;
frameCount
=
0
;
frameCount
=
0
;
haveSync
=
true
;
haveSync
=
true
;
onSynced
();
}
}
lastFramePresentationTimeUs
=
framePresentationTimeUs
;
lastFramePresentationTimeUs
=
framePresentationTimeUs
;
pendingAdjustedFrameTimeNs
=
adjustedFrameTimeNs
;
pendingAdjustedFrameTimeNs
=
adjustedFrameTimeNs
;
if
(
vsyncSampler
==
null
||
vsyncSampler
.
sampledVsyncTimeNs
==
0
)
{
if
(
vsyncSampler
==
null
||
vsyncDurationNs
==
C
.
TIME_UNSET
)
{
return
adjustedReleaseTimeNs
;
}
long
sampledVsyncTimeNs
=
vsyncSampler
.
sampledVsyncTimeNs
;
if
(
sampledVsyncTimeNs
==
C
.
TIME_UNSET
)
{
return
adjustedReleaseTimeNs
;
return
adjustedReleaseTimeNs
;
}
}
// Find the timestamp of the closest vsync. This is the vsync that we're targeting.
// Find the timestamp of the closest vsync. This is the vsync that we're targeting.
long
snappedTimeNs
=
closestVsync
(
adjustedReleaseTimeNs
,
long
snappedTimeNs
=
closestVsync
(
adjustedReleaseTimeNs
,
sampledVsyncTimeNs
,
vsyncDurationNs
);
vsyncSampler
.
sampledVsyncTimeNs
,
vsyncDurationNs
);
// Apply an offset so that we release before the target vsync, but after the previous one.
// Apply an offset so that we release before the target vsync, but after the previous one.
return
snappedTimeNs
-
vsyncOffsetNs
;
return
snappedTimeNs
-
vsyncOffsetNs
;
}
}
protected
void
onSynced
()
{
@TargetApi
(
17
)
// Do nothing.
private
DefaultDisplayListener
maybeBuildDefaultDisplayListenerV17
(
Context
context
)
{
DisplayManager
manager
=
(
DisplayManager
)
context
.
getSystemService
(
Context
.
DISPLAY_SERVICE
);
return
manager
==
null
?
null
:
new
DefaultDisplayListener
(
manager
);
}
private
void
updateDefaultDisplayRefreshRateParams
()
{
// Note: If we fail to update the parameters, we leave them set to their previous values.
Display
defaultDisplay
=
windowManager
.
getDefaultDisplay
();
if
(
defaultDisplay
!=
null
)
{
double
defaultDisplayRefreshRate
=
defaultDisplay
.
getRefreshRate
();
vsyncDurationNs
=
(
long
)
(
C
.
NANOS_PER_SECOND
/
defaultDisplayRefreshRate
);
vsyncOffsetNs
=
(
vsyncDurationNs
*
VSYNC_OFFSET_PERCENTAGE
)
/
100
;
}
}
}
private
boolean
isDriftTooLarge
(
long
frameTimeNs
,
long
releaseTimeNs
)
{
private
boolean
isDriftTooLarge
(
long
frameTimeNs
,
long
releaseTimeNs
)
{
...
@@ -211,10 +223,40 @@ public final class VideoFrameReleaseTimeHelper {
...
@@ -211,10 +223,40 @@ public final class VideoFrameReleaseTimeHelper {
return
snappedAfterDiff
<
snappedBeforeDiff
?
snappedAfterNs
:
snappedBeforeNs
;
return
snappedAfterDiff
<
snappedBeforeDiff
?
snappedAfterNs
:
snappedBeforeNs
;
}
}
private
static
double
getDefaultDisplayRefreshRate
(
Context
context
)
{
@TargetApi
(
17
)
WindowManager
manager
=
(
WindowManager
)
context
.
getSystemService
(
Context
.
WINDOW_SERVICE
);
private
final
class
DefaultDisplayListener
implements
DisplayManager
.
DisplayListener
{
return
manager
!=
null
&&
manager
.
getDefaultDisplay
()
!=
null
?
manager
.
getDefaultDisplay
().
getRefreshRate
()
:
DISPLAY_REFRESH_RATE_UNKNOWN
;
private
final
DisplayManager
displayManager
;
public
DefaultDisplayListener
(
DisplayManager
displayManager
)
{
this
.
displayManager
=
displayManager
;
}
public
void
register
()
{
displayManager
.
registerDisplayListener
(
this
,
null
);
}
public
void
unregister
()
{
displayManager
.
unregisterDisplayListener
(
this
);
}
@Override
public
void
onDisplayAdded
(
int
displayId
)
{
// Do nothing.
}
@Override
public
void
onDisplayRemoved
(
int
displayId
)
{
// Do nothing.
}
@Override
public
void
onDisplayChanged
(
int
displayId
)
{
if
(
displayId
==
Display
.
DEFAULT_DISPLAY
)
{
updateDefaultDisplayRefreshRateParams
();
}
}
}
}
/**
/**
...
@@ -242,6 +284,7 @@ public final class VideoFrameReleaseTimeHelper {
...
@@ -242,6 +284,7 @@ public final class VideoFrameReleaseTimeHelper {
}
}
private
VSyncSampler
()
{
private
VSyncSampler
()
{
sampledVsyncTimeNs
=
C
.
TIME_UNSET
;
choreographerOwnerThread
=
new
HandlerThread
(
"ChoreographerOwner:Handler"
);
choreographerOwnerThread
=
new
HandlerThread
(
"ChoreographerOwner:Handler"
);
choreographerOwnerThread
.
start
();
choreographerOwnerThread
.
start
();
handler
=
new
Handler
(
choreographerOwnerThread
.
getLooper
(),
this
);
handler
=
new
Handler
(
choreographerOwnerThread
.
getLooper
(),
this
);
...
@@ -306,48 +349,7 @@ public final class VideoFrameReleaseTimeHelper {
...
@@ -306,48 +349,7 @@ public final class VideoFrameReleaseTimeHelper {
observerCount
--;
observerCount
--;
if
(
observerCount
==
0
)
{
if
(
observerCount
==
0
)
{
choreographer
.
removeFrameCallback
(
this
);
choreographer
.
removeFrameCallback
(
this
);
sampledVsyncTimeNs
=
0
;
sampledVsyncTimeNs
=
C
.
TIME_UNSET
;
}
}
}
@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
public
void
onDisplayAdded
(
int
displayId
)
{
}
@Override
public
void
onDisplayRemoved
(
int
displayId
)
{
}
@Override
public
void
onDisplayChanged
(
int
displayId
)
{
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
);
}
}
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment