4 * Software equalizer (brightness, contrast, gamma, saturation)
6 * Hampa Hug <hampa@hampa.ch> (original LUT gamma/contrast/brightness filter)
7 * Daniel Moreno <comac@comac.darktech.org> (saturation, R/G/B gamma support)
8 * Richard Felker (original MMX contrast/brightness code (vf_eq.c))
9 * Michael Niedermayer <michalni@gmx.at> (LUT16)
20 #include "cpudetect.h"
23 #include "img_format.h"
29 /* Per channel parameters */
30 typedef struct eq2_param_t
{
31 unsigned char lut
[256];
33 uint16_t lut16
[256*256];
37 void (*adjust
) (struct eq2_param_t
*par
, unsigned char *dst
, unsigned char *src
,
38 unsigned w
, unsigned h
, unsigned dstride
, unsigned sstride
);
46 typedef struct vf_priv_s
{
61 unsigned char *buf
[3];
66 void create_lut (eq2_param_t
*par
)
76 if ((g
< 0.001) || (g
> 1000.0)) {
82 for (i
= 0; i
< 256; i
++) {
83 v
= (double) i
/ 255.0;
84 v
= par
->c
* (v
- 0.5) + 0.5 + par
->b
;
90 v
= v
*lw
+ pow(v
, g
)*gw
;
96 par
->lut
[i
] = (unsigned char) (256.0 * v
);
102 for(i
=0; i
<256*256; i
++){
103 par
->lut16
[i
]= par
->lut
[i
&0xFF] + (par
->lut
[i
>>8]<<8);
112 void affine_1d_MMX (eq2_param_t
*par
, unsigned char *dst
, unsigned char *src
,
113 unsigned w
, unsigned h
, unsigned dstride
, unsigned sstride
)
116 int contrast
, brightness
;
117 unsigned dstep
, sstep
;
122 // printf("\nmmx: src=%p dst=%p w=%d h=%d ds=%d ss=%d\n",src,dst,w,h,dstride,sstride);
124 contrast
= (int) (par
->c
* 256 * 16);
125 brightness
= ((int) (100.0 * par
->b
+ 100.0) * 511) / 200 - 128 - contrast
/ 32;
127 brvec
[0] = brvec
[1] = brvec
[2] = brvec
[3] = brightness
;
128 contvec
[0] = contvec
[1] = contvec
[2] = contvec
[3] = contrast
;
135 "movq (%5), %%mm3 \n\t"
136 "movq (%6), %%mm4 \n\t"
137 "pxor %%mm0, %%mm0 \n\t"
141 "movq (%0), %%mm1 \n\t"
142 "movq (%0), %%mm2 \n\t"
143 "punpcklbw %%mm0, %%mm1 \n\t"
144 "punpckhbw %%mm0, %%mm2 \n\t"
145 "psllw $4, %%mm1 \n\t"
146 "psllw $4, %%mm2 \n\t"
147 "pmulhw %%mm4, %%mm1 \n\t"
148 "pmulhw %%mm4, %%mm2 \n\t"
149 "paddw %%mm3, %%mm1 \n\t"
150 "paddw %%mm3, %%mm2 \n\t"
151 "packuswb %%mm2, %%mm1 \n\t"
153 "movq %%mm1, (%1) \n\t"
157 : "=r" (src
), "=r" (dst
)
158 : "0" (src
), "1" (dst
), "r" (w
>> 3), "r" (brvec
), "r" (contvec
)
162 for (i
= w
& 7; i
> 0; i
--) {
163 pel
= ((*src
++ * contrast
) >> 12) + brightness
;
174 asm volatile ( "emms \n\t" ::: "memory" );
179 void apply_lut (eq2_param_t
*par
, unsigned char *dst
, unsigned char *src
,
180 unsigned w
, unsigned h
, unsigned dstride
, unsigned sstride
)
186 if (!par
->lut_clean
) {
194 for (j
= 0; j
< h
; j
++) {
195 uint16_t *src16
= (uint16_t*)src
;
196 uint16_t *dst16
= (uint16_t*)dst
;
197 for (i
= 0; i
< w2
; i
+=4) {
198 dst16
[i
+0] = lut16
[src16
[i
+0]];
199 dst16
[i
+1] = lut16
[src16
[i
+1]];
200 dst16
[i
+2] = lut16
[src16
[i
+2]];
201 dst16
[i
+3] = lut16
[src16
[i
+3]];
206 for (j
= 0; j
< h
; j
++) {
207 for (i
= 0; i
< w2
; i
+=8) {
208 dst
[i
+0] = lut
[src
[i
+0]];
209 dst
[i
+1] = lut
[src
[i
+1]];
210 dst
[i
+2] = lut
[src
[i
+2]];
211 dst
[i
+3] = lut
[src
[i
+3]];
212 dst
[i
+4] = lut
[src
[i
+4]];
213 dst
[i
+5] = lut
[src
[i
+5]];
214 dst
[i
+6] = lut
[src
[i
+6]];
215 dst
[i
+7] = lut
[src
[i
+7]];
219 dst
[i
] = lut
[src
[i
]];
228 int put_image (vf_instance_t
*vf
, mp_image_t
*src
, double pts
)
233 unsigned long img_n
,img_c
;
237 if ((eq2
->buf_w
[0] != src
->w
) || (eq2
->buf_h
[0] != src
->h
)) {
238 eq2
->buf_w
[0] = src
->w
;
239 eq2
->buf_h
[0] = src
->h
;
240 eq2
->buf_w
[1] = eq2
->buf_w
[2] = src
->w
>> src
->chroma_x_shift
;
241 eq2
->buf_h
[1] = eq2
->buf_h
[2] = src
->h
>> src
->chroma_y_shift
;
242 img_n
= eq2
->buf_w
[0]*eq2
->buf_h
[0];
243 if(src
->num_planes
>1){
244 img_c
= eq2
->buf_w
[1]*eq2
->buf_h
[1];
245 eq2
->buf
[0] = (unsigned char *) realloc (eq2
->buf
[0], img_n
+ 2*img_c
);
246 eq2
->buf
[1] = eq2
->buf
[0] + img_n
;
247 eq2
->buf
[2] = eq2
->buf
[1] + img_c
;
249 eq2
->buf
[0] = (unsigned char *) realloc (eq2
->buf
[0], img_n
);
252 dst
= vf_get_image (vf
->next
, src
->imgfmt
, MP_IMGTYPE_EXPORT
, 0, src
->w
, src
->h
);
254 for (i
= 0; i
< ((src
->num_planes
>1)?3:1); i
++) {
255 if (eq2
->param
[i
].adjust
!= NULL
) {
256 dst
->planes
[i
] = eq2
->buf
[i
];
257 dst
->stride
[i
] = eq2
->buf_w
[i
];
259 eq2
->param
[i
].adjust (&eq2
->param
[i
], dst
->planes
[i
], src
->planes
[i
],
260 eq2
->buf_w
[i
], eq2
->buf_h
[i
], dst
->stride
[i
], src
->stride
[i
]);
263 dst
->planes
[i
] = src
->planes
[i
];
264 dst
->stride
[i
] = src
->stride
[i
];
268 return vf_next_put_image (vf
, dst
, pts
);
272 void check_values (eq2_param_t
*par
)
274 /* yuck! floating point comparisons... */
276 if ((par
->c
== 1.0) && (par
->b
== 0.0) && (par
->g
== 1.0)) {
280 else if (par
->g
== 1.0 && gCpuCaps
.hasMMX
) {
281 par
->adjust
= &affine_1d_MMX
;
285 par
->adjust
= &apply_lut
;
290 void print_values (vf_eq2_t
*eq2
)
292 mp_msg (MSGT_VFILTER
, MSGL_V
, "vf_eq2: c=%.2f b=%.2f g=%.4f s=%.2f \n",
293 eq2
->contrast
, eq2
->brightness
, eq2
->gamma
, eq2
->saturation
298 void set_contrast (vf_eq2_t
*eq2
, double c
)
302 eq2
->param
[0].lut_clean
= 0;
303 check_values (&eq2
->param
[0]);
308 void set_brightness (vf_eq2_t
*eq2
, double b
)
312 eq2
->param
[0].lut_clean
= 0;
313 check_values (&eq2
->param
[0]);
318 void set_gamma (vf_eq2_t
*eq2
, double g
)
322 eq2
->param
[0].g
= eq2
->gamma
* eq2
->ggamma
;
323 eq2
->param
[1].g
= sqrt (eq2
->bgamma
/ eq2
->ggamma
);
324 eq2
->param
[2].g
= sqrt (eq2
->rgamma
/ eq2
->ggamma
);
325 eq2
->param
[0].w
= eq2
->param
[1].w
= eq2
->param
[2].w
= eq2
->gamma_weight
;
327 eq2
->param
[0].lut_clean
= 0;
328 eq2
->param
[1].lut_clean
= 0;
329 eq2
->param
[2].lut_clean
= 0;
331 check_values (&eq2
->param
[0]);
332 check_values (&eq2
->param
[1]);
333 check_values (&eq2
->param
[2]);
339 void set_saturation (vf_eq2_t
*eq2
, double s
)
346 eq2
->param
[1].lut_clean
= 0;
347 eq2
->param
[2].lut_clean
= 0;
349 check_values (&eq2
->param
[1]);
350 check_values (&eq2
->param
[2]);
356 int control (vf_instance_t
*vf
, int request
, void *data
)
361 case VFCTRL_SET_EQUALIZER
:
362 eq
= (vf_equalizer_t
*) data
;
364 if (strcmp (eq
->item
, "gamma") == 0) {
365 set_gamma (vf
->priv
, exp (log (8.0) * eq
->value
/ 100.0));
368 else if (strcmp (eq
->item
, "contrast") == 0) {
369 set_contrast (vf
->priv
, (1.0 / 100.0) * (eq
->value
+ 100));
372 else if (strcmp (eq
->item
, "brightness") == 0) {
373 set_brightness (vf
->priv
, (1.0 / 100.0) * eq
->value
);
376 else if (strcmp (eq
->item
, "saturation") == 0) {
377 set_saturation (vf
->priv
, (double) (eq
->value
+ 100) / 100.0);
382 case VFCTRL_GET_EQUALIZER
:
383 eq
= (vf_equalizer_t
*) data
;
384 if (strcmp (eq
->item
, "gamma") == 0) {
385 eq
->value
= (int) (100.0 * log (vf
->priv
->gamma
) / log (8.0));
388 else if (strcmp (eq
->item
, "contrast") == 0) {
389 eq
->value
= (int) (100.0 * vf
->priv
->contrast
) - 100;
392 else if (strcmp (eq
->item
, "brightness") == 0) {
393 eq
->value
= (int) (100.0 * vf
->priv
->brightness
);
396 else if (strcmp (eq
->item
, "saturation") == 0) {
397 eq
->value
= (int) (100.0 * vf
->priv
->saturation
) - 100;
403 return vf_next_control (vf
, request
, data
);
407 int query_format (vf_instance_t
*vf
, unsigned fmt
)
420 return vf_next_query_format (vf
, fmt
);
427 void uninit (vf_instance_t
*vf
)
429 if (vf
->priv
!= NULL
) {
430 free (vf
->priv
->buf
[0]);
436 int open (vf_instance_t
*vf
, char *args
)
442 vf
->control
= control
;
443 vf
->query_format
= query_format
;
444 vf
->put_image
= put_image
;
447 vf
->priv
= (vf_eq2_t
*) malloc (sizeof (vf_eq2_t
));
450 for (i
= 0; i
< 3; i
++) {
455 eq2
->param
[i
].adjust
= NULL
;
456 eq2
->param
[i
].c
= 1.0;
457 eq2
->param
[i
].b
= 0.0;
458 eq2
->param
[i
].g
= 1.0;
459 eq2
->param
[i
].lut_clean
= 0;
463 eq2
->brightness
= 0.0;
464 eq2
->saturation
= 1.0;
467 eq2
->gamma_weight
= 1.0;
481 sscanf (args
, "%lf:%lf:%lf:%lf:%lf:%lf:%lf:%lf",
482 par
, par
+ 1, par
+ 2, par
+ 3, par
+ 4, par
+ 5, par
+ 6, par
+ 7
485 eq2
->rgamma
= par
[4];
486 eq2
->ggamma
= par
[5];
487 eq2
->bgamma
= par
[6];
488 eq2
->gamma_weight
= par
[7];
490 set_gamma (eq2
, par
[0]);
491 set_contrast (eq2
, par
[1]);
492 set_brightness (eq2
, par
[2]);
493 set_saturation (eq2
, par
[3]);
499 vf_info_t vf_info_eq2
= {
500 "Software equalizer",
502 "Hampa Hug, Daniel Moreno, Richard Felker",