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
c47e6220
authored
Nov 13, 2020
by
olly
Committed by
Ian Baker
Nov 16, 2020
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
Report reasons for not being able to reuse decoders
PiperOrigin-RevId: 342344090
parent
3ef609fa
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
708 additions
and
206 deletions
RELEASENOTES.md
extensions/av1/src/main/java/com/google/android/exoplayer2/ext/av1/Libgav1VideoRenderer.java
extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegVideoRenderer.java
extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java
library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/decoder/DecoderReuseEvaluation.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java
library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java
library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfoTest.java
playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DebugRenderersFactory.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAudioRenderer.java
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeVideoRenderer.java
RELEASENOTES.md
View file @
c47e6220
...
@@ -48,6 +48,12 @@
...
@@ -48,6 +48,12 @@
*
DRM:
*
DRM:
*
Fix playback failure when switching from PlayReady protected content to
*
Fix playback failure when switching from PlayReady protected content to
Widevine or Clearkey protected content in a playlist.
Widevine or Clearkey protected content in a playlist.
*
Analytics:
*
Pass a
`DecoderReuseEvaluation`
to
`AnalyticsListener`
's
`onVideoInputFormatChanged`
and
`onAudioInputFormatChanged`
methods. The
`DecoderReuseEvaluation`
indicates whether it was possible to re-use an
existing decoder instance for the new format, and if not then the
reasons why.
*
IMA extension:
*
IMA extension:
*
Upgrade IMA SDK dependency to 3.21.0, and release the
`AdsLoader`
*
Upgrade IMA SDK dependency to 3.21.0, and release the
`AdsLoader`
(
[
#7344
](
https://github.com/google/ExoPlayer/issues/7344
)
).
(
[
#7344
](
https://github.com/google/ExoPlayer/issues/7344
)
).
...
...
extensions/av1/src/main/java/com/google/android/exoplayer2/ext/av1/Libgav1VideoRenderer.java
View file @
c47e6220
...
@@ -15,12 +15,15 @@
...
@@ -15,12 +15,15 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
ext
.
av1
;
package
com
.
google
.
android
.
exoplayer2
.
ext
.
av1
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
;
import
android.os.Handler
;
import
android.os.Handler
;
import
android.view.Surface
;
import
android.view.Surface
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.TraceUtil
;
import
com.google.android.exoplayer2.util.TraceUtil
;
...
@@ -164,7 +167,13 @@ public class Libgav1VideoRenderer extends DecoderVideoRenderer {
...
@@ -164,7 +167,13 @@ public class Libgav1VideoRenderer extends DecoderVideoRenderer {
}
}
@Override
@Override
protected
boolean
canKeepCodec
(
Format
oldFormat
,
Format
newFormat
)
{
protected
DecoderReuseEvaluation
canReuseDecoder
(
return
true
;
String
decoderName
,
Format
oldFormat
,
Format
newFormat
)
{
return
new
DecoderReuseEvaluation
(
decoderName
,
oldFormat
,
newFormat
,
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
,
/* discardReasons= */
0
);
}
}
}
}
extensions/ffmpeg/src/main/java/com/google/android/exoplayer2/ext/ffmpeg/FfmpegVideoRenderer.java
View file @
c47e6220
...
@@ -15,6 +15,10 @@
...
@@ -15,6 +15,10 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
ext
.
ffmpeg
;
package
com
.
google
.
android
.
exoplayer2
.
ext
.
ffmpeg
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_MIME_TYPE_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
;
import
android.os.Handler
;
import
android.os.Handler
;
import
android.view.Surface
;
import
android.view.Surface
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
...
@@ -22,6 +26,7 @@ import com.google.android.exoplayer2.C;
...
@@ -22,6 +26,7 @@ import com.google.android.exoplayer2.C;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.decoder.Decoder
;
import
com.google.android.exoplayer2.decoder.Decoder
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
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
;
...
@@ -116,7 +121,15 @@ public final class FfmpegVideoRenderer extends DecoderVideoRenderer {
...
@@ -116,7 +121,15 @@ public final class FfmpegVideoRenderer extends DecoderVideoRenderer {
}
}
@Override
@Override
protected
boolean
canKeepCodec
(
Format
oldFormat
,
Format
newFormat
)
{
protected
DecoderReuseEvaluation
canReuseDecoder
(
return
Util
.
areEqual
(
oldFormat
.
sampleMimeType
,
newFormat
.
sampleMimeType
);
String
decoderName
,
Format
oldFormat
,
Format
newFormat
)
{
boolean
sameMimeType
=
Util
.
areEqual
(
oldFormat
.
sampleMimeType
,
newFormat
.
sampleMimeType
);
// TODO: Ability to reuse the decoder may be MIME type dependent.
return
new
DecoderReuseEvaluation
(
decoderName
,
oldFormat
,
newFormat
,
sameMimeType
?
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
:
REUSE_RESULT_NO
,
sameMimeType
?
0
:
DISCARD_REASON_MIME_TYPE_CHANGED
);
}
}
}
}
extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java
View file @
c47e6220
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
ext
.
vp9
;
package
com
.
google
.
android
.
exoplayer2
.
ext
.
vp9
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
;
import
static
java
.
lang
.
Runtime
.
getRuntime
;
import
static
java
.
lang
.
Runtime
.
getRuntime
;
import
android.os.Handler
;
import
android.os.Handler
;
...
@@ -23,6 +24,7 @@ import androidx.annotation.Nullable;
...
@@ -23,6 +24,7 @@ import androidx.annotation.Nullable;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.TraceUtil
;
import
com.google.android.exoplayer2.util.TraceUtil
;
...
@@ -169,7 +171,13 @@ public class LibvpxVideoRenderer extends DecoderVideoRenderer {
...
@@ -169,7 +171,13 @@ public class LibvpxVideoRenderer extends DecoderVideoRenderer {
}
}
@Override
@Override
protected
boolean
canKeepCodec
(
Format
oldFormat
,
Format
newFormat
)
{
protected
DecoderReuseEvaluation
canReuseDecoder
(
return
true
;
String
decoderName
,
Format
oldFormat
,
Format
newFormat
)
{
return
new
DecoderReuseEvaluation
(
decoderName
,
oldFormat
,
newFormat
,
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
,
/* discardReasons= */
0
);
}
}
}
}
library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java
View file @
c47e6220
...
@@ -36,6 +36,7 @@ import com.google.android.exoplayer2.audio.AudioListener;
...
@@ -36,6 +36,7 @@ import com.google.android.exoplayer2.audio.AudioListener;
import
com.google.android.exoplayer2.audio.AudioRendererEventListener
;
import
com.google.android.exoplayer2.audio.AudioRendererEventListener
;
import
com.google.android.exoplayer2.audio.AuxEffectInfo
;
import
com.google.android.exoplayer2.audio.AuxEffectInfo
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.device.DeviceInfo
;
import
com.google.android.exoplayer2.device.DeviceInfo
;
import
com.google.android.exoplayer2.device.DeviceListener
;
import
com.google.android.exoplayer2.device.DeviceListener
;
import
com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
;
import
com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
;
...
@@ -2242,10 +2243,11 @@ public class SimpleExoPlayer extends BasePlayer
...
@@ -2242,10 +2243,11 @@ public class SimpleExoPlayer extends BasePlayer
}
}
@Override
@Override
public
void
onVideoInputFormatChanged
(
Format
format
)
{
public
void
onVideoInputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
videoFormat
=
format
;
videoFormat
=
format
;
for
(
VideoRendererEventListener
videoDebugListener
:
videoDebugListeners
)
{
for
(
VideoRendererEventListener
videoDebugListener
:
videoDebugListeners
)
{
videoDebugListener
.
onVideoInputFormatChanged
(
format
);
videoDebugListener
.
onVideoInputFormatChanged
(
format
,
decoderReuseEvaluation
);
}
}
}
}
...
@@ -2337,10 +2339,11 @@ public class SimpleExoPlayer extends BasePlayer
...
@@ -2337,10 +2339,11 @@ public class SimpleExoPlayer extends BasePlayer
}
}
@Override
@Override
public
void
onAudioInputFormatChanged
(
Format
format
)
{
public
void
onAudioInputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
audioFormat
=
format
;
audioFormat
=
format
;
for
(
AudioRendererEventListener
audioDebugListener
:
audioDebugListeners
)
{
for
(
AudioRendererEventListener
audioDebugListener
:
audioDebugListeners
)
{
audioDebugListener
.
onAudioInputFormatChanged
(
format
);
audioDebugListener
.
onAudioInputFormatChanged
(
format
,
decoderReuseEvaluation
);
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java
View file @
c47e6220
...
@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.audio.AudioAttributes;
...
@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.audio.AudioAttributes;
import
com.google.android.exoplayer2.audio.AudioListener
;
import
com.google.android.exoplayer2.audio.AudioListener
;
import
com.google.android.exoplayer2.audio.AudioRendererEventListener
;
import
com.google.android.exoplayer2.audio.AudioRendererEventListener
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.drm.DrmSessionEventListener
;
import
com.google.android.exoplayer2.drm.DrmSessionEventListener
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.MetadataOutput
;
import
com.google.android.exoplayer2.metadata.MetadataOutput
;
...
@@ -195,11 +196,12 @@ public class AnalyticsCollector
...
@@ -195,11 +196,12 @@ public class AnalyticsCollector
@SuppressWarnings
(
"deprecation"
)
@SuppressWarnings
(
"deprecation"
)
@Override
@Override
public
final
void
onAudioInputFormatChanged
(
Format
format
)
{
public
final
void
onAudioInputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
EventTime
eventTime
=
generateReadingMediaPeriodEventTime
();
EventTime
eventTime
=
generateReadingMediaPeriodEventTime
();
listeners
.
sendEvent
(
listeners
.
sendEvent
(
listener
->
{
listener
->
{
listener
.
onAudioInputFormatChanged
(
eventTime
,
format
);
listener
.
onAudioInputFormatChanged
(
eventTime
,
format
,
decoderReuseEvaluation
);
listener
.
onDecoderInputFormatChanged
(
eventTime
,
C
.
TRACK_TYPE_AUDIO
,
format
);
listener
.
onDecoderInputFormatChanged
(
eventTime
,
C
.
TRACK_TYPE_AUDIO
,
format
);
});
});
}
}
...
@@ -298,11 +300,12 @@ public class AnalyticsCollector
...
@@ -298,11 +300,12 @@ public class AnalyticsCollector
@SuppressWarnings
(
"deprecation"
)
@SuppressWarnings
(
"deprecation"
)
@Override
@Override
public
final
void
onVideoInputFormatChanged
(
Format
format
)
{
public
final
void
onVideoInputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
EventTime
eventTime
=
generateReadingMediaPeriodEventTime
();
EventTime
eventTime
=
generateReadingMediaPeriodEventTime
();
listeners
.
sendEvent
(
listeners
.
sendEvent
(
listener
->
{
listener
->
{
listener
.
onVideoInputFormatChanged
(
eventTime
,
format
);
listener
.
onVideoInputFormatChanged
(
eventTime
,
format
,
decoderReuseEvaluation
);
listener
.
onDecoderInputFormatChanged
(
eventTime
,
C
.
TRACK_TYPE_VIDEO
,
format
);
listener
.
onDecoderInputFormatChanged
(
eventTime
,
C
.
TRACK_TYPE_VIDEO
,
format
);
});
});
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java
View file @
c47e6220
...
@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.Timeline;
...
@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.Timeline;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.audio.AudioSink
;
import
com.google.android.exoplayer2.audio.AudioSink
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.source.LoadEventInfo
;
import
com.google.android.exoplayer2.source.LoadEventInfo
;
import
com.google.android.exoplayer2.source.MediaLoadData
;
import
com.google.android.exoplayer2.source.MediaLoadData
;
...
@@ -452,8 +453,8 @@ public interface AnalyticsListener {
...
@@ -452,8 +453,8 @@ public interface AnalyticsListener {
EventTime
eventTime
,
int
trackType
,
String
decoderName
,
long
initializationDurationMs
)
{}
EventTime
eventTime
,
int
trackType
,
String
decoderName
,
long
initializationDurationMs
)
{}
/**
/**
* @deprecated Use {@link #onAudioInputFormatChanged
} and {@link #onVideoInputFormatChanged
}
* @deprecated Use {@link #onAudioInputFormatChanged
(EventTime, Format, DecoderReuseEvaluation)
}
* instead.
*
and {@link #onVideoInputFormatChanged(EventTime, Format, DecoderReuseEvaluation)}.
instead.
*/
*/
@Deprecated
@Deprecated
default
void
onDecoderInputFormatChanged
(
EventTime
eventTime
,
int
trackType
,
Format
format
)
{}
default
void
onDecoderInputFormatChanged
(
EventTime
eventTime
,
int
trackType
,
Format
format
)
{}
...
@@ -483,12 +484,25 @@ public interface AnalyticsListener {
...
@@ -483,12 +484,25 @@ public interface AnalyticsListener {
EventTime
eventTime
,
String
decoderName
,
long
initializationDurationMs
)
{}
EventTime
eventTime
,
String
decoderName
,
long
initializationDurationMs
)
{}
/**
/**
* @deprecated Use {@link #onAudioInputFormatChanged(EventTime, Format, DecoderReuseEvaluation)}.
*/
@Deprecated
default
void
onAudioInputFormatChanged
(
EventTime
eventTime
,
Format
format
)
{}
/**
* Called when the format of the media being consumed by an audio renderer changes.
* Called when the format of the media being consumed by an audio renderer changes.
*
*
* @param eventTime The event time.
* @param eventTime The event time.
* @param format The new format.
* @param format The new format.
* @param decoderReuseEvaluation The result of the evaluation to determine whether an existing
* decoder instance can be reused for the new format, or {@code null} if the renderer did not
* have a decoder.
*/
*/
default
void
onAudioInputFormatChanged
(
EventTime
eventTime
,
Format
format
)
{}
@SuppressWarnings
(
"deprecation"
)
default
void
onAudioInputFormatChanged
(
EventTime
eventTime
,
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
onAudioInputFormatChanged
(
eventTime
,
format
);
}
/**
/**
* Called when the audio position has increased for the first time since the last pause or
* Called when the audio position has increased for the first time since the last pause or
...
@@ -590,12 +604,25 @@ public interface AnalyticsListener {
...
@@ -590,12 +604,25 @@ public interface AnalyticsListener {
EventTime
eventTime
,
String
decoderName
,
long
initializationDurationMs
)
{}
EventTime
eventTime
,
String
decoderName
,
long
initializationDurationMs
)
{}
/**
/**
* @deprecated Use {@link #onVideoInputFormatChanged(EventTime, Format, DecoderReuseEvaluation)}.
*/
@Deprecated
default
void
onVideoInputFormatChanged
(
EventTime
eventTime
,
Format
format
)
{}
/**
* Called when the format of the media being consumed by a video renderer changes.
* Called when the format of the media being consumed by a video renderer changes.
*
*
* @param eventTime The event time.
* @param eventTime The event time.
* @param format The new format.
* @param format The new format.
* @param decoderReuseEvaluation The result of the evaluation to determine whether an existing
* decoder instance can be reused for the new format, or {@code null} if the renderer did not
* have a decoder.
*/
*/
default
void
onVideoInputFormatChanged
(
EventTime
eventTime
,
Format
format
)
{}
@SuppressWarnings
(
"deprecation"
)
default
void
onVideoInputFormatChanged
(
EventTime
eventTime
,
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
onVideoInputFormatChanged
(
eventTime
,
format
);
}
/**
/**
* Called after video frames have been dropped.
* Called after video frames have been dropped.
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java
View file @
c47e6220
...
@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.Format;
...
@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.Format;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Player
;
import
com.google.android.exoplayer2.Renderer
;
import
com.google.android.exoplayer2.Renderer
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
/**
/**
...
@@ -61,12 +62,23 @@ public interface AudioRendererEventListener {
...
@@ -61,12 +62,23 @@ public interface AudioRendererEventListener {
default
void
onAudioDecoderInitialized
(
default
void
onAudioDecoderInitialized
(
String
decoderName
,
long
initializedTimestampMs
,
long
initializationDurationMs
)
{}
String
decoderName
,
long
initializedTimestampMs
,
long
initializationDurationMs
)
{}
/** @deprecated Use {@link #onAudioInputFormatChanged(Format, DecoderReuseEvaluation)}. */
@Deprecated
default
void
onAudioInputFormatChanged
(
Format
format
)
{}
/**
/**
* Called when the format of the media being consumed by the renderer changes.
* Called when the format of the media being consumed by the renderer changes.
*
*
* @param format The new format.
* @param format The new format.
* @param decoderReuseEvaluation The result of the evaluation to determine whether an existing
* decoder instance can be reused for the new format, or {@code null} if the renderer did not
* have a decoder.
*/
*/
default
void
onAudioInputFormatChanged
(
Format
format
)
{}
@SuppressWarnings
(
"deprecation"
)
default
void
onAudioInputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
onAudioInputFormatChanged
(
format
);
}
/**
/**
* Called when the audio position has increased for the first time since the last pause or
* Called when the audio position has increased for the first time since the last pause or
...
@@ -167,9 +179,11 @@ public interface AudioRendererEventListener {
...
@@ -167,9 +179,11 @@ public interface AudioRendererEventListener {
}
}
/** Invokes {@link AudioRendererEventListener#onAudioInputFormatChanged(Format)}. */
/** Invokes {@link AudioRendererEventListener#onAudioInputFormatChanged(Format)}. */
public
void
inputFormatChanged
(
Format
format
)
{
public
void
inputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
if
(
handler
!=
null
)
{
if
(
handler
!=
null
)
{
handler
.
post
(()
->
castNonNull
(
listener
).
onAudioInputFormatChanged
(
format
));
handler
.
post
(
()
->
castNonNull
(
listener
).
onAudioInputFormatChanged
(
format
,
decoderReuseEvaluation
));
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java
View file @
c47e6220
...
@@ -15,6 +15,9 @@
...
@@ -15,6 +15,9 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
audio
;
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_DRM_SESSION_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
max
;
import
android.media.audiofx.Virtualizer
;
import
android.media.audiofx.Virtualizer
;
...
@@ -38,6 +41,7 @@ import com.google.android.exoplayer2.decoder.Decoder;
...
@@ -38,6 +41,7 @@ import com.google.android.exoplayer2.decoder.Decoder;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderException
;
import
com.google.android.exoplayer2.decoder.DecoderException
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.decoder.SimpleOutputBuffer
;
import
com.google.android.exoplayer2.decoder.SimpleOutputBuffer
;
import
com.google.android.exoplayer2.drm.DrmSession
;
import
com.google.android.exoplayer2.drm.DrmSession
;
import
com.google.android.exoplayer2.drm.DrmSession.DrmSessionException
;
import
com.google.android.exoplayer2.drm.DrmSession.DrmSessionException
;
...
@@ -347,14 +351,19 @@ public abstract class DecoderAudioRenderer<
...
@@ -347,14 +351,19 @@ public abstract class DecoderAudioRenderer<
protected
abstract
Format
getOutputFormat
(
T
decoder
);
protected
abstract
Format
getOutputFormat
(
T
decoder
);
/**
/**
*
Returns whether the existing decoder can be kept for a new format
.
*
Evaluates whether the existing decoder can be reused for a new {@link Format}
.
*
*
* <p>The default implementation does not allow decoder reuse.
*
* @param decoderName The name of the decoder.
* @param oldFormat The previous format.
* @param oldFormat The previous format.
* @param newFormat The new format.
* @param newFormat The new format.
* @return
Whether the existing decoder can be kept
.
* @return
The result of the evaluation
.
*/
*/
protected
boolean
canKeepCodec
(
Format
oldFormat
,
Format
newFormat
)
{
protected
DecoderReuseEvaluation
canReuseDecoder
(
return
false
;
String
decoderName
,
Format
oldFormat
,
Format
newFormat
)
{
return
new
DecoderReuseEvaluation
(
decoderName
,
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
);
}
}
private
boolean
drainOutputBuffer
()
private
boolean
drainOutputBuffer
()
...
@@ -655,10 +664,29 @@ public abstract class DecoderAudioRenderer<
...
@@ -655,10 +664,29 @@ public abstract class DecoderAudioRenderer<
setSourceDrmSession
(
formatHolder
.
drmSession
);
setSourceDrmSession
(
formatHolder
.
drmSession
);
Format
oldFormat
=
inputFormat
;
Format
oldFormat
=
inputFormat
;
inputFormat
=
newFormat
;
inputFormat
=
newFormat
;
encoderDelay
=
newFormat
.
encoderDelay
;
encoderPadding
=
newFormat
.
encoderPadding
;
if
(
decoder
==
null
)
{
if
(
decoder
==
null
)
{
maybeInitDecoder
();
maybeInitDecoder
();
}
else
if
(
sourceDrmSession
!=
decoderDrmSession
||
!
canKeepCodec
(
oldFormat
,
inputFormat
))
{
eventDispatcher
.
inputFormatChanged
(
inputFormat
,
/* decoderReuseEvaluation= */
null
);
return
;
}
DecoderReuseEvaluation
evaluation
;
if
(
sourceDrmSession
!=
decoderDrmSession
)
{
evaluation
=
new
DecoderReuseEvaluation
(
decoder
.
getName
(),
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_DRM_SESSION_CHANGED
);
}
else
{
evaluation
=
canReuseDecoder
(
decoder
.
getName
(),
oldFormat
,
newFormat
);
}
if
(
evaluation
.
result
==
REUSE_RESULT_NO
)
{
if
(
decoderReceivedBuffers
)
{
if
(
decoderReceivedBuffers
)
{
// Signal end of stream and wait for any final output buffers before re-initialization.
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState
=
REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM
;
decoderReinitializationState
=
REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM
;
...
@@ -669,10 +697,7 @@ public abstract class DecoderAudioRenderer<
...
@@ -669,10 +697,7 @@ public abstract class DecoderAudioRenderer<
audioTrackNeedsConfigure
=
true
;
audioTrackNeedsConfigure
=
true
;
}
}
}
}
eventDispatcher
.
inputFormatChanged
(
inputFormat
,
evaluation
);
encoderDelay
=
inputFormat
.
encoderDelay
;
encoderPadding
=
inputFormat
.
encoderPadding
;
eventDispatcher
.
inputFormatChanged
(
inputFormat
);
}
}
private
void
onQueueInputBuffer
(
DecoderInputBuffer
buffer
)
{
private
void
onQueueInputBuffer
(
DecoderInputBuffer
buffer
)
{
...
...
library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java
View file @
c47e6220
...
@@ -15,7 +15,8 @@
...
@@ -15,7 +15,8 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
audio
;
package
com
.
google
.
android
.
exoplayer2
.
audio
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
max
;
...
@@ -41,9 +42,10 @@ import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispa
...
@@ -41,9 +42,10 @@ import com.google.android.exoplayer2.audio.AudioRendererEventListener.EventDispa
import
com.google.android.exoplayer2.audio.AudioSink.InitializationException
;
import
com.google.android.exoplayer2.audio.AudioSink.InitializationException
;
import
com.google.android.exoplayer2.audio.AudioSink.WriteException
;
import
com.google.android.exoplayer2.audio.AudioSink.WriteException
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecAdapter
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecAdapter
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo.KeepCodecResult
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecRenderer
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecRenderer
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecSelector
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecSelector
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecUtil
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecUtil
;
...
@@ -328,13 +330,21 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -328,13 +330,21 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
}
@Override
@Override
@KeepCodecResult
protected
DecoderReuseEvaluation
canReuseCodec
(
protected
int
canKeepCodec
(
MediaCodecInfo
codecInfo
,
Format
oldFormat
,
Format
newFormat
)
{
MediaCodecAdapter
codec
,
MediaCodecInfo
codecInfo
,
Format
oldFormat
,
Format
newFormat
)
{
DecoderReuseEvaluation
evaluation
=
codecInfo
.
canReuseCodec
(
oldFormat
,
newFormat
);
@DecoderDiscardReasons
int
discardReasons
=
evaluation
.
discardReasons
;
if
(
getCodecMaxInputSize
(
codecInfo
,
newFormat
)
>
codecMaxInputSize
)
{
if
(
getCodecMaxInputSize
(
codecInfo
,
newFormat
)
>
codecMaxInputSize
)
{
return
KEEP_CODEC_RESULT_NO
;
discardReasons
|=
DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED
;
}
}
return
codecInfo
.
canKeepCodec
(
oldFormat
,
newFormat
);
return
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
oldFormat
,
newFormat
,
discardReasons
!=
0
?
REUSE_RESULT_NO
:
evaluation
.
result
,
discardReasons
);
}
}
@Override
@Override
...
@@ -370,9 +380,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -370,9 +380,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
}
@Override
@Override
protected
void
onInputFormatChanged
(
FormatHolder
formatHolder
)
throws
ExoPlaybackException
{
@Nullable
super
.
onInputFormatChanged
(
formatHolder
);
protected
DecoderReuseEvaluation
onInputFormatChanged
(
FormatHolder
formatHolder
)
eventDispatcher
.
inputFormatChanged
(
formatHolder
.
format
);
throws
ExoPlaybackException
{
@Nullable
DecoderReuseEvaluation
evaluation
=
super
.
onInputFormatChanged
(
formatHolder
);
eventDispatcher
.
inputFormatChanged
(
formatHolder
.
format
,
evaluation
);
return
evaluation
;
}
}
@Override
@Override
...
@@ -664,7 +677,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
...
@@ -664,7 +677,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
return
maxInputSize
;
return
maxInputSize
;
}
}
for
(
Format
streamFormat
:
streamFormats
)
{
for
(
Format
streamFormat
:
streamFormats
)
{
if
(
codecInfo
.
can
KeepCodec
(
format
,
streamFormat
)
!=
KEEP_CODEC
_RESULT_NO
)
{
if
(
codecInfo
.
can
ReuseCodec
(
format
,
streamFormat
).
result
!=
REUSE
_RESULT_NO
)
{
maxInputSize
=
max
(
maxInputSize
,
getCodecMaxInputSize
(
codecInfo
,
streamFormat
));
maxInputSize
=
max
(
maxInputSize
,
getCodecMaxInputSize
(
codecInfo
,
streamFormat
));
}
}
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/decoder/DecoderReuseEvaluation.java
0 → 100644
View file @
c47e6220
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com
.
google
.
android
.
exoplayer2
.
decoder
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkArgument
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotEmpty
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.Nullable
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.video.ColorInfo
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
/**
* The result of an evaluation to determine whether a decoder can be reused for a new input format.
*/
public
final
class
DecoderReuseEvaluation
{
/** Possible outcomes of the evaluation. */
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
({
REUSE_RESULT_NO
,
REUSE_RESULT_YES_WITH_FLUSH
,
REUSE_RESULT_YES_WITH_RECONFIGURATION
,
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
})
public
@interface
DecoderReuseResult
{}
/** The decoder cannot be reused. */
public
static
final
int
REUSE_RESULT_NO
=
0
;
/** The decoder can be reused, but must be flushed. */
public
static
final
int
REUSE_RESULT_YES_WITH_FLUSH
=
1
;
/**
* The decoder can be reused. It does not need to be flushed, but must be reconfigured by
* prefixing the next input buffer with the new format's configuration data.
*/
public
static
final
int
REUSE_RESULT_YES_WITH_RECONFIGURATION
=
2
;
/** The decoder can be kept. It does not need to be flushed and no reconfiguration is required. */
public
static
final
int
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
=
3
;
/** Possible reasons why reuse is not possible. */
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
(
flag
=
true
,
value
=
{
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
,
DISCARD_REASON_WORKAROUND
,
DISCARD_REASON_APP_OVERRIDE
,
DISCARD_REASON_MIME_TYPE_CHANGED
,
DISCARD_REASON_OPERATING_RATE_CHANGED
,
DISCARD_REASON_INITIALIZATION_DATA_CHANGED
,
DISCARD_REASON_DRM_SESSION_CHANGED
,
DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED
,
DISCARD_REASON_VIDEO_MAX_RESOLUTION_EXCEEDED
,
DISCARD_REASON_VIDEO_RESOLUTION_CHANGED
,
DISCARD_REASON_VIDEO_ROTATION_CHANGED
,
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
,
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED
,
DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED
,
DISCARD_REASON_AUDIO_ENCODING_CHANGED
})
public
@interface
DecoderDiscardReasons
{}
/** Decoder reuse is not implemented. */
public
static
final
int
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
=
1
<<
0
;
/** Decoder reuse is disabled by a workaround. */
public
static
final
int
DISCARD_REASON_WORKAROUND
=
1
<<
1
;
/** Decoder reuse is disabled by overriding behavior in application code. */
public
static
final
int
DISCARD_REASON_APP_OVERRIDE
=
1
<<
2
;
/** The sample MIME type is changing. */
public
static
final
int
DISCARD_REASON_MIME_TYPE_CHANGED
=
1
<<
3
;
/** The codec's operating rate is changing. */
public
static
final
int
DISCARD_REASON_OPERATING_RATE_CHANGED
=
1
<<
4
;
/** The format initialization data is changing. */
public
static
final
int
DISCARD_REASON_INITIALIZATION_DATA_CHANGED
=
1
<<
5
;
/** The new format may exceed the decoder's configured maximum sample size, in bytes. */
public
static
final
int
DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED
=
1
<<
6
;
/** The DRM session is changing. */
public
static
final
int
DISCARD_REASON_DRM_SESSION_CHANGED
=
1
<<
7
;
/** The new format may exceed the decoder's configured maximum resolution. */
public
static
final
int
DISCARD_REASON_VIDEO_MAX_RESOLUTION_EXCEEDED
=
1
<<
8
;
/** The video resolution is changing. */
public
static
final
int
DISCARD_REASON_VIDEO_RESOLUTION_CHANGED
=
1
<<
9
;
/** The video rotation is changing. */
public
static
final
int
DISCARD_REASON_VIDEO_ROTATION_CHANGED
=
1
<<
10
;
/** The video {@link ColorInfo} is changing. */
public
static
final
int
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
=
1
<<
11
;
/** The audio channel count is changing. */
public
static
final
int
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED
=
1
<<
12
;
/** The audio sample rate is changing. */
public
static
final
int
DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED
=
1
<<
13
;
/** The audio encoding is changing. */
public
static
final
int
DISCARD_REASON_AUDIO_ENCODING_CHANGED
=
1
<<
14
;
/** The name of the decoder. */
public
final
String
decoderName
;
/** The {@link Format} for which the decoder was previously configured. */
public
final
Format
oldFormat
;
/** The new {@link Format} being evaluated. */
public
final
Format
newFormat
;
/** The {@link DecoderReuseResult result} of the evaluation. */
@DecoderReuseResult
public
final
int
result
;
/**
* {@link DecoderDiscardReasons Reasons} why the decoder cannot be reused. Always {@code 0} if
* reuse is possible. May also be {code 0} if reuse is not possible for an unspecified reason.
*/
@DecoderDiscardReasons
public
final
int
discardReasons
;
/**
* @param decoderName The name of the decoder.
* @param oldFormat The {@link Format} for which the decoder was previously configured.
* @param newFormat The new {@link Format} being evaluated.
* @param result The {@link DecoderReuseResult result} of the evaluation.
* @param discardReasons One or more {@link DecoderDiscardReasons reasons} why the decoder cannot
* be reused, or {@code 0} if reuse is possible.
*/
public
DecoderReuseEvaluation
(
String
decoderName
,
Format
oldFormat
,
Format
newFormat
,
@DecoderReuseResult
int
result
,
@DecoderDiscardReasons
int
discardReasons
)
{
checkArgument
(
result
==
REUSE_RESULT_NO
||
discardReasons
==
0
);
this
.
decoderName
=
checkNotEmpty
(
decoderName
);
this
.
oldFormat
=
checkNotNull
(
oldFormat
);
this
.
newFormat
=
checkNotNull
(
newFormat
);
this
.
result
=
result
;
this
.
discardReasons
=
discardReasons
;
}
@Override
public
boolean
equals
(
@Nullable
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(
obj
==
null
||
getClass
()
!=
obj
.
getClass
())
{
return
false
;
}
DecoderReuseEvaluation
other
=
(
DecoderReuseEvaluation
)
obj
;
return
result
==
other
.
result
&&
discardReasons
==
other
.
discardReasons
&&
decoderName
.
equals
(
other
.
decoderName
)
&&
oldFormat
.
equals
(
other
.
oldFormat
)
&&
newFormat
.
equals
(
other
.
newFormat
);
}
@Override
public
int
hashCode
()
{
int
hashCode
=
17
;
hashCode
=
31
*
hashCode
+
result
;
hashCode
=
31
*
hashCode
+
discardReasons
;
hashCode
=
31
*
hashCode
+
decoderName
.
hashCode
();
hashCode
=
31
*
hashCode
+
oldFormat
.
hashCode
();
hashCode
=
31
*
hashCode
+
newFormat
.
hashCode
();
return
hashCode
;
}
}
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfo.java
View file @
c47e6220
...
@@ -15,6 +15,20 @@
...
@@ -15,6 +15,20 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
package
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_AUDIO_ENCODING_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_INITIALIZATION_DATA_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_MIME_TYPE_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_VIDEO_RESOLUTION_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_VIDEO_ROTATION_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_WORKAROUND
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITH_FLUSH
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITH_RECONFIGURATION
;
import
android.graphics.Point
;
import
android.graphics.Point
;
import
android.media.MediaCodec
;
import
android.media.MediaCodec
;
import
android.media.MediaCodecInfo.AudioCapabilities
;
import
android.media.MediaCodecInfo.AudioCapabilities
;
...
@@ -22,18 +36,17 @@ import android.media.MediaCodecInfo.CodecCapabilities;
...
@@ -22,18 +36,17 @@ import android.media.MediaCodecInfo.CodecCapabilities;
import
android.media.MediaCodecInfo.CodecProfileLevel
;
import
android.media.MediaCodecInfo.CodecProfileLevel
;
import
android.media.MediaCodecInfo.VideoCapabilities
;
import
android.media.MediaCodecInfo.VideoCapabilities
;
import
android.util.Pair
;
import
android.util.Pair
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.Nullable
;
import
androidx.annotation.RequiresApi
;
import
androidx.annotation.RequiresApi
;
import
androidx.annotation.VisibleForTesting
;
import
androidx.annotation.VisibleForTesting
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderReuseResult
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.Log
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.MimeTypes
;
import
com.google.android.exoplayer2.util.Util
;
import
com.google.android.exoplayer2.util.Util
;
import
java.lang.annotation.Documented
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
/** Information about a {@link MediaCodec} for a given mime type. */
/** Information about a {@link MediaCodec} for a given mime type. */
@SuppressWarnings
(
"InlinedApi"
)
@SuppressWarnings
(
"InlinedApi"
)
...
@@ -47,28 +60,6 @@ public final class MediaCodecInfo {
...
@@ -47,28 +60,6 @@ public final class MediaCodecInfo {
*/
*/
public
static
final
int
MAX_SUPPORTED_INSTANCES_UNKNOWN
=
-
1
;
public
static
final
int
MAX_SUPPORTED_INSTANCES_UNKNOWN
=
-
1
;
/** The possible return values for {@link #canKeepCodec(Format, Format)}. */
@Documented
@Retention
(
RetentionPolicy
.
SOURCE
)
@IntDef
({
KEEP_CODEC_RESULT_NO
,
KEEP_CODEC_RESULT_YES_WITH_FLUSH
,
KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION
,
KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION
})
public
@interface
KeepCodecResult
{}
/** The codec cannot be kept. */
public
static
final
int
KEEP_CODEC_RESULT_NO
=
0
;
/** The codec can be kept, but must be flushed. */
public
static
final
int
KEEP_CODEC_RESULT_YES_WITH_FLUSH
=
1
;
/**
* The codec can be kept. It does not need to be flushed, but must be reconfigured by prefixing
* the next input buffer with the new format's configuration data.
*/
public
static
final
int
KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION
=
2
;
/** The codec can be kept. It does not need to be flushed and no reconfiguration is required. */
public
static
final
int
KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION
=
3
;
/**
/**
* The name of the decoder.
* The name of the decoder.
*
*
...
@@ -361,7 +352,7 @@ public final class MediaCodecInfo {
...
@@ -361,7 +352,7 @@ public final class MediaCodecInfo {
* @param isNewFormatComplete Whether {@code newFormat} is populated with format-specific
* @param isNewFormatComplete Whether {@code newFormat} is populated with format-specific
* metadata.
* metadata.
* @return Whether it is possible to adapt the decoder seamlessly.
* @return Whether it is possible to adapt the decoder seamlessly.
* @deprecated Use {@link #can
Keep
Codec}.
* @deprecated Use {@link #can
Reuse
Codec}.
*/
*/
@Deprecated
@Deprecated
public
boolean
isSeamlessAdaptationSupported
(
public
boolean
isSeamlessAdaptationSupported
(
...
@@ -369,49 +360,68 @@ public final class MediaCodecInfo {
...
@@ -369,49 +360,68 @@ public final class MediaCodecInfo {
if
(!
isNewFormatComplete
&&
oldFormat
.
colorInfo
!=
null
&&
newFormat
.
colorInfo
==
null
)
{
if
(!
isNewFormatComplete
&&
oldFormat
.
colorInfo
!=
null
&&
newFormat
.
colorInfo
==
null
)
{
newFormat
=
newFormat
.
buildUpon
().
setColorInfo
(
oldFormat
.
colorInfo
).
build
();
newFormat
=
newFormat
.
buildUpon
().
setColorInfo
(
oldFormat
.
colorInfo
).
build
();
}
}
@
KeepCodecResult
int
keepCodecResult
=
canKeepCodec
(
oldFormat
,
newFormat
)
;
@
DecoderReuseResult
int
reuseResult
=
canReuseCodec
(
oldFormat
,
newFormat
).
result
;
return
keepCodecResult
==
KEEP_CODEC
_RESULT_YES_WITH_RECONFIGURATION
return
reuseResult
==
REUSE
_RESULT_YES_WITH_RECONFIGURATION
||
keepCodecResult
==
KEEP_CODEC
_RESULT_YES_WITHOUT_RECONFIGURATION
;
||
reuseResult
==
REUSE
_RESULT_YES_WITHOUT_RECONFIGURATION
;
}
}
/**
/**
*
Returns the extent to which it's possible to adapt an instance of this decoder that's currently
*
Evaluates whether it's possible to reuse an instance of this decoder that's currently decoding
*
decoding
{@code oldFormat} to decode {@code newFormat} instead.
* {@code oldFormat} to decode {@code newFormat} instead.
*
*
* <p>For adaptation to succeed, the codec must also be configured with maximum values that are
* <p>For adaptation to succeed, the codec must also be configured with maximum values that are
* compatible with the new format.
* compatible with the new format.
*
*
* @param oldFormat The format being decoded.
* @param oldFormat The format being decoded.
* @param newFormat The new format.
* @param newFormat The new format.
* @return The
extent to which it's possible to adapt an instance of the decoder
.
* @return The
result of the evaluation
.
*/
*/
@KeepCodecResult
public
DecoderReuseEvaluation
canReuseCodec
(
Format
oldFormat
,
Format
newFormat
)
{
public
int
canKeepCodec
(
Format
oldFormat
,
Format
newFormat
)
{
@DecoderDiscardReasons
int
discardReasons
=
0
;
if
(!
Util
.
areEqual
(
oldFormat
.
sampleMimeType
,
newFormat
.
sampleMimeType
))
{
if
(!
Util
.
areEqual
(
oldFormat
.
sampleMimeType
,
newFormat
.
sampleMimeType
))
{
return
KEEP_CODEC_RESULT_NO
;
discardReasons
|=
DISCARD_REASON_MIME_TYPE_CHANGED
;
}
}
if
(
isVideo
)
{
if
(
isVideo
)
{
if
(
oldFormat
.
rotationDegrees
==
newFormat
.
rotationDegrees
if
(
oldFormat
.
rotationDegrees
!=
newFormat
.
rotationDegrees
)
{
&&
(
adaptive
discardReasons
|=
DISCARD_REASON_VIDEO_ROTATION_CHANGED
;
||
(
oldFormat
.
width
==
newFormat
.
width
&&
oldFormat
.
height
==
newFormat
.
height
))
}
&&
Util
.
areEqual
(
oldFormat
.
colorInfo
,
newFormat
.
colorInfo
))
{
if
(!
adaptive
if
(
oldFormat
.
initializationDataEquals
(
newFormat
))
{
&&
(
oldFormat
.
width
!=
newFormat
.
width
||
oldFormat
.
height
!=
newFormat
.
height
))
{
return
KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION
;
discardReasons
|=
DISCARD_REASON_VIDEO_RESOLUTION_CHANGED
;
}
else
if
(!
needsAdaptationReconfigureWorkaround
(
name
))
{
}
return
KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION
;
if
(!
Util
.
areEqual
(
oldFormat
.
colorInfo
,
newFormat
.
colorInfo
))
{
}
discardReasons
|=
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
;
}
if
(
needsAdaptationReconfigureWorkaround
(
name
)
&&
!
oldFormat
.
initializationDataEquals
(
newFormat
))
{
discardReasons
|=
DISCARD_REASON_WORKAROUND
;
}
if
(
discardReasons
==
0
)
{
return
new
DecoderReuseEvaluation
(
name
,
oldFormat
,
newFormat
,
oldFormat
.
initializationDataEquals
(
newFormat
)
?
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
:
REUSE_RESULT_YES_WITH_RECONFIGURATION
,
/* discardReasons= */
0
);
}
}
}
else
{
}
else
{
if
(
oldFormat
.
channelCount
!=
newFormat
.
channelCount
if
(
oldFormat
.
channelCount
!=
newFormat
.
channelCount
)
{
||
oldFormat
.
sampleRate
!=
newFormat
.
sampleRate
discardReasons
|=
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED
;
||
oldFormat
.
pcmEncoding
!=
newFormat
.
pcmEncoding
)
{
}
return
KEEP_CODEC_RESULT_NO
;
if
(
oldFormat
.
sampleRate
!=
newFormat
.
sampleRate
)
{
discardReasons
|=
DISCARD_REASON_AUDIO_SAMPLE_RATE_CHANGED
;
}
if
(
oldFormat
.
pcmEncoding
!=
newFormat
.
pcmEncoding
)
{
discardReasons
|=
DISCARD_REASON_AUDIO_ENCODING_CHANGED
;
}
}
// Check whether we're adapting between two xHE-AAC formats, for which adaptation is possible
// Check whether we're adapting between two xHE-AAC formats, for which adaptation is possible
// without reconfiguration or flushing.
// without reconfiguration or flushing.
if
(
MimeTypes
.
AUDIO_AAC
.
equals
(
mimeType
))
{
if
(
discardReasons
==
0
&&
MimeTypes
.
AUDIO_AAC
.
equals
(
mimeType
))
{
@Nullable
@Nullable
Pair
<
Integer
,
Integer
>
oldCodecProfileLevel
=
Pair
<
Integer
,
Integer
>
oldCodecProfileLevel
=
MediaCodecUtil
.
getCodecProfileAndLevel
(
oldFormat
);
MediaCodecUtil
.
getCodecProfileAndLevel
(
oldFormat
);
...
@@ -423,18 +433,30 @@ public final class MediaCodecInfo {
...
@@ -423,18 +433,30 @@ public final class MediaCodecInfo {
int
newProfile
=
newCodecProfileLevel
.
first
;
int
newProfile
=
newCodecProfileLevel
.
first
;
if
(
oldProfile
==
CodecProfileLevel
.
AACObjectXHE
if
(
oldProfile
==
CodecProfileLevel
.
AACObjectXHE
&&
newProfile
==
CodecProfileLevel
.
AACObjectXHE
)
{
&&
newProfile
==
CodecProfileLevel
.
AACObjectXHE
)
{
return
KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION
;
return
new
DecoderReuseEvaluation
(
name
,
oldFormat
,
newFormat
,
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
,
/* discardReasons= */
0
);
}
}
}
}
}
}
if
(
oldFormat
.
initializationDataEquals
(
newFormat
)
if
(!
oldFormat
.
initializationDataEquals
(
newFormat
))
{
&&
!
needsAdaptationFlushWorkaround
(
mimeType
))
{
discardReasons
|=
DISCARD_REASON_INITIALIZATION_DATA_CHANGED
;
return
KEEP_CODEC_RESULT_YES_WITH_FLUSH
;
}
if
(
needsAdaptationFlushWorkaround
(
mimeType
))
{
discardReasons
|=
DISCARD_REASON_WORKAROUND
;
}
if
(
discardReasons
==
0
)
{
return
new
DecoderReuseEvaluation
(
name
,
oldFormat
,
newFormat
,
REUSE_RESULT_YES_WITH_FLUSH
,
/* discardReasons= */
0
);
}
}
}
}
return
KEEP_CODEC_RESULT_NO
;
return
new
DecoderReuseEvaluation
(
name
,
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
discardReasons
)
;
}
}
/**
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java
View file @
c47e6220
...
@@ -15,10 +15,14 @@
...
@@ -15,10 +15,14 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
package
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_DRM_SESSION_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_YES_WITHOUT_RECONFIGURATION
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_OPERATING_RATE_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_YES_WITH_FLUSH
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_WORKAROUND
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITHOUT_RECONFIGURATION
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITH_FLUSH
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITH_RECONFIGURATION
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkNotNull
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
Assertions
.
checkState
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
max
;
...
@@ -44,11 +48,12 @@ import com.google.android.exoplayer2.Format;
...
@@ -44,11 +48,12 @@ import com.google.android.exoplayer2.Format;
import
com.google.android.exoplayer2.FormatHolder
;
import
com.google.android.exoplayer2.FormatHolder
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons
;
import
com.google.android.exoplayer2.drm.DrmSession
;
import
com.google.android.exoplayer2.drm.DrmSession
;
import
com.google.android.exoplayer2.drm.DrmSession.DrmSessionException
;
import
com.google.android.exoplayer2.drm.DrmSession.DrmSessionException
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.drm.FrameworkMediaCrypto
;
import
com.google.android.exoplayer2.drm.FrameworkMediaCrypto
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo.KeepCodecResult
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException
;
import
com.google.android.exoplayer2.source.MediaPeriod
;
import
com.google.android.exoplayer2.source.MediaPeriod
;
import
com.google.android.exoplayer2.source.SampleStream
;
import
com.google.android.exoplayer2.source.SampleStream
;
...
@@ -710,7 +715,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -710,7 +715,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if
(
codec
!=
null
if
(
codec
!=
null
&&
codecDrainAction
!=
DRAIN_ACTION_REINITIALIZE
&&
codecDrainAction
!=
DRAIN_ACTION_REINITIALIZE
&&
getState
()
!=
STATE_DISABLED
)
{
&&
getState
()
!=
STATE_DISABLED
)
{
update
OperatingRateOrReinitializeCodec
(
codecInputFormat
);
update
CodecOperatingRate
(
codecInputFormat
);
}
}
}
}
...
@@ -1375,9 +1380,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1375,9 +1380,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*
*
* @param formatHolder A {@link FormatHolder} that holds the new {@link Format}.
* @param formatHolder A {@link FormatHolder} that holds the new {@link Format}.
* @throws ExoPlaybackException If an error occurs re-initializing the {@link MediaCodec}.
* @throws ExoPlaybackException If an error occurs re-initializing the {@link MediaCodec}.
* @return The result of the evaluation to determine whether the existing decoder instance can be
* reused for the new format, or {@code null} if the renderer did not have a decoder.
*/
*/
@CallSuper
@CallSuper
protected
void
onInputFormatChanged
(
FormatHolder
formatHolder
)
throws
ExoPlaybackException
{
@Nullable
protected
DecoderReuseEvaluation
onInputFormatChanged
(
FormatHolder
formatHolder
)
throws
ExoPlaybackException
{
waitingForFirstSampleInFormat
=
true
;
waitingForFirstSampleInFormat
=
true
;
Format
newFormat
=
checkNotNull
(
formatHolder
.
format
);
Format
newFormat
=
checkNotNull
(
formatHolder
.
format
);
setSourceDrmSession
(
formatHolder
.
drmSession
);
setSourceDrmSession
(
formatHolder
.
drmSession
);
...
@@ -1385,7 +1394,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1385,7 +1394,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if
(
bypassEnabled
)
{
if
(
bypassEnabled
)
{
bypassDrainAndReinitialize
=
true
;
bypassDrainAndReinitialize
=
true
;
return
;
// Need to drain batch buffer first.
return
null
;
// Need to drain batch buffer first.
}
}
if
(
codec
==
null
)
{
if
(
codec
==
null
)
{
...
@@ -1393,66 +1402,86 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1393,66 +1402,86 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
availableCodecInfos
=
null
;
availableCodecInfos
=
null
;
}
}
maybeInitCodecOrBypass
();
maybeInitCodecOrBypass
();
return
;
return
null
;
}
}
// We have an existing codec that we may need to reconfigure, re-initialize, or release to
// We have an existing codec that we may need to reconfigure, re-initialize, or release to
// switch to bypass. If the existing codec instance is kept then its operating rate and DRM
// switch to bypass. If the existing codec instance is kept then its operating rate and DRM
// session may need to be updated.
// session may need to be updated.
MediaCodecAdapter
oldCodec
=
codec
;
Format
oldFormat
=
codecInputFormat
;
if
(
drmNeedsCodecReinitialization
(
codecInfo
,
newFormat
,
codecDrmSession
,
sourceDrmSession
))
{
if
(
drmNeedsCodecReinitialization
(
codecInfo
,
newFormat
,
codecDrmSession
,
sourceDrmSession
))
{
drainAndReinitializeCodec
();
drainAndReinitializeCodec
();
return
;
return
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_DRM_SESSION_CHANGED
);
}
}
boolean
drainAndUpdateCodecDrmSession
=
sourceDrmSession
!=
codecDrmSession
;
boolean
drainAndUpdateCodecDrmSession
=
sourceDrmSession
!=
codecDrmSession
;
Assertions
.
checkState
(!
drainAndUpdateCodecDrmSession
||
Util
.
SDK_INT
>=
23
);
Assertions
.
checkState
(!
drainAndUpdateCodecDrmSession
||
Util
.
SDK_INT
>=
23
);
switch
(
canKeepCodec
(
codec
,
codecInfo
,
codecInputFormat
,
newFormat
))
{
DecoderReuseEvaluation
evaluation
=
canReuseCodec
(
codecInfo
,
oldFormat
,
newFormat
);
case
KEEP_CODEC_RESULT_NO:
@DecoderDiscardReasons
int
overridingDiscardReasons
=
0
;
switch
(
evaluation
.
result
)
{
case
REUSE_RESULT_NO:
drainAndReinitializeCodec
();
drainAndReinitializeCodec
();
break
;
break
;
case
KEEP_CODEC
_RESULT_YES_WITH_FLUSH:
case
REUSE
_RESULT_YES_WITH_FLUSH:
if
(
updateOperatingRateOrReinitializeCodec
(
newFormat
))
{
if
(
!
updateCodecOperatingRate
(
newFormat
))
{
// Codec re-initialization triggered.
overridingDiscardReasons
|=
DISCARD_REASON_OPERATING_RATE_CHANGED
;
}
else
{
}
else
{
codecInputFormat
=
newFormat
;
codecInputFormat
=
newFormat
;
if
(
drainAndUpdateCodecDrmSession
)
{
if
(
drainAndUpdateCodecDrmSession
)
{
drainAndUpdateCodecDrmSessionV23
();
if
(!
drainAndUpdateCodecDrmSessionV23
())
{
}
else
{
overridingDiscardReasons
|=
DISCARD_REASON_WORKAROUND
;
drainAndFlushCodec
();
}
}
else
if
(!
drainAndFlushCodec
())
{
overridingDiscardReasons
|=
DISCARD_REASON_WORKAROUND
;
}
}
}
}
break
;
break
;
case
KEEP_CODEC
_RESULT_YES_WITH_RECONFIGURATION:
case
REUSE
_RESULT_YES_WITH_RECONFIGURATION:
if
(
updateOperatingRateOrReinitializeCodec
(
newFormat
))
{
if
(
!
updateCodecOperatingRate
(
newFormat
))
{
// Codec re-initialization triggered.
overridingDiscardReasons
|=
DISCARD_REASON_OPERATING_RATE_CHANGED
;
}
else
{
}
else
{
codecReconfigured
=
true
;
codecReconfigured
=
true
;
codecReconfigurationState
=
RECONFIGURATION_STATE_WRITE_PENDING
;
codecReconfigurationState
=
RECONFIGURATION_STATE_WRITE_PENDING
;
codecNeedsAdaptationWorkaroundBuffer
=
codecNeedsAdaptationWorkaroundBuffer
=
codecAdaptationWorkaroundMode
==
ADAPTATION_WORKAROUND_MODE_ALWAYS
codecAdaptationWorkaroundMode
==
ADAPTATION_WORKAROUND_MODE_ALWAYS
||
(
codecAdaptationWorkaroundMode
==
ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
||
(
codecAdaptationWorkaroundMode
==
ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION
&&
newFormat
.
width
==
codecInput
Format
.
width
&&
newFormat
.
width
==
old
Format
.
width
&&
newFormat
.
height
==
codecInput
Format
.
height
);
&&
newFormat
.
height
==
old
Format
.
height
);
codecInputFormat
=
newFormat
;
codecInputFormat
=
newFormat
;
if
(
drainAndUpdateCodecDrmSession
)
{
if
(
drainAndUpdateCodecDrmSession
&&
!
drainAndUpdateCodecDrmSessionV23
()
)
{
drainAndUpdateCodecDrmSessionV23
()
;
overridingDiscardReasons
|=
DISCARD_REASON_WORKAROUND
;
}
}
}
}
break
;
break
;
case
KEEP_CODEC
_RESULT_YES_WITHOUT_RECONFIGURATION:
case
REUSE
_RESULT_YES_WITHOUT_RECONFIGURATION:
if
(
updateOperatingRateOrReinitializeCodec
(
newFormat
))
{
if
(
!
updateCodecOperatingRate
(
newFormat
))
{
// Codec re-initialization triggered.
overridingDiscardReasons
|=
DISCARD_REASON_OPERATING_RATE_CHANGED
;
}
else
{
}
else
{
codecInputFormat
=
newFormat
;
codecInputFormat
=
newFormat
;
if
(
drainAndUpdateCodecDrmSession
)
{
if
(
drainAndUpdateCodecDrmSession
&&
!
drainAndUpdateCodecDrmSessionV23
()
)
{
drainAndUpdateCodecDrmSessionV23
()
;
overridingDiscardReasons
|=
DISCARD_REASON_WORKAROUND
;
}
}
}
}
break
;
break
;
default
:
default
:
throw
new
IllegalStateException
();
// Never happens.
throw
new
IllegalStateException
();
// Never happens.
}
}
if
(
evaluation
.
result
!=
REUSE_RESULT_NO
&&
(
codec
!=
oldCodec
||
codecDrainAction
==
DRAIN_ACTION_REINITIALIZE
))
{
// Initial evaluation indicated reuse was possible, but codec re-initialization was triggered.
// The reasons are indicated by overridingDiscardReasons.
return
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
overridingDiscardReasons
);
}
return
evaluation
;
}
}
/**
/**
...
@@ -1544,21 +1573,24 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1544,21 +1573,24 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
}
/**
/**
*
Determin
es whether the existing {@link MediaCodec} can be kept for a new {@link Format}, and if
*
Evaluat
es whether the existing {@link MediaCodec} can be kept for a new {@link Format}, and if
* it can whether it requires reconfiguration.
* it can whether it requires reconfiguration.
*
*
* <p>The default implementation
returns {@link MediaCodecInfo#KEEP_CODEC_RESULT_NO}
.
* <p>The default implementation
does not allow decoder reuse
.
*
*
* @param codec The existing {@link MediaCodecAdapter} instance.
* @param codecInfo A {@link MediaCodecInfo} describing the decoder.
* @param codecInfo A {@link MediaCodecInfo} describing the decoder.
* @param oldFormat The {@link Format} for which the existing instance is configured.
* @param oldFormat The {@link Format} for which the existing instance is configured.
* @param newFormat The new {@link Format}.
* @param newFormat The new {@link Format}.
* @return
Whether the instance can be kept, and if it can whether it requires reconfigur
ation.
* @return
The result of the evalu
ation.
*/
*/
@KeepCodecResult
protected
DecoderReuseEvaluation
canReuseCodec
(
protected
int
canKeepCodec
(
MediaCodecInfo
codecInfo
,
Format
oldFormat
,
Format
newFormat
)
{
MediaCodecAdapter
codec
,
MediaCodecInfo
codecInfo
,
Format
oldFormat
,
Format
newFormat
)
{
return
new
DecoderReuseEvaluation
(
return
KEEP_CODEC_RESULT_NO
;
codecInfo
.
name
,
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
);
}
}
@Override
@Override
...
@@ -1608,25 +1640,23 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1608,25 +1640,23 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*
*
* @param format The {@link Format} for which the operating rate should be configured.
* @param format The {@link Format} for which the operating rate should be configured.
* @throws ExoPlaybackException If an error occurs releasing or initializing a codec.
* @throws ExoPlaybackException If an error occurs releasing or initializing a codec.
* @return Whether codec release and re-initialization was triggered, rather than the existing
* @return False if codec release and re-initialization was triggered. True in all other cases.
* codec being updated.
*/
*/
private
boolean
updateOperatingRateOrReinitializeCodec
(
Format
format
)
private
boolean
updateCodecOperatingRate
(
Format
format
)
throws
ExoPlaybackException
{
throws
ExoPlaybackException
{
if
(
Util
.
SDK_INT
<
23
)
{
if
(
Util
.
SDK_INT
<
23
)
{
return
fals
e
;
return
tru
e
;
}
}
float
newCodecOperatingRate
=
float
newCodecOperatingRate
=
getCodecOperatingRateV23
(
playbackSpeed
,
format
,
getStreamFormats
());
getCodecOperatingRateV23
(
playbackSpeed
,
format
,
getStreamFormats
());
if
(
codecOperatingRate
==
newCodecOperatingRate
)
{
if
(
codecOperatingRate
==
newCodecOperatingRate
)
{
// No change.
// No change.
return
fals
e
;
return
tru
e
;
}
else
if
(
newCodecOperatingRate
==
CODEC_OPERATING_RATE_UNSET
)
{
}
else
if
(
newCodecOperatingRate
==
CODEC_OPERATING_RATE_UNSET
)
{
// The only way to clear the operating rate is to instantiate a new codec instance. See
// The only way to clear the operating rate is to instantiate a new codec instance. See
// [Internal ref: b/111543954].
// [Internal ref: b/111543954].
drainAndReinitializeCodec
();
drainAndReinitializeCodec
();
return
tru
e
;
return
fals
e
;
}
else
if
(
codecOperatingRate
!=
CODEC_OPERATING_RATE_UNSET
}
else
if
(
codecOperatingRate
!=
CODEC_OPERATING_RATE_UNSET
||
newCodecOperatingRate
>
assumedMinimumCodecOperatingRate
)
{
||
newCodecOperatingRate
>
assumedMinimumCodecOperatingRate
)
{
// We need to set the operating rate, either because we've set it previously or because it's
// We need to set the operating rate, either because we've set it previously or because it's
...
@@ -1635,36 +1665,48 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1635,36 +1665,48 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecParameters
.
putFloat
(
MediaFormat
.
KEY_OPERATING_RATE
,
newCodecOperatingRate
);
codecParameters
.
putFloat
(
MediaFormat
.
KEY_OPERATING_RATE
,
newCodecOperatingRate
);
codec
.
setParameters
(
codecParameters
);
codec
.
setParameters
(
codecParameters
);
codecOperatingRate
=
newCodecOperatingRate
;
codecOperatingRate
=
newCodecOperatingRate
;
return
fals
e
;
return
tru
e
;
}
}
return
fals
e
;
return
tru
e
;
}
}
/** Starts draining the codec for flush. */
/**
private
void
drainAndFlushCodec
()
{
* Starts draining the codec for a flush, or to release and re-initialize the codec if flushing
* will not be possible. If no buffers have been queued to the codec then this method is a no-op.
*
* @return False if codec release and re-initialization was triggered due to the need to apply a
* flush workaround. True in all other cases.
*/
private
boolean
drainAndFlushCodec
()
{
if
(
codecReceivedBuffers
)
{
if
(
codecReceivedBuffers
)
{
codecDrainState
=
DRAIN_STATE_SIGNAL_END_OF_STREAM
;
codecDrainState
=
DRAIN_STATE_SIGNAL_END_OF_STREAM
;
if
(
codecNeedsFlushWorkaround
||
codecNeedsEosFlushWorkaround
)
{
if
(
codecNeedsFlushWorkaround
||
codecNeedsEosFlushWorkaround
)
{
codecDrainAction
=
DRAIN_ACTION_REINITIALIZE
;
codecDrainAction
=
DRAIN_ACTION_REINITIALIZE
;
return
false
;
}
else
{
}
else
{
codecDrainAction
=
DRAIN_ACTION_FLUSH
;
codecDrainAction
=
DRAIN_ACTION_FLUSH
;
}
}
}
}
return
true
;
}
}
/**
/**
* Starts draining the codec to update its DRM session. The update may occur immediately if no
* Starts draining the codec to flush it and update its DRM session, or to release and
* buffers have been queued to the codec.
* re-initialize the codec if flushing will not be possible. If no buffers have been queued to the
* codec then this method updates the DRM session immediately without flushing the codec.
*
*
* @throws ExoPlaybackException If an error occurs updating the codec's DRM session.
* @throws ExoPlaybackException If an error occurs updating the codec's DRM session.
* @return False if codec release and re-initialization was triggered due to the need to apply a
* flush workaround. True in all other cases.
*/
*/
@TargetApi
(
23
)
// Only called when SDK_INT >= 23, but lint isn't clever enough to know.
@TargetApi
(
23
)
// Only called when SDK_INT >= 23, but lint isn't clever enough to know.
private
void
drainAndUpdateCodecDrmSessionV23
()
throws
ExoPlaybackException
{
private
boolean
drainAndUpdateCodecDrmSessionV23
()
throws
ExoPlaybackException
{
if
(
codecReceivedBuffers
)
{
if
(
codecReceivedBuffers
)
{
codecDrainState
=
DRAIN_STATE_SIGNAL_END_OF_STREAM
;
codecDrainState
=
DRAIN_STATE_SIGNAL_END_OF_STREAM
;
if
(
codecNeedsFlushWorkaround
||
codecNeedsEosFlushWorkaround
)
{
if
(
codecNeedsFlushWorkaround
||
codecNeedsEosFlushWorkaround
)
{
codecDrainAction
=
DRAIN_ACTION_REINITIALIZE
;
codecDrainAction
=
DRAIN_ACTION_REINITIALIZE
;
return
false
;
}
else
{
}
else
{
codecDrainAction
=
DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION
;
codecDrainAction
=
DRAIN_ACTION_FLUSH_AND_UPDATE_DRM_SESSION
;
}
}
...
@@ -1672,6 +1714,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
...
@@ -1672,6 +1714,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
// Nothing has been queued to the decoder, so we can do the update immediately.
// Nothing has been queued to the decoder, so we can do the update immediately.
updateDrmSessionV23
();
updateDrmSessionV23
();
}
}
return
true
;
}
}
/**
/**
...
...
library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java
View file @
c47e6220
...
@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.Timeline;
...
@@ -34,6 +34,7 @@ import com.google.android.exoplayer2.Timeline;
import
com.google.android.exoplayer2.analytics.AnalyticsListener
;
import
com.google.android.exoplayer2.analytics.AnalyticsListener
;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.audio.AudioAttributes
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.metadata.Metadata
;
import
com.google.android.exoplayer2.source.LoadEventInfo
;
import
com.google.android.exoplayer2.source.LoadEventInfo
;
import
com.google.android.exoplayer2.source.MediaLoadData
;
import
com.google.android.exoplayer2.source.MediaLoadData
;
...
@@ -328,7 +329,8 @@ public class EventLogger implements AnalyticsListener {
...
@@ -328,7 +329,8 @@ public class EventLogger implements AnalyticsListener {
}
}
@Override
@Override
public
void
onAudioInputFormatChanged
(
EventTime
eventTime
,
Format
format
)
{
public
void
onAudioInputFormatChanged
(
EventTime
eventTime
,
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
logd
(
eventTime
,
"audioInputFormat"
,
Format
.
toLogString
(
format
));
logd
(
eventTime
,
"audioInputFormat"
,
Format
.
toLogString
(
format
));
}
}
...
@@ -393,7 +395,8 @@ public class EventLogger implements AnalyticsListener {
...
@@ -393,7 +395,8 @@ public class EventLogger implements AnalyticsListener {
}
}
@Override
@Override
public
void
onVideoInputFormatChanged
(
EventTime
eventTime
,
Format
format
)
{
public
void
onVideoInputFormatChanged
(
EventTime
eventTime
,
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
logd
(
eventTime
,
"videoInputFormat"
,
Format
.
toLogString
(
format
));
logd
(
eventTime
,
"videoInputFormat"
,
Format
.
toLogString
(
format
));
}
}
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java
View file @
c47e6220
...
@@ -15,6 +15,9 @@
...
@@ -15,6 +15,9 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
video
;
package
com
.
google
.
android
.
exoplayer2
.
video
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_DRM_SESSION_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
max
;
import
android.os.Handler
;
import
android.os.Handler
;
...
@@ -34,6 +37,7 @@ import com.google.android.exoplayer2.decoder.Decoder;
...
@@ -34,6 +37,7 @@ import com.google.android.exoplayer2.decoder.Decoder;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderException
;
import
com.google.android.exoplayer2.decoder.DecoderException
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.drm.DrmSession
;
import
com.google.android.exoplayer2.drm.DrmSession
;
import
com.google.android.exoplayer2.drm.DrmSession.DrmSessionException
;
import
com.google.android.exoplayer2.drm.DrmSession.DrmSessionException
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
import
com.google.android.exoplayer2.drm.ExoMediaCrypto
;
...
@@ -97,9 +101,12 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
...
@@ -97,9 +101,12 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
private
Format
inputFormat
;
private
Format
inputFormat
;
private
Format
outputFormat
;
private
Format
outputFormat
;
@Nullable
private
Decoder
<
private
Decoder
<
VideoDecoderInputBuffer
,
?
extends
VideoDecoderOutputBuffer
,
?
extends
DecoderException
>
VideoDecoderInputBuffer
,
?
extends
VideoDecoderOutputBuffer
,
?
extends
DecoderException
>
decoder
;
decoder
;
private
VideoDecoderInputBuffer
inputBuffer
;
private
VideoDecoderInputBuffer
inputBuffer
;
private
VideoDecoderOutputBuffer
outputBuffer
;
private
VideoDecoderOutputBuffer
outputBuffer
;
@Nullable
private
Surface
surface
;
@Nullable
private
Surface
surface
;
...
@@ -366,7 +373,24 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
...
@@ -366,7 +373,24 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
if
(
decoder
==
null
)
{
if
(
decoder
==
null
)
{
maybeInitDecoder
();
maybeInitDecoder
();
}
else
if
(
sourceDrmSession
!=
decoderDrmSession
||
!
canKeepCodec
(
oldFormat
,
inputFormat
))
{
eventDispatcher
.
inputFormatChanged
(
inputFormat
,
/* decoderReuseEvaluation= */
null
);
return
;
}
DecoderReuseEvaluation
evaluation
;
if
(
sourceDrmSession
!=
decoderDrmSession
)
{
evaluation
=
new
DecoderReuseEvaluation
(
decoder
.
getName
(),
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_DRM_SESSION_CHANGED
);
}
else
{
evaluation
=
canReuseDecoder
(
decoder
.
getName
(),
oldFormat
,
newFormat
);
}
if
(
evaluation
.
result
==
REUSE_RESULT_NO
)
{
if
(
decoderReceivedBuffers
)
{
if
(
decoderReceivedBuffers
)
{
// Signal end of stream and wait for any final output buffers before re-initialization.
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState
=
REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM
;
decoderReinitializationState
=
REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM
;
...
@@ -376,8 +400,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
...
@@ -376,8 +400,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
maybeInitDecoder
();
maybeInitDecoder
();
}
}
}
}
eventDispatcher
.
inputFormatChanged
(
inputFormat
,
evaluation
);
eventDispatcher
.
inputFormatChanged
(
inputFormat
);
}
}
/**
/**
...
@@ -626,14 +649,18 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
...
@@ -626,14 +649,18 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
protected
abstract
void
setDecoderOutputMode
(
@C
.
VideoOutputMode
int
outputMode
);
protected
abstract
void
setDecoderOutputMode
(
@C
.
VideoOutputMode
int
outputMode
);
/**
/**
* Returns whether the existing decoder can be kept for a new format.
* Evaluates whether the existing decoder can be reused for a new {@link Format}.
*
* <p>The default implementation does not allow decoder reuse.
*
*
* @param oldFormat The previous format.
* @param oldFormat The previous format.
* @param newFormat The new format.
* @param newFormat The new format.
* @return
Whether the existing decoder can be kept
.
* @return
The result of the evaluation
.
*/
*/
protected
boolean
canKeepCodec
(
Format
oldFormat
,
Format
newFormat
)
{
protected
DecoderReuseEvaluation
canReuseDecoder
(
return
false
;
String
decoderName
,
Format
oldFormat
,
Format
newFormat
)
{
return
new
DecoderReuseEvaluation
(
decoderName
,
oldFormat
,
newFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_REUSE_NOT_IMPLEMENTED
);
}
}
// Internal methods.
// Internal methods.
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java
View file @
c47e6220
...
@@ -15,7 +15,9 @@
...
@@ -15,7 +15,9 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
video
;
package
com
.
google
.
android
.
exoplayer2
.
video
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_VIDEO_MAX_RESOLUTION_EXCEEDED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
max
;
import
static
java
.
lang
.
Math
.
min
;
import
static
java
.
lang
.
Math
.
min
;
...
@@ -46,11 +48,12 @@ import com.google.android.exoplayer2.PlayerMessage.Target;
...
@@ -46,11 +48,12 @@ import com.google.android.exoplayer2.PlayerMessage.Target;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.RendererCapabilities
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons
;
import
com.google.android.exoplayer2.drm.DrmInitData
;
import
com.google.android.exoplayer2.drm.DrmInitData
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecAdapter
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecAdapter
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecDecoderException
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecDecoderException
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo.KeepCodecResult
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecRenderer
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecRenderer
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecSelector
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecSelector
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecUtil
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecUtil
;
...
@@ -566,15 +569,24 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -566,15 +569,24 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
}
@Override
@Override
@KeepCodecResult
protected
DecoderReuseEvaluation
canReuseCodec
(
protected
int
canKeepCodec
(
MediaCodecInfo
codecInfo
,
Format
oldFormat
,
Format
newFormat
)
{
MediaCodecAdapter
codec
,
MediaCodecInfo
codecInfo
,
Format
oldFormat
,
Format
newFormat
)
{
DecoderReuseEvaluation
evaluation
=
codecInfo
.
canReuseCodec
(
oldFormat
,
newFormat
);
if
(
newFormat
.
width
>
codecMaxValues
.
width
||
newFormat
.
height
>
codecMaxValues
.
height
@DecoderDiscardReasons
int
discardReasons
=
evaluation
.
discardReasons
;
||
getMaxInputSize
(
codecInfo
,
newFormat
)
>
codecMaxValues
.
inputSize
)
{
if
(
newFormat
.
width
>
codecMaxValues
.
width
||
newFormat
.
height
>
codecMaxValues
.
height
)
{
return
KEEP_CODEC_RESULT_NO
;
discardReasons
|=
DISCARD_REASON_VIDEO_MAX_RESOLUTION_EXCEEDED
;
}
if
(
getMaxInputSize
(
codecInfo
,
newFormat
)
>
codecMaxValues
.
inputSize
)
{
discardReasons
|=
DISCARD_REASON_MAX_INPUT_SIZE_EXCEEDED
;
}
}
return
codecInfo
.
canKeepCodec
(
oldFormat
,
newFormat
);
return
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
oldFormat
,
newFormat
,
discardReasons
!=
0
?
REUSE_RESULT_NO
:
evaluation
.
result
,
discardReasons
);
}
}
@CallSuper
@CallSuper
...
@@ -621,9 +633,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -621,9 +633,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
}
@Override
@Override
protected
void
onInputFormatChanged
(
FormatHolder
formatHolder
)
throws
ExoPlaybackException
{
@Nullable
super
.
onInputFormatChanged
(
formatHolder
);
protected
DecoderReuseEvaluation
onInputFormatChanged
(
FormatHolder
formatHolder
)
eventDispatcher
.
inputFormatChanged
(
formatHolder
.
format
);
throws
ExoPlaybackException
{
@Nullable
DecoderReuseEvaluation
evaluation
=
super
.
onInputFormatChanged
(
formatHolder
);
eventDispatcher
.
inputFormatChanged
(
formatHolder
.
format
,
evaluation
);
return
evaluation
;
}
}
/**
/**
...
@@ -1333,7 +1348,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
...
@@ -1333,7 +1348,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// from format to avoid codec re-use being ruled out for only this reason.
// from format to avoid codec re-use being ruled out for only this reason.
streamFormat
=
streamFormat
.
buildUpon
().
setColorInfo
(
format
.
colorInfo
).
build
();
streamFormat
=
streamFormat
.
buildUpon
().
setColorInfo
(
format
.
colorInfo
).
build
();
}
}
if
(
codecInfo
.
can
KeepCodec
(
format
,
streamFormat
)
!=
KEEP_CODEC
_RESULT_NO
)
{
if
(
codecInfo
.
can
ReuseCodec
(
format
,
streamFormat
).
result
!=
REUSE
_RESULT_NO
)
{
haveUnknownDimensions
|=
haveUnknownDimensions
|=
(
streamFormat
.
width
==
Format
.
NO_VALUE
||
streamFormat
.
height
==
Format
.
NO_VALUE
);
(
streamFormat
.
width
==
Format
.
NO_VALUE
||
streamFormat
.
height
==
Format
.
NO_VALUE
);
maxWidth
=
max
(
maxWidth
,
streamFormat
.
width
);
maxWidth
=
max
(
maxWidth
,
streamFormat
.
width
);
...
...
library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java
View file @
c47e6220
...
@@ -25,6 +25,7 @@ import androidx.annotation.Nullable;
...
@@ -25,6 +25,7 @@ import androidx.annotation.Nullable;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Renderer
;
import
com.google.android.exoplayer2.Renderer
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderCounters
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.util.Assertions
;
import
com.google.android.exoplayer2.util.Assertions
;
/**
/**
...
@@ -52,12 +53,23 @@ public interface VideoRendererEventListener {
...
@@ -52,12 +53,23 @@ public interface VideoRendererEventListener {
default
void
onVideoDecoderInitialized
(
default
void
onVideoDecoderInitialized
(
String
decoderName
,
long
initializedTimestampMs
,
long
initializationDurationMs
)
{}
String
decoderName
,
long
initializedTimestampMs
,
long
initializationDurationMs
)
{}
/** @deprecated Use {@link #onVideoInputFormatChanged(Format, DecoderReuseEvaluation)}. */
@Deprecated
default
void
onVideoInputFormatChanged
(
Format
format
)
{}
/**
/**
* Called when the format of the media being consumed by the renderer changes.
* Called when the format of the media being consumed by the renderer changes.
*
*
* @param format The new format.
* @param format The new format.
* @param decoderReuseEvaluation The result of the evaluation to determine whether an existing
* decoder instance can be reused for the new format, or {@code null} if the renderer did not
* have a decoder.
*/
*/
default
void
onVideoInputFormatChanged
(
Format
format
)
{}
@SuppressWarnings
(
"deprecation"
)
default
void
onVideoInputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
onVideoInputFormatChanged
(
format
);
}
/**
/**
* Called to report the number of frames dropped by the renderer. Dropped frames are reported
* Called to report the number of frames dropped by the renderer. Dropped frames are reported
...
@@ -172,10 +184,15 @@ public interface VideoRendererEventListener {
...
@@ -172,10 +184,15 @@ public interface VideoRendererEventListener {
}
}
}
}
/** Invokes {@link VideoRendererEventListener#onVideoInputFormatChanged(Format)}. */
/**
public
void
inputFormatChanged
(
Format
format
)
{
* Invokes {@link VideoRendererEventListener#onVideoInputFormatChanged(Format,
* DecoderReuseEvaluation)}.
*/
public
void
inputFormatChanged
(
Format
format
,
@Nullable
DecoderReuseEvaluation
decoderReuseEvaluation
)
{
if
(
handler
!=
null
)
{
if
(
handler
!=
null
)
{
handler
.
post
(()
->
castNonNull
(
listener
).
onVideoInputFormatChanged
(
format
));
handler
.
post
(
()
->
castNonNull
(
listener
).
onVideoInputFormatChanged
(
format
,
decoderReuseEvaluation
));
}
}
}
}
...
...
library/core/src/test/java/com/google/android/exoplayer2/mediacodec/MediaCodecInfoTest.java
View file @
c47e6220
...
@@ -15,9 +15,15 @@
...
@@ -15,9 +15,15 @@
*/
*/
package
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
package
com
.
google
.
android
.
exoplayer2
.
mediacodec
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_YES_WITH_FLUSH
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_INITIALIZATION_DATA_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
mediacodec
.
MediaCodecInfo
.
KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_MIME_TYPE_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_VIDEO_RESOLUTION_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
DISCARD_REASON_VIDEO_ROTATION_CHANGED
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_NO
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITH_FLUSH
;
import
static
com
.
google
.
android
.
exoplayer2
.
decoder
.
DecoderReuseEvaluation
.
REUSE_RESULT_YES_WITH_RECONFIGURATION
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
MimeTypes
.
AUDIO_AAC
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
MimeTypes
.
AUDIO_AAC
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
MimeTypes
.
VIDEO_AV1
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
MimeTypes
.
VIDEO_AV1
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
MimeTypes
.
VIDEO_H264
;
import
static
com
.
google
.
android
.
exoplayer2
.
util
.
MimeTypes
.
VIDEO_H264
;
...
@@ -26,6 +32,7 @@ import static com.google.common.truth.Truth.assertThat;
...
@@ -26,6 +32,7 @@ import static com.google.common.truth.Truth.assertThat;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.C
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.Format
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.video.ColorInfo
;
import
com.google.android.exoplayer2.video.ColorInfo
;
import
com.google.common.collect.ImmutableList
;
import
com.google.common.collect.ImmutableList
;
import
org.junit.Test
;
import
org.junit.Test
;
...
@@ -71,7 +78,14 @@ public final class MediaCodecInfoTest {
...
@@ -71,7 +78,14 @@ public final class MediaCodecInfoTest {
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
true
);
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
true
);
Format
hdAv1Format
=
FORMAT_H264_HD
.
buildUpon
().
setSampleMimeType
(
VIDEO_AV1
).
build
();
Format
hdAv1Format
=
FORMAT_H264_HD
.
buildUpon
().
setSampleMimeType
(
VIDEO_AV1
).
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_H264_HD
,
hdAv1Format
)).
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_H264_HD
,
hdAv1Format
))
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_H264_HD
,
hdAv1Format
,
REUSE_RESULT_NO
,
DISCARD_REASON_MIME_TYPE_CHANGED
));
}
}
@Test
@Test
...
@@ -79,24 +93,42 @@ public final class MediaCodecInfoTest {
...
@@ -79,24 +93,42 @@ public final class MediaCodecInfoTest {
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
true
);
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
true
);
Format
hdRotatedFormat
=
FORMAT_H264_HD
.
buildUpon
().
setRotationDegrees
(
90
).
build
();
Format
hdRotatedFormat
=
FORMAT_H264_HD
.
buildUpon
().
setRotationDegrees
(
90
).
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_H264_HD
,
hdRotatedFormat
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_H264_HD
,
hdRotatedFormat
))
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_H264_HD
,
hdRotatedFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_VIDEO_ROTATION_CHANGED
));
}
}
@Test
@Test
public
void
canKeepCodec_withResolutionChange_adaptiveCodec_returnsYesWithReconfiguration
()
{
public
void
canKeepCodec_withResolutionChange_adaptiveCodec_returnsYesWithReconfiguration
()
{
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
true
);
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
true
);
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_H264_HD
,
FORMAT_H264_4K
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_H264_HD
,
FORMAT_H264_4K
))
.
isEqualTo
(
KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_H264_HD
,
FORMAT_H264_4K
,
REUSE_RESULT_YES_WITH_RECONFIGURATION
,
/* discardReasons= */
0
));
}
}
@Test
@Test
public
void
canKeepCodec_withResolutionChange_nonAdaptiveCodec_returnsNo
()
{
public
void
canKeepCodec_withResolutionChange_nonAdaptiveCodec_returnsNo
()
{
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
false
);
MediaCodecInfo
codecInfo
=
buildH264CodecInfo
(
/* adaptive= */
false
);
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_H264_HD
,
FORMAT_H264_4K
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_H264_HD
,
FORMAT_H264_4K
))
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_H264_HD
,
FORMAT_H264_4K
,
REUSE_RESULT_NO
,
DISCARD_REASON_VIDEO_RESOLUTION_CHANGED
));
}
}
@Test
@Test
...
@@ -105,8 +137,14 @@ public final class MediaCodecInfoTest {
...
@@ -105,8 +137,14 @@ public final class MediaCodecInfoTest {
Format
hdVariantFormat
=
Format
hdVariantFormat
=
FORMAT_H264_HD
.
buildUpon
().
setInitializationData
(
ImmutableList
.
of
(
new
byte
[]
{
0
})).
build
();
FORMAT_H264_HD
.
buildUpon
().
setInitializationData
(
ImmutableList
.
of
(
new
byte
[]
{
0
})).
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_H264_HD
,
hdVariantFormat
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_H264_HD
,
hdVariantFormat
))
.
isEqualTo
(
KEEP_CODEC_RESULT_YES_WITH_RECONFIGURATION
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_H264_HD
,
hdVariantFormat
,
REUSE_RESULT_YES_WITH_RECONFIGURATION
,
/* discardReasons= */
0
));
}
}
@Test
@Test
...
@@ -115,8 +153,14 @@ public final class MediaCodecInfoTest {
...
@@ -115,8 +153,14 @@ public final class MediaCodecInfoTest {
Format
hdrVariantFormat
=
Format
hdrVariantFormat
=
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT601
)).
build
();
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT601
)).
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
hdrVariantFormat
,
FORMAT_H264_4K
))
assertThat
(
codecInfo
.
canReuseCodec
(
hdrVariantFormat
,
FORMAT_H264_4K
))
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
hdrVariantFormat
,
FORMAT_H264_4K
,
REUSE_RESULT_NO
,
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
));
}
}
@Test
@Test
...
@@ -125,8 +169,14 @@ public final class MediaCodecInfoTest {
...
@@ -125,8 +169,14 @@ public final class MediaCodecInfoTest {
Format
hdrVariantFormat
=
Format
hdrVariantFormat
=
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT601
)).
build
();
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT601
)).
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_H264_4K
,
hdrVariantFormat
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_H264_4K
,
hdrVariantFormat
))
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_H264_4K
,
hdrVariantFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
));
}
}
@Test
@Test
...
@@ -137,18 +187,28 @@ public final class MediaCodecInfoTest {
...
@@ -137,18 +187,28 @@ public final class MediaCodecInfoTest {
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT601
)).
build
();
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT601
)).
build
();
Format
hdrVariantFormat2
=
Format
hdrVariantFormat2
=
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT709
)).
build
();
FORMAT_H264_4K
.
buildUpon
().
setColorInfo
(
buildColorInfo
(
C
.
COLOR_SPACE_BT709
)).
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
hdrVariantFormat1
,
hdrVariantFormat2
))
assertThat
(
codecInfo
.
canReuseCodec
(
hdrVariantFormat1
,
hdrVariantFormat2
))
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
.
isEqualTo
(
assertThat
(
codecInfo
.
canKeepCodec
(
hdrVariantFormat1
,
hdrVariantFormat2
))
new
DecoderReuseEvaluation
(
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
codecInfo
.
name
,
hdrVariantFormat1
,
hdrVariantFormat2
,
REUSE_RESULT_NO
,
DISCARD_REASON_VIDEO_COLOR_INFO_CHANGED
));
}
}
@Test
@Test
public
void
canKeepCodec_audioWithDifferentChannelCounts_returnsNo
()
{
public
void
canKeepCodec_audioWithDifferentChannelCounts_returnsNo
()
{
MediaCodecInfo
codecInfo
=
buildAacCodecInfo
();
MediaCodecInfo
codecInfo
=
buildAacCodecInfo
();
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_AAC_STEREO
,
FORMAT_AAC_SURROUND
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_AAC_STEREO
,
FORMAT_AAC_SURROUND
))
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_AAC_STEREO
,
FORMAT_AAC_SURROUND
,
REUSE_RESULT_NO
,
DISCARD_REASON_AUDIO_CHANNEL_COUNT_CHANGED
));
}
}
@Test
@Test
...
@@ -156,8 +216,14 @@ public final class MediaCodecInfoTest {
...
@@ -156,8 +216,14 @@ public final class MediaCodecInfoTest {
MediaCodecInfo
codecInfo
=
buildAacCodecInfo
();
MediaCodecInfo
codecInfo
=
buildAacCodecInfo
();
Format
stereoVariantFormat
=
FORMAT_AAC_STEREO
.
buildUpon
().
setAverageBitrate
(
100
).
build
();
Format
stereoVariantFormat
=
FORMAT_AAC_STEREO
.
buildUpon
().
setAverageBitrate
(
100
).
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_AAC_STEREO
,
stereoVariantFormat
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_AAC_STEREO
,
stereoVariantFormat
))
.
isEqualTo
(
KEEP_CODEC_RESULT_YES_WITH_FLUSH
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_AAC_STEREO
,
stereoVariantFormat
,
REUSE_RESULT_YES_WITH_FLUSH
,
/* discardReasons= */
0
));
}
}
@Test
@Test
...
@@ -169,8 +235,14 @@ public final class MediaCodecInfoTest {
...
@@ -169,8 +235,14 @@ public final class MediaCodecInfoTest {
.
buildUpon
()
.
buildUpon
()
.
setInitializationData
(
ImmutableList
.
of
(
new
byte
[]
{
0
}))
.
setInitializationData
(
ImmutableList
.
of
(
new
byte
[]
{
0
}))
.
build
();
.
build
();
assertThat
(
codecInfo
.
canKeepCodec
(
FORMAT_AAC_STEREO
,
stereoVariantFormat
))
assertThat
(
codecInfo
.
canReuseCodec
(
FORMAT_AAC_STEREO
,
stereoVariantFormat
))
.
isEqualTo
(
KEEP_CODEC_RESULT_NO
);
.
isEqualTo
(
new
DecoderReuseEvaluation
(
codecInfo
.
name
,
FORMAT_AAC_STEREO
,
stereoVariantFormat
,
REUSE_RESULT_NO
,
DISCARD_REASON_INITIALIZATION_DATA_CHANGED
));
}
}
@Test
@Test
...
...
playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DebugRenderersFactory.java
View file @
c47e6220
...
@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.Format;
...
@@ -30,6 +30,7 @@ import com.google.android.exoplayer2.Format;
import
com.google.android.exoplayer2.FormatHolder
;
import
com.google.android.exoplayer2.FormatHolder
;
import
com.google.android.exoplayer2.Renderer
;
import
com.google.android.exoplayer2.Renderer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderInputBuffer
;
import
com.google.android.exoplayer2.decoder.DecoderReuseEvaluation
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecAdapter
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecAdapter
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecInfo
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecSelector
;
import
com.google.android.exoplayer2.mediacodec.MediaCodecSelector
;
...
@@ -165,12 +166,15 @@ import java.util.ArrayList;
...
@@ -165,12 +166,15 @@ import java.util.ArrayList;
}
}
@Override
@Override
protected
void
onInputFormatChanged
(
FormatHolder
formatHolder
)
throws
ExoPlaybackException
{
@Nullable
super
.
onInputFormatChanged
(
formatHolder
);
protected
DecoderReuseEvaluation
onInputFormatChanged
(
FormatHolder
formatHolder
)
throws
ExoPlaybackException
{
@Nullable
DecoderReuseEvaluation
evaluation
=
super
.
onInputFormatChanged
(
formatHolder
);
// Ensure timestamps of buffers queued after this format change are never inserted into the
// Ensure timestamps of buffers queued after this format change are never inserted into the
// queue of expected output timestamps before those of buffers that have already been queued.
// queue of expected output timestamps before those of buffers that have already been queued.
minimumInsertIndex
=
startIndex
+
queueSize
;
minimumInsertIndex
=
startIndex
+
queueSize
;
inputFormatChanged
=
true
;
inputFormatChanged
=
true
;
return
evaluation
;
}
}
@Override
@Override
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAudioRenderer.java
View file @
c47e6220
...
@@ -55,7 +55,7 @@ public class FakeAudioRenderer extends FakeRenderer {
...
@@ -55,7 +55,7 @@ public class FakeAudioRenderer extends FakeRenderer {
@Override
@Override
protected
void
onFormatChanged
(
Format
format
)
{
protected
void
onFormatChanged
(
Format
format
)
{
eventDispatcher
.
inputFormatChanged
(
format
);
eventDispatcher
.
inputFormatChanged
(
format
,
/* decoderReuseEvaluation= */
null
);
eventDispatcher
.
decoderInitialized
(
eventDispatcher
.
decoderInitialized
(
/* decoderName= */
"fake.audio.decoder"
,
/* decoderName= */
"fake.audio.decoder"
,
/* initializedTimestampMs= */
SystemClock
.
elapsedRealtime
(),
/* initializedTimestampMs= */
SystemClock
.
elapsedRealtime
(),
...
...
testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeVideoRenderer.java
View file @
c47e6220
...
@@ -85,7 +85,7 @@ public class FakeVideoRenderer extends FakeRenderer {
...
@@ -85,7 +85,7 @@ public class FakeVideoRenderer extends FakeRenderer {
@Override
@Override
protected
void
onFormatChanged
(
Format
format
)
{
protected
void
onFormatChanged
(
Format
format
)
{
eventDispatcher
.
inputFormatChanged
(
format
);
eventDispatcher
.
inputFormatChanged
(
format
,
/* decoderReuseEvaluation= */
null
);
eventDispatcher
.
decoderInitialized
(
eventDispatcher
.
decoderInitialized
(
/* decoderName= */
"fake.video.decoder"
,
/* decoderName= */
"fake.video.decoder"
,
/* initializedTimestampMs= */
SystemClock
.
elapsedRealtime
(),
/* initializedTimestampMs= */
SystemClock
.
elapsedRealtime
(),
...
...
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