remove degammaing: change setSdrWorkingColorSpace default
The second stage of the changes remove the conversion to linear colors in the SDR effects pipeline by default. also resolves Issue: androidx/media#1050 PiperOrigin-RevId: 630108296
@ -55,6 +55,9 @@
|
||||
* Fix bug where `TimestampWrapper` crashes when used with
|
||||
`ExoPlayer#setVideoEffects`
|
||||
([#821](https://github.com/androidx/media/issues/821)).
|
||||
* Change default SDR color working space from linear colors to electrical
|
||||
BT 709 SDR video. Also provides third option to retain the original
|
||||
colorspace.
|
||||
* Muxers:
|
||||
* IMA extension:
|
||||
* Promote API that is required for apps to play
|
||||
|
@ -204,6 +204,15 @@ public final class GlProgram {
|
||||
checkNotNull(uniformByName.get(name)).setFloats(value);
|
||||
}
|
||||
|
||||
/** Sets a {@code float[]} type uniform if {@code name} is present, no-op otherwise. */
|
||||
public void setFloatsUniformIfPresent(String name, float[] value) {
|
||||
@Nullable Uniform uniform = uniformByName.get(name);
|
||||
if (uniform == null) {
|
||||
return;
|
||||
}
|
||||
uniform.setFloats(value);
|
||||
}
|
||||
|
||||
/** Binds all attributes and uniforms in the program. */
|
||||
public void bindAttributesAndUniforms() throws GlUtil.GlException {
|
||||
for (Attribute attribute : attributes) {
|
||||
|
@ -438,7 +438,13 @@ public final class DefaultVideoFrameProcessorPixelTest {
|
||||
@Test
|
||||
public void increaseBrightness_matchesGoldenFile() throws Exception {
|
||||
videoFrameProcessorTestRunner =
|
||||
getDefaultFrameProcessorTestRunnerBuilder(testId).setEffects(new Brightness(0.5f)).build();
|
||||
getDefaultFrameProcessorTestRunnerBuilder(testId)
|
||||
.setVideoFrameProcessorFactory(
|
||||
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||
.setSdrWorkingColorSpace(DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR)
|
||||
.build())
|
||||
.setEffects(new Brightness(0.5f))
|
||||
.build();
|
||||
Bitmap expectedBitmap = readBitmap(INCREASE_BRIGHTNESS_PNG_ASSET_PATH);
|
||||
|
||||
videoFrameProcessorTestRunner.processFirstFrameAndEnd();
|
||||
@ -545,6 +551,10 @@ public final class DefaultVideoFrameProcessorPixelTest {
|
||||
public void grayscaleThenIncreaseRedChannel_matchesGoldenFile() throws Exception {
|
||||
videoFrameProcessorTestRunner =
|
||||
getDefaultFrameProcessorTestRunnerBuilder(testId)
|
||||
.setVideoFrameProcessorFactory(
|
||||
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||
.setSdrWorkingColorSpace(DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR)
|
||||
.build())
|
||||
.setEffects(
|
||||
RgbFilter.createGrayscaleFilter(),
|
||||
new RgbAdjustment.Builder().setRedScale(3).build())
|
||||
|
@ -20,9 +20,7 @@
|
||||
// colorspace with the colors transferred to either linear or SMPTE 170M as
|
||||
// requested by uSdrWorkingColorSpace.
|
||||
// 3. Applies a 4x4 RGB color matrix to change the pixel colors.
|
||||
// 4. Outputs as requested by uOutputColorTransfer. Use COLOR_TRANSFER_LINEAR
|
||||
// for outputting to intermediate shaders, or COLOR_TRANSFER_SDR_VIDEO to
|
||||
// output electrical colors via an OETF (e.g. to an encoder).
|
||||
// 4. Outputs as requested by uOutputColorTransfer.
|
||||
|
||||
#extension GL_OES_EGL_image_external : require
|
||||
precision mediump float;
|
||||
|
@ -21,9 +21,7 @@
|
||||
// colorspace with the colors transferred to either linear or SMPTE 170M as
|
||||
// requested by uSdrWorkingColorSpace.
|
||||
// 3. Applies a 4x4 RGB color matrix to change the pixel colors.
|
||||
// 4. Outputs as requested by uOutputColorTransfer. Use COLOR_TRANSFER_LINEAR
|
||||
// for outputting to intermediate shaders, or COLOR_TRANSFER_SDR_VIDEO to
|
||||
// output electrical colors via an OETF (e.g. to an encoder).
|
||||
// 4. Outputs as requested by uOutputColorTransfer.
|
||||
|
||||
precision mediump float;
|
||||
uniform sampler2D uTexSampler;
|
||||
|
@ -30,7 +30,6 @@ import android.opengl.Matrix;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.ColorInfo;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.VideoFrameProcessingException;
|
||||
import androidx.media3.common.VideoFrameProcessor.InputType;
|
||||
import androidx.media3.common.util.GlProgram;
|
||||
@ -74,6 +73,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
"shaders/vertex_shader_transformation_es3.glsl";
|
||||
private static final String FRAGMENT_SHADER_TRANSFORMATION_PATH =
|
||||
"shaders/fragment_shader_transformation_es2.glsl";
|
||||
private static final String FRAGMENT_SHADER_COPY_PATH = "shaders/fragment_shader_copy_es2.glsl";
|
||||
private static final String FRAGMENT_SHADER_OETF_ES3_PATH =
|
||||
"shaders/fragment_shader_oetf_es3.glsl";
|
||||
private static final String FRAGMENT_SHADER_TRANSFORMATION_SDR_OETF_ES2_PATH =
|
||||
@ -180,14 +180,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
List<RgbMatrix> rgbMatrices,
|
||||
boolean useHdr)
|
||||
throws VideoFrameProcessingException {
|
||||
String fragmentShaderFilePath =
|
||||
rgbMatrices.isEmpty()
|
||||
// Ensure colors not multiplied by a uRgbMatrix (even the identity) as it can create
|
||||
// color shifts on electrical pq tonemapped content.
|
||||
? FRAGMENT_SHADER_COPY_PATH
|
||||
: FRAGMENT_SHADER_TRANSFORMATION_PATH;
|
||||
GlProgram glProgram =
|
||||
createGlProgram(
|
||||
context, VERTEX_SHADER_TRANSFORMATION_PATH, FRAGMENT_SHADER_TRANSFORMATION_PATH);
|
||||
createGlProgram(context, VERTEX_SHADER_TRANSFORMATION_PATH, fragmentShaderFilePath);
|
||||
|
||||
// TODO: b/263306471 - when default working color space changes to WORKING_COLOR_SPACE_DEFAULT,
|
||||
// make sure no color transfers are applied in shader.
|
||||
|
||||
// No transfer functions needed, because input and output are both optical colors.
|
||||
// No transfer functions needed/applied, because input and output are in the same color space.
|
||||
return new DefaultShaderProgram(
|
||||
glProgram,
|
||||
ImmutableList.copyOf(matrixTransformations),
|
||||
@ -239,6 +241,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
: FRAGMENT_SHADER_TRANSFORMATION_SDR_INTERNAL_PATH;
|
||||
GlProgram glProgram = createGlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
|
||||
if (!isUsingUltraHdr) {
|
||||
checkArgument(
|
||||
isInputTransferHdr
|
||||
|| inputColorInfo.colorTransfer == C.COLOR_TRANSFER_SRGB
|
||||
|| inputColorInfo.colorTransfer == C.COLOR_TRANSFER_SDR);
|
||||
glProgram.setIntUniform("uInputColorTransfer", inputColorInfo.colorTransfer);
|
||||
}
|
||||
if (isInputTransferHdr) {
|
||||
@ -342,7 +348,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
? FRAGMENT_SHADER_OETF_ES3_PATH
|
||||
: shouldApplyOetf
|
||||
? FRAGMENT_SHADER_TRANSFORMATION_SDR_OETF_ES2_PATH
|
||||
: FRAGMENT_SHADER_TRANSFORMATION_PATH;
|
||||
: rgbMatrices.isEmpty()
|
||||
// Ensure colors not multiplied by a uRgbMatrix (even the identity) as it can
|
||||
// create color shifts on electrical pq tonemapped content.
|
||||
? FRAGMENT_SHADER_COPY_PATH
|
||||
: FRAGMENT_SHADER_TRANSFORMATION_PATH;
|
||||
GlProgram glProgram = createGlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
|
||||
|
||||
@C.ColorTransfer int outputColorTransfer = outputColorInfo.colorTransfer;
|
||||
@ -379,14 +389,22 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@C.ColorTransfer int outputColorTransfer = outputColorInfo.colorTransfer;
|
||||
if (isInputTransferHdr) {
|
||||
// TODO(b/239735341): Add a setBooleanUniform method to GlProgram.
|
||||
checkArgument(outputColorTransfer != Format.NO_VALUE);
|
||||
if (outputColorTransfer == C.COLOR_TRANSFER_SDR) {
|
||||
// When tone-mapping from HDR to SDR, COLOR_TRANSFER_SDR is interpreted as
|
||||
// COLOR_TRANSFER_GAMMA_2_2.
|
||||
outputColorTransfer = C.COLOR_TRANSFER_GAMMA_2_2;
|
||||
}
|
||||
checkArgument(
|
||||
outputColorTransfer == C.COLOR_TRANSFER_LINEAR
|
||||
|| outputColorTransfer == C.COLOR_TRANSFER_GAMMA_2_2
|
||||
|| outputColorTransfer == C.COLOR_TRANSFER_ST2084
|
||||
|| outputColorTransfer == C.COLOR_TRANSFER_HLG);
|
||||
glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer);
|
||||
} else if (isExpandingColorGamut) {
|
||||
checkArgument(
|
||||
outputColorTransfer == C.COLOR_TRANSFER_LINEAR
|
||||
|| outputColorTransfer == C.COLOR_TRANSFER_ST2084
|
||||
|| outputColorTransfer == C.COLOR_TRANSFER_HLG);
|
||||
glProgram.setIntUniform("uOutputColorTransfer", outputColorTransfer);
|
||||
} else {
|
||||
glProgram.setIntUniform("uSdrWorkingColorSpace", sdrWorkingColorSpace);
|
||||
@ -479,7 +497,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
setGainmapSamplerAndUniforms();
|
||||
glProgram.setSamplerTexIdUniform("uTexSampler", inputTexId, /* texUnitIndex= */ 0);
|
||||
glProgram.setFloatsUniform("uTransformationMatrix", compositeTransformationMatrixArray);
|
||||
glProgram.setFloatsUniform("uRgbMatrix", compositeRgbMatrixArray);
|
||||
glProgram.setFloatsUniformIfPresent("uRgbMatrix", compositeRgbMatrixArray);
|
||||
glProgram.setBufferAttribute(
|
||||
"aFramePosition",
|
||||
GlUtil.createVertexBuffer(visiblePolygon),
|
||||
|
@ -140,7 +140,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
||||
|
||||
/** Creates an instance. */
|
||||
public Builder() {
|
||||
sdrWorkingColorSpace = WORKING_COLOR_SPACE_LINEAR;
|
||||
sdrWorkingColorSpace = WORKING_COLOR_SPACE_DEFAULT;
|
||||
requireRegisteringAllInputFrames = true;
|
||||
}
|
||||
|
||||
@ -153,7 +153,6 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
||||
requireRegisteringAllInputFrames = !factory.repeatLastRegisteredFrame;
|
||||
}
|
||||
|
||||
// TODO: b/263306471 - Change default to WORKING_COLOR_SPACE_DEFAULT.
|
||||
/**
|
||||
* Sets the {@link WorkingColorSpace} in which frames passed to intermediate effects will be
|
||||
* represented.
|
||||
|
@ -25,6 +25,7 @@ import static androidx.media3.common.util.Util.newSingleThreadScheduledExecutor;
|
||||
import static androidx.media3.effect.DebugTraceUtil.EVENT_COMPOSITOR_OUTPUT_TEXTURE_RENDERED;
|
||||
import static androidx.media3.effect.DebugTraceUtil.EVENT_VFP_OUTPUT_TEXTURE_RENDERED;
|
||||
import static androidx.media3.effect.DebugTraceUtil.logEvent;
|
||||
import static androidx.media3.effect.DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import android.content.Context;
|
||||
@ -119,6 +120,7 @@ public abstract class MultipleInputVideoGraph implements VideoGraph {
|
||||
// TODO - b/289986435: Support injecting VideoFrameProcessor.Factory.
|
||||
videoFrameProcessorFactory =
|
||||
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||
.setSdrWorkingColorSpace(WORKING_COLOR_SPACE_LINEAR)
|
||||
.setGlObjectsProvider(glObjectsProvider)
|
||||
.setExecutorService(sharedExecutorService)
|
||||
.build();
|
||||
|
@ -23,6 +23,9 @@ import com.google.common.collect.ImmutableList;
|
||||
/**
|
||||
* Applies a list of {@link TextureOverlay}s to a frame in FIFO order (the last overlay in the list
|
||||
* is displayed on top).
|
||||
*
|
||||
* <p>This effect assumes a non-{@linkplain DefaultVideoFrameProcessor#WORKING_COLOR_SPACE_LINEAR
|
||||
* linear} working color space.
|
||||
*/
|
||||
@UnstableApi
|
||||
public final class OverlayEffect implements GlEffect {
|
||||
|
@ -188,21 +188,7 @@ import com.google.common.collect.ImmutableList;
|
||||
.append(" outputColor.a = overlayColor.a + videoColor.a * (1.0 - overlayColor.a);\n")
|
||||
.append(" return outputColor;\n")
|
||||
.append("}\n")
|
||||
.append("\n")
|
||||
.append("float srgbEotfSingleChannel(float srgb) {\n")
|
||||
.append(" return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);\n")
|
||||
.append("}\n")
|
||||
.append("// sRGB EOTF.\n")
|
||||
.append("vec3 applyEotf(const vec3 srgb) {\n")
|
||||
.append("// Reference implementation:\n")
|
||||
.append(
|
||||
"// https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/renderengine/gl/ProgramCache.cpp;drc=de09f10aa504fd8066370591a00c9ff1cafbb7fa;l=235\n")
|
||||
.append(" return vec3(\n")
|
||||
.append(" srgbEotfSingleChannel(srgb.r),\n")
|
||||
.append(" srgbEotfSingleChannel(srgb.g),\n")
|
||||
.append(" srgbEotfSingleChannel(srgb.b)\n")
|
||||
.append(" );\n")
|
||||
.append("}\n");
|
||||
.append("\n");
|
||||
|
||||
for (int texUnitIndex = 1; texUnitIndex <= numOverlays; texUnitIndex++) {
|
||||
shader
|
||||
@ -227,14 +213,10 @@ import com.google.common.collect.ImmutableList;
|
||||
formatInvariant(
|
||||
" uOverlayTexSampler%d, vOverlayTexSamplingCoord%d, uOverlayAlphaScale%d);\n",
|
||||
texUnitIndex, texUnitIndex, texUnitIndex))
|
||||
.append(formatInvariant(" vec4 opticalOverlayColor%d = vec4(\n", texUnitIndex))
|
||||
.append(
|
||||
formatInvariant(
|
||||
" applyEotf(electricalOverlayColor%d.rgb), electricalOverlayColor%d.a);\n",
|
||||
texUnitIndex, texUnitIndex))
|
||||
.append(
|
||||
formatInvariant(
|
||||
" fragColor = getMixColor(fragColor, opticalOverlayColor%d);\n", texUnitIndex));
|
||||
" fragColor = getMixColor(fragColor, electricalOverlayColor%d);\n",
|
||||
texUnitIndex));
|
||||
}
|
||||
|
||||
shader.append(" gl_FragColor = fragColor;\n").append("}\n");
|
||||
|
@ -23,7 +23,12 @@ import androidx.media3.common.VideoFrameProcessingException;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
/** Provides common color filters. */
|
||||
/**
|
||||
* Provides common color filters.
|
||||
*
|
||||
* <p>This effect assumes a {@linkplain DefaultVideoFrameProcessor#WORKING_COLOR_SPACE_LINEAR
|
||||
* linear} working color space.
|
||||
*/
|
||||
@UnstableApi
|
||||
public final class RgbFilter implements RgbMatrix {
|
||||
private static final int COLOR_FILTER_GRAYSCALE_INDEX = 1;
|
||||
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 515 KiB After Width: | Height: | Size: 515 KiB |
Before Width: | Height: | Size: 499 KiB After Width: | Height: | Size: 498 KiB |
Before Width: | Height: | Size: 509 KiB After Width: | Height: | Size: 508 KiB |
Before Width: | Height: | Size: 504 KiB After Width: | Height: | Size: 503 KiB |
Before Width: | Height: | Size: 473 KiB After Width: | Height: | Size: 469 KiB |
Before Width: | Height: | Size: 525 KiB After Width: | Height: | Size: 525 KiB |
Before Width: | Height: | Size: 535 KiB After Width: | Height: | Size: 534 KiB |
Before Width: | Height: | Size: 399 KiB After Width: | Height: | Size: 388 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 34 KiB |
@ -860,6 +860,7 @@ public final class DefaultVideoCompositorPixelTest {
|
||||
DefaultVideoFrameProcessor.Factory.Builder defaultVideoFrameProcessorFactoryBuilder =
|
||||
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||
.setGlObjectsProvider(glObjectsProvider)
|
||||
.setSdrWorkingColorSpace(DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR)
|
||||
.setTextureOutput(
|
||||
/* textureOutputListener= */ (outputTextureProducer,
|
||||
outputTexture,
|
||||
|
@ -38,6 +38,7 @@ import androidx.media3.common.util.Size;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.effect.AlphaScale;
|
||||
import androidx.media3.effect.Contrast;
|
||||
import androidx.media3.effect.DefaultVideoFrameProcessor;
|
||||
import androidx.media3.effect.OverlaySettings;
|
||||
import androidx.media3.effect.Presentation;
|
||||
import androidx.media3.effect.ScaleAndRotateTransformation;
|
||||
@ -103,7 +104,7 @@ public final class TransformerMultiSequenceCompositionTest {
|
||||
VideoCompositorSettings.DEFAULT);
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -137,7 +138,7 @@ public final class TransformerMultiSequenceCompositionTest {
|
||||
VideoCompositorSettings.DEFAULT);
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -193,7 +194,7 @@ public final class TransformerMultiSequenceCompositionTest {
|
||||
pictureInPictureVideoCompositorSettings);
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -202,6 +203,16 @@ public final class TransformerMultiSequenceCompositionTest {
|
||||
extractBitmapsFromVideo(context, checkNotNull(result.filePath)), testId);
|
||||
}
|
||||
|
||||
private Transformer getLinearColorSpaceTransformer() {
|
||||
// Use linear color space for grayscale effects.
|
||||
return new Transformer.Builder(context)
|
||||
.setVideoFrameProcessorFactory(
|
||||
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||
.setSdrWorkingColorSpace(DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static EditedMediaItem editedMediaItemByClippingVideo(String uri, List<Effect> effects) {
|
||||
return new EditedMediaItem.Builder(
|
||||
MediaItem.fromUri(uri)
|
||||
|
@ -43,6 +43,7 @@ import androidx.media3.common.Effect;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.effect.BitmapOverlay;
|
||||
import androidx.media3.effect.DefaultVideoFrameProcessor;
|
||||
import androidx.media3.effect.OverlayEffect;
|
||||
import androidx.media3.effect.Presentation;
|
||||
import androidx.media3.effect.RgbFilter;
|
||||
@ -154,7 +155,7 @@ public final class TransformerSequenceEffectTest {
|
||||
SINGLE_30_FPS_VIDEO_FRAME_THRESHOLD_MS));
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -177,7 +178,7 @@ public final class TransformerSequenceEffectTest {
|
||||
oneFrameFromImage(JPG_PORTRAIT_ASSET_URI_STRING, NO_EFFECT));
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -201,7 +202,7 @@ public final class TransformerSequenceEffectTest {
|
||||
SINGLE_30_FPS_VIDEO_FRAME_THRESHOLD_MS));
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -226,7 +227,7 @@ public final class TransformerSequenceEffectTest {
|
||||
clippedVideo(MP4_ASSET_URI_STRING, NO_EFFECT, SINGLE_30_FPS_VIDEO_FRAME_THRESHOLD_MS));
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -251,7 +252,7 @@ public final class TransformerSequenceEffectTest {
|
||||
oneFrameFromImage(JPG_ASSET_URI_STRING, NO_EFFECT));
|
||||
|
||||
ExportTestResult result =
|
||||
new TransformerAndroidTestRunner.Builder(context, new Transformer.Builder(context).build())
|
||||
new TransformerAndroidTestRunner.Builder(context, getLinearColorSpaceTransformer())
|
||||
.build()
|
||||
.run(testId, composition);
|
||||
|
||||
@ -260,6 +261,16 @@ public final class TransformerSequenceEffectTest {
|
||||
extractBitmapsFromVideo(context, checkNotNull(result.filePath)), testId);
|
||||
}
|
||||
|
||||
private Transformer getLinearColorSpaceTransformer() {
|
||||
// Use linear color space for grayscale effects.
|
||||
return new Transformer.Builder(context)
|
||||
.setVideoFrameProcessorFactory(
|
||||
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||
.setSdrWorkingColorSpace(DefaultVideoFrameProcessor.WORKING_COLOR_SPACE_LINEAR)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static OverlayEffect createOverlayEffect() throws IOException {
|
||||
return new OverlayEffect(
|
||||
ImmutableList.of(
|
||||
|
@ -132,15 +132,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
||||
encoderWrapper.getHdrModeAfterFallback() == HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
|
||||
&& ColorInfo.isTransferHdr(videoGraphInputColor);
|
||||
if (isGlToneMapping) {
|
||||
// For consistency with the Android platform, OpenGL tone mapping outputs colors with
|
||||
// C.COLOR_TRANSFER_GAMMA_2_2 instead of C.COLOR_TRANSFER_SDR, and outputs this as
|
||||
// C.COLOR_TRANSFER_SDR to the encoder.
|
||||
videoGraphOutputColor =
|
||||
new ColorInfo.Builder()
|
||||
.setColorSpace(C.COLOR_SPACE_BT709)
|
||||
.setColorRange(C.COLOR_RANGE_LIMITED)
|
||||
.setColorTransfer(C.COLOR_TRANSFER_GAMMA_2_2)
|
||||
.build();
|
||||
videoGraphOutputColor = SDR_BT709_LIMITED;
|
||||
}
|
||||
|
||||
try {
|
||||
|