1 /*
2 * Copyright (C) 2000-2020 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 * video_out_xv.c, X11 video extension interface for xine
21 *
22 * based on mpeg2dec code from
23 * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
24 *
25 * Xv image support by Gerd Knorr <kraxel@goldbach.in-berlin.de>
26 *
27 * xine-specific code by Guenter Bartsch <bartscgr@studbox.uni-stuttgart.de>
28 *
29 * overlay support by James Courtier-Dutton <James@superbug.demon.co.uk> - July 2001
30 * X11 unscaled overlay support by Miguel Freitas - Nov 2003
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <math.h>
42 #include <pthread.h>
43
44 #include <sys/types.h>
45 #if defined(__FreeBSD__)
46 #include <machine/param.h>
47 #endif
48 #include <sys/ipc.h>
49 #include <sys/shm.h>
50 #include <sys/time.h>
51
52 #include <X11/Xlib.h>
53 #include <X11/Xutil.h>
54 #include <X11/extensions/XShm.h>
55 #include <X11/extensions/Xv.h>
56 #include <X11/extensions/Xvlib.h>
57 #include <time.h>
58
59 #define LOG_MODULE "video_out_xv"
60 #define LOG_VERBOSE
61 /*
62 #define LOG
63 */
64
65 #define DEBUG_EMU
66
67 #include "xine.h"
68 #include <xine/video_out.h>
69 #include <xine/xine_internal.h>
70 /* #include "overlay.h" */
71 #include <xine/xineutils.h>
72 #include <xine/vo_scale.h>
73 #include "x11osd.h"
74 #define XV_PROPS
75 #include "xv_common.h"
76
77 #define LOCK_DISPLAY(this) this->lock_display (this->ld_user_data)
78 #define UNLOCK_DISPLAY(this) this->unlock_display (this->ud_user_data);
79
80 typedef struct xv_driver_s xv_driver_t;
81
82 typedef struct {
83 int initial_value;
84 int value;
85 int min;
86 int max;
87 Atom atom;
88
89 int defer;
90
91 const char *name;
92 cfg_entry_t *entry;
93 xv_driver_t *this;
94 } xv_property_t;
95
96 typedef struct {
97 /* public part */
98 vo_frame_t vo_frame;
99 /* change detection */
100 double ratio;
101 int req_width, req_height, format;
102 /* xv image */
103 int width, height, xvformat;
104 XvImage *image;
105 XShmSegmentInfo shminfo;
106 /* yv12 backend for yuy2 emulation */
107 uint8_t *base[3];
108 int pitches[3];
109 } xv_frame_t;
110
111
112 struct xv_driver_s {
113
114 vo_driver_t vo_driver;
115
116 /* X11 / Xv related stuff */
117 Display *display;
118 int screen;
119 Drawable drawable;
120 unsigned int xv_format_yv12;
121 unsigned int xv_format_yuy2;
122 XVisualInfo vinfo;
123 GC gc;
124 XvPortID xv_port;
125 XColor black;
126
127 int use_shm;
128 int use_pitch_alignment;
129 xv_property_t props[XV_NUM_PROPERTIES];
130 uint32_t capabilities;
131
132 int ovl_changed;
133 xv_frame_t *recent_frames[VO_NUM_RECENT_FRAMES];
134 xv_frame_t *cur_frame;
135 x11osd *xoverlay;
136
137 /* all scaling information goes here */
138 vo_scale_t sc;
139
140 int (*x11_old_error_handler) (Display *, XErrorEvent *);
141
142 xine_t *xine;
143
144 alphablend_t alphablend_extra_data;
145
146 void (*lock_display) (void *);
147 void *ld_user_data;
148
149 void (*unlock_display) (void *);
150 void *ud_user_data;
151
152 int emu_yuy2;
153
154 /* color matrix switching */
155 uint8_t cm_lut[32];
156 int cm_active, cm_state;
157 int fullrange_mode;
158 };
159
160 typedef struct {
161 video_driver_class_t driver_class;
162
163 xine_t *xine;
164 } xv_class_t;
165
166 /* import common color matrix stuff */
167 #define CM_LUT
168 #define CM_DRIVER_T xv_driver_t
169 #include "color_matrix.c"
170
171 static int gX11Fail;
172
173 VIDEO_DEVICE_XV_DECL_BICUBIC_TYPES
174 VIDEO_DEVICE_XV_DECL_PREFER_TYPES
175
xv_get_capabilities(vo_driver_t * this_gen)176 static uint32_t xv_get_capabilities (vo_driver_t *this_gen) {
177 xv_driver_t *this = (xv_driver_t *) this_gen;
178
179 return this->capabilities;
180 }
181
xv_frame_field(vo_frame_t * vo_img,int which_field)182 static void xv_frame_field (vo_frame_t *vo_img, int which_field) {
183 /* not needed for Xv */
184 (void)vo_img;
185 (void)which_field;
186 }
187
188 static void xv_rem_yuy2_emu (xv_frame_t *f);
189
xv_frame_dispose(vo_frame_t * vo_img)190 static void xv_frame_dispose (vo_frame_t *vo_img) {
191 xv_frame_t *frame = (xv_frame_t *) vo_img ;
192 xv_driver_t *this = (xv_driver_t *) vo_img->driver;
193
194 xv_rem_yuy2_emu (frame);
195
196 if (frame->image) {
197
198 if (frame->shminfo.shmaddr) {
199 LOCK_DISPLAY(this);
200 XShmDetach (this->display, &frame->shminfo);
201 XFree (frame->image);
202 UNLOCK_DISPLAY(this);
203
204 shmdt (frame->shminfo.shmaddr);
205 shmctl (frame->shminfo.shmid, IPC_RMID, NULL);
206 }
207 else {
208 LOCK_DISPLAY(this);
209 xine_free_aligned (frame->image->data);
210 XFree (frame->image);
211 UNLOCK_DISPLAY(this);
212 }
213 }
214
215 pthread_mutex_destroy (&frame->vo_frame.mutex);
216 free (frame);
217 }
218
xv_alloc_frame(vo_driver_t * this_gen)219 static vo_frame_t *xv_alloc_frame (vo_driver_t *this_gen) {
220 /* xv_driver_t *this = (xv_driver_t *) this_gen; */
221 xv_frame_t *frame ;
222
223 frame = (xv_frame_t *) calloc(1, sizeof(xv_frame_t));
224 if (!frame)
225 return NULL;
226
227 frame->req_width = 0;
228 frame->req_height = 0;
229 frame->format = 0;
230 frame->width = 0;
231 frame->height = 0;
232 frame->xvformat = 0;
233 frame->image = NULL;
234 frame->base[0] = NULL;
235 frame->vo_frame.proc_slice = NULL;
236 frame->vo_frame.proc_frame = NULL;
237
238 pthread_mutex_init (&frame->vo_frame.mutex, NULL);
239
240 /*
241 * supply required functions
242 */
243 frame->vo_frame.field = xv_frame_field;
244 frame->vo_frame.dispose = xv_frame_dispose;
245 frame->vo_frame.driver = this_gen;
246
247 return &frame->vo_frame;
248 }
249
HandleXError(Display * display,XErrorEvent * xevent)250 static int HandleXError (Display *display, XErrorEvent *xevent) {
251 char str [1024];
252
253 XGetErrorText (display, xevent->error_code, str, 1024);
254 printf ("received X error event: %s\n", str);
255 gX11Fail = 1;
256
257 return 0;
258 }
259
260 /* called xlocked */
x11_InstallXErrorHandler(xv_driver_t * this)261 static void x11_InstallXErrorHandler (xv_driver_t *this) {
262 this->x11_old_error_handler = XSetErrorHandler (HandleXError);
263 XSync(this->display, False);
264 }
265
266 /* called xlocked */
x11_DeInstallXErrorHandler(xv_driver_t * this)267 static void x11_DeInstallXErrorHandler (xv_driver_t *this) {
268 XSetErrorHandler (this->x11_old_error_handler);
269 XSync(this->display, False);
270 this->x11_old_error_handler = NULL;
271 }
272
273 /* called xlocked */
create_ximage(xv_driver_t * this,XShmSegmentInfo * shminfo,int width,int height,int format)274 static XvImage *create_ximage (xv_driver_t *this, XShmSegmentInfo *shminfo,
275 int width, int height, int format) {
276 unsigned int xv_format;
277 XvImage *image = NULL;
278
279 if (this->use_pitch_alignment) {
280 lprintf ("use_pitch_alignment old width=%d",width);
281 width = (width + 7) & ~0x7;
282 lprintf ("use_pitch_alignment new width=%d",width);
283 }
284
285 switch (format) {
286 case XINE_IMGFMT_YV12:
287 xv_format = this->xv_format_yv12;
288 break;
289 case XINE_IMGFMT_YUY2:
290 xv_format = this->xv_format_yuy2;
291 break;
292 default:
293 xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unknown format %08x\n",format);
294 return NULL;
295 }
296
297 if (xv_format == 0) {
298 xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unsupported format %08x\n",format);
299 return NULL;
300 }
301
302 if (this->use_shm) {
303
304 /*
305 * try shm
306 */
307
308 gX11Fail = 0;
309 x11_InstallXErrorHandler (this);
310
311 lprintf( "XvShmCreateImage format=0x%x, width=%d, height=%d\n", xv_format, width, height );
312 image = XvShmCreateImage(this->display, this->xv_port, xv_format, 0,
313 width, height, shminfo);
314
315 if (image == NULL ) {
316 xprintf(this->xine, XINE_VERBOSITY_LOG,
317 _("%s: XvShmCreateImage failed\n"), LOG_MODULE);
318 xprintf(this->xine, XINE_VERBOSITY_LOG,
319 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
320 this->use_shm = 0;
321 goto finishShmTesting;
322 }
323
324 {
325 int q;
326
327 lprintf( "XvImage id %d\n", image->id );
328 lprintf( "XvImage width %d\n", image->width );
329 lprintf( "XvImage height %d\n", image->height );
330 lprintf( "XvImage data_size %d\n", image->data_size );
331 lprintf( "XvImage num_planes %d\n", image->num_planes );
332
333 for( q=0; q < image->num_planes; q++)
334 {
335 lprintf( "XvImage pitches[%d] %d\n", q, image->pitches[q] );
336 lprintf( "XvImage offsets[%d] %d\n", q, image->offsets[q] );
337 }
338 }
339
340 shminfo->shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
341
342 if (image->data_size==0) {
343 xprintf(this->xine, XINE_VERBOSITY_LOG,
344 _("%s: XvShmCreateImage returned a zero size\n"), LOG_MODULE);
345 xprintf(this->xine, XINE_VERBOSITY_LOG,
346 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
347 this->use_shm = 0;
348 goto finishShmTesting;
349 }
350
351 if (shminfo->shmid < 0 ) {
352 xprintf(this->xine, XINE_VERBOSITY_LOG,
353 _("%s: shared memory error in shmget: %s\n"), LOG_MODULE, strerror(errno));
354 xprintf(this->xine, XINE_VERBOSITY_LOG,
355 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
356 this->use_shm = 0;
357 goto finishShmTesting;
358 }
359
360 shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
361
362 if (shminfo->shmaddr == NULL) {
363 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
364 LOG_MODULE ": shared memory error (address error NULL)\n");
365 this->use_shm = 0;
366 goto finishShmTesting;
367 }
368
369 if (shminfo->shmaddr == ((char *) -1)) {
370 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
371 LOG_MODULE ": shared memory error (address error)\n");
372 this->use_shm = 0;
373 goto finishShmTesting;
374 }
375
376 shminfo->readOnly = False;
377 image->data = shminfo->shmaddr;
378
379 XShmAttach(this->display, shminfo);
380
381 XSync(this->display, False);
382 shmctl(shminfo->shmid, IPC_RMID, 0);
383
384 if (gX11Fail) {
385 shmdt (shminfo->shmaddr);
386 shmctl (shminfo->shmid, IPC_RMID, 0);
387 shminfo->shmid = -1;
388 xprintf(this->xine, XINE_VERBOSITY_LOG,
389 _("%s: x11 error during shared memory XImage creation\n"), LOG_MODULE);
390 xprintf(this->xine, XINE_VERBOSITY_LOG,
391 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
392 this->use_shm = 0;
393 goto finishShmTesting;
394 }
395
396 /*
397 * Now that the Xserver has learned about and attached to the
398 * shared memory segment, delete it. It's actually deleted by
399 * the kernel when all users of that segment have detached from
400 * it. Gives an automatic shared memory cleanup in case we crash.
401 */
402 shmctl (shminfo->shmid, IPC_RMID, 0);
403 shminfo->shmid = -1;
404
405 finishShmTesting:
406 XSync(this->display, False);
407 x11_DeInstallXErrorHandler(this);
408 }
409
410
411 /*
412 * fall back to plain Xv if necessary
413 */
414
415 if (!this->use_shm) {
416 image = XvCreateImage (this->display, this->xv_port, xv_format, NULL, width, height);
417 if (image) {
418 image->data = xine_malloc_aligned (image->data_size);
419 if (!image->data) {
420 XFree (image);
421 image = NULL;
422 }
423 }
424 shminfo->shmaddr = 0;
425 }
426
427 return image;
428 }
429
430 /* called xlocked */
dispose_ximage(xv_driver_t * this,XShmSegmentInfo * shminfo,XvImage * myimage)431 static void dispose_ximage (xv_driver_t *this,
432 XShmSegmentInfo *shminfo,
433 XvImage *myimage) {
434
435 if (shminfo->shmaddr) {
436
437 XShmDetach (this->display, shminfo);
438 XFree (myimage);
439 shmdt (shminfo->shmaddr);
440 if (shminfo->shmid >= 0) {
441 shmctl (shminfo->shmid, IPC_RMID, 0);
442 shminfo->shmid = -1;
443 }
444
445 }
446 else {
447 xine_free_aligned (myimage->data);
448
449 XFree (myimage);
450 }
451 }
452
xv_slice_yuy2_emu(vo_frame_t * vo_img,uint8_t ** src)453 static void xv_slice_yuy2_emu (vo_frame_t *vo_img, uint8_t **src) {
454 xv_frame_t *frame = (xv_frame_t *)vo_img;
455 int y = (src[0] - frame->vo_frame.base[0]) / frame->vo_frame.pitches[0];
456 int h;
457
458 if ((y < 0) || (y >= frame->height))
459 return;
460
461 if (!vo_img->proc_called)
462 vo_img->proc_called = 1;
463
464 h = frame->height - y;
465 h = h > 16 ? 16 : h;
466 yuy2_to_yv12 (src[0], frame->vo_frame.pitches[0],
467 frame->base[0] + y * frame->pitches[0], frame->pitches[0],
468 frame->base[1] + (y >> 1) * frame->pitches[1], frame->pitches[1],
469 frame->base[2] + (y >> 1) * frame->pitches[2], frame->pitches[2],
470 frame->width, h);
471 }
472
xv_add_yuy2_emu(xv_frame_t * f)473 static int xv_add_yuy2_emu (xv_frame_t *f) {
474 uint8_t *base;
475 int pitch;
476 if (f->base[0])
477 return 0;
478 pitch = f->image->pitches[0] * 2;
479 base = xine_malloc_aligned (pitch * f->image->height);
480 if (!base)
481 return 1;
482 /* save backend */
483 f->base[0] = f->vo_frame.base[0];
484 f->base[1] = f->vo_frame.base[1];
485 f->base[2] = f->vo_frame.base[2];
486 f->pitches[0] = f->vo_frame.pitches[0];
487 f->pitches[1] = f->vo_frame.pitches[1];
488 f->pitches[2] = f->vo_frame.pitches[2];
489 /* new frontend */
490 f->vo_frame.base[0] = base;
491 f->vo_frame.base[1] =
492 f->vo_frame.base[2] = NULL;
493 f->vo_frame.pitches[0] = pitch;
494 f->vo_frame.pitches[1] =
495 f->vo_frame.pitches[2] = 0;
496 f->format = XINE_IMGFMT_YUY2;
497 f->vo_frame.proc_slice = xv_slice_yuy2_emu;
498 {
499 const union {uint8_t bytes[4]; uint32_t word;} black = {{0, 128, 0, 128}};
500 uint32_t *q = (uint32_t *)base;
501 int i;
502 for (i = pitch * f->image->height / 4; i > 0; i--)
503 *q++ = black.word;
504 }
505 return 0;
506 }
507
xv_rem_yuy2_emu(xv_frame_t * f)508 static void xv_rem_yuy2_emu (xv_frame_t *f) {
509 if (!f->base[0])
510 return;
511 xine_free_aligned (f->vo_frame.base[0]);
512 f->vo_frame.base[0] = f->base[0];
513 f->vo_frame.base[1] = f->base[1];
514 f->vo_frame.base[2] = f->base[2];
515 f->vo_frame.pitches[0] = f->pitches[0];
516 f->vo_frame.pitches[1] = f->pitches[1];
517 f->vo_frame.pitches[2] = f->pitches[2];
518 f->base[0] = NULL;
519 f->format = XINE_IMGFMT_YV12;
520 f->vo_frame.proc_slice = NULL;
521 }
522
xv_update_frame_format(vo_driver_t * this_gen,vo_frame_t * frame_gen,uint32_t width,uint32_t height,double ratio,int format,int flags)523 static void xv_update_frame_format (vo_driver_t *this_gen,
524 vo_frame_t *frame_gen,
525 uint32_t width, uint32_t height,
526 double ratio, int format, int flags) {
527 xv_driver_t *this = (xv_driver_t *) this_gen;
528 xv_frame_t *frame = (xv_frame_t *) frame_gen;
529 int resize;
530
531 (void)flags;
532 if (this->use_pitch_alignment) {
533 width = (width + 7) & ~0x7;
534 }
535 resize = (frame->req_width != (int)width) || (frame->req_height != (int)height);
536
537 if (resize || (frame->format != format)) {
538 int fmt = format;
539 if ((fmt == XINE_IMGFMT_YUY2) && (this->emu_yuy2 || !this->xv_format_yuy2))
540 fmt = XINE_IMGFMT_YV12;
541
542 if (resize || (frame->xvformat != fmt)) {
543 /* get emulation out of the way first if any */
544 xv_rem_yuy2_emu (frame);
545 /* (re-) allocate xvimage */
546 LOCK_DISPLAY (this);
547 if (frame->image)
548 dispose_ximage (this, &frame->shminfo, frame->image);
549 frame->image = create_ximage (this, &frame->shminfo, width, height, fmt);
550 UNLOCK_DISPLAY (this);
551 if (!frame->image) {
552 frame->vo_frame.base[0] = NULL;
553 frame->vo_frame.base[1] = NULL;
554 frame->vo_frame.base[2] = NULL;
555 frame->req_width = 0;
556 frame->vo_frame.width = 0;
557 return;
558 }
559 frame->xvformat = fmt;
560 /* get params, blackfill */
561 if (fmt == XINE_IMGFMT_YUY2) {
562 frame->vo_frame.pitches[0] = frame->image->pitches[0];
563 frame->vo_frame.base[0] = frame->image->data + frame->image->offsets[0];
564 {
565 const union {uint8_t bytes[4]; uint32_t word;} black = {{0, 128, 0, 128}};
566 uint32_t *q = (uint32_t *)frame->vo_frame.base[0];
567 int i;
568 for (i = frame->vo_frame.pitches[0] * frame->image->height / 4; i > 0; i--)
569 *q++ = black.word;
570 }
571 } else { /* XINE_IMGFMT_YV12 */
572 frame->vo_frame.pitches[0] = frame->image->pitches[0];
573 frame->vo_frame.pitches[1] = frame->image->pitches[2];
574 frame->vo_frame.pitches[2] = frame->image->pitches[1];
575 frame->vo_frame.base[0] = frame->image->data + frame->image->offsets[0];
576 frame->vo_frame.base[1] = frame->image->data + frame->image->offsets[2];
577 frame->vo_frame.base[2] = frame->image->data + frame->image->offsets[1];
578 memset (frame->vo_frame.base[0], 0, frame->vo_frame.pitches[0] * frame->image->height);
579 memset (frame->vo_frame.base[1], 128, frame->vo_frame.pitches[1] * (frame->image->height >> 1));
580 memset (frame->vo_frame.base[2], 128, frame->vo_frame.pitches[2] * (frame->image->height >> 1));
581 }
582 }
583 /* update emulation */
584 frame->format = format;
585 if (fmt != format) {
586 if (xv_add_yuy2_emu (frame)) {
587 LOCK_DISPLAY (this);
588 dispose_ximage (this, &frame->shminfo, frame->image);
589 UNLOCK_DISPLAY (this);
590 frame->image = NULL;
591 frame->vo_frame.base[0] = NULL;
592 frame->vo_frame.base[1] = NULL;
593 frame->vo_frame.base[2] = NULL;
594 frame->req_width = 0;
595 frame->vo_frame.width = 0;
596 return;
597 }
598 } else
599 xv_rem_yuy2_emu (frame);
600 /* allocated frame size may not match requested size */
601 frame->req_width = width;
602 frame->req_height = height;
603 frame->width = frame->image->width;
604 frame->height = frame->image->height;
605 }
606
607 if (frame->vo_frame.width > frame->width)
608 frame->vo_frame.width = frame->width;
609 if (frame->vo_frame.height > frame->height)
610 frame->vo_frame.height = frame->height;
611
612 frame->ratio = ratio;
613 }
614
xv_clean_output_area(xv_driver_t * this)615 static void xv_clean_output_area (xv_driver_t *this) {
616 int i;
617
618 LOCK_DISPLAY(this);
619
620 XSetForeground (this->display, this->gc, this->black.pixel);
621
622 for( i = 0; i < 4; i++ ) {
623 if( this->sc.border[i].w && this->sc.border[i].h ) {
624 XFillRectangle(this->display, this->drawable, this->gc,
625 this->sc.border[i].x, this->sc.border[i].y,
626 this->sc.border[i].w, this->sc.border[i].h);
627 }
628 }
629
630 if ((this->props[VO_PROP_COLORKEY].atom != None) ||
631 (this->props[VO_PROP_AUTOPAINT_COLORKEY].value == 1)) {
632 XSetForeground (this->display, this->gc, this->props[VO_PROP_COLORKEY].value);
633 XFillRectangle (this->display, this->drawable, this->gc,
634 this->sc.output_xoffset, this->sc.output_yoffset,
635 this->sc.output_width, this->sc.output_height);
636 }
637
638 if (this->xoverlay) {
639 x11osd_resize (this->xoverlay, this->sc.gui_width, this->sc.gui_height);
640 this->ovl_changed = 1;
641 }
642
643 UNLOCK_DISPLAY(this);
644 }
645
646 /*
647 * convert delivered height/width to ideal width/height
648 * taking into account aspect ratio and zoom factor
649 */
650
xv_compute_ideal_size(xv_driver_t * this)651 static void xv_compute_ideal_size (xv_driver_t *this) {
652 _x_vo_scale_compute_ideal_size( &this->sc );
653 }
654
655
656 /*
657 * make ideal width/height "fit" into the gui
658 */
659
xv_compute_output_size(xv_driver_t * this)660 static void xv_compute_output_size (xv_driver_t *this) {
661
662 _x_vo_scale_compute_output_size( &this->sc );
663 }
664
xv_overlay_begin(vo_driver_t * this_gen,vo_frame_t * frame_gen,int changed)665 static void xv_overlay_begin (vo_driver_t *this_gen,
666 vo_frame_t *frame_gen, int changed) {
667 xv_driver_t *this = (xv_driver_t *) this_gen;
668
669 this->ovl_changed += changed;
670
671 if( this->ovl_changed && this->xoverlay ) {
672 LOCK_DISPLAY(this);
673 x11osd_clear(this->xoverlay);
674 UNLOCK_DISPLAY(this);
675 }
676
677 this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x;
678 this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y;
679 }
680
xv_overlay_end(vo_driver_t * this_gen,vo_frame_t * vo_img)681 static void xv_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img) {
682 xv_driver_t *this = (xv_driver_t *) this_gen;
683
684 (void)vo_img;
685 if( this->ovl_changed && this->xoverlay ) {
686 LOCK_DISPLAY(this);
687 x11osd_expose(this->xoverlay);
688 UNLOCK_DISPLAY(this);
689 }
690
691 this->ovl_changed = 0;
692 }
693
xv_overlay_blend(vo_driver_t * this_gen,vo_frame_t * frame_gen,vo_overlay_t * overlay)694 static void xv_overlay_blend (vo_driver_t *this_gen,
695 vo_frame_t *frame_gen, vo_overlay_t *overlay) {
696 xv_driver_t *this = (xv_driver_t *) this_gen;
697 xv_frame_t *frame = (xv_frame_t *) frame_gen;
698
699 if (overlay->rle) {
700 if( overlay->unscaled ) {
701 if( this->ovl_changed && this->xoverlay ) {
702 LOCK_DISPLAY(this);
703 x11osd_blend(this->xoverlay, overlay);
704 UNLOCK_DISPLAY(this);
705 }
706 } else {
707 if (frame->format == XINE_IMGFMT_YV12)
708 _x_blend_yuv(frame->vo_frame.base, overlay,
709 frame->width, frame->height, frame->vo_frame.pitches,
710 &this->alphablend_extra_data);
711 else
712 _x_blend_yuy2(frame->vo_frame.base[0], overlay,
713 frame->width, frame->height, frame->vo_frame.pitches[0],
714 &this->alphablend_extra_data);
715 }
716 }
717 }
718
xv_add_recent_frame(xv_driver_t * this,xv_frame_t * frame)719 static void xv_add_recent_frame (xv_driver_t *this, xv_frame_t *frame) {
720 int i;
721
722 i = VO_NUM_RECENT_FRAMES-1;
723 if( this->recent_frames[i] )
724 this->recent_frames[i]->vo_frame.free
725 (&this->recent_frames[i]->vo_frame);
726
727 for( ; i ; i-- )
728 this->recent_frames[i] = this->recent_frames[i-1];
729
730 this->recent_frames[0] = frame;
731 }
732
xv_flush_recent_frames(xv_driver_t * this)733 static int xv_flush_recent_frames (xv_driver_t *this) {
734 int i, n = 0;
735
736 for (i = 0; i < VO_NUM_RECENT_FRAMES; i++) {
737 if (this->recent_frames[i]) {
738 this->recent_frames[i]->vo_frame.free (&this->recent_frames[i]->vo_frame);
739 this->recent_frames[i] = NULL;
740 n++;
741 }
742 }
743 return n;
744 }
745
xv_redraw_needed(vo_driver_t * this_gen)746 static int xv_redraw_needed (vo_driver_t *this_gen) {
747 xv_driver_t *this = (xv_driver_t *) this_gen;
748 int ret = !this->cm_active;
749
750 if( this->cur_frame ) {
751
752 this->sc.delivered_height = this->cur_frame->height;
753 this->sc.delivered_width = this->cur_frame->width;
754 this->sc.delivered_ratio = this->cur_frame->ratio;
755
756 this->sc.crop_left = this->cur_frame->vo_frame.crop_left;
757 this->sc.crop_right = this->cur_frame->vo_frame.crop_right;
758 this->sc.crop_top = this->cur_frame->vo_frame.crop_top;
759 this->sc.crop_bottom = this->cur_frame->vo_frame.crop_bottom;
760
761 xv_compute_ideal_size(this);
762
763 if( _x_vo_scale_redraw_needed( &this->sc ) ) {
764
765 xv_compute_output_size (this);
766
767 xv_clean_output_area (this);
768
769 ret = 1;
770 }
771 }
772 else
773 ret = 1;
774
775 return ret;
776 }
777
778 /* Used in xv_display_frame to determine how long XvShmPutImage takes
779 - if slower than 60fps, print a message
780 */
timeOfDay()781 static double timeOfDay()
782 {
783 struct timeval t;
784 gettimeofday( &t, NULL );
785 return ((double)t.tv_sec) + (((double)t.tv_usec)/1000000.0);
786 }
787
xv_new_color(xv_driver_t * this,int cm)788 static void xv_new_color (xv_driver_t *this, int cm) {
789 int brig = this->props[VO_PROP_BRIGHTNESS].value;
790 int cont = this->props[VO_PROP_CONTRAST].value;
791 int satu = this->props[VO_PROP_SATURATION].value;
792 int cm2, fr = 0, a, b;
793 Atom atom;
794
795 if (cm & 1) {
796 /* fullrange emulation. Do not report this via get_property (). */
797 if (this->fullrange_mode == 1) {
798 /* modification routine 1 for TV set style bcs controls 0% - 200% */
799 satu -= this->props[VO_PROP_SATURATION].min;
800 satu = (satu * (112 * 255) + (127 * 219 / 2)) / (127 * 219);
801 satu += this->props[VO_PROP_SATURATION].min;
802 if (satu > this->props[VO_PROP_SATURATION].max)
803 satu = this->props[VO_PROP_SATURATION].max;
804 cont -= this->props[VO_PROP_CONTRAST].min;
805 cont = (cont * 219 + 127) / 255;
806 a = cont * (this->props[VO_PROP_BRIGHTNESS].max - this->props[VO_PROP_BRIGHTNESS].min);
807 cont += this->props[VO_PROP_CONTRAST].min;
808 b = 256 * (this->props[VO_PROP_CONTRAST].max - this->props[VO_PROP_CONTRAST].min);
809 brig += (16 * a + b / 2) / b;
810 if (brig > this->props[VO_PROP_BRIGHTNESS].max)
811 brig = this->props[VO_PROP_BRIGHTNESS].max;
812 fr = 1;
813 }
814 /* maybe add more routines for non-standard controls later */
815 }
816 LOCK_DISPLAY (this);
817 atom = this->props[VO_PROP_BRIGHTNESS].atom;
818 if (atom != None)
819 XvSetPortAttribute (this->display, this->xv_port, atom, brig);
820 atom = this->props[VO_PROP_CONTRAST].atom;
821 if (atom != None)
822 XvSetPortAttribute (this->display, this->xv_port, atom, cont);
823 atom = this->props[VO_PROP_SATURATION].atom;
824 if (atom != None)
825 XvSetPortAttribute (this->display, this->xv_port, atom, satu);
826 UNLOCK_DISPLAY(this);
827
828 if (this->props[XV_PROP_ITURBT_709].atom != None) {
829 /* 0 = 601 (SD), 1 = 709 (HD) */
830 /* so far only binary nvidia drivers support this. why not nuveau? */
831 cm2 = (0xc00c >> cm) & 1;
832 LOCK_DISPLAY(this);
833 XvSetPortAttribute (this->display, this->xv_port, this->props[XV_PROP_ITURBT_709].atom, cm2);
834 UNLOCK_DISPLAY(this);
835 this->props[XV_PROP_ITURBT_709].value = cm2;
836 cm2 = cm2 ? 2 : 10;
837 } else if (this->props[XV_PROP_COLORSPACE].atom != None) {
838 /* radeonhd: 0 = size based auto, 1 = 601 (SD), 2 = 709 (HD) */
839 cm2 = ((0xc00c >> cm) & 1) + 1;
840 LOCK_DISPLAY(this);
841 XvSetPortAttribute (this->display, this->xv_port, this->props[XV_PROP_COLORSPACE].atom, cm2);
842 UNLOCK_DISPLAY(this);
843 this->props[XV_PROP_COLORSPACE].value = cm2;
844 cm2 = cm2 == 2 ? 2 : 10;
845 } else {
846 cm2 = 10;
847 }
848
849 cm2 |= fr;
850 xprintf (this->xine, XINE_VERBOSITY_LOG, "video_out_xv: %s b %d c %d s %d [%s]\n",
851 fr ? "modified " : "", brig, cont, satu, cm_names[cm2]);
852
853 this->cm_active = cm;
854 }
855
xv_display_frame(vo_driver_t * this_gen,vo_frame_t * frame_gen)856 static void xv_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) {
857 xv_driver_t *this = (xv_driver_t *) this_gen;
858 xv_frame_t *frame = (xv_frame_t *) frame_gen;
859 int cm;
860 /*
861 printf (LOG_MODULE ": xv_display_frame...\n");
862 */
863
864 cm = cm_from_frame (frame_gen);
865 if (cm != this->cm_active)
866 xv_new_color (this, cm);
867
868 /*
869 * queue frames (deinterlacing)
870 * free old frames
871 */
872
873 xv_add_recent_frame (this, frame); /* deinterlacing */
874
875 this->cur_frame = frame;
876
877 /*
878 * let's see if this frame is different in size / aspect
879 * ratio from the previous one
880 */
881 if ( (frame->width != this->sc.delivered_width)
882 || (frame->height != this->sc.delivered_height)
883 || (frame->ratio != this->sc.delivered_ratio)
884 || (frame->vo_frame.crop_left != this->sc.crop_left)
885 || (frame->vo_frame.crop_right != this->sc.crop_right)
886 || (frame->vo_frame.crop_top != this->sc.crop_top)
887 || (frame->vo_frame.crop_bottom != this->sc.crop_bottom) ) {
888 lprintf("frame format changed\n");
889 this->sc.force_redraw = 1; /* trigger re-calc of output size */
890 }
891
892 /*
893 * tell gui that we are about to display a frame,
894 * ask for offset and output size
895 */
896 xv_redraw_needed (this_gen);
897 {
898 double start_time;
899 double end_time;
900 double elapse_time;
901 int factor;
902
903 LOCK_DISPLAY(this);
904 start_time = timeOfDay();
905 if (this->use_shm) {
906 XvShmPutImage(this->display, this->xv_port,
907 this->drawable, this->gc, this->cur_frame->image,
908 this->sc.displayed_xoffset, this->sc.displayed_yoffset,
909 this->sc.displayed_width, this->sc.displayed_height,
910 this->sc.output_xoffset, this->sc.output_yoffset,
911 this->sc.output_width, this->sc.output_height, True);
912
913 } else {
914 XvPutImage(this->display, this->xv_port,
915 this->drawable, this->gc, this->cur_frame->image,
916 this->sc.displayed_xoffset, this->sc.displayed_yoffset,
917 this->sc.displayed_width, this->sc.displayed_height,
918 this->sc.output_xoffset, this->sc.output_yoffset,
919 this->sc.output_width, this->sc.output_height);
920 }
921
922 XSync(this->display, False);
923 end_time = timeOfDay();
924
925 UNLOCK_DISPLAY(this);
926
927 elapse_time = end_time - start_time;
928 factor = (int)(elapse_time/(1.0/60.0));
929
930 if( factor > 1 )
931 {
932 lprintf( "%s PutImage %dX interval (%fs)\n",
933 LOG_MODULE, factor, elapse_time );
934 }
935 }
936
937 /*
938 printf (LOG_MODULE ": xv_display_frame... done\n");
939 */
940 }
941
xv_get_property(vo_driver_t * this_gen,int property)942 static int xv_get_property (vo_driver_t *this_gen, int property) {
943 xv_driver_t *this = (xv_driver_t *) this_gen;
944
945 if ((property < 0) || (property >= VO_NUM_PROPERTIES)) return (0);
946
947 switch (property) {
948 case VO_PROP_WINDOW_WIDTH:
949 this->props[property].value = this->sc.gui_width;
950 break;
951 case VO_PROP_WINDOW_HEIGHT:
952 this->props[property].value = this->sc.gui_height;
953 break;
954 case VO_PROP_OUTPUT_WIDTH:
955 this->props[property].value = this->sc.output_width;
956 break;
957 case VO_PROP_OUTPUT_HEIGHT:
958 this->props[property].value = this->sc.output_height;
959 break;
960 case VO_PROP_OUTPUT_XOFFSET:
961 this->props[property].value = this->sc.output_xoffset;
962 break;
963 case VO_PROP_OUTPUT_YOFFSET:
964 this->props[property].value = this->sc.output_yoffset;
965 break;
966 }
967
968 lprintf(LOG_MODULE ": property #%d = %d\n", property, this->props[property].value);
969
970 return this->props[property].value;
971 }
972
xv_set_property(vo_driver_t * this_gen,int property,int value)973 static int xv_set_property (vo_driver_t *this_gen,
974 int property, int value) {
975 xv_driver_t *this = (xv_driver_t *) this_gen;
976
977 printf("xv_set_property: property=%d, value=%d\n", property, value );
978
979 if ((property < 0) || (property >= VO_NUM_PROPERTIES)) return 0;
980
981 if (this->props[property].defer == 1) {
982 /* value is out of bound */
983 if((value < this->props[property].min) || (value > this->props[property].max))
984 value = (this->props[property].min + this->props[property].max) >> 1;
985 this->props[property].value = value;
986 this->cm_active = 0;
987 return value;
988 }
989
990 if (this->props[property].atom != None) {
991
992 /* value is out of bound */
993 if((value < this->props[property].min) || (value > this->props[property].max))
994 value = (this->props[property].min + this->props[property].max) >> 1;
995
996 LOCK_DISPLAY(this);
997 XvSetPortAttribute (this->display, this->xv_port,
998 this->props[property].atom, value);
999 XvGetPortAttribute (this->display, this->xv_port,
1000 this->props[property].atom,
1001 &this->props[property].value);
1002 UNLOCK_DISPLAY(this);
1003
1004 if (this->props[property].entry)
1005 this->props[property].entry->num_value = this->props[property].value;
1006
1007 return this->props[property].value;
1008 }
1009 else {
1010 switch (property) {
1011
1012 case VO_PROP_DISCARD_FRAMES:
1013 if (value == -1)
1014 value = xv_flush_recent_frames (this);
1015 break;
1016
1017 case VO_PROP_ASPECT_RATIO:
1018 if (value>=XINE_VO_ASPECT_NUM_RATIOS)
1019 value = XINE_VO_ASPECT_AUTO;
1020
1021 this->props[property].value = value;
1022 xprintf(this->xine, XINE_VERBOSITY_LOG,
1023 LOG_MODULE ": VO_PROP_ASPECT_RATIO(%d)\n", this->props[property].value);
1024 this->sc.user_ratio = value;
1025
1026 xv_compute_ideal_size (this);
1027
1028 this->sc.force_redraw = 1; /* trigger re-calc of output size */
1029 break;
1030
1031 case VO_PROP_ZOOM_X:
1032 if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
1033 this->props[property].value = value;
1034 xprintf(this->xine, XINE_VERBOSITY_LOG,
1035 LOG_MODULE ": VO_PROP_ZOOM_X = %d\n", this->props[property].value);
1036
1037 this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP;
1038
1039 xv_compute_ideal_size (this);
1040
1041 this->sc.force_redraw = 1; /* trigger re-calc of output size */
1042 }
1043 break;
1044
1045 case VO_PROP_ZOOM_Y:
1046 if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
1047 this->props[property].value = value;
1048 xprintf(this->xine, XINE_VERBOSITY_LOG,
1049 LOG_MODULE ": VO_PROP_ZOOM_Y = %d\n", this->props[property].value);
1050
1051 this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP;
1052
1053 xv_compute_ideal_size (this);
1054
1055 this->sc.force_redraw = 1; /* trigger re-calc of output size */
1056 }
1057 break;
1058 }
1059 }
1060
1061 return value;
1062 }
1063
xv_get_property_min_max(vo_driver_t * this_gen,int property,int * min,int * max)1064 static void xv_get_property_min_max (vo_driver_t *this_gen,
1065 int property, int *min, int *max) {
1066 xv_driver_t *this = (xv_driver_t *) this_gen;
1067
1068 if ((property < 0) || (property >= VO_NUM_PROPERTIES)) {
1069 *min = *max = 0;
1070 return;
1071 }
1072
1073 *min = this->props[property].min;
1074 *max = this->props[property].max;
1075 }
1076
xv_gui_data_exchange(vo_driver_t * this_gen,int data_type,void * data)1077 static int xv_gui_data_exchange (vo_driver_t *this_gen,
1078 int data_type, void *data) {
1079 xv_driver_t *this = (xv_driver_t *) this_gen;
1080
1081 switch (data_type) {
1082 #ifndef XINE_DISABLE_DEPRECATED_FEATURES
1083 case XINE_GUI_SEND_COMPLETION_EVENT:
1084 break;
1085 #endif
1086
1087 case XINE_GUI_SEND_EXPOSE_EVENT: {
1088 /* XExposeEvent * xev = (XExposeEvent *) data; */
1089
1090 if (this->cur_frame) {
1091 int i;
1092
1093 LOCK_DISPLAY(this);
1094
1095 if (this->use_shm) {
1096 XvShmPutImage(this->display, this->xv_port,
1097 this->drawable, this->gc, this->cur_frame->image,
1098 this->sc.displayed_xoffset, this->sc.displayed_yoffset,
1099 this->sc.displayed_width, this->sc.displayed_height,
1100 this->sc.output_xoffset, this->sc.output_yoffset,
1101 this->sc.output_width, this->sc.output_height, True);
1102 } else {
1103 XvPutImage(this->display, this->xv_port,
1104 this->drawable, this->gc, this->cur_frame->image,
1105 this->sc.displayed_xoffset, this->sc.displayed_yoffset,
1106 this->sc.displayed_width, this->sc.displayed_height,
1107 this->sc.output_xoffset, this->sc.output_yoffset,
1108 this->sc.output_width, this->sc.output_height);
1109 }
1110
1111 XSetForeground (this->display, this->gc, this->black.pixel);
1112
1113 for( i = 0; i < 4; i++ ) {
1114 if( this->sc.border[i].w && this->sc.border[i].h ) {
1115 XFillRectangle(this->display, this->drawable, this->gc,
1116 this->sc.border[i].x, this->sc.border[i].y,
1117 this->sc.border[i].w, this->sc.border[i].h);
1118 }
1119 }
1120
1121 if(this->xoverlay)
1122 x11osd_expose(this->xoverlay);
1123
1124 XSync(this->display, False);
1125 UNLOCK_DISPLAY(this);
1126 }
1127 }
1128 break;
1129
1130 case XINE_GUI_SEND_DRAWABLE_CHANGED:
1131 LOCK_DISPLAY(this);
1132 this->drawable = (Drawable) data;
1133 XFreeGC(this->display, this->gc);
1134 this->gc = XCreateGC (this->display, this->drawable, 0, NULL);
1135 if(this->xoverlay)
1136 x11osd_drawable_changed(this->xoverlay, this->drawable);
1137 this->ovl_changed = 1;
1138 UNLOCK_DISPLAY(this);
1139 this->sc.force_redraw = 1;
1140 break;
1141
1142 case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO:
1143 {
1144 int x1, y1, x2, y2;
1145 x11_rectangle_t *rect = data;
1146
1147 _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y,
1148 &x1, &y1);
1149 _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h,
1150 &x2, &y2);
1151 rect->x = x1;
1152 rect->y = y1;
1153 rect->w = x2-x1;
1154 rect->h = y2-y1;
1155 }
1156 break;
1157
1158 default:
1159 return -1;
1160 }
1161
1162 return 0;
1163 }
1164
xv_restore_port_attributes(xv_driver_t * this)1165 static void xv_restore_port_attributes(xv_driver_t *this) {
1166 int i;
1167
1168 for (i = 0; i < XV_NUM_PROPERTIES; i++) {
1169 xv_property_t *prop = &this->props[i];
1170 if (prop->atom == None)
1171 continue;
1172 if (prop->defer || (prop->value != prop->initial_value)) {
1173 LOCK_DISPLAY (this);
1174 XvSetPortAttribute (this->display, this->xv_port, prop->atom, prop->initial_value);
1175 UNLOCK_DISPLAY(this);
1176 }
1177 }
1178
1179 LOCK_DISPLAY(this);
1180 XSync(this->display, False);
1181 UNLOCK_DISPLAY(this);
1182 }
1183
xv_dispose(vo_driver_t * this_gen)1184 static void xv_dispose (vo_driver_t *this_gen) {
1185 xv_driver_t *this = (xv_driver_t *) this_gen;
1186 int i;
1187
1188 /* restore port attributes to their initial values */
1189 xv_restore_port_attributes (this);
1190
1191 LOCK_DISPLAY(this);
1192 if (this->xv_port) {
1193 if (XvUngrabPort (this->display, this->xv_port, CurrentTime) != Success) {
1194 xprintf (this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": xv_exit: XvUngrabPort() failed.\n");
1195 }
1196 }
1197 if (this->gc) {
1198 XFreeGC(this->display, this->gc);
1199 }
1200 UNLOCK_DISPLAY(this);
1201
1202 /* should do nothing as video_out has sent VO_PROP_DISCARD_FRAMES = -1 before */
1203 for( i=0; i < VO_NUM_RECENT_FRAMES; i++ ) {
1204 if( this->recent_frames[i] )
1205 this->recent_frames[i]->vo_frame.dispose
1206 (&this->recent_frames[i]->vo_frame);
1207 this->recent_frames[i] = NULL;
1208 }
1209
1210 if( this->xoverlay ) {
1211 LOCK_DISPLAY(this);
1212 x11osd_destroy (this->xoverlay);
1213 UNLOCK_DISPLAY(this);
1214 }
1215
1216 _x_alphablend_free(&this->alphablend_extra_data);
1217 _x_vo_scale_cleanup (&this->sc, this->xine->config);
1218
1219 cm_close (this);
1220
1221 /* cm_close already does this.
1222 this->xine->config->unregister_callbacks (this->xine->config, NULL, NULL, this, sizeof (*this));
1223 */
1224 free (this);
1225 }
1226
1227 /* called xlocked */
xv_prop_init(xv_driver_t * this,const xv_prop_list_t * l,const XvAttribute attr)1228 static void xv_prop_init (xv_driver_t *this, const xv_prop_list_t *l, const XvAttribute attr) {
1229 xv_property_t *prop = &this->props[l->index];
1230
1231 Atom atom = XInternAtom (this->display, l->name, False);
1232 if (atom == None)
1233 return;
1234 prop->atom = atom;
1235
1236 prop->name = l->name;
1237 this->capabilities |= l->caps;
1238
1239 /*
1240 * some Xv drivers (Gatos ATI) report some ~0 as max values, this is confusing.
1241 */
1242 prop->min = attr.min_value;
1243 prop->max = attr.max_value;
1244 if ((prop->min >= 0) && (prop->max < 0))
1245 prop->max = 2147483615;
1246
1247 XvGetPortAttribute (this->display, this->xv_port, atom, &prop->initial_value);
1248 prop->value = prop->initial_value;
1249
1250 xprintf (this->xine, XINE_VERBOSITY_DEBUG,
1251 LOG_MODULE ": port attribute %s (%d) value is %d\n", l->name, l->index, prop->value);
1252 }
1253
xv_prop_update_int(xv_property_t * prop,int value)1254 static void xv_prop_update_int (xv_property_t *prop, int value) {
1255 xv_driver_t *this = prop->this;
1256
1257 LOCK_DISPLAY (this);
1258 XvSetPortAttribute (this->display, this->xv_port, prop->atom, value);
1259 UNLOCK_DISPLAY (this);
1260 prop->value = value;
1261
1262 xprintf (this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": %s = %d\n", prop->name, value);
1263 }
1264
xv_prop_update(void * prop_gen,xine_cfg_entry_t * entry)1265 static void xv_prop_update (void *prop_gen, xine_cfg_entry_t *entry) {
1266 xv_prop_update_int ((xv_property_t *)prop_gen, entry->num_value);
1267 }
1268
xv_prop_conf(xv_driver_t * this,int property,const char * config_name,const char * config_desc,const char * config_help)1269 static void xv_prop_conf (xv_driver_t *this, int property,
1270 const char *config_name, const char *config_desc, const char *config_help) {
1271 config_values_t *config = this->xine->config;
1272 xv_property_t *prop = &this->props[property];
1273 cfg_entry_t *entry;
1274
1275 /* is this a boolean property ? */
1276 if ((prop->min == 0) && (prop->max == 1))
1277 config->register_bool (config, config_name, prop->value,
1278 config_desc, config_help, 20, xv_prop_update, prop);
1279 else
1280 config->register_range (config, config_name, prop->value,
1281 prop->min, prop->max, config_desc, config_help, 20, xv_prop_update, prop);
1282
1283 entry = config->lookup_entry (config, config_name);
1284
1285 if ((entry->num_value < prop->min) || (entry->num_value > prop->max))
1286 xv_prop_update_int (prop, (prop->min + prop->max) >> 1);
1287
1288 prop->entry = entry;
1289
1290 xv_set_property (&this->vo_driver, property, entry->num_value);
1291 }
1292
xv_update_xv_pitch_alignment(void * this_gen,xine_cfg_entry_t * entry)1293 static void xv_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry) {
1294 xv_driver_t *this = (xv_driver_t *) this_gen;
1295
1296 this->use_pitch_alignment = entry->num_value;
1297 }
1298
xv_fullrange_cb_config(void * this_gen,xine_cfg_entry_t * entry)1299 static void xv_fullrange_cb_config (void *this_gen, xine_cfg_entry_t *entry) {
1300 xv_driver_t *this = (xv_driver_t *)this_gen;
1301 this->fullrange_mode = entry->num_value;
1302 if (this->fullrange_mode)
1303 this->capabilities |= VO_CAP_FULLRANGE;
1304 else
1305 this->capabilities &= ~VO_CAP_FULLRANGE;
1306 this->cm_active = 0;
1307 }
1308
1309 #ifdef DEBUG_EMU
xv_debug_emu_cb_config(void * this_gen,xine_cfg_entry_t * entry)1310 static void xv_debug_emu_cb_config (void *this_gen, xine_cfg_entry_t *entry) {
1311 xv_driver_t *this = (xv_driver_t *)this_gen;
1312 this->emu_yuy2 = entry->num_value;
1313 }
1314 #endif
1315
xv_open_port(xv_driver_t * this,XvPortID port)1316 static int xv_open_port (xv_driver_t *this, XvPortID port) {
1317 {
1318 int i, formats;
1319 XvImageFormatValues *fo;
1320
1321 LOCK_DISPLAY (this);
1322 fo = XvListImageFormats (this->display, port, (int*)&formats);
1323 UNLOCK_DISPLAY (this);
1324 if (!fo)
1325 return 0;
1326
1327 this->xv_format_yv12 = 0;
1328 this->xv_format_yuy2 = 0;
1329
1330 for (i = 0; i < formats; i++) {
1331 lprintf ("Xv image format: 0x%x (%4.4s) %s\n", fo[i].id, (char*)&fo[i].id,
1332 (fo[i].format == XvPacked) ? "packed" : "planar");
1333 switch (fo[i].id) {
1334 case XINE_IMGFMT_YV12:
1335 this->xv_format_yv12 = fo[i].id;
1336 this->capabilities |= VO_CAP_YV12;
1337 xprintf (this->xine, XINE_VERBOSITY_LOG,
1338 _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YV12");
1339 break;
1340 case XINE_IMGFMT_YUY2:
1341 this->xv_format_yuy2 = fo[i].id;
1342 this->capabilities |= VO_CAP_YUY2;
1343 xprintf (this->xine, XINE_VERBOSITY_LOG,
1344 _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YUY2");
1345 break;
1346 default: ;
1347 }
1348 }
1349
1350 LOCK_DISPLAY (this);
1351 XFree (fo);
1352 UNLOCK_DISPLAY (this);
1353 }
1354
1355 /* No yv12: bail out. */
1356 if (!this->xv_format_yv12) {
1357 xprintf (this->xine, XINE_VERBOSITY_LOG,
1358 LOG_MODULE ": this adaptor does not support YV12 format.\n");
1359 return 0;
1360 }
1361 /* No yuy2: just report. Who can deliver yv12 with little effort shall do that.
1362 * Otherwise, accept anyway and emulate. */
1363
1364 {
1365 int ret;
1366 x11_InstallXErrorHandler (this);
1367 ret = XvGrabPort(this->display, port, 0) == Success;
1368 x11_DeInstallXErrorHandler (this);
1369 return ret;
1370 }
1371 }
1372
1373 static unsigned int
xv_find_adaptor_by_port(int port,unsigned int adaptors,XvAdaptorInfo * adaptor_info)1374 xv_find_adaptor_by_port (int port, unsigned int adaptors,
1375 XvAdaptorInfo *adaptor_info)
1376 {
1377 unsigned int an;
1378 for (an = 0; an < adaptors; an++)
1379 if (adaptor_info[an].type & XvImageMask)
1380 if (port >= (int)adaptor_info[an].base_id &&
1381 port < (int)(adaptor_info[an].base_id + adaptor_info[an].num_ports))
1382 return an;
1383 return 0; /* shouldn't happen */
1384 }
1385
xv_autodetect_port(xv_driver_t * this,unsigned int adaptors,XvAdaptorInfo * adaptor_info,unsigned int * adaptor_num,XvPortID base,xv_prefertype prefer_type)1386 static XvPortID xv_autodetect_port(xv_driver_t *this,
1387 unsigned int adaptors,
1388 XvAdaptorInfo *adaptor_info,
1389 unsigned int *adaptor_num,
1390 XvPortID base,
1391 xv_prefertype prefer_type)
1392 {
1393 unsigned int an, j;
1394
1395 for (an = 0; an < adaptors; an++)
1396 if (adaptor_info[an].type & XvImageMask &&
1397 (prefer_type == xv_prefer_none ||
1398 strcasestr (adaptor_info[an].name, prefer_substrings[prefer_type])))
1399 for (j = 0; j < adaptor_info[an].num_ports; j++) {
1400 XvPortID port = adaptor_info[an].base_id + j;
1401 if (port >= base && xv_open_port(this, port)) {
1402 *adaptor_num = an;
1403 return port;
1404 }
1405 }
1406
1407 return 0;
1408 }
1409
xv_default_lock_display(void * user_data)1410 static void xv_default_lock_display (void *user_data) {
1411 xv_driver_t *this = user_data;
1412 XLockDisplay (this->display);
1413 }
1414
xv_default_unlock_display(void * user_data)1415 static void xv_default_unlock_display (void *user_data) {
1416 xv_driver_t *this = user_data;
1417 XUnlockDisplay (this->display);
1418 }
1419
1420 /* expects XINE_VISUAL_TYPE_X11_2 with configurable locking */
open_plugin_2(video_driver_class_t * class_gen,const void * visual_gen)1421 static vo_driver_t *open_plugin_2 (video_driver_class_t *class_gen, const void *visual_gen) {
1422 xv_class_t *class = (xv_class_t *) class_gen;
1423 config_values_t *config = class->xine->config;
1424 xv_driver_t *this;
1425 int i;
1426 const x11_visual_t *visual = (const x11_visual_t *) visual_gen;
1427 XvPortID xv_port;
1428 char *adaptor_name;
1429
1430 this = (xv_driver_t *) calloc(1, sizeof(xv_driver_t));
1431 if (!this)
1432 return NULL;
1433
1434 #ifndef HAVE_ZERO_SAFE_MEM
1435 /* 0/NULL inits, for optimizing away. */
1436 this->x11_old_error_handler = NULL;
1437 this->xoverlay = NULL;
1438 this->ovl_changed = 0;
1439 this->xv_format_yv12 = 0;
1440 this->xv_format_yuy2 = 0;
1441 this->emu_yuy2 = 0;
1442 this->fullrange_mode = 0;
1443 for (i = 0; i < XV_NUM_PROPERTIES; i++) {
1444 this->props[i].initial_value = 0;
1445 this->props[i].value = 0;
1446 this->props[i].min = 0;
1447 this->props[i].max = 0;
1448 this->props[i].defer = 0;
1449 this->props[i].name = NULL;
1450 this->props[i].entry = NULL;
1451 }
1452 #endif
1453
1454 this->use_shm = 1;
1455 this->xine = class->xine;
1456 this->display = visual->display;
1457 this->screen = visual->screen;
1458 this->capabilities = VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y;
1459
1460 /* configurable X11 locking */
1461 if (visual->lock_display) {
1462 this->lock_display = visual->lock_display;
1463 this->ld_user_data = visual->user_data;
1464 } else {
1465 this->lock_display = xv_default_lock_display;
1466 this->ld_user_data = this;
1467 }
1468 if (visual->unlock_display) {
1469 this->unlock_display = visual->unlock_display;
1470 this->ud_user_data = visual->user_data;
1471 } else {
1472 this->unlock_display = xv_default_unlock_display;
1473 this->ud_user_data = this;
1474 }
1475
1476 LOCK_DISPLAY(this);
1477
1478 /*
1479 * check for Xvideo support
1480 */
1481 {
1482 unsigned int ver, rel, req, ev, err;
1483 if (Success != XvQueryExtension (this->display, &ver, &rel, &req, &ev, &err)) {
1484 UNLOCK_DISPLAY (this);
1485 xprintf (class->xine, XINE_VERBOSITY_LOG, _("%s: Xv extension not present.\n"), LOG_MODULE);
1486 free (this);
1487 return NULL;
1488 }
1489 }
1490
1491 /*
1492 * check adaptors, search for one that supports (at least) yuv12
1493 */
1494 {
1495 unsigned int adaptor_num;
1496 xv_prefertype prefer_type;
1497 unsigned int adaptors;
1498 XvAdaptorInfo *adaptor_info;
1499
1500 if (Success != XvQueryAdaptors (this->display, DefaultRootWindow (this->display), &adaptors, &adaptor_info)) {
1501 xprintf (class->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": XvQueryAdaptors failed.\n");
1502 UNLOCK_DISPLAY (this);
1503 free (this);
1504 return NULL;
1505 }
1506
1507 xv_port = config->register_num (config, "video.device.xv_port", 0,
1508 VIDEO_DEVICE_XV_PORT_HELP, 20, NULL, NULL);
1509 prefer_type = config->register_enum (config, "video.device.xv_preferred_method", 0,
1510 (char **)prefer_labels, VIDEO_DEVICE_XV_PREFER_TYPE_HELP, 10, NULL, NULL);
1511
1512 if (xv_port != 0) {
1513 if (!xv_open_port (this, xv_port)) {
1514 xprintf (class->xine, XINE_VERBOSITY_NONE,
1515 _("%s: could not open Xv port %lu - autodetecting\n"), LOG_MODULE, (unsigned long)xv_port);
1516 xv_port = xv_autodetect_port (this, adaptors, adaptor_info, &adaptor_num, xv_port, prefer_type);
1517 } else
1518 adaptor_num = xv_find_adaptor_by_port (xv_port, adaptors, adaptor_info);
1519 }
1520
1521 if (!xv_port)
1522 xv_port = xv_autodetect_port (this, adaptors, adaptor_info, &adaptor_num, 0, prefer_type);
1523
1524 if (!xv_port) {
1525 if (prefer_type)
1526 xprintf (class->xine, XINE_VERBOSITY_NONE,
1527 _("%s: no available ports of type \"%s\", defaulting...\n"), LOG_MODULE, prefer_labels[prefer_type]);
1528 xv_port = xv_autodetect_port (this, adaptors, adaptor_info, &adaptor_num, 0, xv_prefer_none);
1529 }
1530
1531 if (!xv_port) {
1532 xprintf (class->xine, XINE_VERBOSITY_LOG,
1533 _("%s: Xv extension is present but I couldn't find a usable yuv12 port.\n"
1534 "\tLooks like your graphics hardware driver doesn't support Xv?!\n"), LOG_MODULE);
1535 /* XvFreeAdaptorInfo (adaptor_info); this crashed on me (gb)*/
1536 XvFreeAdaptorInfo (adaptor_info);
1537 UNLOCK_DISPLAY (this);
1538 free (this);
1539 return NULL;
1540 }
1541 adaptor_name = strdup (adaptor_info[adaptor_num].name ? adaptor_info[adaptor_num].name : "");
1542 XvFreeAdaptorInfo (adaptor_info);
1543 }
1544
1545 xprintf (class->xine, XINE_VERBOSITY_LOG,
1546 _("%s: using Xv port %ld from adaptor %s for hardware "
1547 "colour space conversion and scaling.\n"), LOG_MODULE, xv_port, adaptor_name);
1548 UNLOCK_DISPLAY (this);
1549
1550 _x_alphablend_init(&this->alphablend_extra_data, class->xine);
1551
1552 this->xv_port = xv_port;
1553
1554 _x_vo_scale_init (&this->sc, 1, 0, config );
1555 this->sc.frame_output_cb = visual->frame_output_cb;
1556 this->sc.user_data = visual->user_data;
1557
1558 this->drawable = visual->d;
1559 LOCK_DISPLAY(this);
1560 this->gc = XCreateGC (this->display, this->drawable, 0, NULL);
1561 UNLOCK_DISPLAY(this);
1562
1563 LOCK_DISPLAY(this);
1564 {
1565 XColor dummy;
1566 XAllocNamedColor (this->display, DefaultColormap (this->display, this->screen),
1567 "black", &this->black, &dummy);
1568 }
1569 UNLOCK_DISPLAY(this);
1570
1571 this->vo_driver.get_capabilities = xv_get_capabilities;
1572 this->vo_driver.alloc_frame = xv_alloc_frame;
1573 this->vo_driver.update_frame_format = xv_update_frame_format;
1574 this->vo_driver.overlay_begin = xv_overlay_begin;
1575 this->vo_driver.overlay_blend = xv_overlay_blend;
1576 this->vo_driver.overlay_end = xv_overlay_end;
1577 this->vo_driver.display_frame = xv_display_frame;
1578 this->vo_driver.get_property = xv_get_property;
1579 this->vo_driver.set_property = xv_set_property;
1580 this->vo_driver.get_property_min_max = xv_get_property_min_max;
1581 this->vo_driver.gui_data_exchange = xv_gui_data_exchange;
1582 this->vo_driver.dispose = xv_dispose;
1583 this->vo_driver.redraw_needed = xv_redraw_needed;
1584
1585 /*
1586 * init properties
1587 */
1588
1589 for (i = 0; i < XV_NUM_PROPERTIES; i++) {
1590 this->props[i].atom = None;
1591 this->props[i].this = this;
1592 }
1593
1594 this->sc.user_ratio =
1595 this->props[VO_PROP_ASPECT_RATIO].value = XINE_VO_ASPECT_AUTO;
1596 this->props[VO_PROP_ZOOM_X].value = 100;
1597 this->props[VO_PROP_ZOOM_Y].value = 100;
1598
1599 cm_init (this);
1600
1601 /*
1602 * check this adaptor's capabilities
1603 */
1604 {
1605 XvAttribute *attr;
1606 int nattr;
1607
1608 LOCK_DISPLAY (this);
1609 attr = XvQueryPortAttributes (this->display, xv_port, &nattr);
1610 if (attr && nattr) {
1611 int k;
1612
1613 for (k = 0; k < nattr; k++) {
1614 if ((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) {
1615 const xv_prop_list_t *l = xv_find_prop (attr[k].name);
1616 if (!l)
1617 continue;
1618 if ((l->index == VO_PROP_HUE) && !strncmp (adaptor_name, "NV", 2)) {
1619 xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n");
1620 continue;
1621 }
1622 xv_prop_init (this, l, attr[k]);
1623
1624 switch (l->index) {
1625 case XV_PROP_ITURBT_709: /* nvidia */
1626 this->cm_active = this->props[XV_PROP_ITURBT_709].value ? 2 : 10;
1627 break;
1628 case XV_PROP_COLORSPACE: /* radeonhd */
1629 this->cm_active = this->props[XV_PROP_COLORSPACE].value == 2 ? 2
1630 : (this->props[XV_PROP_COLORSPACE].value == 1 ? 10 : 0);
1631 break;
1632 case VO_PROP_COLORKEY:
1633 xv_prop_conf (this, VO_PROP_COLORKEY, "video.device.xv_colorkey", VIDEO_DEVICE_XV_COLORKEY_HELP);
1634 break;
1635 case VO_PROP_AUTOPAINT_COLORKEY:
1636 /* disable autopaint colorkey by default, might be overridden using config entry */
1637 this->props[VO_PROP_AUTOPAINT_COLORKEY].value = 0;
1638 xv_prop_conf (this, VO_PROP_AUTOPAINT_COLORKEY,
1639 "video.device.xv_autopaint_colorkey", VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP);
1640 break;
1641 case XV_PROP_FILTER: {
1642 /* This setting is specific to Permedia 2/3 cards. */
1643 int xv_filter = config->register_range (config, "video.device.xv_filter", 0,
1644 attr[k].min_value, attr[k].max_value, VIDEO_DEVICE_XV_FILTER_HELP,
1645 20, xv_prop_update, &this->props[XV_PROP_FILTER]);
1646 xv_prop_update_int (&this->props[XV_PROP_FILTER], xv_filter);
1647 break;
1648 }
1649 case XV_PROP_DOUBLE_BUFFER: {
1650 int xv_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1,
1651 VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP, 20, xv_prop_update, &this->props[XV_PROP_DOUBLE_BUFFER]);
1652 xv_prop_update_int (&this->props[XV_PROP_DOUBLE_BUFFER], xv_double_buffer);
1653 break;
1654 }
1655 case XV_PROP_SYNC_TO_VBLANK: {
1656 int xv_sync_to_vblank = config->register_bool (config, "video.device.xv_sync_to_vblank", 1,
1657 _("enable vblank sync"),
1658 _("This option will synchronize the update of the video image to the "
1659 "repainting of the entire screen (\"vertical retrace\"). This eliminates "
1660 "flickering and tearing artifacts. On nvidia cards one may also "
1661 "need to run \"nvidia-settings\" and choose which display device to "
1662 "sync to under the XVideo Settings tab"),
1663 20, xv_prop_update, &this->props[XV_PROP_SYNC_TO_VBLANK]);
1664 xv_prop_update_int (&this->props[XV_PROP_SYNC_TO_VBLANK], xv_sync_to_vblank);
1665 break;
1666 }
1667 case XV_PROP_BICUBIC: {
1668 int xv_bicubic = config->register_enum (config, "video.device.xv_bicubic", 2,
1669 (char **)bicubic_types, VIDEO_DEVICE_XV_BICUBIC_HELP, 20, xv_prop_update, &this->props[XV_PROP_BICUBIC]);
1670 xv_prop_update_int (&this->props[XV_PROP_BICUBIC], xv_bicubic);
1671 break;
1672 }
1673 }
1674 }
1675 }
1676 XFree (attr);
1677 } else
1678 xprintf (this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": no port attributes defined.\n");
1679 UNLOCK_DISPLAY (this);
1680 }
1681
1682 free (adaptor_name);
1683
1684 this->props[VO_PROP_BRIGHTNESS].defer = 1;
1685 this->props[VO_PROP_CONTRAST].defer = 1;
1686 this->props[VO_PROP_SATURATION].defer = 1;
1687 if ((this->props[VO_PROP_BRIGHTNESS].atom != None) &&
1688 (this->props[VO_PROP_CONTRAST].atom != None)) {
1689 static const char * const xv_fullrange_conf_labels[] = {"Off", "Normal", NULL};
1690 this->fullrange_mode = config->register_enum (
1691 config,
1692 "video.output.xv_fullrange",
1693 0,
1694 (char **)xv_fullrange_conf_labels,
1695 _("Fullrange colour emulation"),
1696 _("Emulate fullrange colour by modifying brightness/contrast/saturation settings.\n\n"
1697 "Off: Let decoders convert such video.\n"
1698 " Works with all graphics cards, but needs a bit more CPU power.\n\n"
1699 "Normal: Fast and better quality. Should work at least with some newer cards\n"
1700 " (GeForce 7+, 210+).\n\n"),
1701 10,
1702 xv_fullrange_cb_config,
1703 this
1704 );
1705 if (this->fullrange_mode)
1706 this->capabilities |= VO_CAP_FULLRANGE;
1707 }
1708
1709 #ifdef DEBUG_EMU
1710 this->emu_yuy2 = config->register_bool (
1711 config,
1712 "video.output.xv_debug_emu",
1713 0,
1714 _("Force emulating yuy2"),
1715 _("Debug."),
1716 10,
1717 xv_debug_emu_cb_config,
1718 this
1719 );
1720 #endif
1721
1722 /*
1723 * check max. supported image size
1724 */
1725 {
1726 unsigned int nencode = 0;
1727 XvEncodingInfo *encodings = NULL;
1728
1729 LOCK_DISPLAY (this);
1730 XvQueryEncodings (this->display, xv_port, &nencode, &encodings);
1731 if (encodings) {
1732 unsigned int n;
1733 for (n = 0; n < nencode; n++) {
1734 if (!strcmp (encodings[n].name, "XV_IMAGE")) {
1735 xprintf (this->xine, XINE_VERBOSITY_LOG,
1736 LOG_MODULE ": max XvImage size %li x %li\n", encodings[n].width, encodings[n].height);
1737 this->props[VO_PROP_MAX_VIDEO_WIDTH].value = encodings[n].width;
1738 this->props[VO_PROP_MAX_VIDEO_HEIGHT].value = encodings[n].height;
1739 break;
1740 }
1741 }
1742 XvFreeEncodingInfo (encodings);
1743 }
1744 UNLOCK_DISPLAY (this);
1745 }
1746
1747 /*
1748 * try to create a shared image
1749 * to find out if MIT shm really works, using supported format
1750 */
1751 LOCK_DISPLAY(this);
1752 {
1753 XvImage *myimage;
1754 XShmSegmentInfo myshminfo;
1755 myimage = create_ximage (this, &myshminfo, 100, 100,
1756 (this->xv_format_yv12 != 0) ? XINE_IMGFMT_YV12 : XINE_IMGFMT_YUY2);
1757 if (myimage)
1758 dispose_ximage (this, &myshminfo, myimage);
1759 }
1760 UNLOCK_DISPLAY(this);
1761
1762 this->use_pitch_alignment =
1763 config->register_bool (config, "video.device.xv_pitch_alignment", 0,
1764 VIDEO_DEVICE_XV_PITCH_ALIGNMENT_HELP,
1765 10, xv_update_xv_pitch_alignment, this);
1766
1767 LOCK_DISPLAY(this);
1768 if ((this->props[VO_PROP_COLORKEY].atom != None) &&
1769 (this->props[VO_PROP_AUTOPAINT_COLORKEY].value != 1)) {
1770 this->xoverlay = x11osd_create (this->xine, this->display, this->screen,
1771 this->drawable, X11OSD_COLORKEY);
1772 if(this->xoverlay)
1773 x11osd_colorkey (this->xoverlay, this->props[VO_PROP_COLORKEY].value, &this->sc);
1774 } else {
1775 this->xoverlay = x11osd_create (this->xine, this->display, this->screen,
1776 this->drawable, X11OSD_SHAPED);
1777 }
1778 UNLOCK_DISPLAY(this);
1779
1780 if( this->xoverlay )
1781 this->capabilities |= VO_CAP_UNSCALED_OVERLAY;
1782
1783 return &this->vo_driver;
1784 }
1785
open_plugin_old(video_driver_class_t * class_gen,const void * visual_gen)1786 static vo_driver_t *open_plugin_old (video_driver_class_t *class_gen, const void *visual_gen) {
1787 const x11_visual_t *old_visual = (const x11_visual_t *) visual_gen;
1788 x11_visual_t visual;
1789
1790 /* provides compatibility for XINE_VISUAL_TYPE_X11 */
1791 visual.display = old_visual->display;
1792 visual.screen = old_visual->screen;
1793 visual.d = old_visual->d;
1794 visual.user_data = old_visual->user_data;
1795 visual.dest_size_cb = old_visual->dest_size_cb;
1796 visual.frame_output_cb = old_visual->frame_output_cb;
1797 visual.lock_display = NULL;
1798 visual.unlock_display = NULL;
1799
1800 return open_plugin_2(class_gen, (void *)&visual);
1801 }
1802
1803 /*
1804 * class functions
1805 */
init_class(xine_t * xine,const void * visual_gen)1806 static void *init_class (xine_t *xine, const void *visual_gen) {
1807 xv_class_t *this;
1808
1809 (void)visual_gen;
1810
1811 this = calloc(1, sizeof(*this));
1812 if (!this)
1813 return NULL;
1814
1815 this->driver_class.open_plugin = open_plugin_old;
1816 this->driver_class.identifier = "Xv";
1817 this->driver_class.description = N_("xine video output plugin using the MIT X video extension");
1818 this->driver_class.dispose = default_video_driver_class_dispose;
1819
1820 this->xine = xine;
1821
1822 return this;
1823 }
1824
init_class_2(xine_t * xine,const void * visual_gen)1825 static void *init_class_2 (xine_t *xine, const void *visual_gen) {
1826 xv_class_t *this;
1827 this = init_class (xine, visual_gen);
1828 if (this) {
1829 this->driver_class.open_plugin = open_plugin_2;
1830 }
1831 return this;
1832 }
1833
1834 static const vo_info_t vo_info_xv = {
1835 .priority = 9,
1836 .visual_type = XINE_VISUAL_TYPE_X11,
1837 };
1838
1839 /* visual type with configurable X11 locking */
1840 static const vo_info_t vo_info_xv_2 = {
1841 .priority = 9,
1842 .visual_type = XINE_VISUAL_TYPE_X11_2,
1843 };
1844
1845 /*
1846 * exported plugin catalog entry
1847 */
1848
1849 const plugin_info_t xine_plugin_info[] EXPORTED = {
1850 /* type, API, "name", version, special_info, init_function */
1851 { PLUGIN_VIDEO_OUT, 22, "xv", XINE_VERSION_CODE, &vo_info_xv, init_class },
1852 { PLUGIN_VIDEO_OUT, 22, "xv", XINE_VERSION_CODE, &vo_info_xv_2, init_class_2 },
1853 { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
1854 };
1855
1856