2 * Common code related to colorspaces and conversion
4 * Copyleft (C) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * You can alternatively redistribute this file and/or
23 * modify it under the terms of the GNU Lesser General Public
24 * License as published by the Free Software Foundation; either
25 * version 2.1 of the License, or (at your option) any later version.
31 #include <libavutil/common.h>
35 char * const mp_csp_names
[MP_CSP_COUNT
] = {
42 char * const mp_csp_equalizer_names
[MP_CSP_EQ_COUNT
] = {
51 enum mp_csp
mp_csp_guess_colorspace(int width
, int height
)
53 return width
>= 1280 || height
> 576 ? MP_CSP_BT_709
: MP_CSP_BT_601
;
57 * \brief little helper function to create a lookup table for gamma
58 * \param map buffer to create map into
59 * \param size size of buffer
60 * \param gamma gamma value
62 void mp_gen_gamma_map(uint8_t *map
, int size
, float gamma
)
65 for (int i
= 0; i
< size
; i
++)
66 map
[i
] = 255 * i
/ (size
- 1);
70 for (int i
= 0; i
< size
; i
++) {
71 float tmp
= (float)i
/ (size
- 1.0);
72 tmp
= pow(tmp
, gamma
);
81 /* Fill in the Y, U, V vectors of a yuv2rgb conversion matrix
82 * based on the given luma weights of the R, G and B components (lr, lg, lb).
83 * lr+lg+lb is assumed to equal 1.
84 * This function is meant for colorspaces satisfying the following
85 * conditions (which are true for common YUV colorspaces):
86 * - The mapping from input [Y, U, V] to output [R, G, B] is linear.
87 * - Y is the vector [1, 1, 1]. (meaning input Y component maps to 1R+1G+1B)
88 * - U maps to a value with zero R and positive B ([0, x, y], y > 0;
89 * i.e. blue and green only).
90 * - V maps to a value with zero B and positive R ([x, y, 0], x > 0;
91 * i.e. red and green only).
92 * - U and V are orthogonal to the luma vector [lr, lg, lb].
93 * - The magnitudes of the vectors U and V are the minimal ones for which
94 * the image of the set Y=[0...1],U=[-0.5...0.5],V=[-0.5...0.5] under the
95 * conversion function will cover the set R=[0...1],G=[0...1],B=[0...1]
96 * (the resulting matrix can be converted for other input/output ranges
97 * outside this function).
98 * Under these conditions the given parameters lr, lg, lb uniquely
99 * determine the mapping of Y, U, V to R, G, B.
101 static void luma_coeffs(float m
[3][4], float lr
, float lg
, float lb
)
103 assert(fabs(lr
+lg
+lb
- 1) < 1e-6);
104 m
[0][0] = m
[1][0] = m
[2][0] = 1;
106 m
[1][1] = -2 * (1-lb
) * lb
/lg
;
107 m
[2][1] = 2 * (1-lb
);
108 m
[0][2] = 2 * (1-lr
);
109 m
[1][2] = -2 * (1-lr
) * lr
/lg
;
111 // Constant coefficients (m[x][3]) not set here
115 * \brief get the coefficients of the yuv -> rgb conversion matrix
116 * \param params struct specifying the properties of the conversion like
118 * \param m array to store coefficients into
120 void mp_get_yuv2rgb_coeffs(struct mp_csp_params
*params
, float m
[3][4])
122 int format
= params
->colorspace
.format
;
123 if (format
<= MP_CSP_AUTO
|| format
>= MP_CSP_COUNT
)
124 format
= MP_CSP_BT_601
;
126 case MP_CSP_BT_601
: luma_coeffs(m
, 0.299, 0.587, 0.114 ); break;
127 case MP_CSP_BT_709
: luma_coeffs(m
, 0.2126, 0.7152, 0.0722); break;
128 case MP_CSP_SMPTE_240M
: luma_coeffs(m
, 0.2122, 0.7013, 0.0865); break;
133 // Hue is equivalent to rotating input [U, V] subvector around the origin.
134 // Saturation scales [U, V].
135 float huecos
= params
->saturation
* cos(params
->hue
);
136 float huesin
= params
->saturation
* sin(params
->hue
);
137 for (int i
= 0; i
< 3; i
++) {
138 float u
= m
[i
][COL_U
];
139 m
[i
][COL_U
] = huecos
* u
- huesin
* m
[i
][COL_V
];
140 m
[i
][COL_V
] = huesin
* u
+ huecos
* m
[i
][COL_V
];
143 int levels_in
= params
->colorspace
.levels_in
;
144 if (levels_in
<= MP_CSP_LEVELS_AUTO
|| levels_in
>= MP_CSP_LEVELS_COUNT
)
145 levels_in
= MP_CSP_LEVELS_TV
;
146 // The values below are written in 0-255 scale
147 struct yuvlevels
{ double ymin
, ymax
, cmin
, cmid
; }
148 yuvlim
= { 16, 235, 16, 128 },
149 yuvfull
= { 0, 255, 1, 128 }, // '1' to make it symmetric around 128
152 case MP_CSP_LEVELS_TV
: yuvlev
= yuvlim
; break;
153 case MP_CSP_LEVELS_PC
: yuvlev
= yuvfull
; break;
158 int levels_out
= params
->colorspace
.levels_out
;
159 if (levels_out
<= MP_CSP_LEVELS_AUTO
|| levels_out
>= MP_CSP_LEVELS_COUNT
)
160 levels_out
= MP_CSP_LEVELS_PC
;
161 struct rgblevels
{ double min
, max
; }
162 rgblim
= { 16, 235 },
163 rgbfull
= { 0, 255 },
165 switch (levels_out
) {
166 case MP_CSP_LEVELS_TV
: rgblev
= rgblim
; break;
167 case MP_CSP_LEVELS_PC
: rgblev
= rgbfull
; break;
172 double ymul
= (rgblev
.max
- rgblev
.min
) / (yuvlev
.ymax
- yuvlev
.ymin
);
173 double cmul
= (rgblev
.max
- rgblev
.min
) / (yuvlev
.cmid
- yuvlev
.cmin
) / 2;
174 for (int i
= 0; i
< 3; i
++) {
178 // Set COL_C so that Y=umin,UV=cmid maps to RGB=min (black to black)
179 m
[i
][COL_C
] = (rgblev
.min
- m
[i
][COL_Y
] * yuvlev
.ymin
180 -(m
[i
][COL_U
] + m
[i
][COL_V
]) * yuvlev
.cmid
) / 255;
183 // Brightness adds a constant to output R,G,B.
184 // Contrast scales Y around 1/2 (not 0 in this implementation).
185 for (int i
= 0; i
< 3; i
++) {
186 m
[i
][COL_C
] += params
->brightness
;
187 m
[i
][COL_Y
] *= params
->contrast
;
188 m
[i
][COL_C
] += (rgblev
.max
-rgblev
.min
)/255 * (1 - params
->contrast
)/2;
191 float depth_multiplier
= params
->input_shift
>= 0 ?
192 (1 << params
->input_shift
) :
193 (1.0 / (1 << -params
->input_shift
));
194 for (int i
= 0; i
< 3; i
++)
195 for (int j
= 0; j
< 3; j
++)
196 m
[i
][j
] *= depth_multiplier
;
199 //! size of gamma map use to avoid slow exp function in gen_yuv2rgb_map
200 #define GMAP_SIZE (1024)
202 * \brief generate a 3D YUV -> RGB map
203 * \param params struct containing parameters like brightness, gamma, ...
204 * \param map where to store map. Must provide space for (size + 2)^3 elements
205 * \param size size of the map, excluding border
207 void mp_gen_yuv2rgb_map(struct mp_csp_params
*params
, unsigned char *map
, int size
)
210 float step
= 1.0 / size
;
213 unsigned char gmaps
[3][GMAP_SIZE
];
214 mp_gen_gamma_map(gmaps
[0], GMAP_SIZE
, params
->rgamma
);
215 mp_gen_gamma_map(gmaps
[1], GMAP_SIZE
, params
->ggamma
);
216 mp_gen_gamma_map(gmaps
[2], GMAP_SIZE
, params
->bgamma
);
217 mp_get_yuv2rgb_coeffs(params
, yuv2rgb
);
218 for (i
= 0; i
< 3; i
++)
219 for (j
= 0; j
< 4; j
++)
220 yuv2rgb
[i
][j
] *= GMAP_SIZE
- 1;
222 for (i
= -1; i
<= size
; i
++) {
224 for (j
= -1; j
<= size
; j
++) {
226 for (k
= -1; k
<= size
; k
++) {
227 for (l
= 0; l
< 3; l
++) {
228 float rgb
= yuv2rgb
[l
][COL_Y
] * y
+ yuv2rgb
[l
][COL_U
] * u
+
229 yuv2rgb
[l
][COL_V
] * v
+ yuv2rgb
[l
][COL_C
];
230 *map
++ = gmaps
[l
][av_clip(rgb
, 0, GMAP_SIZE
- 1)];
232 y
+= (k
== -1 || k
== size
- 1) ? step
/ 2 : step
;
234 u
+= (j
== -1 || j
== size
- 1) ? step
/ 2 : step
;
236 v
+= (i
== -1 || i
== size
- 1) ? step
/ 2 : step
;
240 // Copy settings from eq into params.
241 void mp_csp_copy_equalizer_values(struct mp_csp_params
*params
,
242 const struct mp_csp_equalizer
*eq
)
244 params
->brightness
= eq
->values
[MP_CSP_EQ_BRIGHTNESS
] / 100.0;
245 params
->contrast
= (eq
->values
[MP_CSP_EQ_CONTRAST
] + 100) / 100.0;
246 params
->hue
= eq
->values
[MP_CSP_EQ_HUE
] / 100.0 * 3.1415927;
247 params
->saturation
= (eq
->values
[MP_CSP_EQ_SATURATION
] + 100) / 100.0;
248 float gamma
= exp(log(8.0) * eq
->values
[MP_CSP_EQ_GAMMA
] / 100.0);
249 params
->rgamma
= gamma
;
250 params
->ggamma
= gamma
;
251 params
->bgamma
= gamma
;
254 static int find_eq(int capabilities
, const char *name
)
256 for (int i
= 0; i
< MP_CSP_EQ_COUNT
; i
++) {
257 if (strcmp(name
, mp_csp_equalizer_names
[i
]) == 0)
258 return ((1 << i
) & capabilities
) ? i
: -1;
263 int mp_csp_equalizer_get(struct mp_csp_equalizer
*eq
, const char *property
,
266 int index
= find_eq(eq
->capabilities
, property
);
270 *out_value
= eq
->values
[index
];
275 int mp_csp_equalizer_set(struct mp_csp_equalizer
*eq
, const char *property
,
278 int index
= find_eq(eq
->capabilities
, property
);
282 eq
->values
[index
] = value
;