1 /*
2 * Copyright (C) 2000-2018 the xine project
3 *
4 * This file is part of xine, a free video player.
5 *
6 * xine is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * xine is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19 *
20 * mplayer's eq (soft video equalizer)
21 * Copyright (C) Richard Felker
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "planar.h"
29
30 #include <xine/xine_internal.h>
31 #include <xine/post.h>
32 #include <xine/xineutils.h>
33 #include <pthread.h>
34
35
36 #if defined(ARCH_X86)
37
38 #if defined(ARCH_X86_64)
39 # define MEM1(reg) "(%"reg")"
40 # define MEM2(offs,reg) offs"(%"reg")"
41 # define BUMPPTR(offs,reg) "\n\tleaq\t"offs"(%"reg"), %"reg
42 #elif defined(ARCH_X86_X32)
43 # define MEM1(reg) "(%q"reg")"
44 # define MEM2(offs,reg) offs"(%q"reg")"
45 # define BUMPPTR(offs,reg) "\n\tleaq\t"offs"(%q"reg"), %q"reg
46 #else
47 # define MEM1(reg) "(%"reg")"
48 # define MEM2(offs,reg) offs"(%"reg")"
49 # define BUMPPTR(offs,reg) "\n\tleal\t"offs"(%"reg"), %"reg
50 #endif
51
process_MMX(unsigned char * dest,int dstride,unsigned char * src,int sstride,int w,int h,int brightness,int contrast)52 static void process_MMX(unsigned char *dest, int dstride, unsigned char *src, int sstride,
53 int w, int h, int brightness, int contrast)
54 {
55 int i;
56 int pel;
57 int dstep = dstride - w;
58 int sstep = sstride - w;
59 short cvec[8];
60
61 contrast = ((contrast + 100) * 256 * 16) / 100;
62 brightness = ((brightness + 100) * 511) / 200 - 128 - contrast / 32;
63
64 cvec[0] = cvec[1] = cvec[2] = cvec[3] = brightness;
65 cvec[4] = cvec[5] = cvec[6] = cvec[7] = contrast;
66
67 __asm__ __volatile__ (
68 "\n\tmovq\t"MEM1( "0")", %%mm3"
69 "\n\tmovq\t"MEM2("8", "0")", %%mm4"
70 "\n\tpxor\t%%mm0, %%mm0"
71 :
72 : "r" (cvec)
73 );
74
75 while (h--) {
76 __asm__ __volatile__ (
77 "\n\tmovl\t%4, %%eax"
78 "\n\t"ASMALIGN(4)
79 "\n1:"
80 "\n\tmovq\t"MEM1("0")", %%mm1"
81 "\n\tmovq\t"MEM1("0")", %%mm2"
82 "\n\tpunpcklbw\t%%mm0, %%mm1"
83 "\n\tpunpckhbw\t%%mm0, %%mm2"
84 "\n\tpsllw\t$4, %%mm1"
85 "\n\tpsllw\t$4, %%mm2"
86 "\n\tpmulhw\t%%mm4, %%mm1"
87 "\n\tpmulhw\t%%mm4, %%mm2"
88 "\n\tpaddw\t%%mm3, %%mm1"
89 "\n\tpaddw\t%%mm3, %%mm2"
90 "\n\tpackuswb\t%%mm2, %%mm1"
91 BUMPPTR("8","0")
92 "\n\tmovq\t%%mm1, "MEM1("1")
93 BUMPPTR("8","1")
94 "\n\tdecl\t%%eax"
95 "\n\tjnz\t1b"
96 : "=r" (src), "=r" (dest)
97 : "0" (src), "1" (dest), "r" (w>>3)
98 : "%eax"
99 );
100
101 for (i = w & 7; i; i--) {
102 pel = ((*src++ * contrast) >> 12) + brightness;
103 if (pel & 768)
104 pel = (-pel) >> 31;
105 *dest++ = pel;
106 }
107
108 src += sstep;
109 dest += dstep;
110 }
111 __asm__ __volatile__ ( "emms \n\t" ::: "memory" );
112 }
113 #endif
114
process_C(unsigned char * dest,int dstride,unsigned char * src,int sstride,int w,int h,int brightness,int contrast)115 static void process_C(unsigned char *dest, int dstride, unsigned char *src, int sstride,
116 int w, int h, int brightness, int contrast)
117 {
118 int i;
119 int pel;
120 int dstep = dstride-w;
121 int sstep = sstride-w;
122
123 contrast = ((contrast+100)*256*256)/100;
124 brightness = ((brightness+100)*511)/200-128 - contrast/512;
125
126 while (h--) {
127 for (i = w; i; i--)
128 {
129 pel = ((*src++* contrast)>>16) + brightness;
130 if(pel&768) pel = (-pel)>>31;
131 *dest++ = pel;
132 }
133 src += sstep;
134 dest += dstep;
135 }
136 }
137
138 static void (*process)(unsigned char *dest, int dstride, unsigned char *src, int sstride,
139 int w, int h, int brightness, int contrast);
140
141
142 typedef struct post_plugin_eq_s post_plugin_eq_t;
143
144 /*
145 * this is the struct used by "parameters api"
146 */
147 typedef struct eq_parameters_s {
148
149 int brightness;
150 int contrast;
151
152 } eq_parameters_t;
153
154 /*
155 * description of params struct
156 */
157 START_PARAM_DESCR( eq_parameters_t )
158 PARAM_ITEM( POST_PARAM_TYPE_INT, brightness, NULL, -100, 100, 0,
159 "brightness" )
160 PARAM_ITEM( POST_PARAM_TYPE_INT, contrast, NULL, -100, 100, 0,
161 "contrast" )
162 END_PARAM_DESCR( param_descr )
163
164
165 /* plugin structure */
166 struct post_plugin_eq_s {
167 post_plugin_t post;
168
169 /* private data */
170 eq_parameters_t params;
171
172 pthread_mutex_t lock;
173 };
174
175
set_parameters(xine_post_t * this_gen,const void * param_gen)176 static int set_parameters (xine_post_t *this_gen, const void *param_gen) {
177 post_plugin_eq_t *this = (post_plugin_eq_t *)this_gen;
178 const eq_parameters_t *param = (const eq_parameters_t *)param_gen;
179
180 pthread_mutex_lock (&this->lock);
181
182 memcpy( &this->params, param, sizeof(eq_parameters_t) );
183
184 pthread_mutex_unlock (&this->lock);
185
186 return 1;
187 }
188
get_parameters(xine_post_t * this_gen,void * param_gen)189 static int get_parameters (xine_post_t *this_gen, void *param_gen) {
190 post_plugin_eq_t *this = (post_plugin_eq_t *)this_gen;
191 eq_parameters_t *param = (eq_parameters_t *)param_gen;
192
193
194 memcpy( param, &this->params, sizeof(eq_parameters_t) );
195
196 return 1;
197 }
198
get_param_descr(void)199 static xine_post_api_descr_t * get_param_descr (void) {
200 return ¶m_descr;
201 }
202
get_help(void)203 static char * get_help (void) {
204 return _("Software equalizer with interactive controls just like the hardware "
205 "equalizer, for cards/drivers that do not support brightness and "
206 "contrast controls in hardware.\n"
207 "\n"
208 "Parameters\n"
209 " brightness\n"
210 " contrast\n"
211 "\n"
212 "Note: It is possible to use frontend's control window to set "
213 "these parameters.\n"
214 "\n"
215 "* mplayer's eq (C) Richard Felker\n"
216 );
217 }
218
219
eq_dispose(post_plugin_t * this_gen)220 static void eq_dispose(post_plugin_t *this_gen)
221 {
222 post_plugin_eq_t *this = (post_plugin_eq_t *)this_gen;
223
224 if (_x_post_dispose(this_gen)) {
225 pthread_mutex_destroy(&this->lock);
226 free(this);
227 }
228 }
229
230
eq_get_property(xine_video_port_t * port_gen,int property)231 static int eq_get_property(xine_video_port_t *port_gen, int property) {
232 post_video_port_t *port = (post_video_port_t *)port_gen;
233 post_plugin_eq_t *this = (post_plugin_eq_t *)port->post;
234 if( property == XINE_PARAM_VO_BRIGHTNESS )
235 return 65535 * (this->params.brightness + 100) / 200;
236 else if( property == XINE_PARAM_VO_CONTRAST )
237 return 65535 * (this->params.contrast + 100) / 200;
238 else
239 return port->original_port->get_property(port->original_port, property);
240 }
241
eq_set_property(xine_video_port_t * port_gen,int property,int value)242 static int eq_set_property(xine_video_port_t *port_gen, int property, int value) {
243 post_video_port_t *port = (post_video_port_t *)port_gen;
244 post_plugin_eq_t *this = (post_plugin_eq_t *)port->post;
245 if( property == XINE_PARAM_VO_BRIGHTNESS ) {
246 pthread_mutex_lock (&this->lock);
247 this->params.brightness = (200 * value / 65535) - 100;
248 pthread_mutex_unlock (&this->lock);
249 return value;
250 } else if( property == XINE_PARAM_VO_CONTRAST ) {
251 pthread_mutex_lock (&this->lock);
252 this->params.contrast = (200 * value / 65535) - 100;
253 pthread_mutex_unlock (&this->lock);
254 return value;
255 } else
256 return port->original_port->set_property(port->original_port, property, value);
257 }
258
259
eq_intercept_frame(post_video_port_t * port,vo_frame_t * frame)260 static int eq_intercept_frame(post_video_port_t *port, vo_frame_t *frame)
261 {
262 (void)port;
263 return (frame->format == XINE_IMGFMT_YV12 || frame->format == XINE_IMGFMT_YUY2);
264 }
265
266
eq_draw(vo_frame_t * frame,xine_stream_t * stream)267 static int eq_draw(vo_frame_t *frame, xine_stream_t *stream)
268 {
269 post_video_port_t *port = (post_video_port_t *)frame->port;
270 post_plugin_eq_t *this = (post_plugin_eq_t *)port->post;
271 vo_frame_t *out_frame;
272 vo_frame_t *yv12_frame;
273 int skip;
274
275 if( !frame->bad_frame &&
276 ((this->params.brightness != 0) || (this->params.contrast != 0)) ) {
277
278 /* convert to YV12 if needed */
279 if( frame->format != XINE_IMGFMT_YV12 ) {
280
281 yv12_frame = port->original_port->get_frame(port->original_port,
282 frame->width, frame->height, frame->ratio, XINE_IMGFMT_YV12, frame->flags | VO_BOTH_FIELDS);
283
284 _x_post_frame_copy_down(frame, yv12_frame);
285
286 yuy2_to_yv12(frame->base[0], frame->pitches[0],
287 yv12_frame->base[0], yv12_frame->pitches[0],
288 yv12_frame->base[1], yv12_frame->pitches[1],
289 yv12_frame->base[2], yv12_frame->pitches[2],
290 frame->width, frame->height);
291
292 } else {
293 yv12_frame = frame;
294 yv12_frame->lock(yv12_frame);
295 }
296
297
298 out_frame = port->original_port->get_frame(port->original_port,
299 frame->width, frame->height, frame->ratio, XINE_IMGFMT_YV12, frame->flags | VO_BOTH_FIELDS);
300
301 _x_post_frame_copy_down(frame, out_frame);
302
303 pthread_mutex_lock (&this->lock);
304
305 process(out_frame->base[0], out_frame->pitches[0],
306 yv12_frame->base[0], yv12_frame->pitches[0],
307 frame->width, frame->height,
308 this->params.brightness, this->params.contrast);
309 xine_fast_memcpy(out_frame->base[1],yv12_frame->base[1],
310 yv12_frame->pitches[1] * frame->height/2);
311 xine_fast_memcpy(out_frame->base[2],yv12_frame->base[2],
312 yv12_frame->pitches[2] * frame->height/2);
313
314 pthread_mutex_unlock (&this->lock);
315
316 skip = out_frame->draw(out_frame, stream);
317
318 _x_post_frame_copy_up(frame, out_frame);
319
320 out_frame->free(out_frame);
321 yv12_frame->free(yv12_frame);
322
323 } else {
324 _x_post_frame_copy_down(frame, frame->next);
325 skip = frame->next->draw(frame->next, stream);
326 _x_post_frame_copy_up(frame, frame->next);
327 }
328
329 return skip;
330 }
331
eq_open_plugin(post_class_t * class_gen,int inputs,xine_audio_port_t ** audio_target,xine_video_port_t ** video_target)332 static post_plugin_t *eq_open_plugin(post_class_t *class_gen, int inputs,
333 xine_audio_port_t **audio_target,
334 xine_video_port_t **video_target)
335 {
336 post_plugin_eq_t *this = calloc(1, sizeof(post_plugin_eq_t));
337 post_in_t *input;
338 post_out_t *output;
339 post_video_port_t *port;
340
341 static const xine_post_api_t post_api = {
342 .set_parameters = set_parameters,
343 .get_parameters = get_parameters,
344 .get_param_descr = get_param_descr,
345 .get_help = get_help,
346 };
347 static const xine_post_in_t params_input = {
348 .name = "parameters",
349 .type = XINE_POST_DATA_PARAMETERS,
350 .data = (void *)&post_api,
351 };
352
353 if (!this || !video_target || !video_target[0]) {
354 free(this);
355 return NULL;
356 }
357
358 (void)class_gen;
359 (void)inputs;
360 (void)audio_target;
361
362 process = process_C;
363 #if defined(ARCH_X86)
364 if( xine_mm_accel() & MM_ACCEL_X86_MMX )
365 process = process_MMX;
366 #endif
367
368 _x_post_init(&this->post, 0, 1);
369
370 this->params.brightness = 0;
371 this->params.contrast = 0;
372
373 pthread_mutex_init (&this->lock, NULL);
374
375 port = _x_post_intercept_video_port(&this->post, video_target[0], &input, &output);
376 port->new_port.get_property = eq_get_property;
377 port->new_port.set_property = eq_set_property;
378 port->intercept_frame = eq_intercept_frame;
379 port->new_frame->draw = eq_draw;
380
381 xine_list_push_back(this->post.input, (void *)¶ms_input);
382
383 input->xine_in.name = "video";
384 output->xine_out.name = "eqd video";
385
386 this->post.xine_post.video_input[0] = &port->new_port;
387
388 this->post.dispose = eq_dispose;
389
390 return &this->post;
391 }
392
eq_init_plugin(xine_t * xine,const void * data)393 void *eq_init_plugin(xine_t *xine, const void *data)
394 {
395 static const post_class_t post_eq_class = {
396 .open_plugin = eq_open_plugin,
397 .identifier = "eq",
398 .description = N_("soft video equalizer"),
399 .dispose = NULL,
400 };
401
402 (void)xine;
403 (void)data;
404
405 return (void *)&post_eq_class;
406 }
407