Mercurial > mplayer.hg
comparison libmpcodecs/vf_eq2.c @ 9213:601ed700e1cc
Based on the discussion in the other thread I made a new
patch to vf_eq2.c that essentially combines vf_eq.c and vf_eq2.c.
patch by Hampa Hug <hampa@hampa.ch>
based on R/G/B gamma patch by Daniel Moreno <comac2k@terra.es>
some modifications (credits, buffer allocation, etc) by me
author | arpi |
---|---|
date | Sun, 02 Feb 2003 02:09:23 +0000 |
parents | 916d5392dcc9 |
children | e9a2af584986 |
comparison
equal
deleted
inserted
replaced
9212:24b102dbd0fe | 9213:601ed700e1cc |
---|---|
1 /* | 1 /* |
2 * vf_eq2.c | 2 * vf_eq2.c |
3 * | 3 * |
4 * LUT-based software equalizer (brightness, contrast, gamma) | 4 * Software equalizer (brightness, contrast, gamma, saturation) |
5 * | 5 * |
6 * Hampa Hug <hhug@student.ethz.ch> | 6 * Hampa Hug <hampa@hampa.ch> (original LUT gamma/contrast/brightness filter) |
7 * | 7 * Daniel Moreno <comac@comac.darktech.org> (saturation, R/G/B gamma support) |
8 * Richard Felker (original MMX contrast/brightness code (vf_eq.c)) | |
8 */ | 9 */ |
9 | 10 |
10 #include <stdio.h> | 11 #include <stdio.h> |
11 #include <stdlib.h> | 12 #include <stdlib.h> |
12 #include <string.h> | 13 #include <string.h> |
13 #include <math.h> | 14 #include <math.h> |
14 | 15 |
15 #include "../config.h" | 16 #include "config.h" |
16 #include "../mp_msg.h" | 17 #include "mp_msg.h" |
18 #include "cpudetect.h" | |
17 | 19 |
18 #include "img_format.h" | 20 #include "img_format.h" |
19 #include "mp_image.h" | 21 #include "mp_image.h" |
20 #include "vf.h" | 22 #include "vf.h" |
21 | 23 |
22 #ifdef USE_SETLOCALE | 24 #ifdef USE_SETLOCALE |
23 #include <locale.h> | 25 #include <locale.h> |
24 #endif | 26 #endif |
25 | 27 |
26 | 28 |
29 /* Per channel parameters */ | |
30 typedef struct eq2_param_t { | |
31 unsigned char lut[256]; | |
32 int lut_clean; | |
33 | |
34 void (*adjust) (struct eq2_param_t *par, unsigned char *dst, unsigned char *src, | |
35 unsigned w, unsigned h, unsigned dstride, unsigned sstride); | |
36 | |
37 double c; | |
38 double b; | |
39 double g; | |
40 } eq2_param_t; | |
41 | |
27 typedef struct vf_priv_s { | 42 typedef struct vf_priv_s { |
28 unsigned char *buf; | 43 eq2_param_t param[3]; |
29 int buf_w; | |
30 int buf_h; | |
31 | 44 |
32 double contrast; | 45 double contrast; |
33 double bright; | 46 double brightness; |
47 double saturation; | |
48 | |
34 double gamma; | 49 double gamma; |
35 | 50 double rgamma; |
36 unsigned char lut[256]; | 51 double ggamma; |
52 double bgamma; | |
53 | |
54 unsigned buf_w[3]; | |
55 unsigned buf_h[3]; | |
56 unsigned char *buf[3]; | |
37 } vf_eq2_t; | 57 } vf_eq2_t; |
38 | 58 |
39 | 59 |
40 static | 60 static |
41 void create_lut (vf_eq2_t *eq2) | 61 void create_lut (eq2_param_t *par) |
42 { | 62 { |
43 unsigned i; | 63 unsigned i; |
44 double c, b, g; | 64 double g, v; |
45 double v; | 65 |
46 | 66 g = par->g; |
47 c = eq2->contrast; | |
48 b = eq2->bright; | |
49 g = eq2->gamma; | |
50 | 67 |
51 if ((g < 0.001) || (g > 1000.0)) { | 68 if ((g < 0.001) || (g > 1000.0)) { |
52 g = 1.0; | 69 g = 1.0; |
53 } | 70 } |
54 | 71 |
55 fprintf (stderr, "vf_eq2: c=%.2f b=%.2f g=%.4f\n", c, b, g); | |
56 | |
57 g = 1.0 / g; | 72 g = 1.0 / g; |
58 | 73 |
59 for (i = 0; i < 256; i++) { | 74 for (i = 0; i < 256; i++) { |
60 v = (double) i / 255.0; | 75 v = (double) i / 255.0; |
61 v = c * (v - 0.5) + 0.5 + b; | 76 v = par->c * (v - 0.5) + 0.5 + par->b; |
62 | 77 |
63 if (v <= 0.0) { | 78 if (v <= 0.0) { |
64 eq2->lut[i] = 0; | 79 par->lut[i] = 0; |
65 } | 80 } |
66 else { | 81 else { |
67 v = pow (v, g); | 82 v = pow (v, g); |
68 | 83 |
69 if (v >= 1.0) { | 84 if (v >= 1.0) { |
70 eq2->lut[i] = 255; | 85 par->lut[i] = 255; |
71 } | 86 } |
72 else { | 87 else { |
73 /* we divided by 255.0 so now we also multiply by 255.0, not | 88 par->lut[i] = (unsigned char) (256.0 * v); |
74 by 256.0. "+ 0.5" ensures proper rounding */ | 89 } |
75 eq2->lut[i] = (unsigned char) (255.0 * v + 0.5); | 90 } |
76 } | 91 } |
77 } | 92 |
78 } | 93 par->lut_clean = 1; |
79 } | 94 } |
80 | 95 |
81 /* could inline this */ | 96 #ifdef HAVE_MMX |
82 static | 97 static |
83 void process (unsigned char *dst, int dstride, unsigned char *src, int sstride, | 98 void affine_1d_MMX (eq2_param_t *par, unsigned char *dst, unsigned char *src, |
84 int w, int h, unsigned char lut[256]) | 99 unsigned w, unsigned h, unsigned dstride, unsigned sstride) |
85 { | 100 { |
86 int i, j; | 101 unsigned i; |
102 int contrast, brightness; | |
103 unsigned dstep, sstep; | |
104 int pel; | |
105 short brvec[4]; | |
106 short contvec[4]; | |
107 | |
108 // printf("\nmmx: src=%p dst=%p w=%d h=%d ds=%d ss=%d\n",src,dst,w,h,dstride,sstride); | |
109 | |
110 contrast = (int) (par->c * 256 * 16); | |
111 brightness = ((int) (100.0 * par->b + 100.0) * 511) / 200 - 128 - contrast / 32; | |
112 | |
113 brvec[0] = brvec[1] = brvec[2] = brvec[3] = brightness; | |
114 contvec[0] = contvec[1] = contvec[2] = contvec[3] = contrast; | |
115 | |
116 sstep = sstride - w; | |
117 dstep = dstride - w; | |
118 | |
119 while (h-- > 0) { | |
120 asm volatile ( | |
121 "movq (%5), %%mm3 \n\t" | |
122 "movq (%6), %%mm4 \n\t" | |
123 "pxor %%mm0, %%mm0 \n\t" | |
124 "movl %4, %%eax\n\t" | |
125 ".balign 16 \n\t" | |
126 "1: \n\t" | |
127 "movq (%0), %%mm1 \n\t" | |
128 "movq (%0), %%mm2 \n\t" | |
129 "punpcklbw %%mm0, %%mm1 \n\t" | |
130 "punpckhbw %%mm0, %%mm2 \n\t" | |
131 "psllw $4, %%mm1 \n\t" | |
132 "psllw $4, %%mm2 \n\t" | |
133 "pmulhw %%mm4, %%mm1 \n\t" | |
134 "pmulhw %%mm4, %%mm2 \n\t" | |
135 "paddw %%mm3, %%mm1 \n\t" | |
136 "paddw %%mm3, %%mm2 \n\t" | |
137 "packuswb %%mm2, %%mm1 \n\t" | |
138 "addl $8, %0 \n\t" | |
139 "movq %%mm1, (%1) \n\t" | |
140 "addl $8, %1 \n\t" | |
141 "decl %%eax \n\t" | |
142 "jnz 1b \n\t" | |
143 : "=r" (src), "=r" (dst) | |
144 : "0" (src), "1" (dst), "r" (w >> 3), "r" (brvec), "r" (contvec) | |
145 : "%eax" | |
146 ); | |
147 | |
148 for (i = w & 7; i > 0; i--) { | |
149 pel = ((*src++ * contrast) >> 12) + brightness; | |
150 if (pel & 768) { | |
151 pel = (-pel) >> 31; | |
152 } | |
153 *dst++ = pel; | |
154 } | |
155 | |
156 src += sstep; | |
157 dst += dstep; | |
158 } | |
159 | |
160 asm volatile ( "emms \n\t" ::: "memory" ); | |
161 } | |
162 #endif | |
163 | |
164 static | |
165 void apply_lut (eq2_param_t *par, unsigned char *dst, unsigned char *src, | |
166 unsigned w, unsigned h, unsigned dstride, unsigned sstride) | |
167 { | |
168 unsigned i, j; | |
169 unsigned char *lut; | |
170 | |
171 if (!par->lut_clean) { | |
172 create_lut (par); | |
173 } | |
174 | |
175 lut = par->lut; | |
87 | 176 |
88 for (j = 0; j < h; j++) { | 177 for (j = 0; j < h; j++) { |
89 for (i = 0; i < w; i++) { | 178 for (i = 0; i < w; i++) { |
90 dst[i] = lut[src[i]]; | 179 dst[i] = lut[src[i]]; |
91 } | 180 } |
181 | |
92 src += sstride; | 182 src += sstride; |
93 dst += dstride; | 183 dst += dstride; |
94 } | 184 } |
95 } | 185 } |
96 | 186 |
97 static | 187 static |
98 int put_image (vf_instance_t *vf, mp_image_t *src) | 188 int put_image (vf_instance_t *vf, mp_image_t *src) |
99 { | 189 { |
100 mp_image_t *dst; | 190 unsigned i; |
101 vf_eq2_t *eq2; | 191 vf_eq2_t *eq2; |
192 mp_image_t *dst; | |
193 unsigned long img_n,img_c; | |
102 | 194 |
103 eq2 = vf->priv; | 195 eq2 = vf->priv; |
104 | 196 |
105 if ((eq2->buf == NULL) || (eq2->buf_w != src->stride[0]) || (eq2->buf_h != src->h)) { | 197 if ((eq2->buf_w[0] != src->w) || (eq2->buf_h[0] != src->h)) { |
106 eq2->buf = (unsigned char *) realloc (eq2->buf, src->stride[0] * src->h); | 198 eq2->buf_w[0] = src->w; |
107 eq2->buf_w = src->stride[0]; | 199 eq2->buf_h[0] = src->h; |
108 eq2->buf_h = src->h; | 200 eq2->buf_w[1] = eq2->buf_w[2] = src->w >> src->chroma_x_shift; |
201 eq2->buf_h[1] = eq2->buf_h[2] = src->h >> src->chroma_y_shift; | |
202 img_n = eq2->buf_w[0]*eq2->buf_h[0]; | |
203 if(src->num_planes>1){ | |
204 img_c = eq2->buf_w[1]*eq2->buf_h[1]; | |
205 eq2->buf[0] = (unsigned char *) realloc (eq2->buf[0], img_n + 2*img_c); | |
206 eq2->buf[1] = eq2->buf[0] + img_n; | |
207 eq2->buf[2] = eq2->buf[1] + img_c; | |
208 } else | |
209 eq2->buf[0] = (unsigned char *) realloc (eq2->buf[0], img_n); | |
109 } | 210 } |
110 | 211 |
111 dst = vf_get_image (vf->next, src->imgfmt, MP_IMGTYPE_EXPORT, 0, src->w, src->h); | 212 dst = vf_get_image (vf->next, src->imgfmt, MP_IMGTYPE_EXPORT, 0, src->w, src->h); |
112 | 213 |
113 dst->stride[0] = src->stride[0]; | 214 for (i = 0; i < ((src->num_planes>1)?3:1); i++) { |
114 dst->stride[1] = src->stride[1]; | 215 if (eq2->param[i].adjust != NULL) { |
115 dst->stride[2] = src->stride[2]; | 216 dst->planes[i] = eq2->buf[i]; |
116 dst->planes[0] = vf->priv->buf; | 217 dst->stride[i] = eq2->buf_w[i]; |
117 dst->planes[1] = src->planes[1]; | 218 |
118 dst->planes[2] = src->planes[2]; | 219 eq2->param[i].adjust (&eq2->param[i], dst->planes[i], src->planes[i], |
119 | 220 eq2->buf_w[i], eq2->buf_h[i], dst->stride[i], src->stride[i]); |
120 process ( | 221 } |
121 dst->planes[0], dst->stride[0], src->planes[0], src->stride[0], | 222 else { |
122 src->w, src->h, eq2->lut | 223 dst->planes[i] = src->planes[i]; |
224 dst->stride[i] = src->stride[i]; | |
225 } | |
226 } | |
227 | |
228 return vf_next_put_image (vf, dst); | |
229 } | |
230 | |
231 static | |
232 void check_values (eq2_param_t *par) | |
233 { | |
234 /* yuck! floating point comparisons... */ | |
235 | |
236 if ((par->c == 1.0) && (par->b == 0.0) && (par->g == 1.0)) { | |
237 par->adjust = NULL; | |
238 } | |
239 #ifdef HAVE_MMX | |
240 else if (par->g == 1.0 && gCpuCaps.hasMMX) { | |
241 par->adjust = &affine_1d_MMX; | |
242 } | |
243 #endif | |
244 else { | |
245 par->adjust = &apply_lut; | |
246 } | |
247 } | |
248 | |
249 static | |
250 void print_values (vf_eq2_t *eq2) | |
251 { | |
252 mp_msg (MSGT_VFILTER, MSGL_V, "vf_eq2: c=%.2f b=%.2f g=%.4f s=%.2f \n", | |
253 eq2->contrast, eq2->brightness, eq2->gamma, eq2->saturation | |
123 ); | 254 ); |
124 | 255 } |
125 return vf_next_put_image (vf, dst); | 256 |
257 static | |
258 void set_contrast (vf_eq2_t *eq2, double c) | |
259 { | |
260 eq2->contrast = c; | |
261 eq2->param[0].c = c; | |
262 eq2->param[0].lut_clean = 0; | |
263 check_values (&eq2->param[0]); | |
264 print_values (eq2); | |
265 } | |
266 | |
267 static | |
268 void set_brightness (vf_eq2_t *eq2, double b) | |
269 { | |
270 eq2->brightness = b; | |
271 eq2->param[0].b = b; | |
272 eq2->param[0].lut_clean = 0; | |
273 check_values (&eq2->param[0]); | |
274 print_values (eq2); | |
275 } | |
276 | |
277 static | |
278 void set_gamma (vf_eq2_t *eq2, double g) | |
279 { | |
280 eq2->gamma = g; | |
281 | |
282 eq2->param[0].g = eq2->gamma * eq2->ggamma; | |
283 eq2->param[1].g = sqrt (eq2->bgamma / eq2->ggamma); | |
284 eq2->param[2].g = sqrt (eq2->rgamma / eq2->ggamma); | |
285 | |
286 eq2->param[0].lut_clean = 0; | |
287 eq2->param[1].lut_clean = 0; | |
288 eq2->param[2].lut_clean = 0; | |
289 | |
290 check_values (&eq2->param[0]); | |
291 check_values (&eq2->param[1]); | |
292 check_values (&eq2->param[2]); | |
293 | |
294 print_values (eq2); | |
295 } | |
296 | |
297 static | |
298 void set_saturation (vf_eq2_t *eq2, double s) | |
299 { | |
300 eq2->saturation = s; | |
301 | |
302 eq2->param[1].c = s; | |
303 eq2->param[2].c = s; | |
304 | |
305 eq2->param[1].lut_clean = 0; | |
306 eq2->param[2].lut_clean = 0; | |
307 | |
308 check_values (&eq2->param[1]); | |
309 check_values (&eq2->param[2]); | |
310 | |
311 print_values (eq2); | |
126 } | 312 } |
127 | 313 |
128 static | 314 static |
129 int control (vf_instance_t *vf, int request, void *data) | 315 int control (vf_instance_t *vf, int request, void *data) |
130 { | 316 { |
133 switch (request) { | 319 switch (request) { |
134 case VFCTRL_SET_EQUALIZER: | 320 case VFCTRL_SET_EQUALIZER: |
135 eq = (vf_equalizer_t *) data; | 321 eq = (vf_equalizer_t *) data; |
136 | 322 |
137 if (strcmp (eq->item, "gamma") == 0) { | 323 if (strcmp (eq->item, "gamma") == 0) { |
138 vf->priv->gamma = exp (log (8.0) * eq->value / 100.0); | 324 set_gamma (vf->priv, exp (log (8.0) * eq->value / 100.0)); |
139 create_lut (vf->priv); | |
140 return CONTROL_TRUE; | 325 return CONTROL_TRUE; |
141 } | 326 } |
142 else if (strcmp (eq->item, "contrast") == 0) { | 327 else if (strcmp (eq->item, "contrast") == 0) { |
143 vf->priv->contrast = (1.0 / 100.0) * (eq->value + 100); | 328 set_contrast (vf->priv, (1.0 / 100.0) * (eq->value + 100)); |
144 create_lut (vf->priv); | |
145 return CONTROL_TRUE; | 329 return CONTROL_TRUE; |
146 } | 330 } |
147 else if (strcmp (eq->item, "brightness") == 0) { | 331 else if (strcmp (eq->item, "brightness") == 0) { |
148 vf->priv->bright = (1.0 / 100.0) * eq->value; | 332 set_brightness (vf->priv, (1.0 / 100.0) * eq->value); |
149 create_lut (vf->priv); | 333 return CONTROL_TRUE; |
334 } | |
335 else if (strcmp (eq->item, "saturation") == 0) { | |
336 set_saturation (vf->priv, (double) (eq->value + 100) / 100.0); | |
150 return CONTROL_TRUE; | 337 return CONTROL_TRUE; |
151 } | 338 } |
152 break; | 339 break; |
153 | 340 |
154 case VFCTRL_GET_EQUALIZER: | 341 case VFCTRL_GET_EQUALIZER: |
160 else if (strcmp (eq->item, "contrast") == 0) { | 347 else if (strcmp (eq->item, "contrast") == 0) { |
161 eq->value = (int) (100.0 * vf->priv->contrast) - 100; | 348 eq->value = (int) (100.0 * vf->priv->contrast) - 100; |
162 return CONTROL_TRUE; | 349 return CONTROL_TRUE; |
163 } | 350 } |
164 else if (strcmp (eq->item, "brightness") == 0) { | 351 else if (strcmp (eq->item, "brightness") == 0) { |
165 eq->value = (int) (100.0 * vf->priv->bright); | 352 eq->value = (int) (100.0 * vf->priv->brightness); |
353 return CONTROL_TRUE; | |
354 } | |
355 else if (strcmp (eq->item, "saturation") == 0) { | |
356 eq->value = (int) (100.0 * vf->priv->saturation) - 100; | |
166 return CONTROL_TRUE; | 357 return CONTROL_TRUE; |
167 } | 358 } |
168 break; | 359 break; |
169 } | 360 } |
170 | 361 |
178 case IMGFMT_YVU9: | 369 case IMGFMT_YVU9: |
179 case IMGFMT_IF09: | 370 case IMGFMT_IF09: |
180 case IMGFMT_YV12: | 371 case IMGFMT_YV12: |
181 case IMGFMT_I420: | 372 case IMGFMT_I420: |
182 case IMGFMT_IYUV: | 373 case IMGFMT_IYUV: |
183 case IMGFMT_CLPL: | |
184 case IMGFMT_Y800: | 374 case IMGFMT_Y800: |
185 case IMGFMT_Y8: | 375 case IMGFMT_Y8: |
186 case IMGFMT_NV12: | |
187 case IMGFMT_444P: | 376 case IMGFMT_444P: |
188 case IMGFMT_422P: | 377 case IMGFMT_422P: |
189 case IMGFMT_411P: | 378 case IMGFMT_411P: |
190 return vf_next_query_format (vf, fmt); | 379 return vf_next_query_format (vf, fmt); |
191 } | 380 } |
195 | 384 |
196 static | 385 static |
197 void uninit (vf_instance_t *vf) | 386 void uninit (vf_instance_t *vf) |
198 { | 387 { |
199 if (vf->priv != NULL) { | 388 if (vf->priv != NULL) { |
200 free (vf->priv->buf); | 389 free (vf->priv->buf[0]); |
201 free (vf->priv); | 390 free (vf->priv); |
202 } | 391 } |
203 } | 392 } |
204 | 393 |
205 static | 394 static |
206 int open (vf_instance_t *vf, char *args) | 395 int open (vf_instance_t *vf, char *args) |
207 { | 396 { |
397 unsigned i; | |
208 vf_eq2_t *eq2; | 398 vf_eq2_t *eq2; |
399 double par[7]; | |
209 | 400 |
210 vf->control = control; | 401 vf->control = control; |
211 vf->query_format = query_format; | 402 vf->query_format = query_format; |
212 vf->put_image = put_image; | 403 vf->put_image = put_image; |
213 vf->uninit = uninit; | 404 vf->uninit = uninit; |
214 | 405 |
215 vf->priv = (vf_eq2_t *) malloc (sizeof (vf_eq2_t)); | 406 vf->priv = (vf_eq2_t *) malloc (sizeof (vf_eq2_t)); |
216 eq2 = vf->priv; | 407 eq2 = vf->priv; |
217 | 408 |
218 eq2->buf = NULL; | 409 for (i = 0; i < 3; i++) { |
219 eq2->buf_w = 0; | 410 eq2->buf[i] = NULL; |
220 eq2->buf_h = 0; | 411 eq2->buf_w[i] = 0; |
412 eq2->buf_h[i] = 0; | |
413 | |
414 eq2->param[i].adjust = NULL; | |
415 eq2->param[i].c = 1.0; | |
416 eq2->param[i].b = 0.0; | |
417 eq2->param[i].g = 1.0; | |
418 eq2->param[i].lut_clean = 0; | |
419 } | |
420 | |
421 eq2->contrast = 1.0; | |
422 eq2->brightness = 0.0; | |
423 eq2->saturation = 1.0; | |
221 | 424 |
222 eq2->gamma = 1.0; | 425 eq2->gamma = 1.0; |
223 eq2->contrast = 1.0; | 426 eq2->rgamma = 1.0; |
224 eq2->bright = 0.0; | 427 eq2->ggamma = 1.0; |
428 eq2->bgamma = 1.0; | |
225 | 429 |
226 if (args != NULL) { | 430 if (args != NULL) { |
431 par[0] = 1.0; | |
432 par[1] = 1.0; | |
433 par[2] = 0.0; | |
434 par[3] = 1.0; | |
435 par[4] = 1.0; | |
436 par[5] = 1.0; | |
437 par[6] = 1.0; | |
227 #ifdef USE_SETLOCALE | 438 #ifdef USE_SETLOCALE |
228 setlocale( LC_NUMERIC, "C" ); | 439 setlocale (LC_NUMERIC, "C"); |
229 #endif | 440 #endif |
230 sscanf (args, "%lf:%lf:%lf", &eq2->gamma, &eq2->contrast, &eq2->bright); | 441 sscanf (args, "%lf:%lf:%lf:%lf:%lf:%lf:%lf", |
442 par, par + 1, par + 2, par + 3, par + 4, par + 5, par + 6 | |
443 ); | |
231 #ifdef USE_SETLOCALE | 444 #ifdef USE_SETLOCALE |
232 setlocale( LC_NUMERIC, "" ); | 445 setlocale (LC_NUMERIC, ""); |
233 #endif | 446 #endif |
234 } | 447 |
235 | 448 eq2->rgamma = par[4]; |
236 create_lut (eq2); | 449 eq2->ggamma = par[5]; |
450 eq2->bgamma = par[6]; | |
451 | |
452 set_gamma (eq2, par[0]); | |
453 set_contrast (eq2, par[1]); | |
454 set_brightness (eq2, par[2]); | |
455 set_saturation (eq2, par[3]); | |
456 } | |
237 | 457 |
238 return 1; | 458 return 1; |
239 } | 459 } |
240 | 460 |
241 vf_info_t vf_info_eq2 = { | 461 vf_info_t vf_info_eq2 = { |
242 "LUT-based software equalizer", | 462 "Software equalizer", |
243 "eq2", | 463 "eq2", |
244 "Hampa Hug", | 464 "Hampa Hug, Daniel Moreno, Richard Felker", |
245 "", | 465 "", |
246 &open | 466 &open |
247 }; | 467 }; |