diff --git a/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java b/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java
index a4b871a64f..b1ee267326 100644
--- a/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java
+++ b/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java
@@ -28,7 +28,12 @@ import java.lang.annotation.Target;
import java.util.Arrays;
import org.checkerframework.dataflow.qual.Pure;
-/** Stores color info. */
+/**
+ * Stores color info.
+ *
+ *
When a {@code null} {@code ColorInfo} instance is used, this often represents a generic {@link
+ * #SDR_BT709_LIMITED} instance.
+ */
@UnstableApi
public final class ColorInfo implements Bundleable {
diff --git a/libraries/common/src/main/java/androidx/media3/common/FrameProcessor.java b/libraries/common/src/main/java/androidx/media3/common/FrameProcessor.java
index 491545f933..c52bbb922e 100644
--- a/libraries/common/src/main/java/androidx/media3/common/FrameProcessor.java
+++ b/libraries/common/src/main/java/androidx/media3/common/FrameProcessor.java
@@ -46,17 +46,17 @@ public interface FrameProcessor {
* @param listener A {@link Listener}.
* @param effects The {@link Effect} instances to apply to each frame.
* @param debugViewProvider A {@link DebugViewProvider}.
- * @param useHdr Whether to process the input as an HDR signal.
+ * @param colorInfo The {@link ColorInfo} for input and output frames.
* @return A new instance.
* @throws FrameProcessingException If a problem occurs while creating the {@link
* FrameProcessor}.
*/
FrameProcessor create(
Context context,
- FrameProcessor.Listener listener,
+ Listener listener,
List effects,
DebugViewProvider debugViewProvider,
- boolean useHdr)
+ ColorInfo colorInfo)
throws FrameProcessingException;
}
diff --git a/libraries/effect/src/androidTest/java/androidx/media3/effect/GlEffectsFrameProcessorPixelTest.java b/libraries/effect/src/androidTest/java/androidx/media3/effect/GlEffectsFrameProcessorPixelTest.java
index f36270b2cd..5ccb2491fb 100644
--- a/libraries/effect/src/androidTest/java/androidx/media3/effect/GlEffectsFrameProcessorPixelTest.java
+++ b/libraries/effect/src/androidTest/java/androidx/media3/effect/GlEffectsFrameProcessorPixelTest.java
@@ -34,6 +34,7 @@ import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Pair;
import androidx.annotation.Nullable;
+import androidx.media3.common.ColorInfo;
import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Effect;
import androidx.media3.common.FrameInfo;
@@ -388,7 +389,7 @@ public final class GlEffectsFrameProcessorPixelTest {
},
effects,
DebugViewProvider.NONE,
- /* useHdr= */ false));
+ ColorInfo.SDR_BT709_LIMITED));
glEffectsFrameProcessor.setInputFrameInfo(
new FrameInfo(inputWidth, inputHeight, pixelWidthHeightRatio, /* streamOffsetUs= */ 0));
glEffectsFrameProcessor.registerInputFrame();
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/FinalMatrixTransformationProcessorWrapper.java b/libraries/effect/src/main/java/androidx/media3/effect/FinalMatrixTransformationProcessorWrapper.java
index 77801f3774..a114e7dd47 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/FinalMatrixTransformationProcessorWrapper.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/FinalMatrixTransformationProcessorWrapper.java
@@ -33,6 +33,7 @@ import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.media3.common.C;
+import androidx.media3.common.ColorInfo;
import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.FrameProcessingException;
import androidx.media3.common.FrameProcessor;
@@ -69,7 +70,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final DebugViewProvider debugViewProvider;
private final FrameProcessor.Listener frameProcessorListener;
private final boolean sampleFromExternalTexture;
- private final boolean useHdr;
+ private final ColorInfo colorInfo;
private final float[] textureTransformMatrix;
private final Queue streamOffsetUsQueue;
@@ -91,8 +92,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@Nullable
private EGLSurface outputEglSurface;
- // TODO(b/227624622): Instead of inputting useHdr, input ColorInfo to handle HLG and PQ
- // differently.
public FinalMatrixTransformationProcessorWrapper(
Context context,
EGLDisplay eglDisplay,
@@ -101,7 +100,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
FrameProcessor.Listener frameProcessorListener,
DebugViewProvider debugViewProvider,
boolean sampleFromExternalTexture,
- boolean useHdr) {
+ ColorInfo colorInfo) {
this.context = context;
this.matrixTransformations = matrixTransformations;
this.eglDisplay = eglDisplay;
@@ -109,7 +108,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.debugViewProvider = debugViewProvider;
this.frameProcessorListener = frameProcessorListener;
this.sampleFromExternalTexture = sampleFromExternalTexture;
- this.useHdr = useHdr;
+ this.colorInfo = colorInfo;
textureTransformMatrix = new float[16];
Matrix.setIdentityM(textureTransformMatrix, /* smOffset= */ 0);
@@ -215,7 +214,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
SurfaceInfo outputSurfaceInfo = this.outputSurfaceInfo;
@Nullable EGLSurface outputEglSurface = this.outputEglSurface;
if (outputEglSurface == null) {
- if (useHdr) {
+ boolean colorInfoIsHdr = ColorInfo.isHdr(colorInfo);
+ if (colorInfoIsHdr) {
outputEglSurface = GlUtil.getEglSurfaceRgba1010102(eglDisplay, outputSurfaceInfo.surface);
} else {
outputEglSurface = GlUtil.getEglSurface(eglDisplay, outputSurfaceInfo.surface);
@@ -227,7 +227,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
outputSurfaceInfo.width, outputSurfaceInfo.height);
if (debugSurfaceView != null && !Util.areEqual(this.debugSurfaceView, debugSurfaceView)) {
debugSurfaceViewWrapper =
- new SurfaceViewWrapper(eglDisplay, eglContext, useHdr, debugSurfaceView);
+ new SurfaceViewWrapper(eglDisplay, eglContext, colorInfoIsHdr, debugSurfaceView);
}
this.debugSurfaceView = debugSurfaceView;
}
@@ -266,7 +266,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
context,
matrixTransformationListBuilder.build(),
sampleFromExternalTexture,
- useHdr,
+ colorInfo,
/* outputOpticalColors= */ true);
matrixTransformationProcessor.setTextureTransformMatrix(textureTransformMatrix);
Pair outputSize =
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/GlEffectsFrameProcessor.java b/libraries/effect/src/main/java/androidx/media3/effect/GlEffectsFrameProcessor.java
index 7de1b31357..ed41ab2837 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/GlEffectsFrameProcessor.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/GlEffectsFrameProcessor.java
@@ -29,6 +29,7 @@ import android.view.Surface;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.media3.common.C;
+import androidx.media3.common.ColorInfo;
import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Effect;
import androidx.media3.common.FrameInfo;
@@ -68,7 +69,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
FrameProcessor.Listener listener,
List effects,
DebugViewProvider debugViewProvider,
- boolean useHdr)
+ ColorInfo colorInfo)
throws FrameProcessingException {
ExecutorService singleThreadExecutorService = Util.newSingleThreadExecutor(THREAD_NAME);
@@ -81,7 +82,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
listener,
effects,
debugViewProvider,
- useHdr,
+ colorInfo,
singleThreadExecutorService));
try {
@@ -111,11 +112,14 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
FrameProcessor.Listener listener,
List effects,
DebugViewProvider debugViewProvider,
- boolean useHdr,
+ ColorInfo colorInfo,
ExecutorService singleThreadExecutorService)
throws GlUtil.GlException, FrameProcessingException {
checkState(Thread.currentThread().getName().equals(THREAD_NAME));
+ // TODO(b/237674316): Delay initialization of things requiring the colorInfo, to
+ // configure based on the color info from the decoder output media format instead.
+ boolean useHdr = ColorInfo.isHdr(colorInfo);
EGLDisplay eglDisplay = GlUtil.createEglDisplay();
EGLContext eglContext =
useHdr
@@ -133,7 +137,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
ImmutableList textureProcessors =
getGlTextureProcessorsForGlEffects(
- context, effects, eglDisplay, eglContext, listener, debugViewProvider, useHdr);
+ context, effects, eglDisplay, eglContext, listener, debugViewProvider, colorInfo);
FrameProcessingTaskExecutor frameProcessingTaskExecutor =
new FrameProcessingTaskExecutor(singleThreadExecutorService, listener);
chainTextureProcessorsWithListeners(textureProcessors, frameProcessingTaskExecutor, listener);
@@ -164,7 +168,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
EGLContext eglContext,
FrameProcessor.Listener listener,
DebugViewProvider debugViewProvider,
- boolean useHdr)
+ ColorInfo colorInfo)
throws FrameProcessingException {
ImmutableList.Builder textureProcessorListBuilder =
new ImmutableList.Builder<>();
@@ -187,12 +191,13 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
context,
matrixTransformations,
sampleFromExternalTexture,
- useHdr,
+ colorInfo,
/* outputOpticalColors= */ false));
matrixTransformationListBuilder = new ImmutableList.Builder<>();
sampleFromExternalTexture = false;
}
- textureProcessorListBuilder.add(glEffect.toGlTextureProcessor(context, useHdr));
+ textureProcessorListBuilder.add(
+ glEffect.toGlTextureProcessor(context, ColorInfo.isHdr(colorInfo)));
}
textureProcessorListBuilder.add(
new FinalMatrixTransformationProcessorWrapper(
@@ -203,7 +208,7 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
listener,
debugViewProvider,
sampleFromExternalTexture,
- useHdr));
+ colorInfo));
return textureProcessorListBuilder.build();
}
diff --git a/libraries/effect/src/main/java/androidx/media3/effect/MatrixTransformationProcessor.java b/libraries/effect/src/main/java/androidx/media3/effect/MatrixTransformationProcessor.java
index eb206ba12a..cb13d68851 100644
--- a/libraries/effect/src/main/java/androidx/media3/effect/MatrixTransformationProcessor.java
+++ b/libraries/effect/src/main/java/androidx/media3/effect/MatrixTransformationProcessor.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Pair;
+import androidx.media3.common.ColorInfo;
import androidx.media3.common.FrameProcessingException;
import androidx.media3.common.util.GlProgram;
import androidx.media3.common.util.GlUtil;
@@ -112,11 +113,13 @@ import java.util.Arrays;
Context context, boolean useHdr, MatrixTransformation matrixTransformation)
throws FrameProcessingException {
this(
- context,
+ createGlProgram(
+ context,
+ /* inputOpticalColorsFromExternalTexture= */ false,
+ useHdr,
+ /* outputOpticalColors= */ false),
ImmutableList.of(matrixTransformation),
- /* sampleFromExternalTexture= */ false,
- useHdr,
- /* outputOpticalColors= */ false);
+ useHdr);
}
/**
@@ -133,43 +136,89 @@ import java.util.Arrays;
Context context, boolean useHdr, GlMatrixTransformation matrixTransformation)
throws FrameProcessingException {
this(
- context,
+ createGlProgram(
+ context,
+ /* inputOpticalColorsFromExternalTexture= */ false,
+ useHdr,
+ /* outputOpticalColors= */ false),
ImmutableList.of(matrixTransformation),
- /* sampleFromExternalTexture= */ false,
- useHdr,
- /* outputOpticalColors= */ false);
+ useHdr);
}
/**
* Creates a new instance.
*
+ * Able to convert optical {@link ColorInfo} inputs and outputs to and from the intermediate
+ * {@link GlTextureProcessor} colors of linear RGB BT.2020 for HDR, and gamma RGB BT.709 for SDR.
+ *
* @param context The {@link Context}.
* @param matrixTransformations The {@link GlMatrixTransformation GlMatrixTransformations} to
* apply to each frame in order.
- * @param sampleFromExternalTexture Whether the input will be provided using an external texture.
- * If {@code true}, the caller should use {@link #setTextureTransformMatrix(float[])} to
- * provide the transformation matrix associated with the external texture.
- * @param useHdr Whether to process the input as an HDR signal. Using HDR requires the {@code
- * EXT_YUV_target} OpenGL extension.
- * @param outputOpticalColors If {@code true} and {@code useHdr} is also {@code true}, outputs a
- * non-linear optical, or display light colors, possibly by applying the EOTF (Electro-optical
- * transfer function). Otherwise, outputs linear electrical colors.
+ * @param inputOpticalColorsFromExternalTexture Whether optical color input will be provided using
+ * an external texture. If {@code true}, the caller should use {@link
+ * #setTextureTransformMatrix(float[])} to provide the transformation matrix associated with
+ * the external texture.
+ * @param opticalColorInfo The optical {@link ColorInfo}, only used to transform between color
+ * spaces and transfers, when {@code inputOpticalColorsFromExternalTexture} or {@code
+ * outputOpticalColors} are {@code true}. If it {@link ColorInfo#isHdr(ColorInfo)},
+ * intermediate {@link GlTextureProcessor} colors will be in linear RGB BT.2020. Otherwise,
+ * these colors will be in gamma RGB BT.709.
+ * @param outputOpticalColors If {@code true}, outputs {@code opticalColorInfo}. If {@code false},
+ * outputs intermediate colors of linear RGB BT.2020 if {@code opticalColorInfo} {@link
+ * ColorInfo#isHdr(ColorInfo)}, and gamma RGB BT.709 otherwise.
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
* operation fails or is unsupported.
*/
public MatrixTransformationProcessor(
Context context,
ImmutableList matrixTransformations,
- boolean sampleFromExternalTexture,
- boolean useHdr,
+ boolean inputOpticalColorsFromExternalTexture,
+ ColorInfo opticalColorInfo,
boolean outputOpticalColors)
throws FrameProcessingException {
- super(useHdr);
- if (sampleFromExternalTexture && useHdr && !GlUtil.isYuvTargetExtensionSupported()) {
+ this(
+ createGlProgram(
+ context,
+ inputOpticalColorsFromExternalTexture,
+ ColorInfo.isHdr(opticalColorInfo),
+ outputOpticalColors),
+ matrixTransformations,
+ ColorInfo.isHdr(opticalColorInfo));
+ if (!ColorInfo.isHdr(opticalColorInfo) || !inputOpticalColorsFromExternalTexture) {
+ return;
+ }
+ // TODO(b/227624622): Implement YUV to RGB conversions in COLOR_RANGE_LIMITED as well, using
+ // opticalColorInfo.colorRange to select between them.
+
+ // In HDR editing mode the decoder output is sampled in YUV.
+ if (!GlUtil.isYuvTargetExtensionSupported()) {
throw new FrameProcessingException(
"The EXT_YUV_target extension is required for HDR editing input.");
}
+ glProgram.setFloatsUniform("uColorTransform", MATRIX_YUV_TO_BT2020_COLOR_TRANSFORM);
+ // TODO(b/227624622): Implement PQ and gamma TFs, and use an @IntDef to select between HLG,
+ // PQ, and gamma, coming from opticalColorInfo.colorTransfer.
+ // Applying the OETF will output a linear signal. Not applying the OETF will output an optical
+ // signal.
+ glProgram.setFloatUniform("uApplyHlgOetf", outputOpticalColors ? 0.0f : 1.0f);
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param glProgram The {@link GlProgram}.
+ * @param matrixTransformations The {@link GlMatrixTransformation GlMatrixTransformations} to
+ * apply to each frame in order.
+ * @param useHdr Whether to process the input as an HDR signal. Using HDR requires the {@code
+ * EXT_YUV_target} OpenGL extension.
+ */
+ private MatrixTransformationProcessor(
+ GlProgram glProgram,
+ ImmutableList matrixTransformations,
+ boolean useHdr) {
+ super(useHdr);
+ this.glProgram = glProgram;
this.matrixTransformations = matrixTransformations;
transformationMatrixCache = new float[matrixTransformations.size()][16];
@@ -177,42 +226,44 @@ import java.util.Arrays;
tempResultMatrix = new float[16];
Matrix.setIdentityM(compositeTransformationMatrix, /* smOffset= */ 0);
visiblePolygon = NDC_SQUARE;
+ }
+
+ private static GlProgram createGlProgram(
+ Context context,
+ boolean inputOpticalColorsFromExternalTexture,
+ boolean useHdr,
+ boolean outputOpticalColors)
+ throws FrameProcessingException {
String vertexShaderFilePath;
String fragmentShaderFilePath;
- if (sampleFromExternalTexture) {
- vertexShaderFilePath =
- useHdr ? VERTEX_SHADER_TRANSFORMATION_ES3_PATH : VERTEX_SHADER_TRANSFORMATION_PATH;
- fragmentShaderFilePath =
- useHdr ? FRAGMENT_SHADER_COPY_EXTERNAL_YUV_ES3_PATH : FRAGMENT_SHADER_COPY_EXTERNAL_PATH;
- } else if (outputOpticalColors) {
- vertexShaderFilePath =
- useHdr ? VERTEX_SHADER_TRANSFORMATION_ES3_PATH : VERTEX_SHADER_TRANSFORMATION_PATH;
- fragmentShaderFilePath =
- useHdr ? FRAGMENT_SHADER_HLG_EOTF_ES3_PATH : FRAGMENT_SHADER_COPY_PATH;
+ if (inputOpticalColorsFromExternalTexture) {
+ if (useHdr) {
+ vertexShaderFilePath = VERTEX_SHADER_TRANSFORMATION_ES3_PATH;
+ fragmentShaderFilePath = FRAGMENT_SHADER_COPY_EXTERNAL_YUV_ES3_PATH;
+ } else {
+ vertexShaderFilePath = VERTEX_SHADER_TRANSFORMATION_PATH;
+ fragmentShaderFilePath = FRAGMENT_SHADER_COPY_EXTERNAL_PATH;
+ }
+ } else if (outputOpticalColors && useHdr) {
+ vertexShaderFilePath = VERTEX_SHADER_TRANSFORMATION_ES3_PATH;
+ fragmentShaderFilePath = FRAGMENT_SHADER_HLG_EOTF_ES3_PATH;
} else {
vertexShaderFilePath = VERTEX_SHADER_TRANSFORMATION_PATH;
fragmentShaderFilePath = FRAGMENT_SHADER_COPY_PATH;
}
+ GlProgram glProgram;
try {
glProgram = new GlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
} catch (IOException | GlUtil.GlException e) {
throw new FrameProcessingException(e);
}
- if (useHdr && sampleFromExternalTexture) {
- // In HDR editing mode the decoder output is sampled in YUV.
- glProgram.setFloatsUniform("uColorTransform", MATRIX_YUV_TO_BT2020_COLOR_TRANSFORM);
- // TODO(b/227624622): Implement PQ, and use an @IntDef to select between HLG, PQ, and no
- // transfer function.
- // Applying the OETF will output a linear signal. Not applying the OETF will output an optical
- // signal.
- glProgram.setFloatUniform("uApplyHlgOetf", outputOpticalColors ? 0.0f : 1.0f);
- }
float[] identityMatrix = new float[16];
Matrix.setIdentityM(identityMatrix, /* smOffset= */ 0);
glProgram.setFloatsUniform("uTexTransformationMatrix", identityMatrix);
+ return glProgram;
}
@Override
@@ -276,11 +327,11 @@ import java.util.Arrays;
visiblePolygon = NDC_SQUARE;
for (float[] transformationMatrix : transformationMatrixCache) {
Matrix.multiplyMM(
- tempResultMatrix,
+ /* result= */ tempResultMatrix,
/* resultOffset= */ 0,
- transformationMatrix,
+ /* lhs= */ transformationMatrix,
/* lhsOffset= */ 0,
- compositeTransformationMatrix,
+ /* rhs= */ compositeTransformationMatrix,
/* rhsOffset= */ 0);
System.arraycopy(
/* src= */ tempResultMatrix,
diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java b/libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java
index 912efd5bff..d536e1add9 100644
--- a/libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java
+++ b/libraries/transformer/src/main/java/androidx/media3/transformer/VideoTranscodingSamplePipeline.java
@@ -32,6 +32,7 @@ import androidx.media3.common.FrameInfo;
import androidx.media3.common.FrameProcessingException;
import androidx.media3.common.FrameProcessor;
import androidx.media3.common.SurfaceInfo;
+import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util;
import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.effect.Presentation;
@@ -141,10 +142,11 @@ import org.checkerframework.dataflow.qual.Pure;
},
effectsListBuilder.build(),
debugViewProvider,
- // HDR is only used if the MediaCodec encoder supports FEATURE_HdrEditing. This
- // implies that the OpenGL EXT_YUV_target extension is supported and hence the
- // default FrameProcessor, GlEffectsFrameProcessor, also supports HDR.
- /* useHdr= */ encoderWrapper.isHdrEditingEnabled());
+ // HDR colors are only used if the MediaCodec encoder supports FEATURE_HdrEditing.
+ // This implies that the OpenGL EXT_YUV_target extension is supported and hence the
+ // default FrameProcessor, GlEffectsFrameProcessor, also supports HDR. Otherwise, tone
+ // mapping is applied, which ensures the decoder outputs SDR output for an HDR input.
+ encoderWrapper.getSupportedInputColor());
} catch (FrameProcessingException e) {
throw TransformationException.createForFrameProcessingException(
e, TransformationException.ERROR_CODE_FRAME_PROCESSING_FAILED);
@@ -154,7 +156,8 @@ import org.checkerframework.dataflow.qual.Pure;
decodedWidth, decodedHeight, inputFormat.pixelWidthHeightRatio, streamOffsetUs));
boolean isToneMappingRequired =
- ColorInfo.isHdr(inputFormat.colorInfo) && !encoderWrapper.isHdrEditingEnabled();
+ ColorInfo.isHdr(inputFormat.colorInfo)
+ && !ColorInfo.isHdr(encoderWrapper.getSupportedInputColor());
decoder =
decoderFactory.createForVideoDecoding(
inputFormat, frameProcessor.getInputSurface(), isToneMappingRequired);
@@ -317,6 +320,7 @@ import org.checkerframework.dataflow.qual.Pure;
*/
@VisibleForTesting
/* package */ static final class EncoderWrapper {
+ private static final String TAG = "EncoderWrapper";
private final Codec.EncoderFactory encoderFactory;
private final Format inputFormat;
@@ -353,11 +357,24 @@ import org.checkerframework.dataflow.qual.Pure;
requestedOutputMimeType, inputFormat.colorInfo);
}
- /** Returns whether the wrapped encoder is expecting HDR input for the HDR editing use case. */
- public boolean isHdrEditingEnabled() {
- return transformationRequest.enableHdrEditing
- && !transformationRequest.enableRequestSdrToneMapping
- && !supportedEncoderNamesForHdrEditing.isEmpty();
+ /** Returns the {@link ColorInfo} expected from the input surface. */
+ public ColorInfo getSupportedInputColor() {
+ boolean isHdrEditingEnabled =
+ transformationRequest.enableHdrEditing
+ && !transformationRequest.enableRequestSdrToneMapping
+ && !supportedEncoderNamesForHdrEditing.isEmpty();
+ boolean isInputToneMapped = !isHdrEditingEnabled && ColorInfo.isHdr(inputFormat.colorInfo);
+ if (isInputToneMapped) {
+ // When tone-mapping HDR to SDR is enabled, assume we get BT.709 to avoid having the encoder
+ // populate default color info, which depends on the resolution.
+ // TODO(b/237674316): Get the color info from the decoder output media format instead.
+ return ColorInfo.SDR_BT709_LIMITED;
+ }
+ if (inputFormat.colorInfo == null) {
+ Log.d(TAG, "colorInfo is null. Defaulting to SDR_BT709_LIMITED.");
+ return ColorInfo.SDR_BT709_LIMITED;
+ }
+ return inputFormat.colorInfo;
}
@Nullable
@@ -382,12 +399,6 @@ import org.checkerframework.dataflow.qual.Pure;
outputRotationDegrees = 90;
}
- boolean isInputToneMapped = ColorInfo.isHdr(inputFormat.colorInfo) && !isHdrEditingEnabled();
- // When tone-mapping HDR to SDR is enabled, assume we get BT.709 to avoid having the encoder
- // populate default color info, which depends on the resolution.
- // TODO(b/237674316): Get the color info from the decoder output media format instead.
- ColorInfo outputColorInfo =
- isInputToneMapped ? ColorInfo.SDR_BT709_LIMITED : inputFormat.colorInfo;
Format requestedEncoderFormat =
new Format.Builder()
.setWidth(requestedWidth)
@@ -395,14 +406,14 @@ import org.checkerframework.dataflow.qual.Pure;
.setRotationDegrees(0)
.setFrameRate(inputFormat.frameRate)
.setSampleMimeType(requestedOutputMimeType)
- .setColorInfo(outputColorInfo)
+ .setColorInfo(getSupportedInputColor())
.build();
encoder =
encoderFactory.createForVideoEncoding(requestedEncoderFormat, allowedOutputMimeTypes);
Format encoderSupportedFormat = encoder.getConfigurationFormat();
- if (isHdrEditingEnabled()) {
+ if (ColorInfo.isHdr(requestedEncoderFormat.colorInfo)) {
if (!requestedOutputMimeType.equals(encoderSupportedFormat.sampleMimeType)) {
throw createEncodingException(
new IllegalStateException("MIME type fallback unsupported with HDR editing"),
@@ -413,6 +424,9 @@ import org.checkerframework.dataflow.qual.Pure;
encoderSupportedFormat);
}
}
+ boolean isInputToneMapped =
+ ColorInfo.isHdr(inputFormat.colorInfo)
+ && !ColorInfo.isHdr(requestedEncoderFormat.colorInfo);
fallbackListener.onTransformationRequestFinalized(
createFallbackTransformationRequest(
transformationRequest,