@@ -178,7 +178,7 @@ void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4])
178
178
m [i ][COL_Y ] *= ymul ;
179
179
m [i ][COL_U ] *= cmul ;
180
180
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)
182
182
m [i ][COL_C ] = rgblev .min - m [i ][COL_Y ] * yuvlev .ymin
183
183
- (m [i ][COL_U ] + m [i ][COL_V ]) * yuvlev .cmid ;
184
184
}
@@ -233,6 +233,108 @@ void mp_gen_yuv2rgb_map(struct mp_csp_params *params, unsigned char *map, int si
233
233
}
234
234
}
235
235
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
+
236
338
// Copy settings from eq into params.
237
339
void mp_csp_copy_equalizer_values (struct mp_csp_params * params ,
238
340
const struct mp_csp_equalizer * eq )
0 commit comments