Simplify VideoSink.handleInputFrame

This method was taking positionUs and elapsedRealtimeUs parameters and
throwing a VideoSinkException because it was calling render() to make
room for a new input frame. Instead of doing that, this CL makes sure
render() is called before  handleInputFrame() in the renderer (even
though it may not make a significant difference).

PiperOrigin-RevId: 702273587
This commit is contained in:
kimvde 2024-12-03 03:26:19 -08:00 committed by Copybara-Service
parent 675c1d898a
commit 0037388660
5 changed files with 20 additions and 53 deletions

View File

@ -205,11 +205,7 @@ import java.util.concurrent.Executor;
@Override @Override
public boolean handleInputFrame( public boolean handleInputFrame(
long framePresentationTimeUs, long framePresentationTimeUs, boolean isLastFrame, VideoFrameHandler videoFrameHandler) {
boolean isLastFrame,
long positionUs,
long elapsedRealtimeUs,
VideoFrameHandler videoFrameHandler) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -1096,15 +1096,16 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@CallSuper @CallSuper
@Override @Override
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException { public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
super.render(positionUs, elapsedRealtimeUs);
if (videoSink != null) { if (videoSink != null) {
try { try {
// Drain the sink to make room for a new input frame.
videoSink.render(positionUs, elapsedRealtimeUs); videoSink.render(positionUs, elapsedRealtimeUs);
} catch (VideoSink.VideoSinkException e) { } catch (VideoSink.VideoSinkException e) {
throw createRendererException( throw createRendererException(
e, e.format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED); e, e.format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED);
} }
} }
super.render(positionUs, elapsedRealtimeUs);
} }
@CallSuper @CallSuper
@ -1464,12 +1465,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
if (videoSink != null) { if (videoSink != null) {
long framePresentationTimeUs = bufferPresentationTimeUs + getBufferTimestampAdjustmentUs(); long framePresentationTimeUs = bufferPresentationTimeUs + getBufferTimestampAdjustmentUs();
try {
return videoSink.handleInputFrame( return videoSink.handleInputFrame(
framePresentationTimeUs, framePresentationTimeUs,
isLastBuffer, isLastBuffer,
positionUs,
elapsedRealtimeUs,
new VideoSink.VideoFrameHandler() { new VideoSink.VideoFrameHandler() {
@Override @Override
public void render(long renderTimestampNs) { public void render(long renderTimestampNs) {
@ -1481,10 +1479,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
skipOutputBuffer(codec, bufferIndex, presentationTimeUs); skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
} }
}); });
} catch (VideoSink.VideoSinkException e) {
throw createRendererException(
e, e.format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED);
}
} }
// The frame release action should be retrieved for all frames (even the ones that will be // The frame release action should be retrieved for all frames (even the ones that will be

View File

@ -734,12 +734,7 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
@Override @Override
public boolean handleInputFrame( public boolean handleInputFrame(
long framePresentationTimeUs, long framePresentationTimeUs, boolean isLastFrame, VideoFrameHandler videoFrameHandler) {
boolean isLastFrame,
long positionUs,
long elapsedRealtimeUs,
VideoFrameHandler videoFrameHandler)
throws VideoSinkException {
checkState(isInitialized()); checkState(isInitialized());
// The sink takes in frames with monotonically increasing, non-offset frame // The sink takes in frames with monotonically increasing, non-offset frame
@ -758,9 +753,6 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
return true; return true;
} }
// Drain the sink to make room for a new input frame.
render(positionUs, elapsedRealtimeUs);
if (checkStateNotNull(videoFrameProcessor).getPendingInputFrameCount() if (checkStateNotNull(videoFrameProcessor).getPendingInputFrameCount()
>= videoFrameProcessorMaxPendingFrameCount) { >= videoFrameProcessorMaxPendingFrameCount) {
return false; return false;

View File

@ -18,7 +18,6 @@ package androidx.media3.exoplayer.video;
import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.ElementType.TYPE_USE;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.os.SystemClock;
import android.view.Surface; import android.view.Surface;
import androidx.annotation.FloatRange; import androidx.annotation.FloatRange;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
@ -270,20 +269,12 @@ public interface VideoSink {
* @param isLastFrame Whether this is the last frame of the video stream. This flag is set on a * @param isLastFrame Whether this is the last frame of the video stream. This flag is set on a
* best effort basis, and any logic relying on it should degrade gracefully to handle cases * best effort basis, and any logic relying on it should degrade gracefully to handle cases
* where it's not set. * where it's not set.
* @param positionUs The current playback position, in microseconds.
* @param elapsedRealtimeUs {@link SystemClock#elapsedRealtime()} in microseconds, taken
* approximately at the time the playback position was {@code positionUs}.
* @param videoFrameHandler The {@link VideoFrameHandler} used to handle the input frame. * @param videoFrameHandler The {@link VideoFrameHandler} used to handle the input frame.
* @return Whether the frame was handled successfully. If {@code false}, the caller can try again * @return Whether the frame was handled successfully. If {@code false}, the caller can try again
* later. * later.
*/ */
boolean handleInputFrame( boolean handleInputFrame(
long framePresentationTimeUs, long framePresentationTimeUs, boolean isLastFrame, VideoFrameHandler videoFrameHandler);
boolean isLastFrame,
long positionUs,
long elapsedRealtimeUs,
VideoFrameHandler videoFrameHandler)
throws VideoSinkException;
/** /**
* Handles an input {@link Bitmap}. * Handles an input {@link Bitmap}.

View File

@ -217,15 +217,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override @Override
public boolean handleInputFrame( public boolean handleInputFrame(
long framePresentationTimeUs, long framePresentationTimeUs, boolean isLastFrame, VideoFrameHandler videoFrameHandler) {
boolean isLastFrame,
long positionUs,
long elapsedRealtimeUs,
VideoFrameHandler videoFrameHandler)
throws VideoSinkException {
return videoSink != null return videoSink != null
&& videoSink.handleInputFrame( && videoSink.handleInputFrame(framePresentationTimeUs, isLastFrame, videoFrameHandler);
framePresentationTimeUs, isLastFrame, positionUs, elapsedRealtimeUs, videoFrameHandler);
} }
@Override @Override