diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java b/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java index 10ffcc9f9f..c7b527481a 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Renderer.java @@ -215,9 +215,9 @@ public interface Renderer extends PlayerMessage.Target { @IntDef({STATE_DISABLED, STATE_ENABLED, STATE_STARTED}) @interface State {} /** - * The renderer is disabled. A renderer in this state may hold resources that it requires for - * rendering (e.g. media decoders), for use if it's subsequently enabled. {@link #reset()} can be - * called to force the renderer to release these resources. + * The renderer is disabled. A renderer in this state will not proactively acquire resources that + * it requires for rendering (e.g., media decoders), but may continue to hold any that it already + * has. {@link #reset()} can be called to force the renderer to release such resources. */ int STATE_DISABLED = 0; /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 147f277b8a..c09a43feb6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -2285,6 +2285,13 @@ public class SimpleExoPlayer extends BasePlayer } } + @Override + public void onVideoDecoderReleased(String decoderName) { + for (VideoRendererEventListener videoDebugListener : videoDebugListeners) { + videoDebugListener.onVideoDecoderReleased(decoderName); + } + } + @Override public void onVideoDisabled(DecoderCounters counters) { for (VideoRendererEventListener videoDebugListener : videoDebugListeners) { @@ -2351,6 +2358,13 @@ public class SimpleExoPlayer extends BasePlayer } } + @Override + public void onAudioDecoderReleased(String decoderName) { + for (AudioRendererEventListener audioDebugListener : audioDebugListeners) { + audioDebugListener.onAudioDecoderReleased(decoderName); + } + } + @Override public void onAudioDisabled(DecoderCounters counters) { for (AudioRendererEventListener audioDebugListener : audioDebugListeners) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index 4e46914c4b..b19ed00276 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -220,6 +220,12 @@ public class AnalyticsCollector listener.onAudioUnderrun(eventTime, bufferSize, bufferSizeMs, elapsedSinceLastFeedMs)); } + @Override + public final void onAudioDecoderReleased(String decoderName) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + listeners.sendEvent(listener -> listener.onAudioDecoderReleased(eventTime, decoderName)); + } + @SuppressWarnings("deprecation") @Override public final void onAudioDisabled(DecoderCounters counters) { @@ -307,6 +313,12 @@ public class AnalyticsCollector listeners.sendEvent(listener -> listener.onDroppedVideoFrames(eventTime, count, elapsedMs)); } + @Override + public final void onVideoDecoderReleased(String decoderName) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + listeners.sendEvent(listener -> listener.onVideoDecoderReleased(eventTime, decoderName)); + } + @SuppressWarnings("deprecation") @Override public final void onVideoDisabled(DecoderCounters counters) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java index 65e2abb582..26e93cc982 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java @@ -512,6 +512,14 @@ public interface AnalyticsListener { default void onAudioUnderrun( EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {} + /** + * Called when an audio renderer releases a decoder. + * + * @param eventTime The event time. + * @param decoderName The decoder that was released. + */ + default void onAudioDecoderReleased(EventTime eventTime, String decoderName) {} + /** * Called when an audio renderer is disabled. * @@ -600,6 +608,14 @@ public interface AnalyticsListener { */ default void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {} + /** + * Called when a video renderer releases a decoder. + * + * @param eventTime The event time. + * @param decoderName The decoder that was released. + */ + default void onVideoDecoderReleased(EventTime eventTime, String decoderName) {} + /** * Called when a video renderer is disabled. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java index e51948725b..31c3b1f0b3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java @@ -87,6 +87,13 @@ public interface AudioRendererEventListener { */ default void onAudioUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {} + /** + * Called when a decoder is released. + * + * @param decoderName The decoder that was released. + */ + default void onAudioDecoderReleased(String decoderName) {} + /** * Called when the renderer is disabled. * @@ -184,6 +191,13 @@ public interface AudioRendererEventListener { } } + /** Invokes {@link AudioRendererEventListener#onAudioDecoderReleased(String)}. */ + public void decoderReleased(String decoderName) { + if (handler != null) { + handler.post(() -> castNonNull(listener).onAudioDecoderReleased(decoderName)); + } + } + /** Invokes {@link AudioRendererEventListener#onAudioDisabled(DecoderCounters)}. */ public void disabled(DecoderCounters counters) { counters.ensureUpdated(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java index c8f3d958d6..cff2cd5a57 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java @@ -632,9 +632,10 @@ public abstract class DecoderAudioRenderer< decoderReinitializationState = REINITIALIZATION_STATE_NONE; decoderReceivedBuffers = false; if (decoder != null) { - decoder.release(); - decoder = null; decoderCounters.decoderReleaseCount++; + decoder.release(); + eventDispatcher.decoderReleased(decoder.getName()); + decoder = null; } setDecoderDrmSession(null); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index e051aa1a3f..55deaadd65 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -391,6 +391,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media eventDispatcher.decoderInitialized(name, initializedTimestampMs, initializationDurationMs); } + @Override + protected void onCodecReleased(String name) { + eventDispatcher.decoderReleased(name); + } + @Override protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException { super.onInputFormatChanged(formatHolder); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index d5092a8e51..89bdefba58 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -745,6 +745,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { if (codec != null) { decoderCounters.decoderReleaseCount++; codec.release(); + onCodecReleased(codecInfo.name); } } finally { codec = null; @@ -1384,6 +1385,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer { // Do nothing. } + /** + * Called when a {@link MediaCodec} has been released. + * + *
The default implementation is a no-op. + * + * @param name The name of the codec that was released. + */ + protected void onCodecReleased(String name) { + // Do nothing. + } + /** * Called when a new {@link Format} is read from the upstream {@link MediaPeriod}. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java index d3e61d0290..32fc0be8ed 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java @@ -342,6 +342,11 @@ public class EventLogger implements AnalyticsListener { /* throwable= */ null); } + @Override + public void onAudioDecoderReleased(EventTime eventTime, String decoderName) { + logd(eventTime, "audioDecoderReleased", decoderName); + } + @Override public void onAudioDisabled(EventTime eventTime, DecoderCounters counters) { logd(eventTime, "audioDisabled"); @@ -397,6 +402,11 @@ public class EventLogger implements AnalyticsListener { logd(eventTime, "droppedFrames", Integer.toString(count)); } + @Override + public void onVideoDecoderReleased(EventTime eventTime, String decoderName) { + logd(eventTime, "videoDecoderReleased", decoderName); + } + @Override public void onVideoDisabled(EventTime eventTime, DecoderCounters counters) { logd(eventTime, "videoDisabled"); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java index 6fda6d2e9c..1e4aafa71c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/DecoderVideoRenderer.java @@ -311,22 +311,6 @@ public abstract class DecoderVideoRenderer extends BaseRenderer { super.onStreamChanged(formats, startPositionUs, offsetUs); } - /** - * Called when a decoder has been created and configured. - * - *
The default implementation is a no-op. - * - * @param name The name of the decoder that was initialized. - * @param initializedTimestampMs {@link SystemClock#elapsedRealtime()} when initialization - * finished. - * @param initializationDurationMs The time taken to initialize the decoder, in milliseconds. - */ - @CallSuper - protected void onDecoderInitialized( - String name, long initializedTimestampMs, long initializationDurationMs) { - eventDispatcher.decoderInitialized(name, initializedTimestampMs, initializationDurationMs); - } - /** * Flushes the decoder. * @@ -358,9 +342,10 @@ public abstract class DecoderVideoRenderer extends BaseRenderer { decoderReceivedBuffers = false; buffersInCodecCount = 0; if (decoder != null) { - decoder.release(); - decoder = null; decoderCounters.decoderReleaseCount++; + decoder.release(); + eventDispatcher.decoderReleased(decoder.getName()); + decoder = null; } setDecoderDrmSession(null); } @@ -690,7 +675,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer { decoder = createDecoder(inputFormat, mediaCrypto); setDecoderOutputMode(outputMode); long decoderInitializedTimestamp = SystemClock.elapsedRealtime(); - onDecoderInitialized( + eventDispatcher.decoderInitialized( decoder.getName(), decoderInitializedTimestamp, decoderInitializedTimestamp - decoderInitializingTimestamp); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java index 8eef603ca6..55415b5d33 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/MediaCodecVideoRenderer.java @@ -616,6 +616,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { Assertions.checkNotNull(getCodecInfo()).isHdr10PlusOutOfBandMetadataSupported(); } + @Override + protected void onCodecReleased(String name) { + eventDispatcher.decoderReleased(name); + } + @Override protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException { super.onInputFormatChanged(formatHolder); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java index 992a262dab..c714f3ca21 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/VideoRendererEventListener.java @@ -120,6 +120,13 @@ public interface VideoRendererEventListener { */ default void onRenderedFirstFrame(@Nullable Surface surface) {} + /** + * Called when a decoder is released. + * + * @param decoderName The decoder that was released. + */ + default void onVideoDecoderReleased(String decoderName) {} + /** * Called when the renderer is disabled. * @@ -211,6 +218,13 @@ public interface VideoRendererEventListener { } } + /** Invokes {@link VideoRendererEventListener#onVideoDecoderReleased(String)}. */ + public void decoderReleased(String decoderName) { + if (handler != null) { + handler.post(() -> castNonNull(listener).onVideoDecoderReleased(decoderName)); + } + } + /** Invokes {@link VideoRendererEventListener#onVideoDisabled(DecoderCounters)}. */ public void disabled(DecoderCounters counters) { counters.ensureUpdated();