Decouple output size listener and setting output surface

This is because `onOutputSizeChanged()` should in theory be called on the
listener executor.

PiperOrigin-RevId: 566591784
This commit is contained in:
claincly 2023-09-19 04:40:30 -07:00 committed by Copybara-Service
parent 0c918d2c47
commit 24e700c216
4 changed files with 39 additions and 13 deletions

View File

@ -40,6 +40,7 @@ import androidx.media3.common.Effect;
import androidx.media3.common.FrameInfo; import androidx.media3.common.FrameInfo;
import androidx.media3.common.GlObjectsProvider; import androidx.media3.common.GlObjectsProvider;
import androidx.media3.common.GlTextureInfo; import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.SurfaceInfo;
import androidx.media3.common.VideoFrameProcessingException; import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.VideoFrameProcessor; import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.util.Consumer; import androidx.media3.common.util.Consumer;
@ -195,8 +196,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Override @Override
public void onOutputSizeChanged(int width, int height) { public void onOutputSizeChanged(int width, int height) {
checkNotNull(compositionVideoFrameProcessor) listenerExecutor.execute(() -> listener.onOutputSizeChanged(width, height));
.setOutputSurfaceInfo(listener.onOutputSizeChanged(width, height));
} }
@Override @Override
@ -297,6 +297,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
return preProcessingVideoFrameProcessorWrapper; return preProcessingVideoFrameProcessorWrapper;
} }
@Override
public void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo) {
checkNotNull(compositionVideoFrameProcessor).setOutputSurfaceInfo(outputSurfaceInfo);
}
@Override @Override
public boolean hasProducedFrameWithTimestampZero() { public boolean hasProducedFrameWithTimestampZero() {
return hasProducedFrameWithTimestampZero; return hasProducedFrameWithTimestampZero;

View File

@ -25,6 +25,7 @@ import androidx.media3.common.ColorInfo;
import androidx.media3.common.DebugViewProvider; import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Effect; import androidx.media3.common.Effect;
import androidx.media3.common.FrameInfo; import androidx.media3.common.FrameInfo;
import androidx.media3.common.SurfaceInfo;
import androidx.media3.common.VideoFrameProcessingException; import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.VideoFrameProcessor; import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.util.Consumer; import androidx.media3.common.util.Consumer;
@ -157,9 +158,7 @@ import java.util.concurrent.Executor;
@Override @Override
public void onOutputSizeChanged(int width, int height) { public void onOutputSizeChanged(int width, int height) {
// TODO: b/289986435 - Allow setting output surface info on VideoGraph. listenerExecutor.execute(() -> listener.onOutputSizeChanged(width, height));
checkNotNull(videoFrameProcessingWrapper)
.setOutputSurfaceInfo(listener.onOutputSizeChanged(width, height));
} }
@Override @Override
@ -188,6 +187,11 @@ import java.util.concurrent.Executor;
return videoFrameProcessingWrapper; return videoFrameProcessingWrapper;
} }
@Override
public void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo) {
checkNotNull(videoFrameProcessingWrapper).setOutputSurfaceInfo(outputSurfaceInfo);
}
@Override @Override
public boolean hasProducedFrameWithTimestampZero() { public boolean hasProducedFrameWithTimestampZero() {
return hasProducedFrameWithTimestampZero; return hasProducedFrameWithTimestampZero;

View File

@ -68,12 +68,8 @@ import java.util.concurrent.Executor;
* *
* @param width The new output width in pixels. * @param width The new output width in pixels.
* @param height The new output width in pixels. * @param height The new output width in pixels.
* @return A {@link SurfaceInfo} to which the {@link VideoGraph} renders to, or {@code null} if
* the output is not needed.
*/ */
// TODO - b/289985577: Consider returning void from this method. void onOutputSizeChanged(int width, int height);
@Nullable
SurfaceInfo onOutputSizeChanged(int width, int height);
/** Called after the {@link VideoGraph} has rendered its final output frame. */ /** Called after the {@link VideoGraph} has rendered its final output frame. */
void onEnded(long finalFramePresentationTimeUs); void onEnded(long finalFramePresentationTimeUs);
@ -108,6 +104,23 @@ import java.util.concurrent.Executor;
*/ */
GraphInput createInput() throws VideoFrameProcessingException; GraphInput createInput() throws VideoFrameProcessingException;
/**
* Sets the output surface and supporting information.
*
* <p>The new output {@link SurfaceInfo} is applied from the next output frame rendered onwards.
* If the output {@link SurfaceInfo} is {@code null}, the {@code VideoGraph} will stop rendering
* pending frames and resume rendering once a non-null {@link SurfaceInfo} is set.
*
* <p>If the dimensions given in {@link SurfaceInfo} do not match the {@linkplain
* Listener#onOutputSizeChanged(int,int) output size after applying the final effect} the frames
* are resized before rendering to the surface and letter/pillar-boxing is applied.
*
* <p>The caller is responsible for tracking the lifecycle of the {@link SurfaceInfo#surface}
* including calling this method with a new surface if it is destroyed. When this method returns,
* the previous output surface is no longer being used and can safely be released by the caller.
*/
void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo);
/** /**
* Returns whether the {@code VideoGraph} has produced a frame with zero presentation timestamp. * Returns whether the {@code VideoGraph} has produced a frame with zero presentation timestamp.
*/ */

View File

@ -498,16 +498,15 @@ import org.checkerframework.dataflow.qual.Pure;
initialTimestampOffsetUs); initialTimestampOffsetUs);
} }
@Nullable
@Override @Override
public SurfaceInfo onOutputSizeChanged(int width, int height) { public void onOutputSizeChanged(int width, int height) {
@Nullable SurfaceInfo surfaceInfo = null; @Nullable SurfaceInfo surfaceInfo = null;
try { try {
surfaceInfo = encoderWrapper.getSurfaceInfo(width, height); surfaceInfo = encoderWrapper.getSurfaceInfo(width, height);
} catch (ExportException e) { } catch (ExportException e) {
errorConsumer.accept(e); errorConsumer.accept(e);
} }
return surfaceInfo; setOutputSurfaceInfo(surfaceInfo);
} }
@Override @Override
@ -535,6 +534,11 @@ import org.checkerframework.dataflow.qual.Pure;
return videoGraph.createInput(); return videoGraph.createInput();
} }
@Override
public void setOutputSurfaceInfo(@Nullable SurfaceInfo outputSurfaceInfo) {
videoGraph.setOutputSurfaceInfo(outputSurfaceInfo);
}
@Override @Override
public boolean hasProducedFrameWithTimestampZero() { public boolean hasProducedFrameWithTimestampZero() {
return videoGraph.hasProducedFrameWithTimestampZero(); return videoGraph.hasProducedFrameWithTimestampZero();