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 assert(params
->input_bits
>= 8);
147 assert(params
->texture_bits
>= params
->input_bits
);
148 double s
= (1 << params
->input_bits
-8) / ((1<<params
->texture_bits
)-1.);
149 // The values below are written in 0-255 scale
150 struct yuvlevels
{ double ymin
, ymax
, cmin
, cmid
; }
151 yuvlim
= { 16*s
, 235*s
, 16*s
, 128*s
},
152 yuvfull
= { 0*s
, 255*s
, 1*s
, 128*s
}, // '1' for symmetry around 128
155 case MP_CSP_LEVELS_TV
: yuvlev
= yuvlim
; break;
156 case MP_CSP_LEVELS_PC
: yuvlev
= yuvfull
; break;
161 int levels_out
= params
->colorspace
.levels_out
;
162 if (levels_out
<= MP_CSP_LEVELS_AUTO
|| levels_out
>= MP_CSP_LEVELS_COUNT
)
163 levels_out
= MP_CSP_LEVELS_PC
;
164 struct rgblevels
{ double min
, max
; }
165 rgblim
= { 16/255., 235/255. },
168 switch (levels_out
) {
169 case MP_CSP_LEVELS_TV
: rgblev
= rgblim
; break;
170 case MP_CSP_LEVELS_PC
: rgblev
= rgbfull
; break;
175 double ymul
= (rgblev
.max
- rgblev
.min
) / (yuvlev
.ymax
- yuvlev
.ymin
);
176 double cmul
= (rgblev
.max
- rgblev
.min
) / (yuvlev
.cmid
- yuvlev
.cmin
) / 2;
177 for (int i
= 0; i
< 3; i
++) {
181 // Set COL_C so that Y=umin,UV=cmid maps to RGB=min (black to black)
182 m
[i
][COL_C
] = rgblev
.min
- m
[i
][COL_Y
] * yuvlev
.ymin
183 -(m
[i
][COL_U
] + m
[i
][COL_V
]) * yuvlev
.cmid
;
186 // Brightness adds a constant to output R,G,B.
187 // Contrast scales Y around 1/2 (not 0 in this implementation).
188 for (int i
= 0; i
< 3; i
++) {
189 m
[i
][COL_C
] += params
->brightness
;
190 m
[i
][COL_Y
] *= params
->contrast
;
191 m
[i
][COL_C
] += (rgblev
.max
-rgblev
.min
) * (1 - params
->contrast
)/2;
195 //! size of gamma map use to avoid slow exp function in gen_yuv2rgb_map
196 #define GMAP_SIZE (1024)
198 * \brief generate a 3D YUV -> RGB map
199 * \param params struct containing parameters like brightness, gamma, ...
200 * \param map where to store map. Must provide space for (size + 2)^3 elements
201 * \param size size of the map, excluding border
203 void mp_gen_yuv2rgb_map(struct mp_csp_params
*params
, unsigned char *map
, int size
)
206 float step
= 1.0 / size
;
209 unsigned char gmaps
[3][GMAP_SIZE
];
210 mp_gen_gamma_map(gmaps
[0], GMAP_SIZE
, params
->rgamma
);
211 mp_gen_gamma_map(gmaps
[1], GMAP_SIZE
, params
->ggamma
);
212 mp_gen_gamma_map(gmaps
[2], GMAP_SIZE
, params
->bgamma
);
213 mp_get_yuv2rgb_coeffs(params
, yuv2rgb
);
214 for (i
= 0; i
< 3; i
++)
215 for (j
= 0; j
< 4; j
++)
216 yuv2rgb
[i
][j
] *= GMAP_SIZE
- 1;
218 for (i
= -1; i
<= size
; i
++) {
220 for (j
= -1; j
<= size
; j
++) {
222 for (k
= -1; k
<= size
; k
++) {
223 for (l
= 0; l
< 3; l
++) {
224 float rgb
= yuv2rgb
[l
][COL_Y
] * y
+ yuv2rgb
[l
][COL_U
] * u
+
225 yuv2rgb
[l
][COL_V
] * v
+ yuv2rgb
[l
][COL_C
];
226 *map
++ = gmaps
[l
][av_clip(rgb
, 0, GMAP_SIZE
- 1)];
228 y
+= (k
== -1 || k
== size
- 1) ? step
/ 2 : step
;
230 u
+= (j
== -1 || j
== size
- 1) ? step
/ 2 : step
;
232 v
+= (i
== -1 || i
== size
- 1) ? step
/ 2 : step
;
236 // Copy settings from eq into params.
237 void mp_csp_copy_equalizer_values(struct mp_csp_params
*params
,
238 const struct mp_csp_equalizer
*eq
)
240 params
->brightness
= eq
->values
[MP_CSP_EQ_BRIGHTNESS
] / 100.0;
241 params
->contrast
= (eq
->values
[MP_CSP_EQ_CONTRAST
] + 100) / 100.0;
242 params
->hue
= eq
->values
[MP_CSP_EQ_HUE
] / 100.0 * 3.1415927;
243 params
->saturation
= (eq
->values
[MP_CSP_EQ_SATURATION
] + 100) / 100.0;
244 float gamma
= exp(log(8.0) * eq
->values
[MP_CSP_EQ_GAMMA
] / 100.0);
245 params
->rgamma
= gamma
;
246 params
->ggamma
= gamma
;
247 params
->bgamma
= gamma
;
250 static int find_eq(int capabilities
, const char *name
)
252 for (int i
= 0; i
< MP_CSP_EQ_COUNT
; i
++) {
253 if (strcmp(name
, mp_csp_equalizer_names
[i
]) == 0)
254 return ((1 << i
) & capabilities
) ? i
: -1;
259 int mp_csp_equalizer_get(struct mp_csp_equalizer
*eq
, const char *property
,
262 int index
= find_eq(eq
->capabilities
, property
);
266 *out_value
= eq
->values
[index
];
271 int mp_csp_equalizer_set(struct mp_csp_equalizer
*eq
, const char *property
,
274 int index
= find_eq(eq
->capabilities
, property
);
278 eq
->values
[index
] = value
;