diff options
Diffstat (limited to 'video/csputils.c')
-rw-r--r-- | video/csputils.c | 71 |
1 files changed, 41 insertions, 30 deletions
diff --git a/video/csputils.c b/video/csputils.c index 60cdc54746..fb9d971517 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -3,7 +3,7 @@ * * Copyleft (C) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de> * - * mp_invert_yuv2rgb based on DarkPlaces engine, original code (GPL2 or later) + * mp_invert_cmat based on DarkPlaces engine, original code (GPL2 or later) * * This file is part of mpv. * @@ -527,10 +527,10 @@ void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest // get the coefficients of an SMPTE 428-1 xyz -> rgb conversion matrix // intent = the rendering intent used to convert to the target primaries -void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, - struct mp_csp_primaries prim, - enum mp_render_intent intent, struct mp_cmat *m) +static void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, + enum mp_render_intent intent, struct mp_cmat *m) { + struct mp_csp_primaries prim = mp_get_csp_primaries(params->primaries); float brightness = params->brightness; mp_get_rgb2xyz_matrix(prim, m->m); mp_invert_matrix3x3(m->m); @@ -552,7 +552,28 @@ void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params, m->c[i] = brightness; } -/* Fill in the Y, U, V vectors of a yuv2rgb conversion matrix +// Get multiplication factor required if image data is fit within the LSBs of a +// higher smaller bit depth isfixed-point texture data. +double mp_get_csp_mul(enum mp_csp csp, int input_bits, int texture_bits) +{ + assert(texture_bits >= input_bits); + + // Convenience for some irrelevant cases, e.g. rgb565 or disabling expansion. + if (!input_bits) + return 1; + + // RGB always uses the full range available. + if (csp == MP_CSP_RGB) + return ((1LL << input_bits) - 1.) / ((1LL << texture_bits) - 1.); + + if (csp == MP_CSP_XYZ) + return 1; + + // High bit depth YUV uses a range shifted from 8 bit. + return (1LL << input_bits) / ((1LL << texture_bits) - 1.) * 255 / 256; +} + +/* Fill in the Y, U, V vectors of a yuv-to-rgb conversion matrix * based on the given luma weights of the R, G and B components (lr, lg, lb). * lr+lg+lb is assumed to equal 1. * This function is meant for colorspaces satisfying the following @@ -584,7 +605,7 @@ static void luma_coeffs(struct mp_cmat *mat, float lr, float lg, float lb) } // get the coefficients of the yuv -> rgb conversion matrix -void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, struct mp_cmat *m) +void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m) { int colorspace = params->colorspace; if (colorspace <= MP_CSP_AUTO || colorspace >= MP_CSP_COUNT) @@ -615,8 +636,7 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, struct mp_cmat *m) // The vo should probably not be using a matrix generated by this // function for XYZ sources, but if it does, let's just assume it // wants BT.709 with D65 white point (virtually all other content). - mp_get_xyz2rgb_coeffs(params, mp_get_csp_primaries(MP_CSP_PRIM_BT_709), - MP_INTENT_RELATIVE_COLORIMETRIC, m); + mp_get_xyz2rgb_coeffs(params, MP_INTENT_RELATIVE_COLORIMETRIC, m); levels_in = -1; break; } @@ -642,10 +662,9 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, struct mp_cmat *m) m->m[i][2] = huesin * u + huecos * v; } - assert(params->input_bits >= 8); - assert(params->texture_bits >= params->input_bits); - double s = (1 << (params->input_bits-8)) / ((1<<params->texture_bits)-1.); - // The values below are written in 0-255 scale + // The values below are written in 0-255 scale - thus bring s into range. + double s = + mp_get_csp_mul(colorspace, params->input_bits, params->texture_bits) / 255; 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 @@ -690,16 +709,6 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, struct mp_cmat *m) - (m->m[i][1] + m->m[i][2]) * yuvlev.cmid + params->brightness; } - - int in_bits = FFMAX(params->int_bits_in, 1); - int out_bits = FFMAX(params->int_bits_out, 1); - double in_scale = (1 << in_bits) - 1.0; - double out_scale = (1 << out_bits) - 1.0; - for (int i = 0; i < 3; i++) { - m->c[i] *= out_scale; // constant is 1.0 - for (int x = 0; x < 3; x++) - m->m[i][x] *= out_scale / in_scale; - } } // Set colorspace related fields in p from f. Don't touch other fields. @@ -710,6 +719,7 @@ void mp_csp_set_image_params(struct mp_csp_params *params, mp_image_params_guess_csp(&p); // ensure consistency params->colorspace = p.colorspace; params->levels_in = p.colorlevels; + params->primaries = p.primaries; } // Copy settings from eq into params. @@ -757,7 +767,7 @@ int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property, return 1; } -void mp_invert_yuv2rgb(struct mp_cmat *out, struct mp_cmat *in) +void mp_invert_cmat(struct mp_cmat *out, struct mp_cmat *in) { *out = *in; mp_invert_matrix3x3(out->m); @@ -773,16 +783,17 @@ void mp_invert_yuv2rgb(struct mp_cmat *out, struct mp_cmat *in) } // Multiply the color in c with the given matrix. -// c is {R, G, B} or {Y, U, V} (depending on input/output and matrix). -// Output is clipped to the given number of bits. -void mp_map_int_color(struct mp_cmat *matrix, int clip_bits, int c[3]) +// i/o is {R, G, B} or {Y, U, V} (depending on input/output and matrix), using +// a fixed point representation with the given number of bits (so for bits==8, +// [0,255] maps to [0,1]). The output is clipped to the range as needed. +void mp_map_fixp_color(struct mp_cmat *matrix, int ibits, int in[3], + int obits, int out[3]) { - int in[3] = {c[0], c[1], c[2]}; for (int i = 0; i < 3; i++) { double val = matrix->c[i]; for (int x = 0; x < 3; x++) - val += matrix->m[i][x] * in[x]; - int ival = lrint(val); - c[i] = av_clip(ival, 0, (1 << clip_bits) - 1); + val += matrix->m[i][x] * in[x] / ((1 << ibits) - 1); + int ival = lrint(val * ((1 << obits) - 1)); + out[i] = av_clip(ival, 0, (1 << obits) - 1); } } |