mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Update sdr internal fsh to accept input color transfer
PiperOrigin-RevId: 527271212
This commit is contained in:
parent
3693ca4bbb
commit
178a323897
4 changed files with 64 additions and 22 deletions
|
|
@ -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;
|
||||||
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;
|
||||||
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) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
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) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package androidx.media3.effect;
|
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.checkArgument;
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
|
|
||||||
|
|
@ -25,6 +26,7 @@ import androidx.media3.common.C;
|
||||||
import androidx.media3.common.ColorInfo;
|
import androidx.media3.common.ColorInfo;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.VideoFrameProcessingException;
|
import androidx.media3.common.VideoFrameProcessingException;
|
||||||
|
import androidx.media3.common.VideoFrameProcessor.InputType;
|
||||||
import androidx.media3.common.util.GlProgram;
|
import androidx.media3.common.util.GlProgram;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.media3.common.util.Size;
|
import androidx.media3.common.util.Size;
|
||||||
|
|
@ -199,16 +201,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,
|
||||||
|
|
|
||||||
|
|
@ -595,7 +595,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;
|
||||||
rgbMatrices,
|
rgbMatrices,
|
||||||
inputColorInfo,
|
inputColorInfo,
|
||||||
outputColorInfo,
|
outputColorInfo,
|
||||||
enableColorTransfers);
|
enableColorTransfers,
|
||||||
|
inputType);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defaultShaderProgram =
|
defaultShaderProgram =
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue