Call VideoFrameReleaseControl.isReady from VideoSink when enabled
PiperOrigin-RevId: 646385384
This commit is contained in:
parent
babc9c69c6
commit
304c4e41f8
@ -426,8 +426,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isReady() {
|
||||
return pendingFlushCount == 0 && videoFrameRenderControl.isReady();
|
||||
private boolean isReady(boolean rendererOtherwiseReady) {
|
||||
return videoFrameRenderControl.isReady(
|
||||
/* rendererOtherwiseReady= */ rendererOtherwiseReady && pendingFlushCount == 0);
|
||||
}
|
||||
|
||||
private boolean hasReleasedFrame(long presentationTimeUs) {
|
||||
@ -585,8 +586,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return isInitialized() && CompositingVideoSinkProvider.this.isReady();
|
||||
public boolean isReady(boolean rendererOtherwiseReady) {
|
||||
return CompositingVideoSinkProvider.this.isReady(
|
||||
/* rendererOtherwiseReady= */ rendererOtherwiseReady && isInitialized());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -748,15 +748,18 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
boolean readyToReleaseFrames = super.isReady() && (videoSink == null || videoSink.isReady());
|
||||
if (readyToReleaseFrames
|
||||
boolean rendererOtherwiseReady = super.isReady();
|
||||
if (videoSink != null) {
|
||||
return videoSink.isReady(rendererOtherwiseReady);
|
||||
}
|
||||
if (rendererOtherwiseReady
|
||||
&& ((placeholderSurface != null && displaySurface == placeholderSurface)
|
||||
|| getCodec() == null
|
||||
|| tunneling)) {
|
||||
// Not releasing frames.
|
||||
return true;
|
||||
}
|
||||
return videoFrameReleaseControl.isReady(readyToReleaseFrames);
|
||||
return videoFrameReleaseControl.isReady(rendererOtherwiseReady);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -277,12 +277,14 @@ public final class VideoFrameReleaseControl {
|
||||
/**
|
||||
* Whether the release control is ready to start playback.
|
||||
*
|
||||
* @see Renderer#isReady()
|
||||
* @param rendererReady Whether the renderer is ready.
|
||||
* <p>The renderer should be {@linkplain Renderer#isReady() ready} if and only if the release
|
||||
* control is ready.
|
||||
*
|
||||
* @param rendererOtherwiseReady Whether the renderer is ready except for the release control.
|
||||
* @return Whether the release control is ready.
|
||||
*/
|
||||
public boolean isReady(boolean rendererReady) {
|
||||
if (rendererReady && firstFrameState == C.FIRST_FRAME_RENDERED) {
|
||||
public boolean isReady(boolean rendererOtherwiseReady) {
|
||||
if (rendererOtherwiseReady && firstFrameState == C.FIRST_FRAME_RENDERED) {
|
||||
// Ready. If we were joining then we've now joined, so clear the joining deadline.
|
||||
joiningDeadlineMs = C.TIME_UNSET;
|
||||
return true;
|
||||
|
@ -123,8 +123,8 @@ import androidx.media3.exoplayer.ExoPlaybackException;
|
||||
}
|
||||
|
||||
/** Returns whether the renderer is ready. */
|
||||
public boolean isReady() {
|
||||
return videoFrameReleaseControl.isReady(/* rendererReady= */ true);
|
||||
public boolean isReady(boolean rendererOtherwiseReady) {
|
||||
return videoFrameReleaseControl.isReady(rendererOtherwiseReady);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,6 +28,7 @@ import androidx.media3.common.VideoSize;
|
||||
import androidx.media3.common.util.Size;
|
||||
import androidx.media3.common.util.TimestampIterator;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.exoplayer.Renderer;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -148,8 +149,13 @@ public interface VideoSink {
|
||||
|
||||
/**
|
||||
* Returns whether the video sink is able to immediately render media from the current position.
|
||||
*
|
||||
* <p>The renderer should be {@linkplain Renderer#isReady() ready} if and only if the video sink
|
||||
* is ready.
|
||||
*
|
||||
* @param rendererOtherwiseReady Whether the renderer is ready except for the video sink.
|
||||
*/
|
||||
boolean isReady();
|
||||
boolean isReady(boolean rendererOtherwiseReady);
|
||||
|
||||
/**
|
||||
* Returns whether all queued video frames have been rendered, including the frame marked as last
|
||||
|
@ -31,8 +31,8 @@ public class VideoFrameReleaseControlTest {
|
||||
public void isReady_onNewInstance_returnsFalse() {
|
||||
VideoFrameReleaseControl videoFrameReleaseControl = createVideoFrameReleaseControl();
|
||||
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ true)).isFalse();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ false)).isFalse();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ true)).isFalse();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ false)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -40,7 +40,7 @@ public class VideoFrameReleaseControlTest {
|
||||
VideoFrameReleaseControl videoFrameReleaseControl = createVideoFrameReleaseControl();
|
||||
|
||||
assertThat(videoFrameReleaseControl.onFrameReleasedIsFirstFrame()).isTrue();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ true)).isTrue();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ true)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -52,7 +52,7 @@ public class VideoFrameReleaseControlTest {
|
||||
|
||||
videoFrameReleaseControl.join(/* renderNextFrameImmediately= */ true);
|
||||
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ false)).isTrue();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ false)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -64,7 +64,7 @@ public class VideoFrameReleaseControlTest {
|
||||
|
||||
videoFrameReleaseControl.join(/* renderNextFrameImmediately= */ false);
|
||||
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ false)).isTrue();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ false)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -75,11 +75,11 @@ public class VideoFrameReleaseControlTest {
|
||||
videoFrameReleaseControl.setClock(clock);
|
||||
|
||||
videoFrameReleaseControl.join(/* renderNextFrameImmediately= */ true);
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ false)).isTrue();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ false)).isTrue();
|
||||
|
||||
clock.advanceTime(/* timeDiffMs= */ 101);
|
||||
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ false)).isFalse();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ false)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -90,11 +90,11 @@ public class VideoFrameReleaseControlTest {
|
||||
videoFrameReleaseControl.setClock(clock);
|
||||
|
||||
videoFrameReleaseControl.join(/* renderNextFrameImmediately= */ false);
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ false)).isTrue();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ false)).isTrue();
|
||||
|
||||
clock.advanceTime(/* timeDiffMs= */ 101);
|
||||
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ false)).isFalse();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ false)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -132,10 +132,10 @@ public class VideoFrameReleaseControlTest {
|
||||
VideoFrameReleaseControl videoFrameReleaseControl = createVideoFrameReleaseControl();
|
||||
|
||||
videoFrameReleaseControl.onFrameReleasedIsFirstFrame();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ true)).isTrue();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ true)).isTrue();
|
||||
videoFrameReleaseControl.reset();
|
||||
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererReady= */ true)).isFalse();
|
||||
assertThat(videoFrameReleaseControl.isReady(/* rendererOtherwiseReady= */ true)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -43,7 +43,7 @@ public class VideoFrameRenderControlTest {
|
||||
new VideoFrameRenderControl(
|
||||
mock(VideoFrameRenderControl.FrameRenderer.class), createVideoFrameReleaseControl());
|
||||
|
||||
assertThat(videoFrameRenderControl.isReady()).isFalse();
|
||||
assertThat(videoFrameRenderControl.isReady(/* rendererOtherwiseReady= */ true)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -60,7 +60,7 @@ public class VideoFrameRenderControlTest {
|
||||
videoFrameRenderControl.onOutputFrameAvailableForRendering(/* presentationTimeUs= */ 0);
|
||||
videoFrameRenderControl.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
||||
assertThat(videoFrameRenderControl.isReady()).isTrue();
|
||||
assertThat(videoFrameRenderControl.isReady(/* rendererOtherwiseReady= */ true)).isTrue();
|
||||
InOrder inOrder = Mockito.inOrder(frameRenderer);
|
||||
inOrder
|
||||
.verify(frameRenderer)
|
||||
@ -92,7 +92,7 @@ public class VideoFrameRenderControlTest {
|
||||
videoFrameRenderControl.onOutputFrameAvailableForRendering(/* presentationTimeUs= */ 10_000);
|
||||
|
||||
videoFrameRenderControl.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(videoFrameRenderControl.isReady()).isTrue();
|
||||
assertThat(videoFrameRenderControl.isReady(/* rendererOtherwiseReady= */ true)).isTrue();
|
||||
InOrder inOrder = Mockito.inOrder(frameRenderer);
|
||||
inOrder
|
||||
.verify(frameRenderer)
|
||||
@ -141,7 +141,7 @@ public class VideoFrameRenderControlTest {
|
||||
videoFrameRenderControl.onOutputFrameAvailableForRendering(/* presentationTimeUs= */ 0);
|
||||
videoFrameRenderControl.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
||||
assertThat(videoFrameRenderControl.isReady()).isTrue();
|
||||
assertThat(videoFrameRenderControl.isReady(/* rendererOtherwiseReady= */ true)).isTrue();
|
||||
InOrder inOrder = Mockito.inOrder(frameRenderer);
|
||||
inOrder
|
||||
.verify(frameRenderer)
|
||||
|
@ -48,7 +48,6 @@ import androidx.media3.exoplayer.source.MediaSource;
|
||||
import androidx.media3.exoplayer.text.TextOutput;
|
||||
import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
|
||||
import androidx.media3.exoplayer.video.MediaCodecVideoRenderer;
|
||||
import androidx.media3.exoplayer.video.VideoFrameReleaseControl;
|
||||
import androidx.media3.exoplayer.video.VideoRendererEventListener;
|
||||
import androidx.media3.exoplayer.video.VideoSink;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@ -296,7 +295,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
private final SequencePlayerRenderersWrapper sequencePlayerRenderersWrapper;
|
||||
private final CompositingVideoSinkProvider compositingVideoSinkProvider;
|
||||
private final VideoSink videoSink;
|
||||
private final VideoFrameReleaseControl videoFrameReleaseControl;
|
||||
|
||||
private ImmutableList<Effect> videoEffects;
|
||||
private @MonotonicNonNull ConstantRateTimestampIterator timestampIterator;
|
||||
@ -314,8 +312,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
compositingVideoSinkProvider =
|
||||
checkStateNotNull(sequencePlayerRenderersWrapper.compositingVideoSinkProvider);
|
||||
videoSink = compositingVideoSinkProvider.getSink();
|
||||
videoFrameReleaseControl =
|
||||
checkStateNotNull(compositingVideoSinkProvider.getVideoFrameReleaseControl());
|
||||
videoEffects = ImmutableList.of();
|
||||
streamOffsetUs = C.TIME_UNSET;
|
||||
}
|
||||
@ -357,11 +353,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
// If the renderer was enabled with mayRenderStartOfStream set to false, meaning the image
|
||||
// renderer is playing after a video, we don't need to wait until the first frame is rendered.
|
||||
// If the renderer was enabled with mayRenderStartOfStream, we must wait until the first frame
|
||||
// is rendered, which is checked by VideoSink.isReady().
|
||||
return super.isReady() && (!mayRenderStartOfStream || videoSink.isReady());
|
||||
if (mayRenderStartOfStream) {
|
||||
// The image renderer is not playing after a video. We must wait until the first frame is
|
||||
// rendered.
|
||||
return videoSink.isReady(/* rendererOtherwiseReady= */ super.isReady());
|
||||
} else {
|
||||
// The image renderer is playing after a video. We don't need to wait until the first frame
|
||||
// is rendered.
|
||||
return super.isReady();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user