mirror of
https://github.com/samsonjs/media.git
synced 2026-03-26 09:35:47 +00:00
Tweak video renderer surface swaps
Fixes the following issues: 1. When a surface is set, it's expected that the renderer will notify video size + when a frame is rendered to it. This is true even if the surface isn't changing. Right now this is achieved by setting renderedFirstFrame to false, but this is problematic in the case that the surface isn't changing because (a) it will force rendering of a subsequent frame to the output even when paused, which is incorrect, and (b) isReady will return false until this occurs. 2. When the surface really is changing, isReady can return false until the first frame has been rendered into the new surface, which will break seamless surface switching. This change allows isReady to return true up to allowedJoiningTimeMs for this case. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=154171111
This commit is contained in:
parent
e07b8fe7d5
commit
fb88087ac4
2 changed files with 98 additions and 25 deletions
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in a new issue