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