Commit b96164d6 by tofunmi Committed by Ian Baker

Update sdr internal fsh to accept input color transfer

PiperOrigin-RevId: 527271212
parent 062ccdf2
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
// texture created from a bitmap), with uTexSampler copying from this texture // texture created from a bitmap), with uTexSampler copying from this texture
// to the current output. // to the current output.
// 2. Transforms the electrical colors to optical colors using the SMPTE 170M // 2. Transforms the electrical colors to optical colors using the SMPTE 170M
// EOTF. // EOTF or the sRGB EOTF, as requested by uInputColorTransfer.
// 3. Applies a 4x4 RGB color matrix to change the pixel colors. // 3. Applies a 4x4 RGB color matrix to change the pixel colors.
// 4. Outputs as requested by uOutputColorTransfer. Use COLOR_TRANSFER_LINEAR // 4. Outputs as requested by uOutputColorTransfer. Use COLOR_TRANSFER_LINEAR
// for outputting to intermediate shaders, or COLOR_TRANSFER_SDR_VIDEO to // for outputting to intermediate shaders, or COLOR_TRANSFER_SDR_VIDEO to
...@@ -31,6 +31,7 @@ uniform mat4 uRgbMatrix; ...@@ -31,6 +31,7 @@ uniform mat4 uRgbMatrix;
varying vec2 vTexSamplingCoord; varying vec2 vTexSamplingCoord;
// C.java#ColorTransfer value. // C.java#ColorTransfer value.
// Only COLOR_TRANSFER_LINEAR and COLOR_TRANSFER_SDR_VIDEO are allowed. // Only COLOR_TRANSFER_LINEAR and COLOR_TRANSFER_SDR_VIDEO are allowed.
uniform int uInputColorTransfer;
uniform int uOutputColorTransfer; uniform int uOutputColorTransfer;
uniform int uEnableColorTransfer; uniform int uEnableColorTransfer;
...@@ -38,6 +39,10 @@ const float inverseGamma = 0.4500; ...@@ -38,6 +39,10 @@ const float inverseGamma = 0.4500;
const float gamma = 1.0 / inverseGamma; const float gamma = 1.0 / inverseGamma;
const int GL_FALSE = 0; const int GL_FALSE = 0;
const int GL_TRUE = 1; const int GL_TRUE = 1;
// LINT.IfChange(color_transfer)
const int COLOR_TRANSFER_LINEAR = 1;
const int COLOR_TRANSFER_SRGB = 2;
const int COLOR_TRANSFER_SDR_VIDEO = 3;
// Transforms a single channel from electrical to optical SDR using the sRGB // Transforms a single channel from electrical to optical SDR using the sRGB
// EOTF. // EOTF.
...@@ -58,6 +63,24 @@ vec3 srgbEotf(const vec3 electricalColor) { ...@@ -58,6 +63,24 @@ vec3 srgbEotf(const vec3 electricalColor) {
); );
} }
// Transforms a single channel from electrical to optical SDR using the SMPTE
// 170M OETF.
float smpte170mEotfSingleChannel(float electricalChannel) {
// Specification:
// https://www.itu.int/rec/R-REC-BT.1700-0-200502-I/en
return electricalChannel < 0.0812
? electricalChannel / 4.500
: pow((electricalChannel + 0.099) / 1.099, gamma);
}
// Transforms electrical to optical SDR using the SMPTE 170M EOTF.
vec3 smpte170mEotf(vec3 electricalColor) {
return vec3(
smpte170mEotfSingleChannel(electricalColor.r),
smpte170mEotfSingleChannel(electricalColor.g),
smpte170mEotfSingleChannel(electricalColor.b));
}
// Transforms a single channel from optical to electrical SDR. // Transforms a single channel from optical to electrical SDR.
float smpte170mOetfSingleChannel(float opticalChannel) { float smpte170mOetfSingleChannel(float opticalChannel) {
// Specification: // Specification:
...@@ -74,13 +97,29 @@ vec3 smpte170mOetf(vec3 opticalColor) { ...@@ -74,13 +97,29 @@ vec3 smpte170mOetf(vec3 opticalColor) {
smpte170mOetfSingleChannel(opticalColor.g), smpte170mOetfSingleChannel(opticalColor.g),
smpte170mOetfSingleChannel(opticalColor.b)); smpte170mOetfSingleChannel(opticalColor.b));
} }
// Applies the appropriate EOTF to convert nonlinear electrical signals to linear
// optical signals. Input and output are both normalized to [0, 1].
vec3 applyEotf(vec3 electricalColor){
if (uEnableColorTransfer == GL_TRUE){
if (uInputColorTransfer == COLOR_TRANSFER_SRGB){
return srgbEotf(electricalColor) ;
} else if (uInputColorTransfer == COLOR_TRANSFER_SDR_VIDEO) {
return smpte170mEotf(electricalColor);
} else {
// Output blue as an obviously visible error.
return vec3(0.0, 0.0, 1.0);
}
} else if (uEnableColorTransfer == GL_FALSE) {
return electricalColor;
} else {
// Output blue as an obviously visible error.
return vec3(0.0, 0.0, 1.0);
}
}
// Applies the appropriate OETF to convert linear optical signals to nonlinear // Applies the appropriate OETF to convert linear optical signals to nonlinear
// electrical signals. Input and output are both normalized to [0, 1]. // electrical signals. Input and output are both normalized to [0, 1].
highp vec3 applyOetf(highp vec3 linearColor) { highp vec3 applyOetf(highp vec3 linearColor) {
// LINT.IfChange(color_transfer)
const int COLOR_TRANSFER_LINEAR = 1;
const int COLOR_TRANSFER_SDR_VIDEO = 3;
if (uOutputColorTransfer == COLOR_TRANSFER_LINEAR if (uOutputColorTransfer == COLOR_TRANSFER_LINEAR
|| uEnableColorTransfer == GL_FALSE) { || uEnableColorTransfer == GL_FALSE) {
return linearColor; return linearColor;
...@@ -92,27 +131,22 @@ highp vec3 applyOetf(highp vec3 linearColor) { ...@@ -92,27 +131,22 @@ highp vec3 applyOetf(highp vec3 linearColor) {
} }
} }
vec3 applyEotf(vec3 electricalColor){ vec2 getAdjustedTexSamplingCoord(vec2 originalTexSamplingCoord){
if (uEnableColorTransfer == GL_TRUE){ if (uInputColorTransfer == COLOR_TRANSFER_SRGB){
return srgbEotf(electricalColor) ; // Whereas the Android system uses the top-left corner as (0,0) of the
} else if (uEnableColorTransfer == GL_FALSE) { // coordinate system, OpenGL uses the bottom-left corner as (0,0), so the
return electricalColor; // texture gets flipped. We flip the texture vertically to ensure the
// orientation of the output is correct.
return vec2(originalTexSamplingCoord.x, 1.0 - originalTexSamplingCoord.y);
} else { } else {
// Output blue as an obviously visible error. return originalTexSamplingCoord;
return vec3(0.0, 0.0, 1.0);
} }
} }
void main() { void main() {
vec2 vTexSamplingCoordFlipped = vec4 inputColor = texture2D(
vec2(vTexSamplingCoord.x, 1.0 - vTexSamplingCoord.y); uTexSampler, getAdjustedTexSamplingCoord(vTexSamplingCoord));
// Whereas the Android system uses the top-left corner as (0,0) of the
// coordinate system, OpenGL uses the bottom-left corner as (0,0), so the
// texture gets flipped. We flip the texture vertically to ensure the
// orientation of the output is correct.
vec4 inputColor = texture2D(uTexSampler, vTexSamplingCoordFlipped);
vec3 linearInputColor = applyEotf(inputColor.rgb); vec3 linearInputColor = applyEotf(inputColor.rgb);
vec4 transformedColors = uRgbMatrix * vec4(linearInputColor, 1); vec4 transformedColors = uRgbMatrix * vec4(linearInputColor, 1);
gl_FragColor = vec4(applyOetf(transformedColors.rgb), inputColor.a); gl_FragColor = vec4(applyOetf(transformedColors.rgb), inputColor.a);
......
...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.effect; ...@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.effect;
import static com.google.android.exoplayer2.util.Assertions.checkArgument; import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import static com.google.android.exoplayer2.util.Assertions.checkState; import static com.google.android.exoplayer2.util.Assertions.checkState;
import static com.google.android.exoplayer2.util.VideoFrameProcessor.INPUT_TYPE_BITMAP;
import android.content.Context; import android.content.Context;
import android.opengl.GLES20; import android.opengl.GLES20;
...@@ -27,6 +28,7 @@ import com.google.android.exoplayer2.util.GlProgram; ...@@ -27,6 +28,7 @@ import com.google.android.exoplayer2.util.GlProgram;
import com.google.android.exoplayer2.util.GlUtil; import com.google.android.exoplayer2.util.GlUtil;
import com.google.android.exoplayer2.util.Size; import com.google.android.exoplayer2.util.Size;
import com.google.android.exoplayer2.util.VideoFrameProcessingException; import com.google.android.exoplayer2.util.VideoFrameProcessingException;
import com.google.android.exoplayer2.util.VideoFrameProcessor.InputType;
import com.google.android.exoplayer2.video.ColorInfo; import com.google.android.exoplayer2.video.ColorInfo;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.io.IOException; import java.io.IOException;
...@@ -197,16 +199,20 @@ import java.util.List; ...@@ -197,16 +199,20 @@ import java.util.List;
List<RgbMatrix> rgbMatrices, List<RgbMatrix> rgbMatrices,
ColorInfo inputColorInfo, ColorInfo inputColorInfo,
ColorInfo outputColorInfo, ColorInfo outputColorInfo,
boolean enableColorTransfers) boolean enableColorTransfers,
@InputType int inputType)
throws VideoFrameProcessingException { throws VideoFrameProcessingException {
checkState( checkState(
!ColorInfo.isTransferHdr(inputColorInfo), !ColorInfo.isTransferHdr(inputColorInfo),
"DefaultShaderProgram doesn't support HDR internal sampler input yet."); "DefaultShaderProgram doesn't support HDR internal sampler input yet.");
checkState(
inputColorInfo.colorTransfer != C.COLOR_TRANSFER_SRGB || inputType == INPUT_TYPE_BITMAP);
GlProgram glProgram = GlProgram glProgram =
createGlProgram( createGlProgram(
context, context,
VERTEX_SHADER_TRANSFORMATION_PATH, VERTEX_SHADER_TRANSFORMATION_PATH,
FRAGMENT_SHADER_TRANSFORMATION_SDR_INTERNAL_PATH); FRAGMENT_SHADER_TRANSFORMATION_SDR_INTERNAL_PATH);
glProgram.setIntUniform("uInputColorTransfer", inputColorInfo.colorTransfer);
return createWithSampler( return createWithSampler(
glProgram, glProgram,
matrixTransformations, matrixTransformations,
......
...@@ -593,7 +593,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor { ...@@ -593,7 +593,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
rgbMatrices, rgbMatrices,
inputColorInfo, inputColorInfo,
linearColorInfo, linearColorInfo,
enableColorTransfers); enableColorTransfers,
inputType);
} }
} else { } else {
defaultShaderProgram = defaultShaderProgram =
......
...@@ -477,7 +477,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; ...@@ -477,7 +477,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
rgbMatrices, rgbMatrices,
inputColorInfo, inputColorInfo,
outputColorInfo, outputColorInfo,
enableColorTransfers); enableColorTransfers,
inputType);
} }
} else { } else {
defaultShaderProgram = defaultShaderProgram =
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment