summaryrefslogtreecommitdiffstats
path: root/video/csputils.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/csputils.c')
-rw-r--r--video/csputils.c71
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);
}
}