Use WORKING_COLOR_SPACE_DEFAULT in multi-sequence compositions

Build upon Transformer.videoFrameProcessorFactory in MultipleInputVideoGraph
Check that Transformer.videoFrameProcessorFactory is DefaultVideoFrameProcessor
for multi-input video

Fixes https://github.com/androidx/media/issues/1509

PiperOrigin-RevId: 655232381
This commit is contained in:
dancho 2024-07-23 11:11:03 -07:00 committed by Copybara-Service
parent 9a42d03466
commit 7103f21da9
11 changed files with 46 additions and 18 deletions

View File

@ -17,6 +17,7 @@
package androidx.media3.effect; package androidx.media3.effect;
import static androidx.media3.common.VideoFrameProcessor.INPUT_TYPE_TEXTURE_ID; import static androidx.media3.common.VideoFrameProcessor.INPUT_TYPE_TEXTURE_ID;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull; import static androidx.media3.common.util.Assertions.checkStateNotNull;
@ -25,7 +26,6 @@ import static androidx.media3.common.util.Util.newSingleThreadScheduledExecutor;
import static androidx.media3.effect.DebugTraceUtil.COMPONENT_COMPOSITOR; import static androidx.media3.effect.DebugTraceUtil.COMPONENT_COMPOSITOR;
import static androidx.media3.effect.DebugTraceUtil.COMPONENT_VFP; import static androidx.media3.effect.DebugTraceUtil.COMPONENT_VFP;
import static androidx.media3.effect.DebugTraceUtil.EVENT_OUTPUT_TEXTURE_RENDERED; import static androidx.media3.effect.DebugTraceUtil.EVENT_OUTPUT_TEXTURE_RENDERED;
import static androidx.media3.effect.DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.Context; import android.content.Context;
@ -99,6 +99,7 @@ public abstract class MultipleInputVideoGraph implements VideoGraph {
protected MultipleInputVideoGraph( protected MultipleInputVideoGraph(
Context context, Context context,
VideoFrameProcessor.Factory videoFrameProcessorFactory,
ColorInfo outputColorInfo, ColorInfo outputColorInfo,
DebugViewProvider debugViewProvider, DebugViewProvider debugViewProvider,
Listener listener, Listener listener,
@ -106,6 +107,7 @@ public abstract class MultipleInputVideoGraph implements VideoGraph {
VideoCompositorSettings videoCompositorSettings, VideoCompositorSettings videoCompositorSettings,
List<Effect> compositionEffects, List<Effect> compositionEffects,
long initialTimestampOffsetUs) { long initialTimestampOffsetUs) {
checkArgument(videoFrameProcessorFactory instanceof DefaultVideoFrameProcessor.Factory);
this.context = context; this.context = context;
this.outputColorInfo = outputColorInfo; this.outputColorInfo = outputColorInfo;
this.debugViewProvider = debugViewProvider; this.debugViewProvider = debugViewProvider;
@ -118,10 +120,10 @@ public abstract class MultipleInputVideoGraph implements VideoGraph {
preProcessors = new SparseArray<>(); preProcessors = new SparseArray<>();
sharedExecutorService = newSingleThreadScheduledExecutor(SHARED_EXECUTOR_NAME); sharedExecutorService = newSingleThreadScheduledExecutor(SHARED_EXECUTOR_NAME);
glObjectsProvider = new SingleContextGlObjectsProvider(); glObjectsProvider = new SingleContextGlObjectsProvider();
// TODO - b/289986435: Support injecting VideoFrameProcessor.Factory. // TODO - b/289986435: Support injecting arbitrary VideoFrameProcessor.Factory.
videoFrameProcessorFactory = this.videoFrameProcessorFactory =
new DefaultVideoFrameProcessor.Factory.Builder() ((DefaultVideoFrameProcessor.Factory) videoFrameProcessorFactory)
.setSdrWorkingColorSpace(WORKING_COLOR_SPACE_LINEAR) .buildUpon()
.setGlObjectsProvider(glObjectsProvider) .setGlObjectsProvider(glObjectsProvider)
.setExecutorService(sharedExecutorService) .setExecutorService(sharedExecutorService)
.build(); .build();

View File

@ -43,7 +43,6 @@ import androidx.media3.effect.Presentation;
import androidx.media3.effect.ScaleAndRotateTransformation; import androidx.media3.effect.ScaleAndRotateTransformation;
import androidx.media3.effect.VideoCompositorSettings; import androidx.media3.effect.VideoCompositorSettings;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -53,9 +52,12 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TestName; import org.junit.rules.TestName;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
/** Tests for using multiple {@link EditedMediaItemSequence} in a composition. */ /** Tests for using multiple {@link EditedMediaItemSequence} in a composition. */
@RunWith(AndroidJUnit4.class) @RunWith(Parameterized.class)
public final class TransformerMultiSequenceCompositionTest { public final class TransformerMultiSequenceCompositionTest {
// Bitmaps are generated on a Pixel 6 or 7 Pro instead of an emulator, due to an emulator bug. // Bitmaps are generated on a Pixel 6 or 7 Pro instead of an emulator, due to an emulator bug.
@ -69,11 +71,18 @@ public final class TransformerMultiSequenceCompositionTest {
private static final int EXPORT_WIDTH = 360; private static final int EXPORT_WIDTH = 360;
private static final int EXPORT_HEIGHT = 240; private static final int EXPORT_HEIGHT = 240;
@Parameters(name = "{0}")
public static ImmutableList<Boolean> workingColorSpaceLinear() {
return ImmutableList.of(false, true);
}
private final Context context = ApplicationProvider.getApplicationContext(); private final Context context = ApplicationProvider.getApplicationContext();
@Rule public final TestName testName = new TestName(); @Rule public final TestName testName = new TestName();
private String testId; private String testId;
@Parameter public boolean workingColorSpaceLinear;
@Before @Before
public void setUpTestId() { public void setUpTestId() {
testId = testName.getMethodName(); testId = testName.getMethodName();
@ -106,7 +115,7 @@ public final class TransformerMultiSequenceCompositionTest {
VideoCompositorSettings.DEFAULT); VideoCompositorSettings.DEFAULT);
ExportTestResult result = ExportTestResult result =
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer()) new TransformerAndroidTestRunner.Builder(context, buildTransformer())
.build() .build()
.run(testId, composition); .run(testId, composition);
@ -142,7 +151,7 @@ public final class TransformerMultiSequenceCompositionTest {
VideoCompositorSettings.DEFAULT); VideoCompositorSettings.DEFAULT);
ExportTestResult result = ExportTestResult result =
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer()) new TransformerAndroidTestRunner.Builder(context, buildTransformer())
.build() .build()
.run(testId, composition); .run(testId, composition);
@ -200,7 +209,7 @@ public final class TransformerMultiSequenceCompositionTest {
pictureInPictureVideoCompositorSettings); pictureInPictureVideoCompositorSettings);
ExportTestResult result = ExportTestResult result =
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer()) new TransformerAndroidTestRunner.Builder(context, buildTransformer())
.build() .build()
.run(testId, composition); .run(testId, composition);
@ -209,14 +218,16 @@ public final class TransformerMultiSequenceCompositionTest {
extractBitmapsFromVideo(context, checkNotNull(result.filePath)), testId); extractBitmapsFromVideo(context, checkNotNull(result.filePath)), testId);
} }
private Transformer getLinearColorSpaceTransformer() { private Transformer buildTransformer() {
// Use linear color space for grayscale effects. // Use linear color space for grayscale effects.
return new Transformer.Builder(context) Transformer.Builder builder = new Transformer.Builder(context);
.setVideoFrameProcessorFactory( if (workingColorSpaceLinear) {
builder.setVideoFrameProcessorFactory(
new DefaultVideoFrameProcessor.Factory.Builder() new DefaultVideoFrameProcessor.Factory.Builder()
.setSdrWorkingColorSpace(DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR) .setSdrWorkingColorSpace(DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR)
.build()) .build());
.build(); }
return builder.build();
} }
private static EditedMediaItem editedMediaItemByClippingVideo(String uri, List<Effect> effects) { private static EditedMediaItem editedMediaItemByClippingVideo(String uri, List<Effect> effects) {

View File

@ -463,6 +463,10 @@ public final class Transformer {
* <p>If passing in a {@link DefaultVideoFrameProcessor.Factory}, the caller must not {@link * <p>If passing in a {@link DefaultVideoFrameProcessor.Factory}, the caller must not {@link
* DefaultVideoFrameProcessor.Factory.Builder#setTextureOutput set the texture output}. * DefaultVideoFrameProcessor.Factory.Builder#setTextureOutput set the texture output}.
* *
* <p>If exporting a {@link Composition} with multiple video {@linkplain EditedMediaItemSequence
* sequences}, the {@link VideoFrameProcessor.Factory} must be a {@link
* DefaultVideoFrameProcessor.Factory}.
*
* @param videoFrameProcessorFactory A {@link VideoFrameProcessor.Factory}. * @param videoFrameProcessorFactory A {@link VideoFrameProcessor.Factory}.
* @return This builder. * @return This builder.
*/ */

View File

@ -21,6 +21,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.VideoFrameProcessingException; import androidx.media3.common.VideoFrameProcessingException;
import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.VideoGraph; import androidx.media3.common.VideoGraph;
import androidx.media3.effect.MultipleInputVideoGraph; import androidx.media3.effect.MultipleInputVideoGraph;
import androidx.media3.effect.VideoCompositorSettings; import androidx.media3.effect.VideoCompositorSettings;
@ -36,6 +37,13 @@ import java.util.concurrent.Executor;
/** A factory for creating {@link TransformerMultipleInputVideoGraph} instances. */ /** A factory for creating {@link TransformerMultipleInputVideoGraph} instances. */
public static final class Factory implements TransformerVideoGraph.Factory { public static final class Factory implements TransformerVideoGraph.Factory {
private final VideoFrameProcessor.Factory videoFrameProcessorFactory;
public Factory(VideoFrameProcessor.Factory videoFrameProcessorFactory) {
this.videoFrameProcessorFactory = videoFrameProcessorFactory;
}
@Override @Override
public TransformerMultipleInputVideoGraph create( public TransformerMultipleInputVideoGraph create(
Context context, Context context,
@ -48,6 +56,7 @@ import java.util.concurrent.Executor;
long initialTimestampOffsetUs) { long initialTimestampOffsetUs) {
return new TransformerMultipleInputVideoGraph( return new TransformerMultipleInputVideoGraph(
context, context,
videoFrameProcessorFactory,
outputColorInfo, outputColorInfo,
debugViewProvider, debugViewProvider,
listener, listener,
@ -60,6 +69,7 @@ import java.util.concurrent.Executor;
private TransformerMultipleInputVideoGraph( private TransformerMultipleInputVideoGraph(
Context context, Context context,
VideoFrameProcessor.Factory videoFrameProcessorFactory,
ColorInfo outputColorInfo, ColorInfo outputColorInfo,
DebugViewProvider debugViewProvider, DebugViewProvider debugViewProvider,
Listener listener, Listener listener,
@ -69,6 +79,7 @@ import java.util.concurrent.Executor;
long initialTimestampOffsetUs) { long initialTimestampOffsetUs) {
super( super(
context, context,
videoFrameProcessorFactory,
outputColorInfo, outputColorInfo,
debugViewProvider, debugViewProvider,
listener, listener,

View File

@ -136,7 +136,7 @@ import org.checkerframework.dataflow.qual.Pure;
new VideoGraphWrapper( new VideoGraphWrapper(
context, context,
hasMultipleInputs hasMultipleInputs
? new TransformerMultipleInputVideoGraph.Factory() ? new TransformerMultipleInputVideoGraph.Factory(videoFrameProcessorFactory)
: new TransformerSingleInputVideoGraph.Factory(videoFrameProcessorFactory), : new TransformerSingleInputVideoGraph.Factory(videoFrameProcessorFactory),
videoGraphOutputColor, videoGraphOutputColor,
errorConsumer, errorConsumer,