2 * Software equalizer (brightness, contrast, gamma, saturation)
4 * Hampa Hug <hampa@hampa.ch> (original LUT gamma/contrast/brightness filter)
5 * Daniel Moreno <comac@comac.darktech.org> (saturation, R/G/B gamma support)
6 * Richard Felker (original MMX contrast/brightness code (vf_eq.c))
7 * Michael Niedermayer <michalni@gmx.at> (LUT16)
9 * This file is part of MPlayer.
11 * MPlayer is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * MPlayer is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include "cpudetect.h"
36 #include "img_format.h"
42 /* Per channel parameters */
43 typedef struct eq2_param_t
{
44 unsigned char lut
[256];
46 uint16_t lut16
[256*256];
50 void (*adjust
) (struct eq2_param_t
*par
, unsigned char *dst
, unsigned char *src
,
51 unsigned w
, unsigned h
, unsigned dstride
, unsigned sstride
);
59 typedef struct vf_priv_s
{
74 unsigned char *buf
[3];
79 void create_lut (eq2_param_t
*par
)
89 if ((g
< 0.001) || (g
> 1000.0)) {
95 for (i
= 0; i
< 256; i
++) {
96 v
= (double) i
/ 255.0;
97 v
= par
->c
* (v
- 0.5) + 0.5 + par
->b
;
103 v
= v
*lw
+ pow(v
, g
)*gw
;
109 par
->lut
[i
] = (unsigned char) (256.0 * v
);
115 for(i
=0; i
<256*256; i
++){
116 par
->lut16
[i
]= par
->lut
[i
&0xFF] + (par
->lut
[i
>>8]<<8);
125 void affine_1d_MMX (eq2_param_t
*par
, unsigned char *dst
, unsigned char *src
,
126 unsigned w
, unsigned h
, unsigned dstride
, unsigned sstride
)
129 int contrast
, brightness
;
130 unsigned dstep
, sstep
;
135 // printf("\nmmx: src=%p dst=%p w=%d h=%d ds=%d ss=%d\n",src,dst,w,h,dstride,sstride);
137 contrast
= (int) (par
->c
* 256 * 16);
138 brightness
= ((int) (100.0 * par
->b
+ 100.0) * 511) / 200 - 128 - contrast
/ 32;
140 brvec
[0] = brvec
[1] = brvec
[2] = brvec
[3] = brightness
;
141 contvec
[0] = contvec
[1] = contvec
[2] = contvec
[3] = contrast
;
148 "movq (%5), %%mm3 \n\t"
149 "movq (%6), %%mm4 \n\t"
150 "pxor %%mm0, %%mm0 \n\t"
154 "movq (%0), %%mm1 \n\t"
155 "movq (%0), %%mm2 \n\t"
156 "punpcklbw %%mm0, %%mm1 \n\t"
157 "punpckhbw %%mm0, %%mm2 \n\t"
158 "psllw $4, %%mm1 \n\t"
159 "psllw $4, %%mm2 \n\t"
160 "pmulhw %%mm4, %%mm1 \n\t"
161 "pmulhw %%mm4, %%mm2 \n\t"
162 "paddw %%mm3, %%mm1 \n\t"
163 "paddw %%mm3, %%mm2 \n\t"
164 "packuswb %%mm2, %%mm1 \n\t"
166 "movq %%mm1, (%1) \n\t"
170 : "=r" (src
), "=r" (dst
)
171 : "0" (src
), "1" (dst
), "r" (w
>> 3), "r" (brvec
), "r" (contvec
)
175 for (i
= w
& 7; i
> 0; i
--) {
176 pel
= ((*src
++ * contrast
) >> 12) + brightness
;
187 __asm__
volatile ( "emms \n\t" ::: "memory" );
192 void apply_lut (eq2_param_t
*par
, unsigned char *dst
, unsigned char *src
,
193 unsigned w
, unsigned h
, unsigned dstride
, unsigned sstride
)
199 if (!par
->lut_clean
) {
207 for (j
= 0; j
< h
; j
++) {
208 uint16_t *src16
= (uint16_t*)src
;
209 uint16_t *dst16
= (uint16_t*)dst
;
210 for (i
= 0; i
< w2
; i
+=4) {
211 dst16
[i
+0] = lut16
[src16
[i
+0]];
212 dst16
[i
+1] = lut16
[src16
[i
+1]];
213 dst16
[i
+2] = lut16
[src16
[i
+2]];
214 dst16
[i
+3] = lut16
[src16
[i
+3]];
219 for (j
= 0; j
< h
; j
++) {
220 for (i
= 0; i
< w2
; i
+=8) {
221 dst
[i
+0] = lut
[src
[i
+0]];
222 dst
[i
+1] = lut
[src
[i
+1]];
223 dst
[i
+2] = lut
[src
[i
+2]];
224 dst
[i
+3] = lut
[src
[i
+3]];
225 dst
[i
+4] = lut
[src
[i
+4]];
226 dst
[i
+5] = lut
[src
[i
+5]];
227 dst
[i
+6] = lut
[src
[i
+6]];
228 dst
[i
+7] = lut
[src
[i
+7]];
232 dst
[i
] = lut
[src
[i
]];
241 int put_image (vf_instance_t
*vf
, mp_image_t
*src
, double pts
)
246 unsigned long img_n
,img_c
;
250 if ((eq2
->buf_w
[0] != src
->w
) || (eq2
->buf_h
[0] != src
->h
)) {
251 eq2
->buf_w
[0] = src
->w
;
252 eq2
->buf_h
[0] = src
->h
;
253 eq2
->buf_w
[1] = eq2
->buf_w
[2] = src
->w
>> src
->chroma_x_shift
;
254 eq2
->buf_h
[1] = eq2
->buf_h
[2] = src
->h
>> src
->chroma_y_shift
;
255 img_n
= eq2
->buf_w
[0]*eq2
->buf_h
[0];
256 if(src
->num_planes
>1){
257 img_c
= eq2
->buf_w
[1]*eq2
->buf_h
[1];
258 eq2
->buf
[0] = realloc (eq2
->buf
[0], img_n
+ 2*img_c
);
259 eq2
->buf
[1] = eq2
->buf
[0] + img_n
;
260 eq2
->buf
[2] = eq2
->buf
[1] + img_c
;
262 eq2
->buf
[0] = realloc (eq2
->buf
[0], img_n
);
265 dst
= vf_get_image (vf
->next
, src
->imgfmt
, MP_IMGTYPE_EXPORT
, 0, src
->w
, src
->h
);
267 for (i
= 0; i
< ((src
->num_planes
>1)?3:1); i
++) {
268 if (eq2
->param
[i
].adjust
!= NULL
) {
269 dst
->planes
[i
] = eq2
->buf
[i
];
270 dst
->stride
[i
] = eq2
->buf_w
[i
];
272 eq2
->param
[i
].adjust (&eq2
->param
[i
], dst
->planes
[i
], src
->planes
[i
],
273 eq2
->buf_w
[i
], eq2
->buf_h
[i
], dst
->stride
[i
], src
->stride
[i
]);
276 dst
->planes
[i
] = src
->planes
[i
];
277 dst
->stride
[i
] = src
->stride
[i
];
281 return vf_next_put_image (vf
, dst
, pts
);
285 void check_values (eq2_param_t
*par
)
287 /* yuck! floating point comparisons... */
289 if ((par
->c
== 1.0) && (par
->b
== 0.0) && (par
->g
== 1.0)) {
293 else if (par
->g
== 1.0 && gCpuCaps
.hasMMX
) {
294 par
->adjust
= &affine_1d_MMX
;
298 par
->adjust
= &apply_lut
;
303 void print_values (vf_eq2_t
*eq2
)
305 mp_msg (MSGT_VFILTER
, MSGL_V
, "vf_eq2: c=%.2f b=%.2f g=%.4f s=%.2f \n",
306 eq2
->contrast
, eq2
->brightness
, eq2
->gamma
, eq2
->saturation
311 void set_contrast (vf_eq2_t
*eq2
, double c
)
315 eq2
->param
[0].lut_clean
= 0;
316 check_values (&eq2
->param
[0]);
321 void set_brightness (vf_eq2_t
*eq2
, double b
)
325 eq2
->param
[0].lut_clean
= 0;
326 check_values (&eq2
->param
[0]);
331 void set_gamma (vf_eq2_t
*eq2
, double g
)
335 eq2
->param
[0].g
= eq2
->gamma
* eq2
->ggamma
;
336 eq2
->param
[1].g
= sqrt (eq2
->bgamma
/ eq2
->ggamma
);
337 eq2
->param
[2].g
= sqrt (eq2
->rgamma
/ eq2
->ggamma
);
338 eq2
->param
[0].w
= eq2
->param
[1].w
= eq2
->param
[2].w
= eq2
->gamma_weight
;
340 eq2
->param
[0].lut_clean
= 0;
341 eq2
->param
[1].lut_clean
= 0;
342 eq2
->param
[2].lut_clean
= 0;
344 check_values (&eq2
->param
[0]);
345 check_values (&eq2
->param
[1]);
346 check_values (&eq2
->param
[2]);
352 void set_saturation (vf_eq2_t
*eq2
, double s
)
359 eq2
->param
[1].lut_clean
= 0;
360 eq2
->param
[2].lut_clean
= 0;
362 check_values (&eq2
->param
[1]);
363 check_values (&eq2
->param
[2]);
369 int control (vf_instance_t
*vf
, int request
, void *data
)
374 case VFCTRL_SET_EQUALIZER
:
375 eq
= (vf_equalizer_t
*) data
;
377 if (strcmp (eq
->item
, "gamma") == 0) {
378 set_gamma (vf
->priv
, exp (log (8.0) * eq
->value
/ 100.0));
381 else if (strcmp (eq
->item
, "contrast") == 0) {
382 set_contrast (vf
->priv
, (1.0 / 100.0) * (eq
->value
+ 100));
385 else if (strcmp (eq
->item
, "brightness") == 0) {
386 set_brightness (vf
->priv
, (1.0 / 100.0) * eq
->value
);
389 else if (strcmp (eq
->item
, "saturation") == 0) {
390 set_saturation (vf
->priv
, (double) (eq
->value
+ 100) / 100.0);
395 case VFCTRL_GET_EQUALIZER
:
396 eq
= (vf_equalizer_t
*) data
;
397 if (strcmp (eq
->item
, "gamma") == 0) {
398 eq
->value
= (int) (100.0 * log (vf
->priv
->gamma
) / log (8.0));
401 else if (strcmp (eq
->item
, "contrast") == 0) {
402 eq
->value
= (int) (100.0 * vf
->priv
->contrast
) - 100;
405 else if (strcmp (eq
->item
, "brightness") == 0) {
406 eq
->value
= (int) (100.0 * vf
->priv
->brightness
);
409 else if (strcmp (eq
->item
, "saturation") == 0) {
410 eq
->value
= (int) (100.0 * vf
->priv
->saturation
) - 100;
416 return vf_next_control (vf
, request
, data
);
420 int query_format (vf_instance_t
*vf
, unsigned fmt
)
433 return vf_next_query_format (vf
, fmt
);
440 void uninit (vf_instance_t
*vf
)
442 if (vf
->priv
!= NULL
) {
443 free (vf
->priv
->buf
[0]);
449 int vf_open(vf_instance_t
*vf
, char *args
)
455 vf
->control
= control
;
456 vf
->query_format
= query_format
;
457 vf
->put_image
= put_image
;
460 vf
->priv
= malloc (sizeof (vf_eq2_t
));
463 for (i
= 0; i
< 3; i
++) {
468 eq2
->param
[i
].adjust
= NULL
;
469 eq2
->param
[i
].c
= 1.0;
470 eq2
->param
[i
].b
= 0.0;
471 eq2
->param
[i
].g
= 1.0;
472 eq2
->param
[i
].lut_clean
= 0;
476 eq2
->brightness
= 0.0;
477 eq2
->saturation
= 1.0;
480 eq2
->gamma_weight
= 1.0;
494 sscanf (args
, "%lf:%lf:%lf:%lf:%lf:%lf:%lf:%lf",
495 par
, par
+ 1, par
+ 2, par
+ 3, par
+ 4, par
+ 5, par
+ 6, par
+ 7
498 eq2
->rgamma
= par
[4];
499 eq2
->ggamma
= par
[5];
500 eq2
->bgamma
= par
[6];
501 eq2
->gamma_weight
= par
[7];
503 set_gamma (eq2
, par
[0]);
504 set_contrast (eq2
, par
[1]);
505 set_brightness (eq2
, par
[2]);
506 set_saturation (eq2
, par
[3]);
512 const vf_info_t vf_info_eq2
= {
513 "Software equalizer",
515 "Hampa Hug, Daniel Moreno, Richard Felker",