diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java index 2f3517b35a..c44c703bb1 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer2/ext/vp9/LibvpxVideoRenderer.java @@ -464,13 +464,16 @@ public final class LibvpxVideoRenderer extends BaseRenderer { protected void onPositionReset(long positionUs, boolean joining) { inputStreamEnded = false; outputStreamEnded = false; - renderedFirstFrame = false; + clearRenderedFirstFrame(); consecutiveDroppedFrameCount = 0; if (decoder != null) { flushDecoder(); } - joiningDeadlineMs = joining && allowedJoiningTimeMs > 0 - ? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET; + if (joining) { + setJoiningDeadlineMs(); + } else { + joiningDeadlineMs = C.TIME_UNSET; + } } @Override @@ -492,6 +495,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { format = null; waitingForKeys = false; clearReportedVideoSize(); + clearRenderedFirstFrame(); try { releaseDecoder(); } finally { @@ -568,28 +572,44 @@ public final class LibvpxVideoRenderer extends BaseRenderer { private void setOutput(Surface surface, VpxOutputBufferRenderer outputBufferRenderer) { // At most one output may be non-null. Both may be null if the output is being cleared. Assertions.checkState(surface == null || outputBufferRenderer == null); - // We only need to update the decoder if the output has changed. if (this.surface != surface || this.outputBufferRenderer != outputBufferRenderer) { + // The output has changed. this.surface = surface; this.outputBufferRenderer = outputBufferRenderer; outputMode = outputBufferRenderer != null ? VpxDecoder.OUTPUT_MODE_YUV : surface != null ? VpxDecoder.OUTPUT_MODE_RGB : VpxDecoder.OUTPUT_MODE_NONE; - // If outputMode is OUTPUT_MODE_NONE we leave the mode of the underlying decoder unchanged in - // anticipation that a subsequent output will likely be of the same type as the one that was - // set previously. - if (decoder != null && outputMode != VpxDecoder.OUTPUT_MODE_NONE) { - decoder.setOutputMode(outputMode); + if (outputMode != VpxDecoder.OUTPUT_MODE_NONE) { + if (decoder != null) { + decoder.setOutputMode(outputMode); + } + // If we know the video size, report it again immediately. + maybeRenotifyVideoSizeChanged(); + // We haven't rendered to the new output yet. + clearRenderedFirstFrame(); + if (getState() == STATE_STARTED) { + setJoiningDeadlineMs(); + } + } else { + // The output has been removed. We leave the outputMode of the underlying decoder unchanged + // in anticipation that a subsequent output will likely be of the same type. + clearReportedVideoSize(); + clearRenderedFirstFrame(); } + } else if (outputMode != VpxDecoder.OUTPUT_MODE_NONE) { + // The output is unchanged and non-null. If we know the video size and/or have already + // rendered to the output, report these again immediately. + maybeRenotifyVideoSizeChanged(); + maybeRenotifyRenderedFirstFrame(); } - // Clear state so that we always call the event listener with the video size and when a frame - // is rendered, even if the output hasn't changed. - renderedFirstFrame = false; - clearReportedVideoSize(); } - private void clearReportedVideoSize() { - reportedWidth = Format.NO_VALUE; - reportedHeight = Format.NO_VALUE; + private void setJoiningDeadlineMs() { + joiningDeadlineMs = allowedJoiningTimeMs > 0 + ? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET; + } + + private void clearRenderedFirstFrame() { + renderedFirstFrame = false; } private void maybeNotifyRenderedFirstFrame() { @@ -599,6 +619,17 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } + private void maybeRenotifyRenderedFirstFrame() { + if (renderedFirstFrame) { + eventDispatcher.renderedFirstFrame(surface); + } + } + + private void clearReportedVideoSize() { + reportedWidth = Format.NO_VALUE; + reportedHeight = Format.NO_VALUE; + } + private void maybeNotifyVideoSizeChanged(int width, int height) { if (reportedWidth != width || reportedHeight != height) { reportedWidth = width; @@ -607,6 +638,12 @@ public final class LibvpxVideoRenderer extends BaseRenderer { } } + private void maybeRenotifyVideoSizeChanged() { + if (reportedWidth != Format.NO_VALUE || reportedHeight != Format.NO_VALUE) { + eventDispatcher.videoSizeChanged(reportedWidth, reportedHeight, 0, 1); + } + } + private void maybeNotifyDroppedFrames() { if (droppedFrames > 0) { long now = SystemClock.elapsedRealtime(); 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 a4985f066b..ac4bb36035 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 @@ -166,7 +166,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { currentPixelWidthHeightRatio = Format.NO_VALUE; pendingPixelWidthHeightRatio = Format.NO_VALUE; scalingMode = C.VIDEO_SCALING_MODE_DEFAULT; - clearLastReportedVideoSize(); + clearReportedVideoSize(); } @Override @@ -229,8 +229,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { super.onPositionReset(positionUs, joining); clearRenderedFirstFrame(); consecutiveDroppedFrameCount = 0; - joiningDeadlineMs = joining && allowedJoiningTimeMs > 0 - ? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET; + if (joining) { + setJoiningDeadlineMs(); + } else { + joiningDeadlineMs = C.TIME_UNSET; + } } @Override @@ -272,7 +275,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { currentHeight = Format.NO_VALUE; currentPixelWidthHeightRatio = Format.NO_VALUE; pendingPixelWidthHeightRatio = Format.NO_VALUE; - clearLastReportedVideoSize(); + clearReportedVideoSize(); + clearRenderedFirstFrame(); frameReleaseTimeHelper.disable(); tunnelingOnFrameRenderedListener = null; try { @@ -312,11 +316,25 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { maybeInitCodec(); } } + if (surface != null) { + // If we know the video size, report it again immediately. + maybeRenotifyVideoSizeChanged(); + // We haven't rendered to the new surface yet. + clearRenderedFirstFrame(); + if (state == STATE_STARTED) { + setJoiningDeadlineMs(); + } + } else { + // The surface has been removed. + clearReportedVideoSize(); + clearRenderedFirstFrame(); + } + } else if (surface != null) { + // The surface is unchanged and non-null. If we know the video size and/or have already + // rendered to the surface, report these again immediately. + maybeRenotifyVideoSizeChanged(); + maybeRenotifyRenderedFirstFrame(); } - // Clear state so that we always call the event listener with the video size and when a frame - // is rendered, even if the surface hasn't changed. - clearRenderedFirstFrame(); - clearLastReportedVideoSize(); } @Override @@ -521,6 +539,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { maybeNotifyRenderedFirstFrame(); } + private void setJoiningDeadlineMs() { + joiningDeadlineMs = allowedJoiningTimeMs > 0 + ? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET; + } + private void clearRenderedFirstFrame() { renderedFirstFrame = false; // The first frame notification is triggered by renderOutputBuffer or renderOutputBufferV21 for @@ -543,7 +566,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } } - private void clearLastReportedVideoSize() { + private void maybeRenotifyRenderedFirstFrame() { + if (renderedFirstFrame) { + eventDispatcher.renderedFirstFrame(surface); + } + } + + private void clearReportedVideoSize() { reportedWidth = Format.NO_VALUE; reportedHeight = Format.NO_VALUE; reportedPixelWidthHeightRatio = Format.NO_VALUE; @@ -563,6 +592,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { } } + private void maybeRenotifyVideoSizeChanged() { + if (reportedWidth != Format.NO_VALUE || reportedHeight != Format.NO_VALUE) { + eventDispatcher.videoSizeChanged(currentWidth, currentHeight, currentUnappliedRotationDegrees, + currentPixelWidthHeightRatio); + } + } + private void maybeNotifyDroppedFrames() { if (droppedFrames > 0) { long now = SystemClock.elapsedRealtime();