Skip to content

Commit 9a5ed65

Browse files
committed
csputils: add mp_get_rgb2yuv_coeffs for inverse matrix calculation
1 parent 1934141 commit 9a5ed65

File tree

2 files changed

+111
-1
lines changed

2 files changed

+111
-1
lines changed

libvo/csputils.c

+103-1
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
178178
m[i][COL_Y] *= ymul;
179179
m[i][COL_U] *= cmul;
180180
m[i][COL_V] *= cmul;
181-
// Set COL_C so that Y=umin,UV=cmid maps to RGB=min (black to black)
181+
// Set COL_C so that Y=ymin,UV=cmid maps to RGB=min (black to black)
182182
m[i][COL_C] = rgblev.min - m[i][COL_Y] * yuvlev.ymin
183183
-(m[i][COL_U] + m[i][COL_V]) * yuvlev.cmid;
184184
}
@@ -233,6 +233,108 @@ void mp_gen_yuv2rgb_map(struct mp_csp_params *params, unsigned char *map, int si
233233
}
234234
}
235235

236+
/* Fill in the R, G, B vectors of an rgb2yuv conversion matrix
237+
* based on the given luma weights of the components (lr, lg, lb).
238+
* lr+lg+lb is assumed to equal 1.
239+
* All the conditions listed for luma_coeffs apply.
240+
*/
241+
static void rgb_coeffs(float m[3][4], float lr, float lg, float lb)
242+
{
243+
assert(fabs(lr+lg+lb - 1) < 1e-6);
244+
m[0][0] = lr;
245+
m[0][1] = lg;
246+
m[0][2] = lb;
247+
m[1][0] = -0.5f * lr / (1-lb);
248+
m[1][1] = -0.5f * lg / (1-lb);
249+
m[1][2] = m[2][0] = 0.5f;
250+
m[2][1] = -0.5f * lg / (1-lr);
251+
m[2][2] = -0.5f * lb / (1-lr);
252+
// Constant coefficients (m[x][3]) not set here
253+
}
254+
255+
/**
256+
* \brief get the coefficients of the inverse yuv -> rgb conversion matrix
257+
* \param params struct specifying the properties of the conversion like
258+
* brightness, ...
259+
* \param m array to store coefficients into
260+
*/
261+
void mp_get_rgb2yuv_coeffs(struct mp_csp_params *params, float m[3][4])
262+
{
263+
int format = params->colorspace.format;
264+
if (format <= MP_CSP_AUTO || format >= MP_CSP_COUNT)
265+
format = MP_CSP_BT_601;
266+
switch (format) {
267+
case MP_CSP_BT_601: rgb_coeffs(m, 0.299, 0.587, 0.114 ); break;
268+
case MP_CSP_BT_709: rgb_coeffs(m, 0.2126, 0.7152, 0.0722); break;
269+
case MP_CSP_SMPTE_240M: rgb_coeffs(m, 0.2122, 0.7013, 0.0865); break;
270+
default:
271+
abort();
272+
};
273+
274+
// Hue is equivalent to rotating the [U, V] subvector around the origin.
275+
// Saturation scales [U, V].
276+
float huecos = cos(params->hue) / params->saturation;
277+
float huesin = sin(params->hue) / params->saturation;
278+
for (int i = 0; i < 3; i++) {
279+
float u = m[ROW_U][i];
280+
m[ROW_U][i] = huecos * u - huesin * m[ROW_V][i];
281+
m[ROW_V][i] = huesin * u + huecos * m[ROW_V][i];
282+
}
283+
284+
int levels_in = params->colorspace.levels_in;
285+
if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT)
286+
levels_in = MP_CSP_LEVELS_TV;
287+
assert(params->input_bits >= 8);
288+
assert(params->texture_bits >= params->input_bits);
289+
double s = (1 << params->input_bits-8) / ((1<<params->texture_bits)-1.);
290+
// The values below are written in 0-255 scale
291+
struct yuvlevels { double ymin, ymax, cmin, cmid; }
292+
yuvlim = { 16*s, 235*s, 16*s, 128*s },
293+
yuvfull = { 0*s, 255*s, 1*s, 128*s }, // '1' for symmetry around 128
294+
yuvlev;
295+
switch (levels_in) {
296+
case MP_CSP_LEVELS_TV: yuvlev = yuvlim; break;
297+
case MP_CSP_LEVELS_PC: yuvlev = yuvfull; break;
298+
default:
299+
abort();
300+
}
301+
302+
int levels_out = params->colorspace.levels_out;
303+
if (levels_out <= MP_CSP_LEVELS_AUTO || levels_out >= MP_CSP_LEVELS_COUNT)
304+
levels_out = MP_CSP_LEVELS_PC;
305+
struct rgblevels { double min, max; }
306+
rgblim = { 16/255., 235/255. },
307+
rgbfull = { 0, 1 },
308+
rgblev;
309+
switch (levels_out) {
310+
case MP_CSP_LEVELS_TV: rgblev = rgblim; break;
311+
case MP_CSP_LEVELS_PC: rgblev = rgbfull; break;
312+
default:
313+
abort();
314+
}
315+
316+
double ymul = (yuvlev.ymax - yuvlev.ymin) / (rgblev.max - rgblev.min);
317+
double cmul = 2 * (yuvlev.cmid - yuvlev.cmin) / (rgblev.max - rgblev.min);
318+
for (int i = 0; i < 3; i++) {
319+
m[ROW_Y][i] *= ymul;
320+
m[ROW_U][i] *= cmul;
321+
m[ROW_V][i] *= cmul;
322+
}
323+
324+
// Set COL_C so that RGB=min+brightness maps to Y=ymin,UV=cmid (black).
325+
// Invert the crazy contrast calculations of mp_get_yuv2rgb_coeffs.
326+
m[ROW_Y][COL_C] = yuvlev.ymin;
327+
m[ROW_U][COL_C] = yuvlev.cmid;
328+
m[ROW_V][COL_C] = yuvlev.cmid;
329+
for (int i = 0; i < 3; i++) {
330+
float offset = rgblev.min + params->brightness +
331+
(rgblev.max-rgblev.min) * (1 - params->contrast)/2;
332+
m[i][COL_C] -= offset * (m[i][0] + m[i][1] + m[i][2]);
333+
}
334+
for (int i = 0; i < 4; i++)
335+
m[ROW_Y][i] /= params->contrast;
336+
}
337+
236338
// Copy settings from eq into params.
237339
void mp_csp_copy_equalizer_values(struct mp_csp_params *params,
238340
const struct mp_csp_equalizer *eq)

libvo/csputils.h

+8
Original file line numberDiff line numberDiff line change
@@ -123,5 +123,13 @@ void mp_gen_gamma_map(unsigned char *map, int size, float gamma);
123123
#define COL_C 3
124124
void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]);
125125
void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size);
126+
#define ROW_Y 0
127+
#define ROW_U 1
128+
#define ROW_V 2
129+
#define COL_R 0
130+
#define COL_G 1
131+
#define COL_B 2
132+
// COL_C 3
133+
void mp_get_rgb2yuv_coeffs(struct mp_csp_params *params, float rgb2yuv[3][4]);
126134

127135
#endif /* MPLAYER_CSPUTILS_H */

0 commit comments

Comments
 (0)