HDR: Use factory for MatrixTransformationProcessor.
Separate MatrixTransformationProcessor constructors by color input and output. PiperOrigin-RevId: 471034768
This commit is contained in:
parent
b48ca6e040
commit
1b6482960e
@ -28,6 +28,7 @@ import android.opengl.EGLSurface;
|
|||||||
import androidx.media3.common.FrameProcessingException;
|
import androidx.media3.common.FrameProcessingException;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
@ -94,11 +95,10 @@ public final class MatrixTransformationProcessorPixelTest {
|
|||||||
public void drawFrame_noEdits_producesExpectedOutput() throws Exception {
|
public void drawFrame_noEdits_producesExpectedOutput() throws Exception {
|
||||||
String testId = "drawFrame_noEdits";
|
String testId = "drawFrame_noEdits";
|
||||||
Matrix identityMatrix = new Matrix();
|
Matrix identityMatrix = new Matrix();
|
||||||
|
MatrixTransformation noEditsTransformation = (long presentationTimeUs) -> identityMatrix;
|
||||||
matrixTransformationFrameProcessor =
|
matrixTransformationFrameProcessor =
|
||||||
new MatrixTransformationProcessor(
|
MatrixTransformationProcessor.create(
|
||||||
context,
|
context, ImmutableList.of(noEditsTransformation), /* useHdr= */ false);
|
||||||
/* useHdr= */ false,
|
|
||||||
/* matrixTransformation= */ (long presentationTimeUs) -> identityMatrix);
|
|
||||||
matrixTransformationFrameProcessor.configure(width, height);
|
matrixTransformationFrameProcessor.configure(width, height);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ORIGINAL_PNG_ASSET_PATH);
|
||||||
|
|
||||||
@ -120,11 +120,11 @@ public final class MatrixTransformationProcessorPixelTest {
|
|||||||
String testId = "drawFrame_translateRight";
|
String testId = "drawFrame_translateRight";
|
||||||
Matrix translateRightMatrix = new Matrix();
|
Matrix translateRightMatrix = new Matrix();
|
||||||
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
|
translateRightMatrix.postTranslate(/* dx= */ 1, /* dy= */ 0);
|
||||||
|
MatrixTransformation translateRightTransformation =
|
||||||
|
(long presentationTimeUs) -> translateRightMatrix;
|
||||||
matrixTransformationFrameProcessor =
|
matrixTransformationFrameProcessor =
|
||||||
new MatrixTransformationProcessor(
|
MatrixTransformationProcessor.create(
|
||||||
context,
|
context, ImmutableList.of(translateRightTransformation), /* useHdr= */ false);
|
||||||
/* useHdr= */ false,
|
|
||||||
/* matrixTransformation= */ (long presentationTimeUs) -> translateRightMatrix);
|
|
||||||
matrixTransformationFrameProcessor.configure(width, height);
|
matrixTransformationFrameProcessor.configure(width, height);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(TRANSLATE_RIGHT_PNG_ASSET_PATH);
|
||||||
|
|
||||||
@ -146,11 +146,10 @@ public final class MatrixTransformationProcessorPixelTest {
|
|||||||
String testId = "drawFrame_scaleNarrow";
|
String testId = "drawFrame_scaleNarrow";
|
||||||
Matrix scaleNarrowMatrix = new Matrix();
|
Matrix scaleNarrowMatrix = new Matrix();
|
||||||
scaleNarrowMatrix.postScale(.5f, 1.2f);
|
scaleNarrowMatrix.postScale(.5f, 1.2f);
|
||||||
|
MatrixTransformation scaleNarrowTransformation = (long presentationTimeUs) -> scaleNarrowMatrix;
|
||||||
matrixTransformationFrameProcessor =
|
matrixTransformationFrameProcessor =
|
||||||
new MatrixTransformationProcessor(
|
MatrixTransformationProcessor.create(
|
||||||
context,
|
context, ImmutableList.of(scaleNarrowTransformation), /* useHdr= */ false);
|
||||||
/* useHdr= */ false,
|
|
||||||
/* matrixTransformation= */ (long presentationTimeUs) -> scaleNarrowMatrix);
|
|
||||||
matrixTransformationFrameProcessor.configure(width, height);
|
matrixTransformationFrameProcessor.configure(width, height);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(SCALE_NARROW_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(SCALE_NARROW_PNG_ASSET_PATH);
|
||||||
|
|
||||||
@ -172,11 +171,10 @@ public final class MatrixTransformationProcessorPixelTest {
|
|||||||
String testId = "drawFrame_rotate90";
|
String testId = "drawFrame_rotate90";
|
||||||
Matrix rotate90Matrix = new Matrix();
|
Matrix rotate90Matrix = new Matrix();
|
||||||
rotate90Matrix.postRotate(/* degrees= */ 90);
|
rotate90Matrix.postRotate(/* degrees= */ 90);
|
||||||
|
MatrixTransformation rotate90Transformation = (long presentationTimeUs) -> rotate90Matrix;
|
||||||
matrixTransformationFrameProcessor =
|
matrixTransformationFrameProcessor =
|
||||||
new MatrixTransformationProcessor(
|
MatrixTransformationProcessor.create(
|
||||||
context,
|
context, ImmutableList.of(rotate90Transformation), /* useHdr= */ false);
|
||||||
/* useHdr= */ false,
|
|
||||||
/* matrixTransformation= */ (long presentationTimeUs) -> rotate90Matrix);
|
|
||||||
matrixTransformationFrameProcessor.configure(width, height);
|
matrixTransformationFrameProcessor.configure(width, height);
|
||||||
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_90_PNG_ASSET_PATH);
|
Bitmap expectedBitmap = BitmapTestUtil.readBitmap(ROTATE_90_PNG_ASSET_PATH);
|
||||||
|
|
||||||
|
@ -368,13 +368,19 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
Presentation.createForWidthAndHeight(
|
Presentation.createForWidthAndHeight(
|
||||||
outputSurfaceInfo.width, outputSurfaceInfo.height, Presentation.LAYOUT_SCALE_TO_FIT));
|
outputSurfaceInfo.width, outputSurfaceInfo.height, Presentation.LAYOUT_SCALE_TO_FIT));
|
||||||
|
|
||||||
MatrixTransformationProcessor matrixTransformationProcessor =
|
MatrixTransformationProcessor matrixTransformationProcessor;
|
||||||
new MatrixTransformationProcessor(
|
ImmutableList<GlMatrixTransformation> expandedMatrixTransformations =
|
||||||
context,
|
matrixTransformationListBuilder.build();
|
||||||
matrixTransformationListBuilder.build(),
|
if (sampleFromExternalTexture) {
|
||||||
sampleFromExternalTexture,
|
matrixTransformationProcessor =
|
||||||
colorInfo,
|
MatrixTransformationProcessor.createWithExternalSamplerApplyingEotfThenOetf(
|
||||||
/* outputElectricalColors= */ true);
|
context, expandedMatrixTransformations, colorInfo);
|
||||||
|
} else {
|
||||||
|
matrixTransformationProcessor =
|
||||||
|
MatrixTransformationProcessor.createApplyingOetf(
|
||||||
|
context, expandedMatrixTransformations, colorInfo);
|
||||||
|
}
|
||||||
|
|
||||||
matrixTransformationProcessor.setTextureTransformMatrix(textureTransformMatrix);
|
matrixTransformationProcessor.setTextureTransformMatrix(textureTransformMatrix);
|
||||||
Pair<Integer, Integer> outputSize =
|
Pair<Integer, Integer> outputSize =
|
||||||
matrixTransformationProcessor.configure(inputWidth, inputHeight);
|
matrixTransformationProcessor.configure(inputWidth, inputHeight);
|
||||||
|
@ -206,13 +206,17 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
|||||||
ImmutableList<GlMatrixTransformation> matrixTransformations =
|
ImmutableList<GlMatrixTransformation> matrixTransformations =
|
||||||
matrixTransformationListBuilder.build();
|
matrixTransformationListBuilder.build();
|
||||||
if (!matrixTransformations.isEmpty() || sampleFromExternalTexture) {
|
if (!matrixTransformations.isEmpty() || sampleFromExternalTexture) {
|
||||||
textureProcessorListBuilder.add(
|
MatrixTransformationProcessor matrixTransformationProcessor;
|
||||||
new MatrixTransformationProcessor(
|
if (sampleFromExternalTexture) {
|
||||||
context,
|
matrixTransformationProcessor =
|
||||||
matrixTransformations,
|
MatrixTransformationProcessor.createWithExternalSamplerApplyingEotf(
|
||||||
sampleFromExternalTexture,
|
context, matrixTransformations, colorInfo);
|
||||||
colorInfo,
|
} else {
|
||||||
/* outputElectricalColors= */ false));
|
matrixTransformationProcessor =
|
||||||
|
MatrixTransformationProcessor.create(
|
||||||
|
context, matrixTransformations, ColorInfo.isTransferHdr(colorInfo));
|
||||||
|
}
|
||||||
|
textureProcessorListBuilder.add(matrixTransformationProcessor);
|
||||||
matrixTransformationListBuilder = new ImmutableList.Builder<>();
|
matrixTransformationListBuilder = new ImmutableList.Builder<>();
|
||||||
sampleFromExternalTexture = false;
|
sampleFromExternalTexture = false;
|
||||||
}
|
}
|
||||||
@ -237,12 +241,8 @@ public final class GlEffectsFrameProcessor implements FrameProcessor {
|
|||||||
// TODO(b/239757183): Remove the unnecessary MatrixTransformationProcessor after it got
|
// TODO(b/239757183): Remove the unnecessary MatrixTransformationProcessor after it got
|
||||||
// merged with RgbMatrixProcessor.
|
// merged with RgbMatrixProcessor.
|
||||||
textureProcessorListBuilder.add(
|
textureProcessorListBuilder.add(
|
||||||
new MatrixTransformationProcessor(
|
MatrixTransformationProcessor.createWithExternalSamplerApplyingEotf(
|
||||||
context,
|
context, /* matrixTransformations= */ ImmutableList.of(), colorInfo));
|
||||||
ImmutableList.of(),
|
|
||||||
sampleFromExternalTexture,
|
|
||||||
colorInfo,
|
|
||||||
/* outputElectricalColors= */ false));
|
|
||||||
sampleFromExternalTexture = false;
|
sampleFromExternalTexture = false;
|
||||||
}
|
}
|
||||||
textureProcessorListBuilder.add(
|
textureProcessorListBuilder.add(
|
||||||
|
@ -20,6 +20,7 @@ import android.opengl.Matrix;
|
|||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import androidx.media3.common.FrameProcessingException;
|
import androidx.media3.common.FrameProcessingException;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies a 4x4 transformation {@link Matrix} to apply in the vertex shader for each frame.
|
* Specifies a 4x4 transformation {@link Matrix} to apply in the vertex shader for each frame.
|
||||||
@ -54,6 +55,7 @@ public interface GlMatrixTransformation extends GlEffect {
|
|||||||
@Override
|
@Override
|
||||||
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
default SingleFrameGlTextureProcessor toGlTextureProcessor(Context context, boolean useHdr)
|
||||||
throws FrameProcessingException {
|
throws FrameProcessingException {
|
||||||
return new MatrixTransformationProcessor(context, useHdr, /* matrixTransformation= */ this);
|
return MatrixTransformationProcessor.create(
|
||||||
|
context, /* matrixTransformations= */ ImmutableList.of(this), useHdr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,97 +112,61 @@ import java.util.Arrays;
|
|||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*
|
*
|
||||||
* @param context The {@link Context}.
|
* <p>Input and output are both intermediate optical colors, which are linear RGB BT.2020 if
|
||||||
* @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be
|
* {@code useHdr} is {@code true} and gamma RGB BT.709 if not.
|
||||||
* in linear RGB BT.2020. If {@code false}, colors will be in gamma RGB BT.709.
|
|
||||||
* @param matrixTransformation A {@link MatrixTransformation} that specifies the transformation
|
|
||||||
* matrix to use for each frame.
|
|
||||||
* @throws FrameProcessingException If a problem occurs while reading shader files.
|
|
||||||
*/
|
|
||||||
public MatrixTransformationProcessor(
|
|
||||||
Context context, boolean useHdr, MatrixTransformation matrixTransformation)
|
|
||||||
throws FrameProcessingException {
|
|
||||||
this(
|
|
||||||
createGlProgram(
|
|
||||||
context,
|
|
||||||
/* inputElectricalColorsFromExternalTexture= */ false,
|
|
||||||
useHdr,
|
|
||||||
/* outputElectricalColors= */ false),
|
|
||||||
ImmutableList.of(matrixTransformation),
|
|
||||||
useHdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance.
|
|
||||||
*
|
|
||||||
* @param context The {@link Context}.
|
|
||||||
* @param useHdr Whether input textures come from an HDR source. If {@code true}, colors will be
|
|
||||||
* in linear RGB BT.2020. If {@code false}, colors will be in gamma RGB BT.709.
|
|
||||||
* @param matrixTransformation A {@link GlMatrixTransformation} that specifies the transformation
|
|
||||||
* matrix to use for each frame.
|
|
||||||
* @throws FrameProcessingException If a problem occurs while reading shader files.
|
|
||||||
*/
|
|
||||||
public MatrixTransformationProcessor(
|
|
||||||
Context context, boolean useHdr, GlMatrixTransformation matrixTransformation)
|
|
||||||
throws FrameProcessingException {
|
|
||||||
this(
|
|
||||||
createGlProgram(
|
|
||||||
context,
|
|
||||||
/* inputElectricalColorsFromExternalTexture= */ false,
|
|
||||||
useHdr,
|
|
||||||
/* outputElectricalColors= */ false),
|
|
||||||
ImmutableList.of(matrixTransformation),
|
|
||||||
useHdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance.
|
|
||||||
*
|
|
||||||
* <p>Able to convert nonlinear electrical {@link ColorInfo} inputs and outputs to and from the
|
|
||||||
* intermediate optical {@link GlTextureProcessor} colors of linear RGB BT.2020 for HDR, and gamma
|
|
||||||
* RGB BT.709 for SDR.
|
|
||||||
*
|
*
|
||||||
* @param context The {@link Context}.
|
* @param context The {@link Context}.
|
||||||
* @param matrixTransformations The {@link GlMatrixTransformation GlMatrixTransformations} to
|
* @param matrixTransformations The {@link GlMatrixTransformation GlMatrixTransformations} to
|
||||||
* apply to each frame in order.
|
* apply to each frame in order.
|
||||||
* @param inputElectricalColorsFromExternalTexture Whether electrical color input will be provided
|
* @param useHdr Whether input and output colors are HDR.
|
||||||
* 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 electricalColorInfo The electrical {@link ColorInfo}, only used to transform between
|
|
||||||
* color spaces and transfers, when {@code inputElectricalColorsFromExternalTexture} or {@code
|
|
||||||
* outputElectricalColors} are {@code true}. If it is {@linkplain
|
|
||||||
* ColorInfo#isTransferHdr(ColorInfo) HDR}, intermediate {@link GlTextureProcessor} colors
|
|
||||||
* will be in linear RGB BT.2020. Otherwise, these colors will be in gamma RGB BT.709.
|
|
||||||
* @param outputElectricalColors If {@code true}, outputs {@code electricalColorInfo}. If {@code
|
|
||||||
* false}, outputs intermediate colors of linear RGB BT.2020 if {@code electricalColorInfo} is
|
|
||||||
* {@linkplain ColorInfo#isTransferHdr(ColorInfo) HDR}, and gamma RGB BT.709 otherwise.
|
|
||||||
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
|
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
|
||||||
* operation fails or is unsupported.
|
* operation fails or is unsupported.
|
||||||
*/
|
*/
|
||||||
public MatrixTransformationProcessor(
|
public static MatrixTransformationProcessor create(
|
||||||
|
Context context, ImmutableList<GlMatrixTransformation> matrixTransformations, boolean useHdr)
|
||||||
|
throws FrameProcessingException {
|
||||||
|
GlProgram glProgram =
|
||||||
|
createGlProgram(context, VERTEX_SHADER_TRANSFORMATION_PATH, FRAGMENT_SHADER_COPY_PATH);
|
||||||
|
|
||||||
|
// No transfer functions needed, because input and output are both optical colors.
|
||||||
|
return new MatrixTransformationProcessor(glProgram, matrixTransformations, useHdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*
|
||||||
|
* <p>Input will be sampled from an external texture. The caller should use {@link
|
||||||
|
* #setTextureTransformMatrix(float[])} to provide the transformation matrix associated with the
|
||||||
|
* external texture.
|
||||||
|
*
|
||||||
|
* <p>Applies the {@code electricalColorInfo} EOTF to convert from electrical color input, to
|
||||||
|
* intermediate optical {@link GlTextureProcessor} color output, before {@code
|
||||||
|
* matrixTransformations} are applied.
|
||||||
|
*
|
||||||
|
* <p>Intermediate optical colors are linear RGB BT.2020 if {@code electricalColorInfo} is
|
||||||
|
* {@linkplain ColorInfo#isTransferHdr(ColorInfo) HDR}, and gamma RGB BT.709 if not.
|
||||||
|
*
|
||||||
|
* @param context The {@link Context}.
|
||||||
|
* @param matrixTransformations The {@link GlMatrixTransformation GlMatrixTransformations} to
|
||||||
|
* apply to each frame in order.
|
||||||
|
* @param electricalColorInfo The electrical {@link ColorInfo} describing input colors.
|
||||||
|
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
|
||||||
|
* operation fails or is unsupported.
|
||||||
|
*/
|
||||||
|
public static MatrixTransformationProcessor createWithExternalSamplerApplyingEotf(
|
||||||
Context context,
|
Context context,
|
||||||
ImmutableList<GlMatrixTransformation> matrixTransformations,
|
ImmutableList<GlMatrixTransformation> matrixTransformations,
|
||||||
boolean inputElectricalColorsFromExternalTexture,
|
ColorInfo electricalColorInfo)
|
||||||
ColorInfo electricalColorInfo,
|
|
||||||
boolean outputElectricalColors)
|
|
||||||
throws FrameProcessingException {
|
throws FrameProcessingException {
|
||||||
this(
|
boolean useHdr = ColorInfo.isTransferHdr(electricalColorInfo);
|
||||||
createGlProgram(
|
String vertexShaderFilePath =
|
||||||
context,
|
useHdr ? VERTEX_SHADER_TRANSFORMATION_ES3_PATH : VERTEX_SHADER_TRANSFORMATION_PATH;
|
||||||
inputElectricalColorsFromExternalTexture,
|
String fragmentShaderFilePath =
|
||||||
ColorInfo.isTransferHdr(electricalColorInfo),
|
useHdr ? FRAGMENT_SHADER_COPY_EXTERNAL_YUV_ES3_PATH : FRAGMENT_SHADER_COPY_EXTERNAL_PATH;
|
||||||
outputElectricalColors),
|
GlProgram glProgram = createGlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
|
||||||
matrixTransformations,
|
|
||||||
ColorInfo.isTransferHdr(electricalColorInfo));
|
|
||||||
if (!ColorInfo.isTransferHdr(electricalColorInfo)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@C.ColorTransfer int colorTransfer = electricalColorInfo.colorTransfer;
|
// TODO(b/241902517): Implement gamma transfer functions.
|
||||||
checkArgument(
|
if (useHdr) {
|
||||||
colorTransfer == C.COLOR_TRANSFER_HLG || colorTransfer == C.COLOR_TRANSFER_ST2084);
|
|
||||||
if (inputElectricalColorsFromExternalTexture) {
|
|
||||||
// In HDR editing mode the decoder output is sampled in YUV.
|
// In HDR editing mode the decoder output is sampled in YUV.
|
||||||
if (!GlUtil.isYuvTargetExtensionSupported()) {
|
if (!GlUtil.isYuvTargetExtensionSupported()) {
|
||||||
throw new FrameProcessingException(
|
throw new FrameProcessingException(
|
||||||
@ -214,14 +178,102 @@ import java.util.Arrays;
|
|||||||
? BT2020_FULL_RANGE_YUV_TO_RGB_COLOR_TRANSFORM_MATRIX
|
? BT2020_FULL_RANGE_YUV_TO_RGB_COLOR_TRANSFORM_MATRIX
|
||||||
: BT2020_LIMITED_RANGE_YUV_TO_RGB_COLOR_TRANSFORM_MATRIX);
|
: BT2020_LIMITED_RANGE_YUV_TO_RGB_COLOR_TRANSFORM_MATRIX);
|
||||||
|
|
||||||
// TODO(b/241902517): Implement gamma transfer functions.
|
@C.ColorTransfer int colorTransfer = electricalColorInfo.colorTransfer;
|
||||||
|
checkArgument(
|
||||||
|
colorTransfer == C.COLOR_TRANSFER_HLG || colorTransfer == C.COLOR_TRANSFER_ST2084);
|
||||||
|
glProgram.setIntUniform("uEotfColorTransfer", colorTransfer);
|
||||||
|
}
|
||||||
|
|
||||||
// If electrical colors are both input and output, no EOTF is needed.
|
return new MatrixTransformationProcessor(glProgram, matrixTransformations, useHdr);
|
||||||
glProgram.setIntUniform(
|
}
|
||||||
"uEotfColorTransfer", outputElectricalColors ? Format.NO_VALUE : colorTransfer);
|
|
||||||
} else if (outputElectricalColors) {
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*
|
||||||
|
* <p>Applies the {@code electricalColorInfo} OETF to convert from intermediate optical {@link
|
||||||
|
* GlTextureProcessor} color input, to electrical color output, after {@code
|
||||||
|
* matrixTransformations} are applied.
|
||||||
|
*
|
||||||
|
* <p>Intermediate optical colors are linear RGB BT.2020 if {@code electricalColorInfo} is
|
||||||
|
* {@linkplain ColorInfo#isTransferHdr(ColorInfo) HDR}, and gamma RGB BT.709 if not.
|
||||||
|
*
|
||||||
|
* @param context The {@link Context}.
|
||||||
|
* @param matrixTransformations The {@link GlMatrixTransformation GlMatrixTransformations} to
|
||||||
|
* apply to each frame in order.
|
||||||
|
* @param electricalColorInfo The electrical {@link ColorInfo} describing output colors.
|
||||||
|
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
|
||||||
|
* operation fails or is unsupported.
|
||||||
|
*/
|
||||||
|
public static MatrixTransformationProcessor createApplyingOetf(
|
||||||
|
Context context,
|
||||||
|
ImmutableList<GlMatrixTransformation> matrixTransformations,
|
||||||
|
ColorInfo electricalColorInfo)
|
||||||
|
throws FrameProcessingException {
|
||||||
|
boolean useHdr = ColorInfo.isTransferHdr(electricalColorInfo);
|
||||||
|
String vertexShaderFilePath =
|
||||||
|
useHdr ? VERTEX_SHADER_TRANSFORMATION_ES3_PATH : VERTEX_SHADER_TRANSFORMATION_PATH;
|
||||||
|
String fragmentShaderFilePath =
|
||||||
|
useHdr ? FRAGMENT_SHADER_OETF_ES3_PATH : FRAGMENT_SHADER_COPY_PATH;
|
||||||
|
GlProgram glProgram = createGlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
|
||||||
|
|
||||||
|
// TODO(b/241902517): Implement gamma transfer functions.
|
||||||
|
if (useHdr) {
|
||||||
|
@C.ColorTransfer int colorTransfer = electricalColorInfo.colorTransfer;
|
||||||
|
checkArgument(
|
||||||
|
colorTransfer == C.COLOR_TRANSFER_HLG || colorTransfer == C.COLOR_TRANSFER_ST2084);
|
||||||
glProgram.setIntUniform("uOetfColorTransfer", colorTransfer);
|
glProgram.setIntUniform("uOetfColorTransfer", colorTransfer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new MatrixTransformationProcessor(glProgram, matrixTransformations, useHdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance.
|
||||||
|
*
|
||||||
|
* <p>Input will be sampled from an external texture. The caller should use {@link
|
||||||
|
* #setTextureTransformMatrix(float[])} to provide the transformation matrix associated with the
|
||||||
|
* external texture.
|
||||||
|
*
|
||||||
|
* <p>Applies the OETF, {@code matrixTransformations}, then the EOTF, to convert from and to input
|
||||||
|
* and output electrical colors.
|
||||||
|
*
|
||||||
|
* @param context The {@link Context}.
|
||||||
|
* @param matrixTransformations The {@link GlMatrixTransformation GlMatrixTransformations} to
|
||||||
|
* apply to each frame in order.
|
||||||
|
* @param electricalColorInfo The electrical {@link ColorInfo} describing input and output colors.
|
||||||
|
* @throws FrameProcessingException If a problem occurs while reading shader files or an OpenGL
|
||||||
|
* operation fails or is unsupported.
|
||||||
|
*/
|
||||||
|
public static MatrixTransformationProcessor createWithExternalSamplerApplyingEotfThenOetf(
|
||||||
|
Context context,
|
||||||
|
ImmutableList<GlMatrixTransformation> matrixTransformations,
|
||||||
|
ColorInfo electricalColorInfo)
|
||||||
|
throws FrameProcessingException {
|
||||||
|
boolean useHdr = ColorInfo.isTransferHdr(electricalColorInfo);
|
||||||
|
String vertexShaderFilePath =
|
||||||
|
useHdr ? VERTEX_SHADER_TRANSFORMATION_ES3_PATH : VERTEX_SHADER_TRANSFORMATION_PATH;
|
||||||
|
String fragmentShaderFilePath =
|
||||||
|
useHdr ? FRAGMENT_SHADER_COPY_EXTERNAL_YUV_ES3_PATH : FRAGMENT_SHADER_COPY_EXTERNAL_PATH;
|
||||||
|
GlProgram glProgram = createGlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
|
||||||
|
|
||||||
|
// TODO(b/241902517): Implement gamma transfer functions.
|
||||||
|
if (useHdr) {
|
||||||
|
// 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(
|
||||||
|
"uYuvToRgbColorTransform",
|
||||||
|
electricalColorInfo.colorRange == C.COLOR_RANGE_FULL
|
||||||
|
? BT2020_FULL_RANGE_YUV_TO_RGB_COLOR_TRANSFORM_MATRIX
|
||||||
|
: BT2020_LIMITED_RANGE_YUV_TO_RGB_COLOR_TRANSFORM_MATRIX);
|
||||||
|
|
||||||
|
// No transfer functions needed, because the EOTF and OETF cancel out.
|
||||||
|
glProgram.setIntUniform("uEotfColorTransfer", Format.NO_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MatrixTransformationProcessor(glProgram, matrixTransformations, useHdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -243,36 +295,15 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
transformationMatrixCache = new float[matrixTransformations.size()][16];
|
transformationMatrixCache = new float[matrixTransformations.size()][16];
|
||||||
compositeTransformationMatrix = new float[16];
|
compositeTransformationMatrix = new float[16];
|
||||||
tempResultMatrix = new float[16];
|
|
||||||
Matrix.setIdentityM(compositeTransformationMatrix, /* smOffset= */ 0);
|
Matrix.setIdentityM(compositeTransformationMatrix, /* smOffset= */ 0);
|
||||||
|
tempResultMatrix = new float[16];
|
||||||
visiblePolygon = NDC_SQUARE;
|
visiblePolygon = NDC_SQUARE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GlProgram createGlProgram(
|
private static GlProgram createGlProgram(
|
||||||
Context context,
|
Context context, String vertexShaderFilePath, String fragmentShaderFilePath)
|
||||||
boolean inputElectricalColorsFromExternalTexture,
|
|
||||||
boolean useHdr,
|
|
||||||
boolean outputElectricalColors)
|
|
||||||
throws FrameProcessingException {
|
throws FrameProcessingException {
|
||||||
|
|
||||||
String vertexShaderFilePath;
|
|
||||||
String fragmentShaderFilePath;
|
|
||||||
if (inputElectricalColorsFromExternalTexture) {
|
|
||||||
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 (outputElectricalColors && useHdr) {
|
|
||||||
vertexShaderFilePath = VERTEX_SHADER_TRANSFORMATION_ES3_PATH;
|
|
||||||
fragmentShaderFilePath = FRAGMENT_SHADER_OETF_ES3_PATH;
|
|
||||||
} else {
|
|
||||||
vertexShaderFilePath = VERTEX_SHADER_TRANSFORMATION_PATH;
|
|
||||||
fragmentShaderFilePath = FRAGMENT_SHADER_COPY_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
GlProgram glProgram;
|
GlProgram glProgram;
|
||||||
try {
|
try {
|
||||||
glProgram = new GlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
|
glProgram = new GlProgram(context, vertexShaderFilePath, fragmentShaderFilePath);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user