Compositor: Move Settings to DefaultVideoCompositor.

This previously was in the VideoCompositor class, but wasn't
referenced at all from that interface.

PiperOrigin-RevId: 565409646
This commit is contained in:
huangdarwin 2023-09-14 10:31:14 -07:00 committed by Copybara-Service
parent 03b793e2ee
commit 5ef5d46708
5 changed files with 83 additions and 49 deletions

View File

@ -76,19 +76,6 @@ public final class DefaultVideoCompositor implements VideoCompositor {
// * Add support for mixing SDR streams with different ColorInfo. // * Add support for mixing SDR streams with different ColorInfo.
// * Add support for HDR input. // * Add support for HDR input.
/** A default implementation of {@link VideoCompositor.Settings}. */
public static final class Settings implements VideoCompositor.Settings {
@Override
public Size getOutputSize(List<Size> inputSizes) {
return inputSizes.get(PRIMARY_INPUT_ID);
}
@Override
public OverlaySettings getOverlaySettings(int inputId, long presentationTimeUs) {
return new OverlaySettings.Builder().build();
}
}
private static final String THREAD_NAME = "Effect:DefaultVideoCompositor:GlThread"; private static final String THREAD_NAME = "Effect:DefaultVideoCompositor:GlThread";
private static final String TAG = "DefaultVideoCompositor"; private static final String TAG = "DefaultVideoCompositor";
private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl"; private static final String VERTEX_SHADER_PATH = "shaders/vertex_shader_transformation_es2.glsl";
@ -99,7 +86,7 @@ public final class DefaultVideoCompositor implements VideoCompositor {
private final VideoCompositor.Listener listener; private final VideoCompositor.Listener listener;
private final GlTextureProducer.Listener textureOutputListener; private final GlTextureProducer.Listener textureOutputListener;
private final GlObjectsProvider glObjectsProvider; private final GlObjectsProvider glObjectsProvider;
private final VideoCompositor.Settings settings; private final VideoCompositorSettings settings;
private final OverlayMatrixProvider overlayMatrixProvider; private final OverlayMatrixProvider overlayMatrixProvider;
private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor; private final VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor;
@ -130,7 +117,7 @@ public final class DefaultVideoCompositor implements VideoCompositor {
public DefaultVideoCompositor( public DefaultVideoCompositor(
Context context, Context context,
GlObjectsProvider glObjectsProvider, GlObjectsProvider glObjectsProvider,
VideoCompositor.Settings settings, VideoCompositorSettings settings,
@Nullable ExecutorService executorService, @Nullable ExecutorService executorService,
VideoCompositor.Listener listener, VideoCompositor.Listener listener,
GlTextureProducer.Listener textureOutputListener, GlTextureProducer.Listener textureOutputListener,

View File

@ -18,9 +18,7 @@ package androidx.media3.effect;
import androidx.media3.common.ColorInfo; import androidx.media3.common.ColorInfo;
import androidx.media3.common.GlTextureInfo; import androidx.media3.common.GlTextureInfo;
import androidx.media3.common.VideoFrameProcessingException; import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import java.util.List;
/** /**
* Interface for a video compositor that combines frames from multiple input sources to produce * Interface for a video compositor that combines frames from multiple input sources to produce
@ -47,23 +45,6 @@ public interface VideoCompositor extends GlTextureProducer {
void onEnded(); void onEnded();
} }
/** Settings for the {@link VideoCompositor}. */
interface Settings {
// TODO: b/262694346 - Consider adding more features, like selecting a:
// * custom order for drawing (instead of primary stream on top), and
// * different primary source.
/**
* Returns an output texture {@link Size}, based on {@code inputSizes}.
*
* @param inputSizes The {@link Size} of each input frame, ordered by {@code inputId}.
*/
Size getOutputSize(List<Size> inputSizes);
/** Returns {@link OverlaySettings} for {@code inputId} at time {@code presentationTimeUs}. */
OverlaySettings getOverlaySettings(int inputId, long presentationTimeUs);
}
/** /**
* Registers a new input source, and returns a unique {@code inputId} corresponding to this * Registers a new input source, and returns a unique {@code inputId} corresponding to this
* source, to be used in {@link #queueInputTexture}. * source, to be used in {@link #queueInputTexture}.

View File

@ -0,0 +1,61 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.effect;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.UnstableApi;
import java.util.List;
/** Settings for the {@link VideoCompositor}. */
@UnstableApi
public interface VideoCompositorSettings {
// TODO: b/262694346 - Consider adding more features, like selecting a:
// * custom order for drawing (instead of primary stream on top), and
// * different primary source.
VideoCompositorSettings DEFAULT =
new VideoCompositorSettings() {
/**
* {@inheritDoc}
*
* <p>Returns the primary stream's {@link Size}.
*/
@Override
public Size getOutputSize(List<Size> inputSizes) {
return inputSizes.get(0);
}
/**
* {@inheritDoc}
*
* <p>Returns a default {@link OverlaySettings} instance.
*/
@Override
public OverlaySettings getOverlaySettings(int inputId, long presentationTimeUs) {
return new OverlaySettings.Builder().build();
}
};
/**
* Returns an output texture {@link Size}, based on {@code inputSizes}.
*
* @param inputSizes The {@link Size} of each input frame, ordered by {@code inputId}.
*/
Size getOutputSize(List<Size> inputSizes);
/** Returns {@link OverlaySettings} for {@code inputId} at time {@code presentationTimeUs}. */
OverlaySettings getOverlaySettings(int inputId, long presentationTimeUs);
}

View File

@ -58,6 +58,7 @@ import androidx.media3.effect.RgbFilter;
import androidx.media3.effect.ScaleAndRotateTransformation; import androidx.media3.effect.ScaleAndRotateTransformation;
import androidx.media3.effect.TextOverlay; import androidx.media3.effect.TextOverlay;
import androidx.media3.effect.VideoCompositor; import androidx.media3.effect.VideoCompositor;
import androidx.media3.effect.VideoCompositorSettings;
import androidx.media3.test.utils.BitmapPixelTestUtil; import androidx.media3.test.utils.BitmapPixelTestUtil;
import androidx.media3.test.utils.TextureBitmapReader; import androidx.media3.test.utils.TextureBitmapReader;
import androidx.media3.test.utils.VideoFrameProcessorTestRunner; import androidx.media3.test.utils.VideoFrameProcessorTestRunner;
@ -548,8 +549,8 @@ public final class DefaultVideoCompositorPixelTest {
public void compositeTwoInputs_pictureInPicture_matchesExpectedBitmap() throws Exception { public void compositeTwoInputs_pictureInPicture_matchesExpectedBitmap() throws Exception {
ImmutableList<ImmutableList<Effect>> inputEffectLists = ImmutableList<ImmutableList<Effect>> inputEffectLists =
ImmutableList.of(ImmutableList.of(), ImmutableList.of(RgbFilter.createGrayscaleFilter())); ImmutableList.of(ImmutableList.of(), ImmutableList.of(RgbFilter.createGrayscaleFilter()));
VideoCompositor.Settings pictureInPictureSettings = VideoCompositorSettings pictureInPictureVideoCompositorSettings =
new VideoCompositor.Settings() { new VideoCompositorSettings() {
@Override @Override
public Size getOutputSize(List<Size> inputSizes) { public Size getOutputSize(List<Size> inputSizes) {
return inputSizes.get(0); return inputSizes.get(0);
@ -573,7 +574,7 @@ public final class DefaultVideoCompositorPixelTest {
}; };
compositorTestRunner = compositorTestRunner =
new VideoCompositorTestRunner( new VideoCompositorTestRunner(
testId, useSharedExecutor, inputEffectLists, pictureInPictureSettings); testId, useSharedExecutor, inputEffectLists, pictureInPictureVideoCompositorSettings);
compositorTestRunner.queueBitmapToAllInputs(1); compositorTestRunner.queueBitmapToAllInputs(1);
compositorTestRunner.endCompositing(); compositorTestRunner.endCompositing();
@ -590,8 +591,8 @@ public final class DefaultVideoCompositorPixelTest {
ImmutableList.of( ImmutableList.of(
Presentation.createForWidthAndHeight(100, 100, Presentation.LAYOUT_STRETCH_TO_FIT)), Presentation.createForWidthAndHeight(100, 100, Presentation.LAYOUT_STRETCH_TO_FIT)),
ImmutableList.of(RgbFilter.createGrayscaleFilter())); ImmutableList.of(RgbFilter.createGrayscaleFilter()));
VideoCompositor.Settings secondStreamAsOutputSizeSettings = VideoCompositorSettings secondStreamAsOutputSizeVideoCompositorSettings =
new VideoCompositor.Settings() { new VideoCompositorSettings() {
@Override @Override
public Size getOutputSize(List<Size> inputSizes) { public Size getOutputSize(List<Size> inputSizes) {
return Iterables.getLast(inputSizes); return Iterables.getLast(inputSizes);
@ -604,7 +605,10 @@ public final class DefaultVideoCompositorPixelTest {
}; };
compositorTestRunner = compositorTestRunner =
new VideoCompositorTestRunner( new VideoCompositorTestRunner(
testId, useSharedExecutor, inputEffectLists, secondStreamAsOutputSizeSettings); testId,
useSharedExecutor,
inputEffectLists,
secondStreamAsOutputSizeVideoCompositorSettings);
compositorTestRunner.queueBitmapToAllInputs(1); compositorTestRunner.queueBitmapToAllInputs(1);
compositorTestRunner.endCompositing(); compositorTestRunner.endCompositing();
@ -621,8 +625,8 @@ public final class DefaultVideoCompositorPixelTest {
ImmutableList.of(RgbFilter.createGrayscaleFilter()), ImmutableList.of(RgbFilter.createGrayscaleFilter()),
ImmutableList.of(), ImmutableList.of(),
ImmutableList.of(RgbFilter.createInvertedFilter())); ImmutableList.of(RgbFilter.createInvertedFilter()));
VideoCompositor.Settings stackedFrameSettings = VideoCompositorSettings stackedFrameVideoCompositorSettings =
new VideoCompositor.Settings() { new VideoCompositorSettings() {
private static final int NUMBER_OF_INPUT_STREAMS = 3; private static final int NUMBER_OF_INPUT_STREAMS = 3;
@Override @Override
@ -647,7 +651,7 @@ public final class DefaultVideoCompositorPixelTest {
}; };
compositorTestRunner = compositorTestRunner =
new VideoCompositorTestRunner( new VideoCompositorTestRunner(
testId, useSharedExecutor, inputEffectLists, stackedFrameSettings); testId, useSharedExecutor, inputEffectLists, stackedFrameVideoCompositorSettings);
compositorTestRunner.queueBitmapToAllInputs(1); compositorTestRunner.queueBitmapToAllInputs(1);
compositorTestRunner.endCompositing(); compositorTestRunner.endCompositing();
@ -673,7 +677,7 @@ public final class DefaultVideoCompositorPixelTest {
private final String testId; private final String testId;
/** /**
* Creates an instance using {@link DefaultVideoCompositor.Settings}. * Creates an instance using {@link VideoCompositorSettings}.
* *
* @param testId The {@link String} identifier for the test, used to name output files. * @param testId The {@link String} identifier for the test, used to name output files.
* @param useSharedExecutor Whether to use a shared executor for {@link * @param useSharedExecutor Whether to use a shared executor for {@link
@ -688,7 +692,7 @@ public final class DefaultVideoCompositorPixelTest {
boolean useSharedExecutor, boolean useSharedExecutor,
ImmutableList<ImmutableList<Effect>> inputEffectLists) ImmutableList<ImmutableList<Effect>> inputEffectLists)
throws GlUtil.GlException, VideoFrameProcessingException { throws GlUtil.GlException, VideoFrameProcessingException {
this(testId, useSharedExecutor, inputEffectLists, new DefaultVideoCompositor.Settings()); this(testId, useSharedExecutor, inputEffectLists, VideoCompositorSettings.DEFAULT);
} }
/** /**
@ -701,13 +705,13 @@ public final class DefaultVideoCompositorPixelTest {
* The size of this outer {@link List} is the amount of inputs. One inner list of {@link * The size of this outer {@link List} is the amount of inputs. One inner list of {@link
* Effect}s is used for each input. For each input, the frame timestamp and {@code inputId} * Effect}s is used for each input. For each input, the frame timestamp and {@code inputId}
* are overlaid via {@link TextOverlay} prior to its effects being applied. * are overlaid via {@link TextOverlay} prior to its effects being applied.
* @param settings The {@link VideoCompositor.Settings}. * @param videoCompositorSettings The {@link VideoCompositorSettings}.
*/ */
public VideoCompositorTestRunner( public VideoCompositorTestRunner(
String testId, String testId,
boolean useSharedExecutor, boolean useSharedExecutor,
ImmutableList<ImmutableList<Effect>> inputEffectLists, ImmutableList<ImmutableList<Effect>> inputEffectLists,
VideoCompositor.Settings settings) VideoCompositorSettings videoCompositorSettings)
throws GlUtil.GlException, VideoFrameProcessingException { throws GlUtil.GlException, VideoFrameProcessingException {
this.testId = testId; this.testId = testId;
timeoutMs = inputEffectLists.size() * VIDEO_FRAME_PROCESSING_WAIT_MS; timeoutMs = inputEffectLists.size() * VIDEO_FRAME_PROCESSING_WAIT_MS;
@ -725,7 +729,7 @@ public final class DefaultVideoCompositorPixelTest {
new DefaultVideoCompositor( new DefaultVideoCompositor(
getApplicationContext(), getApplicationContext(),
glObjectsProvider, glObjectsProvider,
settings, videoCompositorSettings,
sharedExecutorService, sharedExecutorService,
new VideoCompositor.Listener() { new VideoCompositor.Listener() {
@Override @Override

View File

@ -49,6 +49,7 @@ import androidx.media3.effect.DefaultVideoCompositor;
import androidx.media3.effect.DefaultVideoFrameProcessor; import androidx.media3.effect.DefaultVideoFrameProcessor;
import androidx.media3.effect.GlTextureProducer; import androidx.media3.effect.GlTextureProducer;
import androidx.media3.effect.VideoCompositor; import androidx.media3.effect.VideoCompositor;
import androidx.media3.effect.VideoCompositorSettings;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
@ -225,7 +226,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
new DefaultVideoCompositor( new DefaultVideoCompositor(
context, context,
glObjectsProvider, glObjectsProvider,
new DefaultVideoCompositor.Settings(), VideoCompositorSettings.DEFAULT,
sharedExecutorService, sharedExecutorService,
new VideoCompositor.Listener() { new VideoCompositor.Listener() {
// All of this listener's methods are called on the sharedExecutorService. // All of this listener's methods are called on the sharedExecutorService.