summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-05-01 23:59:00 +0200
committerwm4 <wm4@nowhere>2013-05-04 01:32:50 +0200
commit872aefaa1521a8cf70c6e14f3356e9d00ed7efa3 (patch)
tree4f04a63b9c31d71a326a112004e8d8e213e739e4
parent16d40828aecf4028acadeeecaf0294756298f970 (diff)
downloadmpv-872aefaa1521a8cf70c6e14f3356e9d00ed7efa3.tar.bz2
mpv-872aefaa1521a8cf70c6e14f3356e9d00ed7efa3.tar.xz
vo_opengl: XYZ input support
Useful for the j2k decoder. Matrix taken from http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html (XYZ to sRGB, whitepoint D65) Gamma conversion follows what libswscale does (2.6 in, 2.2 out). If linear RGB is used internally for scaling, the gamma conversion will be undone by setting the exponent to 1. Unfortunately, the two gamma values don't compensate each others exactly (2.2 vs. 1/0.45=2.22...), so output is a little bit incorrect in sRGB or color-managed mode. But for now try hard to match libswscale output, which may or may not be correct.
-rw-r--r--video/csputils.c26
-rw-r--r--video/csputils.h1
-rw-r--r--video/out/gl_video.c47
-rw-r--r--video/out/gl_video_shaders.glsl8
4 files changed, 70 insertions, 12 deletions
diff --git a/video/csputils.c b/video/csputils.c
index 23eb099f69..e7ea5a388b 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -40,6 +40,7 @@ char * const mp_csp_names[MP_CSP_COUNT] = {
"BT.709 (HD)",
"SMPTE-240M",
"RGB",
+ "XYZ",
};
char * const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = {
@@ -165,10 +166,30 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
int format = params->colorspace.format;
if (format <= MP_CSP_AUTO || format >= MP_CSP_COUNT)
format = MP_CSP_BT_601;
+ int levels_in = params->colorspace.levels_in;
+ if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT)
+ levels_in = MP_CSP_LEVELS_TV;
+
switch (format) {
case MP_CSP_BT_601: luma_coeffs(m, 0.299, 0.587, 0.114 ); break;
case MP_CSP_BT_709: luma_coeffs(m, 0.2126, 0.7152, 0.0722); break;
case MP_CSP_SMPTE_240M: luma_coeffs(m, 0.2122, 0.7013, 0.0865); break;
+ case MP_CSP_RGB: {
+ static const float ident[3][4] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+ memcpy(m, ident, sizeof(ident));
+ levels_in = -1;
+ break;
+ }
+ case MP_CSP_XYZ: {
+ static const float xyz_to_rgb[3][4] = {
+ {3.2404542, -1.5371385, -0.4985314},
+ {-0.9692660, 1.8760108, 0.0415560},
+ {0.0556434, -0.2040259, 1.0572252},
+ };
+ memcpy(m, xyz_to_rgb, sizeof(xyz_to_rgb));
+ levels_in = -1;
+ break;
+ }
default:
abort();
};
@@ -183,9 +204,6 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
m[i][COL_V] = huesin * u + huecos * m[i][COL_V];
}
- int levels_in = params->colorspace.levels_in;
- if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT)
- levels_in = MP_CSP_LEVELS_TV;
assert(params->input_bits >= 8);
assert(params->texture_bits >= params->input_bits);
double s = (1 << params->input_bits-8) / ((1<<params->texture_bits)-1.);
@@ -193,10 +211,12 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
struct yuvlevels { double ymin, ymax, cmin, cmid; }
yuvlim = { 16*s, 235*s, 16*s, 128*s },
yuvfull = { 0*s, 255*s, 1*s, 128*s }, // '1' for symmetry around 128
+ anyfull = { 0*s, 255*s, -255*s/2, 0 },
yuvlev;
switch (levels_in) {
case MP_CSP_LEVELS_TV: yuvlev = yuvlim; break;
case MP_CSP_LEVELS_PC: yuvlev = yuvfull; break;
+ case -1: yuvlev = anyfull; break;
default:
abort();
}
diff --git a/video/csputils.h b/video/csputils.h
index d66bb86fa3..184e1ee76a 100644
--- a/video/csputils.h
+++ b/video/csputils.h
@@ -40,6 +40,7 @@ enum mp_csp {
MP_CSP_BT_709,
MP_CSP_SMPTE_240M,
MP_CSP_RGB,
+ MP_CSP_XYZ,
MP_CSP_COUNT
};
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index 43dbb843f1..a000624f9c 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -168,6 +168,8 @@ struct gl_video {
bool is_yuv, is_rgb;
bool is_linear_rgb;
+ float input_gamma, conv_gamma;
+
// per pixel (full pixel when packed, each component when planar)
int plane_bits;
int plane_count;
@@ -452,6 +454,11 @@ static void update_uniforms(struct gl_video *p, GLuint program)
.texture_bits = (p->plane_bits + 7) & ~7,
};
mp_csp_copy_equalizer_values(&cparams, &p->video_eq);
+ if (p->image_desc.flags & MP_IMGFLAG_XYZ) {
+ cparams.colorspace.format = MP_CSP_XYZ;
+ cparams.input_bits = 8;
+ cparams.texture_bits = 8;
+ }
loc = gl->GetUniformLocation(program, "transform");
if (loc >= 0) {
@@ -463,11 +470,16 @@ static void update_uniforms(struct gl_video *p, GLuint program)
loc = gl->GetUniformLocation(program, "colormatrix");
if (loc >= 0) {
float yuv2rgb[3][4] = {{0}};
- if (p->is_yuv)
- mp_get_yuv2rgb_coeffs(&cparams, yuv2rgb);
+ mp_get_yuv2rgb_coeffs(&cparams, yuv2rgb);
gl->UniformMatrix4x3fv(loc, 1, GL_TRUE, &yuv2rgb[0][0]);
}
+ gl->Uniform1f(gl->GetUniformLocation(program, "input_gamma"),
+ p->input_gamma);
+
+ gl->Uniform1f(gl->GetUniformLocation(program, "conv_gamma"),
+ p->conv_gamma);
+
gl->Uniform3f(gl->GetUniformLocation(program, "inv_gamma"),
1.0 / cparams.rgamma,
1.0 / cparams.ggamma,
@@ -704,8 +716,22 @@ static void compile_shaders(struct gl_video *p)
char *header_final = talloc_strdup(tmp, "");
char *header_sep = NULL;
- bool convert_input_to_linear = !p->is_linear_rgb &&
- (p->opts.srgb || p->use_lut_3d);
+ float input_gamma = 1.0;
+ float conv_gamma = 1.0;
+
+ if (p->image_desc.flags & MP_IMGFLAG_XYZ) {
+ input_gamma *= 2.6;
+ conv_gamma *= 1.0 / 2.2;
+ }
+
+ if (!p->is_linear_rgb && (p->opts.srgb || p->use_lut_3d))
+ conv_gamma *= 1.0 / 0.45;
+
+ p->input_gamma = input_gamma;
+ p->conv_gamma = conv_gamma;
+
+ bool convert_input_gamma = p->input_gamma != 1.0;
+ bool convert_input_to_linear = p->conv_gamma != 1.0;
if (p->image_format == IMGFMT_NV12 || p->image_format == IMGFMT_NV21) {
shader_def(&header_conv, "USE_CONV", "CONV_NV12");
@@ -716,8 +742,9 @@ static void compile_shaders(struct gl_video *p)
shader_def_opt(&header_conv, "USE_GBRP", p->image_format == IMGFMT_GBRP);
shader_def_opt(&header_conv, "USE_SWAP_UV", p->image_format == IMGFMT_NV21);
shader_def_opt(&header_conv, "USE_YGRAY", p->is_yuv && p->plane_count == 1);
- shader_def_opt(&header_conv, "USE_COLORMATRIX", p->is_yuv);
- shader_def_opt(&header_conv, "USE_LINEAR_CONV", convert_input_to_linear);
+ shader_def_opt(&header_conv, "USE_INPUT_GAMMA", convert_input_gamma);
+ shader_def_opt(&header_conv, "USE_COLORMATRIX", !p->is_rgb);
+ shader_def_opt(&header_conv, "USE_CONV_GAMMA", convert_input_to_linear);
if (p->opts.enable_alpha && p->plane_count == 4)
shader_def(&header_conv, "USE_ALPHA_PLANE", "3");
@@ -745,7 +772,7 @@ static void compile_shaders(struct gl_video *p)
// Don't sample from input video textures before converting the input to
// linear light. (Unneeded when sRGB textures are used.)
- if (convert_input_to_linear)
+ if (convert_input_gamma || convert_input_to_linear)
use_indirect = true;
// It doesn't make sense to scale the chroma with cscale in the 1. scale
@@ -1634,6 +1661,12 @@ static bool init_format(int fmt, struct gl_video *init)
plane_format[0] = byte_formats[1];
}
+ // XYZ (same roganization as RGB packed, but requires conversion matrix)
+ if (!supported && fmt == IMGFMT_XYZ12) {
+ supported = true;
+ plane_format[0] = IMGFMT_RGB48;
+ }
+
// All formats in mp_to_gl_formats[] are supported
// If it's not in the table, it will be rejected below.
// Includes packed RGB and YUV formats
diff --git a/video/out/gl_video_shaders.glsl b/video/out/gl_video_shaders.glsl
index 2f10e5fdf6..b968cb2c87 100644
--- a/video/out/gl_video_shaders.glsl
+++ b/video/out/gl_video_shaders.glsl
@@ -122,6 +122,7 @@ uniform sampler3D lut_3d;
uniform sampler2D dither;
uniform mat4x3 colormatrix;
uniform vec3 inv_gamma;
+uniform float input_gamma;
uniform float conv_gamma;
uniform float dither_quantization;
uniform float dither_multiply;
@@ -351,11 +352,14 @@ void main() {
// wrong for 9/10 bit input
color.gb = vec2(128.0/255.0);
#endif
+#ifdef USE_INPUT_GAMMA
+ color = pow(color, vec3(input_gamma));
+#endif
#ifdef USE_COLORMATRIX
color = mat3(colormatrix) * color + colormatrix[3];
#endif
-#ifdef USE_LINEAR_CONV
- color = pow(color, vec3(1.0/0.45));
+#ifdef USE_CONV_GAMMA
+ color = pow(color, vec3(conv_gamma));
#endif
#ifdef USE_LINEAR_CONV_INV
// Convert from linear RGB to gamma RGB before putting it through the 3D-LUT