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
862a6e4d
authored
May 04, 2020
by
olly
Committed by
Oliver Woodman
May 05, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Pass appropriate frame-rate to Surface.setFrameRate
PiperOrigin-RevId: 309746009
parent
c926acb3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
92 additions
and
6 deletions
RELEASENOTES.md
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
RELEASENOTES.md
View file @
862a6e4d
...
@@ -83,6 +83,7 @@
...
@@ -83,6 +83,7 @@
(
[
#7247
](
https://github.com/google/ExoPlayer/pull/7247
)
).
(
[
#7247
](
https://github.com/google/ExoPlayer/pull/7247
)
).
*
Replace
`CacheDataSinkFactory`
and
`CacheDataSourceFactory`
with
*
Replace
`CacheDataSinkFactory`
and
`CacheDataSourceFactory`
with
`CacheDataSink.Factory`
and
`CacheDataSource.Factory`
respectively.
`CacheDataSink.Factory`
and
`CacheDataSource.Factory`
respectively.
*
Video: Pass frame rate hint to
`Surface.setFrameRate`
on Android R devices.
*
Text:
*
Text:
*
Parse
`<ruby>`
and
`<rt>`
tags in WebVTT subtitles (rendering is coming
*
Parse
`<ruby>`
and
`<rt>`
tags in WebVTT subtitles (rendering is coming
later).
later).
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
View file @
862a6e4d
...
@@ -374,7 +374,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -374,7 +374,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Nullable
private
MediaCrypto
mediaCrypto
;
@Nullable
private
MediaCrypto
mediaCrypto
;
private
boolean
mediaCryptoRequiresSecureDecoder
;
private
boolean
mediaCryptoRequiresSecureDecoder
;
private
long
renderTimeLimitMs
;
private
long
renderTimeLimitMs
;
private
float
rendererO
peratingRate
;
private
float
o
peratingRate
;
@Nullable
private
MediaCodec
codec
;
@Nullable
private
MediaCodec
codec
;
@Nullable
private
MediaCodecAdapter
codecAdapter
;
@Nullable
private
MediaCodecAdapter
codecAdapter
;
@Nullable
private
Format
codecFormat
;
@Nullable
private
Format
codecFormat
;
...
@@ -447,7 +447,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -447,7 +447,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
formatQueue
=
new
TimedValueQueue
<>();
formatQueue
=
new
TimedValueQueue
<>();
decodeOnlyPresentationTimestamps
=
new
ArrayList
<>();
decodeOnlyPresentationTimestamps
=
new
ArrayList
<>();
outputBufferInfo
=
new
MediaCodec
.
BufferInfo
();
outputBufferInfo
=
new
MediaCodec
.
BufferInfo
();
rendererO
peratingRate
=
1
f
;
o
peratingRate
=
1
f
;
renderTimeLimitMs
=
C
.
TIME_UNSET
;
renderTimeLimitMs
=
C
.
TIME_UNSET
;
mediaCodecOperationMode
=
OPERATION_MODE_SYNCHRONOUS
;
mediaCodecOperationMode
=
OPERATION_MODE_SYNCHRONOUS
;
pendingOutputStreamOffsetsUs
=
new
long
[
MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT
];
pendingOutputStreamOffsetsUs
=
new
long
[
MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT
];
...
@@ -710,8 +710,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -710,8 +710,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
}
@Override
@Override
public
final
void
setOperatingRate
(
float
operatingRate
)
throws
ExoPlaybackException
{
public
void
setOperatingRate
(
float
operatingRate
)
throws
ExoPlaybackException
{
rendererO
peratingRate
=
operatingRate
;
this
.
o
peratingRate
=
operatingRate
;
if
(
codec
!=
null
if
(
codec
!=
null
&&
codecDrainAction
!=
DRAIN_ACTION_REINITIALIZE
&&
codecDrainAction
!=
DRAIN_ACTION_REINITIALIZE
&&
getState
()
!=
STATE_DISABLED
)
{
&&
getState
()
!=
STATE_DISABLED
)
{
...
@@ -1031,7 +1031,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1031,7 +1031,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
float
codecOperatingRate
=
float
codecOperatingRate
=
Util
.
SDK_INT
<
23
Util
.
SDK_INT
<
23
?
CODEC_OPERATING_RATE_UNSET
?
CODEC_OPERATING_RATE_UNSET
:
getCodecOperatingRateV23
(
rendererO
peratingRate
,
inputFormat
,
getStreamFormats
());
:
getCodecOperatingRateV23
(
o
peratingRate
,
inputFormat
,
getStreamFormats
());
if
(
codecOperatingRate
<=
assumedMinimumCodecOperatingRate
)
{
if
(
codecOperatingRate
<=
assumedMinimumCodecOperatingRate
)
{
codecOperatingRate
=
CODEC_OPERATING_RATE_UNSET
;
codecOperatingRate
=
CODEC_OPERATING_RATE_UNSET
;
}
}
...
@@ -1561,6 +1561,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1561,6 +1561,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
&&
SystemClock
.
elapsedRealtime
()
<
codecHotswapDeadlineMs
));
&&
SystemClock
.
elapsedRealtime
()
<
codecHotswapDeadlineMs
));
}
}
/** Returns the renderer operating rate, as set by {@link #setOperatingRate}. */
protected
float
getOperatingRate
()
{
return
operatingRate
;
}
/**
/**
* Returns the {@link MediaFormat#KEY_OPERATING_RATE} value for a given renderer operating rate,
* Returns the {@link MediaFormat#KEY_OPERATING_RATE} value for a given renderer operating rate,
* current {@link Format} and set of possible stream formats.
* current {@link Format} and set of possible stream formats.
...
@@ -1589,7 +1594,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1589,7 +1594,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
}
float
newCodecOperatingRate
=
float
newCodecOperatingRate
=
getCodecOperatingRateV23
(
rendererO
peratingRate
,
codecFormat
,
getStreamFormats
());
getCodecOperatingRateV23
(
o
peratingRate
,
codecFormat
,
getStreamFormats
());
if
(
codecOperatingRate
==
newCodecOperatingRate
)
{
if
(
codecOperatingRate
==
newCodecOperatingRate
)
{
// No change.
// No change.
}
else
if
(
newCodecOperatingRate
==
CODEC_OPERATING_RATE_UNSET
)
{
}
else
if
(
newCodecOperatingRate
==
CODEC_OPERATING_RATE_UNSET
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
View file @
862a6e4d
...
@@ -55,6 +55,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
...
@@ -55,6 +55,7 @@ import com.google.android.exoplayer2.util.MimeTypes;
import
com.google.android.exoplayer2.util.TraceUtil
;
import
com.google.android.exoplayer2.util.TraceUtil
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.video.VideoRendererEventListener.EventDispatcher
;
import
com.google.android.exoplayer2.video.VideoRendererEventListener.EventDispatcher
;
import
java.lang.reflect.Method
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.util.Collections
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
...
@@ -98,6 +99,24 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -98,6 +99,24 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
/** Magic frame render timestamp that indicates the EOS in tunneling mode. */
/** Magic frame render timestamp that indicates the EOS in tunneling mode. */
private
static
final
long
TUNNELING_EOS_PRESENTATION_TIME_US
=
Long
.
MAX_VALUE
;
private
static
final
long
TUNNELING_EOS_PRESENTATION_TIME_US
=
Long
.
MAX_VALUE
;
// TODO: Remove reflection once we target API level 30.
@Nullable
private
static
final
Method
surfaceSetFrameRateMethod
;
static
{
@Nullable
Method
setFrameRateMethod
=
null
;
if
(
Util
.
SDK_INT
>=
30
)
{
try
{
setFrameRateMethod
=
Surface
.
class
.
getMethod
(
"setFrameRate"
,
float
.
class
,
int
.
class
);
}
catch
(
NoSuchMethodException
e
)
{
// Do nothing.
}
}
surfaceSetFrameRateMethod
=
setFrameRateMethod
;
}
// TODO: Remove these constants and use those defined by Surface once we target API level 30.
private
static
final
int
SURFACE_FRAME_RATE_COMPATIBILITY_DEFAULT
=
0
;
private
static
final
int
SURFACE_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
=
1
;
private
static
boolean
evaluatedDeviceNeedsSetOutputSurfaceWorkaround
;
private
static
boolean
evaluatedDeviceNeedsSetOutputSurfaceWorkaround
;
private
static
boolean
deviceNeedsSetOutputSurfaceWorkaround
;
private
static
boolean
deviceNeedsSetOutputSurfaceWorkaround
;
...
@@ -113,6 +132,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -113,6 +132,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private
boolean
codecHandlesHdr10PlusOutOfBandMetadata
;
private
boolean
codecHandlesHdr10PlusOutOfBandMetadata
;
private
Surface
surface
;
private
Surface
surface
;
private
float
surfaceFrameRate
;
private
Surface
dummySurface
;
private
Surface
dummySurface
;
@VideoScalingMode
private
int
scalingMode
;
@VideoScalingMode
private
int
scalingMode
;
private
boolean
renderedFirstFrameAfterReset
;
private
boolean
renderedFirstFrameAfterReset
;
...
@@ -135,6 +155,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -135,6 +155,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private
int
currentHeight
;
private
int
currentHeight
;
private
int
currentUnappliedRotationDegrees
;
private
int
currentUnappliedRotationDegrees
;
private
float
currentPixelWidthHeightRatio
;
private
float
currentPixelWidthHeightRatio
;
private
float
currentFrameRate
;
private
int
reportedWidth
;
private
int
reportedWidth
;
private
int
reportedHeight
;
private
int
reportedHeight
;
private
int
reportedUnappliedRotationDegrees
;
private
int
reportedUnappliedRotationDegrees
;
...
@@ -409,6 +430,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -409,6 +430,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
lastRenderTimeUs
=
SystemClock
.
elapsedRealtime
()
*
1000
;
lastRenderTimeUs
=
SystemClock
.
elapsedRealtime
()
*
1000
;
totalVideoFrameProcessingOffsetUs
=
0
;
totalVideoFrameProcessingOffsetUs
=
0
;
videoFrameProcessingOffsetCount
=
0
;
videoFrameProcessingOffsetCount
=
0
;
updateSurfaceFrameRate
(
/* isNewSurface= */
false
);
}
}
@Override
@Override
...
@@ -416,6 +438,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -416,6 +438,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
joiningDeadlineMs
=
C
.
TIME_UNSET
;
joiningDeadlineMs
=
C
.
TIME_UNSET
;
maybeNotifyDroppedFrames
();
maybeNotifyDroppedFrames
();
maybeNotifyVideoFrameProcessingOffset
();
maybeNotifyVideoFrameProcessingOffset
();
clearSurfaceFrameRate
();
super
.
onStopped
();
super
.
onStopped
();
}
}
...
@@ -480,7 +503,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -480,7 +503,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
}
// We only need to update the codec if the surface has changed.
// We only need to update the codec if the surface has changed.
if
(
this
.
surface
!=
surface
)
{
if
(
this
.
surface
!=
surface
)
{
clearSurfaceFrameRate
();
this
.
surface
=
surface
;
this
.
surface
=
surface
;
updateSurfaceFrameRate
(
/* isNewSurface= */
true
);
@State
int
state
=
getState
();
@State
int
state
=
getState
();
MediaCodec
codec
=
getCodec
();
MediaCodec
codec
=
getCodec
();
if
(
codec
!=
null
)
{
if
(
codec
!=
null
)
{
...
@@ -578,6 +604,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -578,6 +604,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
}
@Override
@Override
public
void
setOperatingRate
(
float
operatingRate
)
throws
ExoPlaybackException
{
super
.
setOperatingRate
(
operatingRate
);
updateSurfaceFrameRate
(
/* isNewSurface= */
false
);
}
@Override
protected
float
getCodecOperatingRateV23
(
protected
float
getCodecOperatingRateV23
(
float
operatingRate
,
Format
format
,
Format
[]
streamFormats
)
{
float
operatingRate
,
Format
format
,
Format
[]
streamFormats
)
{
// Use the highest known stream frame-rate up front, to avoid having to reconfigure the codec
// Use the highest known stream frame-rate up front, to avoid having to reconfigure the codec
...
@@ -682,6 +714,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -682,6 +714,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// On API level 20 and below the decoder does not apply the rotation.
// On API level 20 and below the decoder does not apply the rotation.
currentUnappliedRotationDegrees
=
outputFormat
.
rotationDegrees
;
currentUnappliedRotationDegrees
=
outputFormat
.
rotationDegrees
;
}
}
currentFrameRate
=
outputFormat
.
frameRate
;
updateSurfaceFrameRate
(
/* isNewSurface= */
false
);
}
}
@Override
@Override
...
@@ -1049,6 +1083,52 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1049,6 +1083,52 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
maybeNotifyRenderedFirstFrame
();
maybeNotifyRenderedFirstFrame
();
}
}
/**
* Updates the frame-rate of the current {@link #surface} based on the renderer operating rate,
* frame-rate of the content, and whether the renderer is started.
*
* @param isNewSurface Whether the current {@link #surface} is new.
*/
private
void
updateSurfaceFrameRate
(
boolean
isNewSurface
)
{
if
(
Util
.
SDK_INT
<
30
||
surface
==
null
||
surface
==
dummySurface
)
{
return
;
}
boolean
shouldSetFrameRate
=
getState
()
==
STATE_STARTED
&&
currentFrameRate
!=
Format
.
NO_VALUE
;
float
surfaceFrameRate
=
shouldSetFrameRate
?
currentFrameRate
*
getOperatingRate
()
:
0
;
// We always set the frame-rate if we have a new surface, since we have no way of knowing what
// it might have been set to previously.
if
(
this
.
surfaceFrameRate
==
surfaceFrameRate
&&
!
isNewSurface
)
{
return
;
}
this
.
surfaceFrameRate
=
surfaceFrameRate
;
setSurfaceFrameRateV30
(
surface
,
surfaceFrameRate
);
}
/** Clears the frame-rate of the current {@link #surface}. */
private
void
clearSurfaceFrameRate
()
{
if
(
Util
.
SDK_INT
<
30
||
surface
==
null
||
surface
==
dummySurface
||
surfaceFrameRate
==
0
)
{
return
;
}
surfaceFrameRate
=
0
;
setSurfaceFrameRateV30
(
surface
,
/* frameRate= */
0
);
}
@RequiresApi
(
30
)
private
void
setSurfaceFrameRateV30
(
Surface
surface
,
float
frameRate
)
{
if
(
surfaceSetFrameRateMethod
==
null
)
{
Log
.
e
(
TAG
,
"Failed to call Surface.setFrameRate (method does not exist)"
);
}
int
compatibility
=
frameRate
==
0
?
SURFACE_FRAME_RATE_COMPATIBILITY_DEFAULT
:
SURFACE_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE
;
try
{
surfaceSetFrameRateMethod
.
invoke
(
surface
,
frameRate
,
compatibility
);
}
catch
(
Exception
e
)
{
Log
.
e
(
TAG
,
"Failed to call Surface.setFrameRate"
,
e
);
}
}
private
boolean
shouldUseDummySurface
(
MediaCodecInfo
codecInfo
)
{
private
boolean
shouldUseDummySurface
(
MediaCodecInfo
codecInfo
)
{
return
Util
.
SDK_INT
>=
23
return
Util
.
SDK_INT
>=
23
&&
!
tunneling
&&
!
tunneling
...
...
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