Skip to content

Commit

Permalink
Update sdr internal fsh to accept input color transfer
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 527271212
  • Loading branch information
tof-tof authored and icbaker committed Apr 27, 2023
1 parent 3693ca4 commit 178a323
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// texture created from a bitmap), with uTexSampler copying from this texture
// to the current output.
// 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.
// 4. Outputs as requested by uOutputColorTransfer. Use COLOR_TRANSFER_LINEAR
// for outputting to intermediate shaders, or COLOR_TRANSFER_SDR_VIDEO to
Expand All @@ -31,13 +31,18 @@ uniform mat4 uRgbMatrix;
varying vec2 vTexSamplingCoord;
// C.java#ColorTransfer value.
// Only COLOR_TRANSFER_LINEAR and COLOR_TRANSFER_SDR_VIDEO are allowed.
uniform int uInputColorTransfer;
uniform int uOutputColorTransfer;
uniform int uEnableColorTransfer;

const float inverseGamma = 0.4500;
const float gamma = 1.0 / inverseGamma;
const int GL_FALSE = 0;
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
// EOTF.
Expand All @@ -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.
float smpte170mOetfSingleChannel(float opticalChannel) {
// Specification:
Expand All @@ -74,13 +97,29 @@ vec3 smpte170mOetf(vec3 opticalColor) {
smpte170mOetfSingleChannel(opticalColor.g),
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
// electrical signals. Input and output are both normalized to [0, 1].
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
|| uEnableColorTransfer == GL_FALSE) {
return linearColor;
Expand All @@ -92,27 +131,22 @@ highp vec3 applyOetf(highp vec3 linearColor) {
}
}

vec3 applyEotf(vec3 electricalColor){
if (uEnableColorTransfer == GL_TRUE){
return srgbEotf(electricalColor) ;
} else if (uEnableColorTransfer == GL_FALSE) {
return electricalColor;
vec2 getAdjustedTexSamplingCoord(vec2 originalTexSamplingCoord){
if (uInputColorTransfer == COLOR_TRANSFER_SRGB){
// 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.
return vec2(originalTexSamplingCoord.x, 1.0 - originalTexSamplingCoord.y);
} else {
// Output blue as an obviously visible error.
return vec3(0.0, 0.0, 1.0);
return originalTexSamplingCoord;
}
}

void main() {
vec2 vTexSamplingCoordFlipped =
vec2(vTexSamplingCoord.x, 1.0 - vTexSamplingCoord.y);
// 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);
vec4 inputColor = texture2D(
uTexSampler, getAdjustedTexSamplingCoord(vTexSamplingCoord));
vec3 linearInputColor = applyEotf(inputColor.rgb);

vec4 transformedColors = uRgbMatrix * vec4(linearInputColor, 1);

gl_FragColor = vec4(applyOetf(transformedColors.rgb), inputColor.a);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package androidx.media3.effect;

import static androidx.media3.common.VideoFrameProcessor.INPUT_TYPE_BITMAP;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkState;

Expand All @@ -25,6 +26,7 @@
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;
import androidx.media3.common.util.GlUtil;
import androidx.media3.common.util.Size;
Expand Down Expand Up @@ -199,16 +201,20 @@ public static DefaultShaderProgram createWithInternalSampler(
List<RgbMatrix> rgbMatrices,
ColorInfo inputColorInfo,
ColorInfo outputColorInfo,
boolean enableColorTransfers)
boolean enableColorTransfers,
@InputType int inputType)
throws VideoFrameProcessingException {
checkState(
!ColorInfo.isTransferHdr(inputColorInfo),
"DefaultShaderProgram doesn't support HDR internal sampler input yet.");
checkState(
inputColorInfo.colorTransfer != C.COLOR_TRANSFER_SRGB || inputType == INPUT_TYPE_BITMAP);
GlProgram glProgram =
createGlProgram(
context,
VERTEX_SHADER_TRANSFORMATION_PATH,
FRAGMENT_SHADER_TRANSFORMATION_SDR_INTERNAL_PATH);
glProgram.setIntUniform("uInputColorTransfer", inputColorInfo.colorTransfer);
return createWithSampler(
glProgram,
matrixTransformations,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,8 @@ private static ImmutableList<GlShaderProgram> getGlShaderProgramsForGlEffects(
rgbMatrices,
inputColorInfo,
linearColorInfo,
enableColorTransfers);
enableColorTransfers,
inputType);
}
} else {
defaultShaderProgram =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,8 @@ private synchronized DefaultShaderProgram createDefaultShaderProgram(
rgbMatrices,
inputColorInfo,
outputColorInfo,
enableColorTransfers);
enableColorTransfers,
inputType);
}
} else {
defaultShaderProgram =
Expand Down

0 comments on commit 178a323

Please sign in to comment.