summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2014-03-31 04:51:47 +0200
committerwm4 <wm4@nowhere>2014-06-22 19:02:06 +0200
commit7f3ea1280228175664241ba5b8edaee48fd33439 (patch)
tree5871bc9e91fbf9f2ff7a9aae28518d7295d536d5
parent17762a1919947db0e66e025bd2084de896eaa3fa (diff)
downloadmpv-7f3ea1280228175664241ba5b8edaee48fd33439.tar.bz2
mpv-7f3ea1280228175664241ba5b8edaee48fd33439.tar.xz
video: Better support for XYZ input
With this change, XYZ input is directly converted to the output colorspace wherever possible, and to the colorspace specified by the tags and/or --primaries option, otherwise. This commit also restructures some of the CMS code in gl_video.c to hopefully make it clearer which decision is being done where and why.
-rw-r--r--video/csputils.c30
-rw-r--r--video/csputils.h3
-rw-r--r--video/mp_image.c5
-rw-r--r--video/out/gl_video.c40
4 files changed, 67 insertions, 11 deletions
diff --git a/video/csputils.c b/video/csputils.c
index 8b36615de6..bd56a1e29f 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -436,6 +436,36 @@ static void luma_coeffs(float m[3][4], float lr, float lg, float lb)
}
/**
+ * \brief get the coefficients of an xyz -> rgb conversion matrix
+ * \param params parameters for the conversion, only brightness is used
+ * \param prim primaries of the RGB space to transform to
+ * \param m array to store the coefficients into
+ */
+void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, struct mp_csp_primaries prim, float m[3][4])
+{
+ float tmp[3][3], brightness = params->brightness;
+ mp_get_rgb2xyz_matrix(prim, tmp);
+ mp_invert_matrix3x3(tmp);
+
+ // Since this outputs linear RGB rather than companded RGB, we
+ // want to linearize any brightness additions. 2 is a reasonable
+ // approximation for any sort of gamma function that could be in use.
+ // As this is an aesthetic setting only, any exact values do not matter.
+ if (brightness < 0) {
+ brightness *= -brightness;
+ } else {
+ brightness *= brightness;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++)
+ m[i][j] = tmp[i][j];
+
+ m[i][COL_C] = brightness;
+ }
+}
+
+/**
* \brief get the coefficients of the yuv -> rgb conversion matrix
* \param params struct specifying the properties of the conversion like
* brightness, ...
diff --git a/video/csputils.h b/video/csputils.h
index 8a17c23110..f2e96beb3d 100644
--- a/video/csputils.h
+++ b/video/csputils.h
@@ -127,6 +127,7 @@ enum mp_csp_equalizer_param {
| (1 << MP_CSP_EQ_SATURATION) )
#define MP_CSP_EQ_CAPS_GAMMA (1 << MP_CSP_EQ_GAMMA)
+#define MP_CSP_EQ_CAPS_BRIGHTNESS (1 << MP_CSP_EQ_BRIGHTNESS)
extern const char *const mp_csp_equalizer_names[MP_CSP_EQ_COUNT];
@@ -188,6 +189,8 @@ struct mp_csp_primaries mp_get_csp_primaries(enum mp_csp_prim csp);
void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest, float cms_matrix[3][3]);
void mp_get_rgb2xyz_matrix(struct mp_csp_primaries space, float m[3][3]);
+
+void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, struct mp_csp_primaries prim, float xyz2rgb[3][4]);
void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]);
void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size);
diff --git a/video/mp_image.c b/video/mp_image.c
index 521b3d8e90..eb754499d1 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -566,7 +566,10 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
// since that's the most likely scenario. Proper VOs should ignore
// this field as well as the matrix and treat XYZ input as absolute,
// but for VOs which use the matrix (and hence, consult this field)
- // this is the correct parameter.
+ // this is the correct parameter. This doubles as a reasonable output
+ // gamut for VOs which *do* use the specialized XYZ matrix but don't
+ // know any better output gamut other than whatever the source is
+ // tagged with.
if (params->primaries == MP_CSP_PRIM_AUTO)
params->primaries = MP_CSP_PRIM_BT_709;
} else {
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index c2ed11be5c..989c1792db 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -575,9 +575,13 @@ static void update_uniforms(struct gl_video *p, GLuint program)
loc = gl->GetUniformLocation(program, "colormatrix");
if (loc >= 0) {
- float yuv2rgb[3][4] = {{0}};
- mp_get_yuv2rgb_coeffs(&cparams, yuv2rgb);
- gl->UniformMatrix4x3fv(loc, 1, GL_TRUE, &yuv2rgb[0][0]);
+ float m[3][4] = {{0}};
+ if (p->image_desc.flags & MP_IMGFLAG_XYZ) {
+ mp_get_xyz2rgb_coeffs(&cparams, p->csp_src, m);
+ } else {
+ mp_get_yuv2rgb_coeffs(&cparams, m);
+ }
+ gl->UniformMatrix4x3fv(loc, 1, GL_TRUE, &m[0][0]);
}
gl->Uniform1f(gl->GetUniformLocation(program, "input_gamma"),
@@ -880,15 +884,29 @@ static void compile_shaders(struct gl_video *p)
bool convert_to_linear_gamma = !p->is_linear_rgb && use_cms || use_const_luma;
// Figure out the right color spaces we need to convert, if any
- enum mp_csp_prim dest = p->opts.srgb ? MP_CSP_PRIM_BT_709 : MP_CSP_PRIM_BT_2020;
- bool use_cms_matrix = false;
-
- if (use_cms && p->image_params.primaries != dest) {
- p->csp_src = mp_get_csp_primaries(p->image_params.primaries);
- p->csp_dest = mp_get_csp_primaries(dest);
- use_cms_matrix = true;
+ enum mp_csp_prim prim_src = p->image_params.primaries, prim_dest;
+ if (use_cms) {
+ // sRGB mode wants sRGB aka BT.709 primaries, but the 3DLUT is
+ // always built against BT.2020.
+ prim_dest = p->opts.srgb ? MP_CSP_PRIM_BT_709 : MP_CSP_PRIM_BT_2020;
+ } else {
+ // If no CMS is being done we just want to output stuff as-is,
+ // in the native colorspace of the source.
+ prim_dest = prim_src;
}
+ // XYZ input has no defined input color space, so we can directly convert
+ // it to whatever output space we actually need.
+ if (p->image_desc.flags & MP_IMGFLAG_XYZ)
+ prim_src = prim_dest;
+
+ // Set the colorspace primaries and figure out whether we need to perform
+ // an extra conversion.
+ p->csp_src = mp_get_csp_primaries(prim_src);
+ p->csp_dest = mp_get_csp_primaries(prim_dest);
+
+ bool use_cms_matrix = prim_src != prim_dest;
+
if (p->gl_target == GL_TEXTURE_RECTANGLE) {
shader_def(&header, "VIDEO_SAMPLER", "sampler2DRect");
shader_def_opt(&header, "USE_RECTANGLE", true);
@@ -1368,6 +1386,8 @@ static void init_video(struct gl_video *p, const struct mp_image_params *params)
int eq_caps = MP_CSP_EQ_CAPS_GAMMA;
if (p->is_yuv && p->image_params.colorspace != MP_CSP_BT_2020_C)
eq_caps |= MP_CSP_EQ_CAPS_COLORMATRIX;
+ if (p->image_desc.flags & MP_IMGFLAG_XYZ)
+ eq_caps |= MP_CSP_EQ_CAPS_BRIGHTNESS;
p->video_eq.capabilities = eq_caps;
debug_check_gl(p, "before video texture creation");