Decouple displaySurface from placeholderSurface
We currently use displaySurface == placeholderSurface IF codec != null as a signal that the codec is configured with a placeholder. In the future, this placeholder might not be needed and we can decouple this state a bit better by leaving displaySurface == null in this case and only using placeholderSurface instead of null when setting a Surface to the codec. PiperOrigin-RevId: 652391729
This commit is contained in:
parent
d035b745cd
commit
e96ca5a242
@ -671,15 +671,18 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
new VideoSink.Listener() {
|
new VideoSink.Listener() {
|
||||||
@Override
|
@Override
|
||||||
public void onFirstFrameRendered(VideoSink videoSink) {
|
public void onFirstFrameRendered(VideoSink videoSink) {
|
||||||
checkStateNotNull(displaySurface);
|
if (displaySurface != null) {
|
||||||
notifyRenderedFirstFrame();
|
notifyRenderedFirstFrame();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFrameDropped(VideoSink videoSink) {
|
public void onFrameDropped(VideoSink videoSink) {
|
||||||
|
if (displaySurface != null) {
|
||||||
updateDroppedBufferCounters(
|
updateDroppedBufferCounters(
|
||||||
/* droppedInputBufferCount= */ 0, /* droppedDecoderBufferCount= */ 1);
|
/* droppedInputBufferCount= */ 0, /* droppedDecoderBufferCount= */ 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onVideoSizeChanged(VideoSink videoSink, VideoSize videoSize) {
|
public void onVideoSizeChanged(VideoSink videoSink, VideoSize videoSize) {
|
||||||
@ -797,10 +800,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
if (videoSink != null) {
|
if (videoSink != null) {
|
||||||
return videoSink.isReady(rendererOtherwiseReady);
|
return videoSink.isReady(rendererOtherwiseReady);
|
||||||
}
|
}
|
||||||
if (rendererOtherwiseReady
|
if (rendererOtherwiseReady && (getCodec() == null || displaySurface == null || tunneling)) {
|
||||||
&& ((placeholderSurface != null && displaySurface == placeholderSurface)
|
|
||||||
|| getCodec() == null
|
|
||||||
|| tunneling)) {
|
|
||||||
// Not releasing frames.
|
// Not releasing frames.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -862,11 +862,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
} finally {
|
} finally {
|
||||||
hasSetVideoSink = false;
|
hasSetVideoSink = false;
|
||||||
startPositionUs = C.TIME_UNSET;
|
startPositionUs = C.TIME_UNSET;
|
||||||
if (placeholderSurface != null) {
|
|
||||||
releasePlaceholderSurface();
|
releasePlaceholderSurface();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onRelease() {
|
protected void onRelease() {
|
||||||
@ -946,20 +944,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
// Handle unsupported (i.e., non-Surface) outputs by clearing the display surface.
|
// Handle unsupported (i.e., non-Surface) outputs by clearing the display surface.
|
||||||
@Nullable Surface displaySurface = output instanceof Surface ? (Surface) output : null;
|
@Nullable Surface displaySurface = output instanceof Surface ? (Surface) output : null;
|
||||||
|
|
||||||
if (displaySurface == null) {
|
|
||||||
// Use a placeholder surface if possible.
|
|
||||||
if (placeholderSurface != null) {
|
|
||||||
displaySurface = placeholderSurface;
|
|
||||||
} else {
|
|
||||||
MediaCodecInfo codecInfo = getCodecInfo();
|
|
||||||
if (codecInfo != null && shouldUsePlaceholderSurface(codecInfo)) {
|
|
||||||
placeholderSurface = PlaceholderSurface.newInstance(context, codecInfo.secure);
|
|
||||||
displaySurface = placeholderSurface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only need to update the codec if the display surface has changed.
|
|
||||||
if (this.displaySurface != displaySurface) {
|
if (this.displaySurface != displaySurface) {
|
||||||
this.displaySurface = displaySurface;
|
this.displaySurface = displaySurface;
|
||||||
if (videoSink == null) {
|
if (videoSink == null) {
|
||||||
@ -970,14 +954,16 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
@State int state = getState();
|
@State int state = getState();
|
||||||
@Nullable MediaCodecAdapter codec = getCodec();
|
@Nullable MediaCodecAdapter codec = getCodec();
|
||||||
if (codec != null && videoSink == null) {
|
if (codec != null && videoSink == null) {
|
||||||
if (Util.SDK_INT >= 23 && displaySurface != null && !codecNeedsSetOutputSurfaceWorkaround) {
|
MediaCodecInfo codecInfo = checkNotNull(getCodecInfo());
|
||||||
setOutputSurfaceV23(codec, displaySurface);
|
boolean canUpdateSurface = hasSurfaceForCodec(codecInfo);
|
||||||
|
if (Util.SDK_INT >= 23 && canUpdateSurface && !codecNeedsSetOutputSurfaceWorkaround) {
|
||||||
|
setOutputSurfaceV23(codec, getSurfaceForCodec(codecInfo));
|
||||||
} else {
|
} else {
|
||||||
releaseCodec();
|
releaseCodec();
|
||||||
maybeInitCodecOrBypass();
|
maybeInitCodecOrBypass();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (displaySurface != null && displaySurface != placeholderSurface) {
|
if (displaySurface != null) {
|
||||||
// If we know the video size, report it again immediately.
|
// If we know the video size, report it again immediately.
|
||||||
maybeRenotifyVideoSizeChanged();
|
maybeRenotifyVideoSizeChanged();
|
||||||
if (state == STATE_STARTED) {
|
if (state == STATE_STARTED) {
|
||||||
@ -999,7 +985,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
maybeSetupTunnelingForFirstFrame();
|
maybeSetupTunnelingForFirstFrame();
|
||||||
} else if (displaySurface != null && displaySurface != placeholderSurface) {
|
} else if (displaySurface != null) {
|
||||||
// The display surface is set and unchanged. If we know the video size and/or have already
|
// The display surface is set and unchanged. If we know the video size and/or have already
|
||||||
// rendered to the display surface, report these again immediately.
|
// rendered to the display surface, report these again immediately.
|
||||||
maybeRenotifyVideoSizeChanged();
|
maybeRenotifyVideoSizeChanged();
|
||||||
@ -1009,7 +995,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldInitCodec(MediaCodecInfo codecInfo) {
|
protected boolean shouldInitCodec(MediaCodecInfo codecInfo) {
|
||||||
return displaySurface != null || shouldUsePlaceholderSurface(codecInfo);
|
return hasSurfaceForCodec(codecInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1024,10 +1010,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
Format format,
|
Format format,
|
||||||
@Nullable MediaCrypto crypto,
|
@Nullable MediaCrypto crypto,
|
||||||
float codecOperatingRate) {
|
float codecOperatingRate) {
|
||||||
if (placeholderSurface != null && placeholderSurface.secure != codecInfo.secure) {
|
|
||||||
// We can't re-use the current DummySurface instance with the new decoder.
|
|
||||||
releasePlaceholderSurface();
|
|
||||||
}
|
|
||||||
String codecMimeType = codecInfo.codecMimeType;
|
String codecMimeType = codecInfo.codecMimeType;
|
||||||
codecMaxValues = getCodecMaxValues(codecInfo, format, getStreamFormats());
|
codecMaxValues = getCodecMaxValues(codecInfo, format, getStreamFormats());
|
||||||
MediaFormat mediaFormat =
|
MediaFormat mediaFormat =
|
||||||
@ -1038,22 +1020,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
codecOperatingRate,
|
codecOperatingRate,
|
||||||
deviceNeedsNoPostProcessWorkaround,
|
deviceNeedsNoPostProcessWorkaround,
|
||||||
tunneling ? tunnelingAudioSessionId : C.AUDIO_SESSION_ID_UNSET);
|
tunneling ? tunnelingAudioSessionId : C.AUDIO_SESSION_ID_UNSET);
|
||||||
if (displaySurface == null) {
|
Surface codecSurface = getSurfaceForCodec(codecInfo);
|
||||||
if (!shouldUsePlaceholderSurface(codecInfo)) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
if (placeholderSurface == null) {
|
|
||||||
placeholderSurface = PlaceholderSurface.newInstance(context, codecInfo.secure);
|
|
||||||
}
|
|
||||||
displaySurface = placeholderSurface;
|
|
||||||
}
|
|
||||||
maybeSetKeyAllowFrameDrop(mediaFormat);
|
maybeSetKeyAllowFrameDrop(mediaFormat);
|
||||||
return MediaCodecAdapter.Configuration.createForVideoDecoding(
|
return MediaCodecAdapter.Configuration.createForVideoDecoding(
|
||||||
codecInfo,
|
codecInfo, mediaFormat, format, codecSurface, crypto);
|
||||||
mediaFormat,
|
|
||||||
format,
|
|
||||||
videoSink != null ? videoSink.getInputSurface() : displaySurface,
|
|
||||||
crypto);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("InlinedApi") // VideoSink will check the API level
|
@SuppressWarnings("InlinedApi") // VideoSink will check the API level
|
||||||
@ -1505,7 +1475,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We are not rendering on a surface, the renderer will wait until a surface is set.
|
// We are not rendering on a surface, the renderer will wait until a surface is set.
|
||||||
if (displaySurface == placeholderSurface) {
|
if (displaySurface == null) {
|
||||||
// Skip frames in sync with playback, so we'll be at the right frame if the mode changes.
|
// Skip frames in sync with playback, so we'll be at the right frame if the mode changes.
|
||||||
if (videoFrameReleaseInfo.getEarlyUs() < 30_000) {
|
if (videoFrameReleaseInfo.getEarlyUs() < 30_000) {
|
||||||
skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
|
skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
|
||||||
@ -1843,6 +1813,32 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean hasSurfaceForCodec(MediaCodecInfo codecInfo) {
|
||||||
|
return displaySurface != null || shouldUsePlaceholderSurface(codecInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns surface to be set on the codec. Must only be called if {@link
|
||||||
|
* #hasSurfaceForCodec(MediaCodecInfo)} returns true.
|
||||||
|
*/
|
||||||
|
private Surface getSurfaceForCodec(MediaCodecInfo codecInfo) {
|
||||||
|
if (videoSink != null) {
|
||||||
|
return videoSink.getInputSurface();
|
||||||
|
} else if (displaySurface != null) {
|
||||||
|
return displaySurface;
|
||||||
|
} else {
|
||||||
|
checkState(shouldUsePlaceholderSurface(codecInfo));
|
||||||
|
if (placeholderSurface != null && placeholderSurface.secure != codecInfo.secure) {
|
||||||
|
// We can't re-use the current placeholder surface instance with the new decoder.
|
||||||
|
releasePlaceholderSurface();
|
||||||
|
}
|
||||||
|
if (placeholderSurface == null) {
|
||||||
|
placeholderSurface = PlaceholderSurface.newInstance(context, codecInfo.secure);
|
||||||
|
}
|
||||||
|
return placeholderSurface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean shouldUsePlaceholderSurface(MediaCodecInfo codecInfo) {
|
private boolean shouldUsePlaceholderSurface(MediaCodecInfo codecInfo) {
|
||||||
return Util.SDK_INT >= 23
|
return Util.SDK_INT >= 23
|
||||||
&& !tunneling
|
&& !tunneling
|
||||||
@ -1851,9 +1847,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void releasePlaceholderSurface() {
|
private void releasePlaceholderSurface() {
|
||||||
if (displaySurface == placeholderSurface) {
|
|
||||||
displaySurface = null;
|
|
||||||
}
|
|
||||||
if (placeholderSurface != null) {
|
if (placeholderSurface != null) {
|
||||||
placeholderSurface.release();
|
placeholderSurface.release();
|
||||||
placeholderSurface = null;
|
placeholderSurface = null;
|
||||||
|
@ -173,10 +173,6 @@ public final class VideoFrameReleaseHelper {
|
|||||||
* @param surface The new {@link Surface}, or {@code null} if the renderer does not have one.
|
* @param surface The new {@link Surface}, or {@code null} if the renderer does not have one.
|
||||||
*/
|
*/
|
||||||
public void onSurfaceChanged(@Nullable Surface surface) {
|
public void onSurfaceChanged(@Nullable Surface surface) {
|
||||||
if (surface instanceof PlaceholderSurface) {
|
|
||||||
// We don't care about dummy surfaces for release timing, since they're not visible.
|
|
||||||
surface = null;
|
|
||||||
}
|
|
||||||
if (this.surface == surface) {
|
if (this.surface == surface) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user