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_xshm.c, X11 shared memory extension interface for xine
21 *
22 * based on mpeg2dec code from
23 * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
24 *
25 * xine-specific code by Guenter Bartsch <bartscgr@studbox.uni-stuttgart.de>
26 *
27 * fullrange/HD color and crop support added by Torsten Jager <t.jager@gmx.de>
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <math.h>
38
39 #include <X11/Xlib.h>
40 #include <X11/Xutil.h>
41 #include <X11/Xatom.h>
42 #include <errno.h>
43
44 #include <X11/extensions/XShm.h>
45 #include <sys/ipc.h>
46 #include <sys/shm.h>
47 #include <sys/time.h>
48
49 #include <pthread.h>
50 #include <netinet/in.h>
51
52
53
54 #define LOG_MODULE "video_out_xshm"
55 #define LOG_VERBOSE
56 /*
57 #define LOG
58 */
59
60 #include "xine.h"
61 #include <xine/video_out.h>
62 #include <xine/xine_internal.h>
63 #include "yuv2rgb.h"
64 #include <xine/xineutils.h>
65 #include <xine/vo_scale.h>
66 #include "x11osd.h"
67 #include "xine_mmx.h"
68
69 #define LOCK_DISPLAY(this) {if(this->lock_display) this->lock_display(this->user_data); \
70 else XLockDisplay(this->display);}
71 #define UNLOCK_DISPLAY(this) {if(this->unlock_display) this->unlock_display(this->user_data); \
72 else XUnlockDisplay(this->display);}
73 typedef struct {
74 vo_frame_t vo_frame;
75
76 /* frame properties as delivered by the decoder: */
77 /* obs: for width/height use vo_scale_t struct */
78 int format;
79 int flags;
80
81 vo_scale_t sc;
82
83 XImage *image;
84 XShmSegmentInfo shminfo;
85
86 yuv2rgb_t *yuv2rgb; /* yuv2rgb converter set up for this frame */
87 uint8_t *rgb_dst;
88
89 int state, offs0, offs1; /* crop helpers */
90 uint8_t *crop_start, *crop_flush, *crop_stop;
91 } xshm_frame_t;
92
93 /* frame.state */
94 #define FS_DONE 1
95 #define FS_LATE 2
96 #define FS_FLAGS 4
97
98 typedef struct {
99
100 vo_driver_t vo_driver;
101
102 /* X11 / XShm related stuff */
103 Display *display;
104 int screen;
105 Drawable drawable;
106 Visual *visual;
107 GC gc;
108 int depth, bpp, bytes_per_pixel, image_byte_order;
109 int use_shm;
110 XColor black;
111
112 int brightness;
113 int contrast;
114 int saturation;
115 uint8_t *yuv2rgb_cmap;
116 yuv2rgb_factory_t *yuv2rgb_factory;
117
118 /* color matrix switching */
119 int cm_active, cm_state;
120 uint8_t cm_lut[32];
121
122 vo_scale_t sc;
123
124 xshm_frame_t *cur_frame;
125 x11osd *xoverlay;
126 int ovl_changed;
127
128 int (*x11_old_error_handler) (Display *, XErrorEvent *);
129
130 xine_t *xine;
131
132 alphablend_t alphablend_extra_data;
133
134 void (*lock_display) (void *);
135
136 void (*unlock_display) (void *);
137
138 void *user_data;
139
140 } xshm_driver_t;
141
142 typedef struct {
143 video_driver_class_t driver_class;
144
145 xine_t *xine;
146 } xshm_class_t;
147
148
149 /* import common color matrix stuff */
150 #define CM_LUT
151 #define CM_DRIVER_T xshm_driver_t
152 #include "color_matrix.c"
153
154 static int gX11Fail;
155
156 /*
157 * first, some utility functions
158 */
159
160 /* called xlocked */
HandleXError(Display * display,XErrorEvent * xevent)161 static int HandleXError (Display *display, XErrorEvent *xevent) {
162 char str [1024];
163
164 XGetErrorText (display, xevent->error_code, str, 1024);
165 printf (LOG_MODULE ": received X error event: %s\n", str);
166 gX11Fail = 1;
167
168 return 0;
169 }
170
171 /* called xlocked */
x11_InstallXErrorHandler(xshm_driver_t * this)172 static void x11_InstallXErrorHandler (xshm_driver_t *this) {
173 this->x11_old_error_handler = XSetErrorHandler (HandleXError);
174 XSync(this->display, False);
175 }
176
x11_DeInstallXErrorHandler(xshm_driver_t * this)177 static void x11_DeInstallXErrorHandler (xshm_driver_t *this) {
178 XSetErrorHandler (this->x11_old_error_handler);
179 XSync(this->display, False);
180 this->x11_old_error_handler = NULL;
181 }
182
183 /*
184 * allocate an XImage, try XShm first but fall back to
185 * plain X11 if XShm should fail
186 */
187 /* called xlocked */
create_ximage(xshm_driver_t * this,XShmSegmentInfo * shminfo,int width,int height)188 static XImage *create_ximage (xshm_driver_t *this, XShmSegmentInfo *shminfo,
189 int width, int height) {
190 XImage *myimage = NULL;
191
192 if (this->use_shm) {
193
194 /*
195 * try shm
196 */
197
198 gX11Fail = 0;
199 x11_InstallXErrorHandler (this);
200
201 myimage = XShmCreateImage(this->display,
202 this->visual,
203 this->depth,
204 ZPixmap, NULL,
205 shminfo,
206 width,
207 height);
208
209 if (myimage == NULL ) {
210 xprintf(this->xine, XINE_VERBOSITY_LOG,
211 _("%s: shared memory error when allocating image\n"), LOG_MODULE);
212 xprintf(this->xine, XINE_VERBOSITY_LOG,
213 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
214 this->use_shm = 0;
215 goto finishShmTesting;
216 }
217
218 this->bpp = myimage->bits_per_pixel;
219 this->bytes_per_pixel = this->bpp / 8;
220 this->image_byte_order = myimage->byte_order;
221
222 shminfo->shmid=shmget(IPC_PRIVATE,
223 myimage->bytes_per_line * myimage->height,
224 IPC_CREAT | 0777);
225
226 if (shminfo->shmid < 0 ) {
227 xprintf(this->xine, XINE_VERBOSITY_LOG,
228 _("%s: %s: allocating image\n"), LOG_MODULE, strerror(errno));
229 xprintf(this->xine, XINE_VERBOSITY_LOG,
230 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
231 this->use_shm = 0;
232 goto finishShmTesting;
233 }
234
235 shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
236
237 if (shminfo->shmaddr == ((char *) -1)) {
238 xprintf(this->xine, XINE_VERBOSITY_LOG,
239 _("%s: shared memory error (address error) when allocating image \n"), LOG_MODULE);
240 xprintf(this->xine, XINE_VERBOSITY_LOG,
241 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
242 shmctl (shminfo->shmid, IPC_RMID, 0);
243 shminfo->shmid = -1;
244 this->use_shm = 0;
245 goto finishShmTesting;
246 }
247
248 shminfo->readOnly = False;
249 myimage->data = shminfo->shmaddr;
250
251 XShmAttach(this->display, shminfo);
252
253 XSync(this->display, False);
254
255 if (gX11Fail) {
256 shmdt (shminfo->shmaddr);
257 xprintf(this->xine, XINE_VERBOSITY_LOG,
258 _("%s: x11 error during shared memory XImage creation\n"), LOG_MODULE);
259 xprintf(this->xine, XINE_VERBOSITY_LOG,
260 _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE);
261 shmctl (shminfo->shmid, IPC_RMID, 0);
262 shminfo->shmid = -1;
263 this->use_shm = 0;
264 goto finishShmTesting;
265 }
266
267 /*
268 * Now that the Xserver has learned about and attached to the
269 * shared memory segment, delete it. It's actually deleted by
270 * the kernel when all users of that segment have detached from
271 * it. Gives an automatic shared memory cleanup in case we crash.
272 */
273 shmctl (shminfo->shmid, IPC_RMID, 0);
274 shminfo->shmid = -1;
275
276 finishShmTesting:
277 x11_DeInstallXErrorHandler(this);
278
279 }
280
281 /*
282 * fall back to plain X11 if necessary
283 */
284
285 if (!this->use_shm) {
286
287 myimage = XCreateImage (this->display,
288 this->visual,
289 this->depth,
290 ZPixmap, 0,
291 NULL,
292 width,
293 height,
294 8, 0);
295
296 this->bpp = myimage->bits_per_pixel;
297 this->bytes_per_pixel = this->bpp / 8;
298 this->image_byte_order = myimage->byte_order;
299
300 myimage->data = calloc (width * height, this->bytes_per_pixel);
301 }
302
303 return myimage;
304
305 }
306
307 /* called xlocked */
dispose_ximage(xshm_driver_t * this,XShmSegmentInfo * shminfo,XImage * myimage)308 static void dispose_ximage (xshm_driver_t *this,
309 XShmSegmentInfo *shminfo,
310 XImage *myimage) {
311
312 if (this->use_shm) {
313
314 XShmDetach (this->display, shminfo);
315 XDestroyImage (myimage);
316 shmdt (shminfo->shmaddr);
317 if (shminfo->shmid >= 0) {
318 shmctl (shminfo->shmid, IPC_RMID, 0);
319 shminfo->shmid = -1;
320 }
321
322 }
323 else
324 XDestroyImage (myimage);
325 }
326
327
328 /*
329 * and now, the driver functions
330 */
331
xshm_get_capabilities(vo_driver_t * this_gen)332 static uint32_t xshm_get_capabilities (vo_driver_t *this_gen) {
333 xshm_driver_t *this = (xshm_driver_t *) this_gen;
334 uint32_t capabilities = VO_CAP_CROP | VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_BRIGHTNESS
335 | VO_CAP_CONTRAST | VO_CAP_SATURATION | VO_CAP_COLOR_MATRIX | VO_CAP_FULLRANGE;
336
337 if( this->xoverlay )
338 capabilities |= VO_CAP_UNSCALED_OVERLAY;
339
340 return capabilities;
341 }
342
xshm_compute_ideal_size(xshm_driver_t * this,xshm_frame_t * frame)343 static void xshm_compute_ideal_size (xshm_driver_t *this, xshm_frame_t *frame) {
344 (void)this;
345 _x_vo_scale_compute_ideal_size( &frame->sc );
346 }
347
xshm_compute_rgb_size(xshm_driver_t * this,xshm_frame_t * frame)348 static void xshm_compute_rgb_size (xshm_driver_t *this, xshm_frame_t *frame) {
349 (void)this;
350 _x_vo_scale_compute_output_size( &frame->sc );
351
352 /* avoid problems in yuv2rgb */
353 if (frame->sc.output_height < 1)
354 frame->sc.output_height = 1;
355 if (frame->sc.output_width < 8)
356 frame->sc.output_width = 8;
357 if (frame->sc.output_width & 1) /* yuv2rgb_mlib needs an even YUV2 width */
358 frame->sc.output_width++;
359
360 lprintf("frame source (%d) %d x %d => screen output %d x %d%s\n",
361 frame->vo_frame.id,
362 frame->sc.delivered_width, frame->sc.delivered_height,
363 frame->sc.output_width, frame->sc.output_height,
364 ( frame->sc.delivered_width != frame->sc.output_width
365 || frame->sc.delivered_height != frame->sc.output_height
366 ? ", software scaling"
367 : "" )
368 );
369 }
370
xshm_frame_field(vo_frame_t * vo_img,int which_field)371 static void xshm_frame_field (vo_frame_t *vo_img, int which_field) {
372 xshm_frame_t *frame = (xshm_frame_t *) vo_img ;
373 /* xshm_driver_t *this = (xshm_driver_t *) vo_img->driver; */
374
375 switch (which_field) {
376 case VO_TOP_FIELD:
377 frame->rgb_dst = (uint8_t *)frame->image->data;
378 break;
379 case VO_BOTTOM_FIELD:
380 frame->rgb_dst = (uint8_t *)frame->image->data + frame->image->bytes_per_line ;
381 break;
382 case VO_BOTH_FIELDS:
383 frame->rgb_dst = (uint8_t *)frame->image->data;
384 break;
385 }
386
387 frame->yuv2rgb->next_slice (frame->yuv2rgb, NULL);
388 }
389
xshm_frame_proc_setup(vo_frame_t * vo_img)390 static void xshm_frame_proc_setup (vo_frame_t *vo_img) {
391 xshm_frame_t *frame = (xshm_frame_t *) vo_img ;
392 xshm_driver_t *this = (xshm_driver_t *) vo_img->driver;
393 int changed = 0, i;
394 int width, height, gui_width, gui_height;
395 double gui_pixel_aspect;
396
397 /* Aargh... libmpeg2 decoder calls frame->proc_slice directly, preferredly
398 while still in mmx mode. This will trash our floating point aspect ratio
399 calculations below. Switching back once per frame should not harm
400 performance too much. */
401 #ifdef HAVE_MMX
402 emms ();
403 #endif
404
405 if (!(frame->state & FS_LATE)) {
406 /* adjust cropping to what yuv2rgb can handle */
407 if (vo_img->format == XINE_IMGFMT_YV12) {
408 vo_img->crop_left &= ~7;
409 vo_img->crop_top &= ~1;
410 } else {
411 vo_img->crop_left &= ~3;
412 }
413 /* check for crop changes */
414 if ((vo_img->crop_left != frame->sc.crop_left)
415 || (vo_img->crop_top != frame->sc.crop_top)
416 || (vo_img->crop_right != frame->sc.crop_right)
417 || (vo_img->crop_bottom != frame->sc.crop_bottom)) {
418 frame->sc.crop_left = vo_img->crop_left;
419 frame->sc.crop_top = vo_img->crop_top;
420 frame->sc.crop_right = vo_img->crop_right;
421 frame->sc.crop_bottom = vo_img->crop_bottom;
422 changed = 1;
423 }
424 }
425
426 if (!(frame->state & FS_DONE))
427 changed = 1;
428
429 /* just deal with cropped part */
430 width = frame->sc.delivered_width - frame->sc.crop_left - frame->sc.crop_right;
431 height = frame->sc.delivered_height - frame->sc.crop_top - frame->sc.crop_bottom;
432
433 if (frame->sc.delivered_ratio == 0.0) {
434 frame->sc.delivered_ratio = height ? (double)width / (double)height : 1.0;
435 changed = 1;
436 }
437
438 /* ask gui what output size we'll have for this frame */
439 /* get the gui_pixel_aspect before calling xshm_compute_ideal_size() */
440 /* note: gui_width and gui_height may be bogus because we may have not yet */
441 /* updated video_pixel_aspect (see _x_vo_scale_compute_ideal_size). */
442 frame->sc.dest_size_cb (frame->sc.user_data, width, height,
443 frame->sc.video_pixel_aspect, &gui_width, &gui_height, &gui_pixel_aspect);
444
445 if (changed || (gui_pixel_aspect != frame->sc.gui_pixel_aspect)
446 || (this->sc.user_ratio != frame->sc.user_ratio)) {
447
448 frame->sc.gui_pixel_aspect = gui_pixel_aspect;
449 frame->sc.user_ratio = this->sc.user_ratio;
450
451 xshm_compute_ideal_size (this, frame);
452
453 /* now we have updated video_aspect_pixel we use the callback */
454 /* again to obtain the correct gui_width and gui_height values. */
455 frame->sc.dest_size_cb (frame->sc.user_data, width, height,
456 frame->sc.video_pixel_aspect, &gui_width, &gui_height, &gui_pixel_aspect);
457
458 changed = 1;
459 }
460
461 if (changed || (frame->sc.gui_width != gui_width)
462 || (frame->sc.gui_height != gui_height)) {
463 int w = frame->sc.output_width, h = frame->sc.output_height;
464
465 frame->sc.gui_width = gui_width;
466 frame->sc.gui_height = gui_height;
467
468 xshm_compute_rgb_size (this, frame);
469
470 if (!frame->image || (w != frame->sc.output_width) || (h != frame->sc.output_height)) {
471 /* (re)allocate XImage */
472 LOCK_DISPLAY(this);
473 if (frame->image)
474 dispose_ximage (this, &frame->shminfo, frame->image);
475 frame->image = create_ximage (this, &frame->shminfo,
476 frame->sc.output_width, frame->sc.output_height);
477 UNLOCK_DISPLAY(this);
478 }
479
480 changed = 1;
481 }
482
483 if (changed || !(frame->state & FS_FLAGS)) {
484 /* set up colorspace converter */
485 switch (vo_img->flags & VO_BOTH_FIELDS) {
486 case VO_TOP_FIELD:
487 case VO_BOTTOM_FIELD:
488 frame->yuv2rgb->configure (frame->yuv2rgb, width, height,
489 2 * frame->vo_frame.pitches[0], 2 * frame->vo_frame.pitches[1],
490 frame->sc.output_width, frame->sc.output_height,
491 frame->image->bytes_per_line * 2);
492 break;
493 case VO_BOTH_FIELDS:
494 frame->yuv2rgb->configure (frame->yuv2rgb, width, height,
495 frame->vo_frame.pitches[0], frame->vo_frame.pitches[1],
496 frame->sc.output_width, frame->sc.output_height,
497 frame->image->bytes_per_line);
498 break;
499 }
500 }
501
502 frame->state |= FS_FLAGS | FS_DONE;
503
504 xshm_frame_field (vo_img, vo_img->flags & VO_BOTH_FIELDS);
505
506 /* cache helpers */
507 i = frame->sc.crop_top & 15;
508 if (i)
509 i -= 16;
510 if (vo_img->format == XINE_IMGFMT_YV12) {
511 frame->offs0 = i * vo_img->pitches[0] + frame->sc.crop_left;
512 frame->offs1 = (i * vo_img->pitches[1] + frame->sc.crop_left) / 2;
513 } else {
514 frame->offs0 = i * vo_img->pitches[0] + frame->sc.crop_left * 2;
515 }
516 frame->crop_start = vo_img->base[0] + frame->sc.crop_top * vo_img->pitches[0];
517 frame->crop_flush = frame->crop_stop = vo_img->base[0]
518 + (frame->sc.delivered_height - frame->sc.crop_bottom) * vo_img->pitches[0];
519 if (i + frame->sc.crop_bottom < 0)
520 frame->crop_flush -= 16 * vo_img->pitches[0];
521
522 /* switch color matrix/range */
523 i = cm_from_frame (vo_img);
524 if (i != this->cm_active) {
525 this->cm_active = i;
526 this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory,
527 this->brightness, this->contrast, this->saturation, i);
528 xprintf (this->xine, XINE_VERBOSITY_LOG,
529 "video_out_xshm: b %d c %d s %d [%s]\n",
530 this->brightness, this->contrast, this->saturation, cm_names[i]);
531 }
532 }
533
xshm_frame_proc_slice(vo_frame_t * vo_img,uint8_t ** src)534 static void xshm_frame_proc_slice (vo_frame_t *vo_img, uint8_t **src) {
535 xshm_frame_t *frame = (xshm_frame_t *) vo_img ;
536 uint8_t *src0;
537
538 /* delayed setup */
539 if (!vo_img->proc_called) {
540 xshm_frame_proc_setup (vo_img);
541 vo_img->proc_called = 1;
542 }
543
544 src0 = src[0] + frame->offs0;
545 if ((src0 < frame->crop_start) || (src0 >= frame->crop_stop))
546 return;
547
548 lprintf ("copy... (format %d)\n", frame->format);
549
550 if (frame->format == XINE_IMGFMT_YV12)
551 frame->yuv2rgb->yuv2rgb_fun (frame->yuv2rgb, frame->rgb_dst,
552 src0, src[1] + frame->offs1, src[2] + frame->offs1);
553 else
554 frame->yuv2rgb->yuy22rgb_fun (frame->yuv2rgb, frame->rgb_dst,
555 src0);
556
557 if (src0 >= frame->crop_flush) {
558 if (vo_img->format == XINE_IMGFMT_YV12) {
559 frame->yuv2rgb->yuv2rgb_fun (frame->yuv2rgb, frame->rgb_dst,
560 src0 + 16 * vo_img->pitches[0],
561 src[1] + frame->offs1 + 8 * vo_img->pitches[1],
562 src[2] + frame->offs1 + 8 * vo_img->pitches[2]);
563 } else {
564 frame->yuv2rgb->yuy22rgb_fun (frame->yuv2rgb, frame->rgb_dst,
565 src0 + 16 * vo_img->pitches[0]);
566 }
567 }
568
569 lprintf ("copy...done\n");
570 }
571
xshm_frame_dispose(vo_frame_t * vo_img)572 static void xshm_frame_dispose (vo_frame_t *vo_img) {
573 xshm_frame_t *frame = (xshm_frame_t *) vo_img ;
574 xshm_driver_t *this = (xshm_driver_t *) vo_img->driver;
575
576 if (frame->image) {
577 LOCK_DISPLAY(this);
578 dispose_ximage (this, &frame->shminfo, frame->image);
579 UNLOCK_DISPLAY(this);
580 }
581
582 frame->yuv2rgb->dispose (frame->yuv2rgb);
583
584 xine_free_aligned (frame->vo_frame.base[0]);
585 xine_free_aligned (frame->vo_frame.base[1]);
586 xine_free_aligned (frame->vo_frame.base[2]);
587 pthread_mutex_destroy (&frame->vo_frame.mutex);
588 free (frame);
589 }
590
591
xshm_alloc_frame(vo_driver_t * this_gen)592 static vo_frame_t *xshm_alloc_frame (vo_driver_t *this_gen) {
593 xshm_frame_t *frame;
594 xshm_driver_t *this = (xshm_driver_t *) this_gen;
595
596 frame = (xshm_frame_t *) calloc(1, sizeof(xshm_frame_t));
597 if (!frame)
598 return NULL;
599
600 /*
601 * colorspace converter for this frame
602 */
603
604 frame->yuv2rgb = this->yuv2rgb_factory->create_converter (this->yuv2rgb_factory);
605 if (!frame->yuv2rgb) {
606 free(frame);
607 return NULL;
608 }
609
610 memcpy (&frame->sc, &this->sc, sizeof(vo_scale_t));
611
612 pthread_mutex_init (&frame->vo_frame.mutex, NULL);
613
614 /*
615 * supply required functions/fields
616 */
617
618 frame->vo_frame.proc_slice = xshm_frame_proc_slice;
619 frame->vo_frame.proc_frame = NULL;
620 frame->vo_frame.field = xshm_frame_field;
621 frame->vo_frame.dispose = xshm_frame_dispose;
622 frame->vo_frame.driver = this_gen;
623
624 return (vo_frame_t *) frame;
625 }
626
xshm_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)627 static void xshm_update_frame_format (vo_driver_t *this_gen,
628 vo_frame_t *frame_gen,
629 uint32_t width, uint32_t height,
630 double ratio, int format, int flags) {
631 xshm_frame_t *frame = (xshm_frame_t *) frame_gen;
632 int j, y_pitch, uv_pitch;
633
634 (void)this_gen;
635 flags &= VO_BOTH_FIELDS;
636
637 /* (re)allocate yuv buffers */
638 if (((int)width != frame->sc.delivered_width)
639 || ((int)height != frame->sc.delivered_height)
640 || (format != frame->format)) {
641
642 frame->sc.delivered_width = width;
643 frame->sc.delivered_height = height;
644 frame->format = format;
645
646 xine_freep_aligned (&frame->vo_frame.base[0]);
647 xine_freep_aligned (&frame->vo_frame.base[1]);
648 xine_freep_aligned (&frame->vo_frame.base[2]);
649
650 /* bottom black pad for certain crop_top > crop_bottom cases */
651 if (format == XINE_IMGFMT_YV12) {
652 y_pitch = (width + 7) & ~7;
653 frame->vo_frame.pitches[0] = y_pitch;
654 frame->vo_frame.base[0] = xine_malloc_aligned (y_pitch * (height + 16));
655 uv_pitch = ((width + 15) & ~15) >> 1;
656 frame->vo_frame.pitches[1] = uv_pitch;
657 frame->vo_frame.pitches[2] = uv_pitch;
658 frame->vo_frame.base[1] = xine_malloc_aligned (uv_pitch * ((height + 17) / 2));
659 frame->vo_frame.base[2] = xine_malloc_aligned (uv_pitch * ((height + 17) / 2));
660 if (!frame->vo_frame.base[0] || !frame->vo_frame.base[1] || !frame->vo_frame.base[2]) {
661 xine_freep_aligned (&frame->vo_frame.base[0]);
662 xine_freep_aligned (&frame->vo_frame.base[1]);
663 xine_freep_aligned (&frame->vo_frame.base[2]);
664 frame->sc.delivered_width = 0;
665 frame->vo_frame.width = 0;
666 } else {
667 memset (frame->vo_frame.base[0], 0, y_pitch * (height + 16));
668 memset (frame->vo_frame.base[1], 128, uv_pitch * (height + 16) / 2);
669 memset (frame->vo_frame.base[2], 128, uv_pitch * (height + 16) / 2);
670 }
671 } else {
672 y_pitch = ((width + 3) & ~3) << 1;
673 frame->vo_frame.pitches[0] = y_pitch;
674 frame->vo_frame.base[0] = xine_malloc_aligned (y_pitch * (height + 16));
675 if (frame->vo_frame.base[0]) {
676 const union {uint8_t bytes[4]; uint32_t word;} black = {{0, 128, 0, 128}};
677 uint32_t *q = (uint32_t *)frame->vo_frame.base[0];
678 for (j = y_pitch * (height + 16) / 4; j > 0; j--)
679 *q++ = black.word;
680 } else {
681 frame->sc.delivered_width = 0;
682 frame->vo_frame.width = 0;
683 }
684 }
685
686 /* defer the rest to xshm_frame_proc_setup () */
687 frame->state &= ~(FS_DONE | FS_LATE);
688 }
689
690 if (!isnan (ratio) && (ratio < 1000.0) && (ratio > 0.001)
691 && (ratio != frame->sc.delivered_ratio)) {
692 frame->sc.delivered_ratio = ratio;
693 frame->state &= ~FS_DONE;
694 }
695
696 if (flags != frame->flags) {
697 frame->flags = flags;
698 frame->state &= ~FS_FLAGS;
699 }
700 }
701
xshm_overlay_clut_yuv2rgb(xshm_driver_t * this,vo_overlay_t * overlay,xshm_frame_t * frame)702 static void xshm_overlay_clut_yuv2rgb(xshm_driver_t *this, vo_overlay_t *overlay,
703 xshm_frame_t *frame) {
704 int i;
705 uint32_t *rgb;
706
707 (void)this;
708 if (!overlay->rgb_clut) {
709 rgb = overlay->color;
710 for (i = sizeof (overlay->color) / sizeof (overlay->color[0]); i > 0; i--) {
711 clut_t *yuv = (clut_t *)rgb;
712 *rgb++ = frame->yuv2rgb->yuv2rgb_single_pixel_fun (frame->yuv2rgb, yuv->y, yuv->cb, yuv->cr);
713 }
714 overlay->rgb_clut++;
715 }
716
717 if (!overlay->hili_rgb_clut) {
718 rgb = overlay->hili_color;
719 for (i = sizeof (overlay->color) / sizeof (overlay->color[0]); i > 0; i--) {
720 clut_t *yuv = (clut_t *)rgb;
721 *rgb++ = frame->yuv2rgb->yuv2rgb_single_pixel_fun (frame->yuv2rgb, yuv->y, yuv->cb, yuv->cr);
722 }
723 overlay->hili_rgb_clut++;
724 }
725 }
726
xshm_overlay_begin(vo_driver_t * this_gen,vo_frame_t * frame_gen,int changed)727 static void xshm_overlay_begin (vo_driver_t *this_gen,
728 vo_frame_t *frame_gen, int changed) {
729 xshm_driver_t *this = (xshm_driver_t *) this_gen;
730
731 this->ovl_changed += changed;
732
733 if( this->ovl_changed && this->xoverlay ) {
734 LOCK_DISPLAY(this);
735 x11osd_clear(this->xoverlay);
736 UNLOCK_DISPLAY(this);
737 }
738
739 this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x;
740 this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y;
741 }
742
xshm_overlay_end(vo_driver_t * this_gen,vo_frame_t * vo_img)743 static void xshm_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img) {
744 xshm_driver_t *this = (xshm_driver_t *) this_gen;
745
746 (void)vo_img;
747 if( this->ovl_changed && this->xoverlay ) {
748 LOCK_DISPLAY(this);
749 x11osd_expose(this->xoverlay);
750 UNLOCK_DISPLAY(this);
751 }
752
753 this->ovl_changed = 0;
754 }
755
xshm_overlay_blend(vo_driver_t * this_gen,vo_frame_t * frame_gen,vo_overlay_t * overlay)756 static void xshm_overlay_blend (vo_driver_t *this_gen,
757 vo_frame_t *frame_gen, vo_overlay_t *overlay) {
758 xshm_driver_t *this = (xshm_driver_t *) this_gen;
759 xshm_frame_t *frame = (xshm_frame_t *) frame_gen;
760 int width = frame->sc.delivered_width - frame->sc.crop_left - frame->sc.crop_right;
761 int height = frame->sc.delivered_height - frame->sc.crop_top - frame->sc.crop_bottom;
762
763 /* Alpha Blend here */
764 if (overlay->rle) {
765 if( overlay->unscaled ) {
766 if( this->ovl_changed && this->xoverlay ) {
767 LOCK_DISPLAY(this);
768 x11osd_blend(this->xoverlay, overlay);
769 UNLOCK_DISPLAY(this);
770 }
771 } else {
772 if (!overlay->rgb_clut || !overlay->hili_rgb_clut)
773 xshm_overlay_clut_yuv2rgb (this, overlay, frame);
774
775 switch (this->bpp) {
776 case 16:
777 _x_blend_rgb16 ((uint8_t *)frame->image->data, overlay,
778 frame->sc.output_width, frame->sc.output_height,
779 width, height,
780 &this->alphablend_extra_data);
781 break;
782 case 24:
783 _x_blend_rgb24 ((uint8_t *)frame->image->data, overlay,
784 frame->sc.output_width, frame->sc.output_height,
785 width, height,
786 &this->alphablend_extra_data);
787 break;
788 case 32:
789 _x_blend_rgb32 ((uint8_t *)frame->image->data, overlay,
790 frame->sc.output_width, frame->sc.output_height,
791 width, height,
792 &this->alphablend_extra_data);
793 break;
794 default:
795 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
796 "xine-lib:video_out_xshm:xshm_overlay_blend: Cannot blend bpp:%i\n", this->bpp);
797 /* it should never get here, unless a user tries to play in bpp:8 */
798 break;
799 }
800 }
801 }
802 }
803
clean_output_area(xshm_driver_t * this,xshm_frame_t * frame)804 static void clean_output_area (xshm_driver_t *this, xshm_frame_t *frame) {
805 int i;
806
807 memcpy( this->sc.border, frame->sc.border, sizeof(this->sc.border) );
808
809 LOCK_DISPLAY(this);
810 XSetForeground (this->display, this->gc, this->black.pixel);
811
812 for( i = 0; i < 4; i++ ) {
813 if( this->sc.border[i].w && this->sc.border[i].h )
814 XFillRectangle(this->display, this->drawable, this->gc,
815 this->sc.border[i].x, this->sc.border[i].y,
816 this->sc.border[i].w, this->sc.border[i].h);
817 }
818 if (this->xoverlay) {
819 x11osd_resize (this->xoverlay, this->sc.gui_width, this->sc.gui_height);
820 this->ovl_changed = 1;
821 }
822
823 UNLOCK_DISPLAY(this);
824 }
825
xshm_redraw_needed(vo_driver_t * this_gen)826 static int xshm_redraw_needed (vo_driver_t *this_gen) {
827 xshm_driver_t *this = (xshm_driver_t *) this_gen;
828 int ret = 0;
829
830 if( this->cur_frame ) {
831 this->sc.delivered_height = this->cur_frame->sc.delivered_height;
832 this->sc.delivered_width = this->cur_frame->sc.delivered_width;
833 this->sc.video_pixel_aspect = this->cur_frame->sc.video_pixel_aspect;
834
835 this->sc.crop_left = this->cur_frame->sc.crop_left;
836 this->sc.crop_right = this->cur_frame->sc.crop_right;
837 this->sc.crop_top = this->cur_frame->sc.crop_top;
838 this->sc.crop_bottom = this->cur_frame->sc.crop_bottom;
839
840 if( _x_vo_scale_redraw_needed( &this->sc ) ) {
841
842 clean_output_area (this, this->cur_frame);
843 ret = 1;
844 }
845 }
846 else
847 ret = 1;
848
849 return ret;
850 }
851
xshm_display_frame(vo_driver_t * this_gen,vo_frame_t * frame_gen)852 static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) {
853 xshm_driver_t *this = (xshm_driver_t *) this_gen;
854 xshm_frame_t *frame = (xshm_frame_t *) frame_gen;
855
856 lprintf ("display frame...\n");
857 lprintf ("about to draw frame (%d) %d x %d...\n",
858 frame->vo_frame.id,
859 frame->sc.output_width, frame->sc.output_height);
860
861 /*
862 * tell gui that we are about to display a frame,
863 * ask for offset
864 */
865
866 this->sc.delivered_height = frame->sc.delivered_height;
867 this->sc.delivered_width = frame->sc.delivered_width;
868 this->sc.video_pixel_aspect = frame->sc.video_pixel_aspect;
869
870 this->sc.crop_left = frame->sc.crop_left;
871 this->sc.crop_right = frame->sc.crop_right;
872 this->sc.crop_top = frame->sc.crop_top;
873 this->sc.crop_bottom = frame->sc.crop_bottom;
874
875 if( _x_vo_scale_redraw_needed( &this->sc ) ) {
876
877 clean_output_area (this, frame);
878 }
879
880 if (this->cur_frame) {
881
882 if ( (this->cur_frame->sc.output_width != frame->sc.output_width)
883 || (this->cur_frame->sc.output_height != frame->sc.output_height)
884 || (this->cur_frame->sc.output_xoffset != frame->sc.output_xoffset)
885 || (this->cur_frame->sc.output_yoffset != frame->sc.output_yoffset) )
886 clean_output_area (this, frame);
887
888 this->cur_frame->vo_frame.free (&this->cur_frame->vo_frame);
889 }
890
891 this->cur_frame = frame;
892
893 LOCK_DISPLAY(this);
894 lprintf ("display locked...\n");
895
896 if (this->use_shm) {
897
898 lprintf ("put image (shm)\n");
899 XShmPutImage(this->display,
900 this->drawable, this->gc, frame->image,
901 0, 0, frame->sc.output_xoffset, frame->sc.output_yoffset,
902 frame->sc.output_width, frame->sc.output_height, True);
903
904 } else {
905
906 lprintf ("put image (plain/remote)\n");
907 XPutImage(this->display,
908 this->drawable, this->gc, frame->image,
909 0, 0, frame->sc.output_xoffset, frame->sc.output_yoffset,
910 frame->sc.output_width, frame->sc.output_height);
911
912 }
913 XSync(this->display, False);
914 UNLOCK_DISPLAY(this);
915
916 lprintf ("display frame done\n");
917
918 /* just in case somebody changes crop this late - take over for next time */
919 /* adjust cropping to what yuv2rgb can handle */
920 if (frame_gen->format == XINE_IMGFMT_YV12) {
921 frame_gen->crop_left &= ~7;
922 frame_gen->crop_top &= ~1;
923 } else {
924 frame_gen->crop_left &= ~3;
925 }
926 /* check for crop changes */
927 if ((frame_gen->crop_left != frame->sc.crop_left)
928 || (frame_gen->crop_top != frame->sc.crop_top)
929 || (frame_gen->crop_right != frame->sc.crop_right)
930 || (frame_gen->crop_bottom != frame->sc.crop_bottom)) {
931 frame->sc.crop_left = frame_gen->crop_left;
932 frame->sc.crop_top = frame_gen->crop_top;
933 frame->sc.crop_right = frame_gen->crop_right;
934 frame->sc.crop_bottom = frame_gen->crop_bottom;
935 frame->state &= ~FS_DONE;
936 frame->state |= FS_LATE;
937 }
938 }
939
xshm_get_property(vo_driver_t * this_gen,int property)940 static int xshm_get_property (vo_driver_t *this_gen, int property) {
941 xshm_driver_t *this = (xshm_driver_t *) this_gen;
942
943 switch (property) {
944 case VO_PROP_ASPECT_RATIO:
945 return this->sc.user_ratio;
946 case VO_PROP_MAX_NUM_FRAMES:
947 return 15;
948 case VO_PROP_BRIGHTNESS:
949 return this->brightness;
950 case VO_PROP_CONTRAST:
951 return this->contrast;
952 case VO_PROP_SATURATION:
953 return this->saturation;
954 case VO_PROP_WINDOW_WIDTH:
955 return this->sc.gui_width;
956 case VO_PROP_WINDOW_HEIGHT:
957 return this->sc.gui_height;
958 case VO_PROP_OUTPUT_WIDTH:
959 return this->cur_frame->sc.output_width;
960 case VO_PROP_OUTPUT_HEIGHT:
961 return this->cur_frame->sc.output_height;
962 case VO_PROP_OUTPUT_XOFFSET:
963 return this->cur_frame->sc.output_xoffset;
964 case VO_PROP_OUTPUT_YOFFSET:
965 return this->cur_frame->sc.output_yoffset;
966 default:
967 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
968 LOG_MODULE ": tried to get unsupported property %d\n", property);
969 }
970
971 return 0;
972 }
973
xshm_set_property(vo_driver_t * this_gen,int property,int value)974 static int xshm_set_property (vo_driver_t *this_gen,
975 int property, int value) {
976 xshm_driver_t *this = (xshm_driver_t *) this_gen;
977
978 switch (property) {
979 case VO_PROP_DISCARD_FRAMES:
980 if (value == -1) {
981 value = 0;
982 if (this->cur_frame) {
983 this->cur_frame->vo_frame.free (&this->cur_frame->vo_frame);
984 this->cur_frame = NULL;
985 value = 1;
986 }
987 }
988 break;
989
990 case VO_PROP_ASPECT_RATIO:
991 if (value>=XINE_VO_ASPECT_NUM_RATIOS)
992 value = XINE_VO_ASPECT_AUTO;
993 this->sc.user_ratio = value;
994 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
995 LOG_MODULE ": aspect ratio changed to %s\n", _x_vo_scale_aspect_ratio_name_table[value]);
996 break;
997
998 case VO_PROP_BRIGHTNESS:
999 this->brightness = value;
1000 this->cm_active = 0;
1001 this->sc.force_redraw = 1;
1002 break;
1003
1004 case VO_PROP_CONTRAST:
1005 this->contrast = value;
1006 this->cm_active = 0;
1007 this->sc.force_redraw = 1;
1008 break;
1009
1010 case VO_PROP_SATURATION:
1011 this->saturation = value;
1012 this->cm_active = 0;
1013 this->sc.force_redraw = 1;
1014 break;
1015
1016 default:
1017 xprintf (this->xine, XINE_VERBOSITY_DEBUG,
1018 LOG_MODULE ": tried to set unsupported property %d\n", property);
1019 }
1020
1021 return value;
1022 }
1023
xshm_get_property_min_max(vo_driver_t * this_gen,int property,int * min,int * max)1024 static void xshm_get_property_min_max (vo_driver_t *this_gen,
1025 int property, int *min, int *max) {
1026 /* xshm_driver_t *this = (xshm_driver_t *) this_gen; */
1027
1028 (void)this_gen;
1029 if (property == VO_PROP_BRIGHTNESS) {
1030 *min = -128;
1031 *max = +127;
1032 } else if (property == VO_PROP_CONTRAST) {
1033 *min = 0;
1034 *max = 255;
1035 } else if (property == VO_PROP_SATURATION) {
1036 *min = 0;
1037 *max = 255;
1038 } else {
1039 *min = 0;
1040 *max = 0;
1041 }
1042 }
1043
xshm_gui_data_exchange(vo_driver_t * this_gen,int data_type,void * data)1044 static int xshm_gui_data_exchange (vo_driver_t *this_gen,
1045 int data_type, void *data) {
1046 xshm_driver_t *this = (xshm_driver_t *) this_gen;
1047
1048 switch (data_type) {
1049 #ifndef XINE_DISABLE_DEPRECATED_FEATURES
1050 case XINE_GUI_SEND_COMPLETION_EVENT:
1051 break;
1052 #endif
1053
1054 case XINE_GUI_SEND_EXPOSE_EVENT:
1055
1056 lprintf ("expose event\n");
1057
1058 if (this->cur_frame) {
1059 XExposeEvent * xev = (XExposeEvent *) data;
1060
1061 if (xev && xev->count == 0) {
1062 int i;
1063
1064 LOCK_DISPLAY(this);
1065 if (this->use_shm) {
1066 XShmPutImage(this->display,
1067 this->drawable, this->gc, this->cur_frame->image,
1068 0, 0, this->cur_frame->sc.output_xoffset, this->cur_frame->sc.output_yoffset,
1069 this->cur_frame->sc.output_width, this->cur_frame->sc.output_height,
1070 False);
1071 }
1072 else {
1073 XPutImage(this->display,
1074 this->drawable, this->gc, this->cur_frame->image,
1075 0, 0, this->cur_frame->sc.output_xoffset, this->cur_frame->sc.output_yoffset,
1076 this->cur_frame->sc.output_width, this->cur_frame->sc.output_height);
1077 }
1078
1079 XSetForeground (this->display, this->gc, this->black.pixel);
1080
1081 for( i = 0; i < 4; i++ ) {
1082 if( this->sc.border[i].w && this->sc.border[i].h )
1083 XFillRectangle(this->display, this->drawable, this->gc,
1084 this->sc.border[i].x, this->sc.border[i].y,
1085 this->sc.border[i].w, this->sc.border[i].h);
1086 }
1087
1088 if(this->xoverlay)
1089 x11osd_expose(this->xoverlay);
1090
1091 XSync(this->display, False);
1092 UNLOCK_DISPLAY(this);
1093 }
1094 }
1095 break;
1096
1097 case XINE_GUI_SEND_DRAWABLE_CHANGED:
1098 this->drawable = (Drawable) data;
1099
1100 LOCK_DISPLAY(this);
1101 XFreeGC(this->display, this->gc);
1102 this->gc = XCreateGC (this->display, this->drawable, 0, NULL);
1103 if(this->xoverlay)
1104 x11osd_drawable_changed(this->xoverlay, this->drawable);
1105 this->ovl_changed = 1;
1106 UNLOCK_DISPLAY(this);
1107 break;
1108
1109 case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO:
1110
1111 if (this->cur_frame) {
1112 x11_rectangle_t *rect = data;
1113 int x1, y1, x2, y2;
1114
1115 _x_vo_scale_translate_gui2video(&this->cur_frame->sc,
1116 rect->x, rect->y,
1117 &x1, &y1);
1118 _x_vo_scale_translate_gui2video(&this->cur_frame->sc,
1119 rect->x + rect->w, rect->y + rect->h,
1120 &x2, &y2);
1121 rect->x = x1;
1122 rect->y = y1;
1123 rect->w = x2-x1;
1124 rect->h = y2-y1;
1125 }
1126 break;
1127
1128 default:
1129 return -1;
1130 }
1131
1132 return 0;
1133 }
1134
xshm_dispose(vo_driver_t * this_gen)1135 static void xshm_dispose (vo_driver_t *this_gen) {
1136 xshm_driver_t *this = (xshm_driver_t *) this_gen;
1137
1138 if (this->cur_frame)
1139 this->cur_frame->vo_frame.dispose (&this->cur_frame->vo_frame);
1140
1141 if (this->yuv2rgb_factory)
1142 this->yuv2rgb_factory->dispose (this->yuv2rgb_factory);
1143
1144 cm_close (this);
1145
1146 LOCK_DISPLAY(this);
1147 XFreeGC(this->display, this->gc);
1148 UNLOCK_DISPLAY(this);
1149
1150 if( this->xoverlay ) {
1151 LOCK_DISPLAY(this);
1152 x11osd_destroy (this->xoverlay);
1153 UNLOCK_DISPLAY(this);
1154 }
1155
1156 _x_alphablend_free(&this->alphablend_extra_data);
1157 _x_vo_scale_cleanup (&this->sc, this->xine->config);
1158
1159 free (this);
1160 }
1161
1162 /* called xlocked */
ImlibPaletteLUTGet(xshm_driver_t * this)1163 static int ImlibPaletteLUTGet(xshm_driver_t *this) {
1164 unsigned char *retval;
1165 Atom type_ret;
1166 unsigned long bytes_after, num_ret;
1167 int format_ret;
1168 long length;
1169 Atom to_get;
1170
1171 retval = NULL;
1172 length = 0x7fffffff;
1173 to_get = XInternAtom(this->display, "_IMLIB_COLORMAP", False);
1174 XGetWindowProperty(this->display, RootWindow(this->display, this->screen),
1175 to_get, 0, length, False,
1176 XA_CARDINAL, &type_ret, &format_ret, &num_ret,
1177 &bytes_after, &retval);
1178 if (retval != 0 && num_ret > 0 && format_ret > 0) {
1179 if (format_ret == 8) {
1180 unsigned int i;
1181 unsigned long j;
1182
1183 j = 1 + retval[0]*4;
1184 this->yuv2rgb_cmap = malloc(sizeof(uint8_t) * 32 * 32 * 32);
1185 for (i = 0; i < 32 * 32 * 32 && j < num_ret; i++)
1186 this->yuv2rgb_cmap[i] = retval[1+4*retval[j++]+3];
1187
1188 XFree(retval);
1189 return 1;
1190 } else
1191 XFree(retval);
1192 }
1193 return 0;
1194 }
1195
1196
visual_class_name(Visual * visual)1197 static const char *visual_class_name(Visual *visual) {
1198
1199 switch (visual->class) {
1200 case StaticGray:
1201 return "StaticGray";
1202 case GrayScale:
1203 return "GrayScale";
1204 case StaticColor:
1205 return "StaticColor";
1206 case PseudoColor:
1207 return "PseudoColor";
1208 case TrueColor:
1209 return "TrueColor";
1210 case DirectColor:
1211 return "DirectColor";
1212 default:
1213 return "unknown visual class";
1214 }
1215 }
1216
1217 /* expects XINE_VISUAL_TYPE_X11_2 with configurable locking */
xshm_open_plugin_2(video_driver_class_t * class_gen,const void * visual_gen)1218 static vo_driver_t *xshm_open_plugin_2 (video_driver_class_t *class_gen, const void *visual_gen) {
1219 xshm_class_t *class = (xshm_class_t *) class_gen;
1220 config_values_t *config = class->xine->config;
1221 const x11_visual_t *visual = (const x11_visual_t *) visual_gen;
1222 xshm_driver_t *this;
1223 XWindowAttributes attribs;
1224 XImage *myimage;
1225 XShmSegmentInfo myshminfo;
1226 int mode;
1227 int swapped;
1228 int cpu_byte_order;
1229 XColor dummy;
1230
1231 this = (xshm_driver_t *) calloc(1, sizeof(xshm_driver_t));
1232
1233 if (!this)
1234 return NULL;
1235
1236 _x_alphablend_init(&this->alphablend_extra_data, class->xine);
1237
1238 this->display = visual->display;
1239 this->screen = visual->screen;
1240
1241 /* configurable X11 locking */
1242 this->lock_display = visual->lock_display;
1243 this->unlock_display = visual->unlock_display;
1244 this->user_data = visual->user_data;
1245
1246 _x_vo_scale_init( &this->sc, 0, 0, config );
1247 this->sc.frame_output_cb = visual->frame_output_cb;
1248 this->sc.dest_size_cb = visual->dest_size_cb;
1249 this->sc.user_data = visual->user_data;
1250
1251 this->sc.user_ratio = XINE_VO_ASPECT_AUTO;
1252
1253 this->drawable = visual->d;
1254 this->cur_frame = NULL;
1255 LOCK_DISPLAY(this);
1256 this->gc = XCreateGC (this->display, this->drawable, 0, NULL);
1257 UNLOCK_DISPLAY(this);
1258 this->xoverlay = NULL;
1259 this->ovl_changed = 0;
1260
1261 this->x11_old_error_handler = NULL;
1262 this->xine = class->xine;
1263
1264 this->vo_driver.get_capabilities = xshm_get_capabilities;
1265 this->vo_driver.alloc_frame = xshm_alloc_frame;
1266 this->vo_driver.update_frame_format = xshm_update_frame_format;
1267 this->vo_driver.overlay_begin = xshm_overlay_begin;
1268 this->vo_driver.overlay_blend = xshm_overlay_blend;
1269 this->vo_driver.overlay_end = xshm_overlay_end;
1270 this->vo_driver.display_frame = xshm_display_frame;
1271 this->vo_driver.get_property = xshm_get_property;
1272 this->vo_driver.set_property = xshm_set_property;
1273 this->vo_driver.get_property_min_max = xshm_get_property_min_max;
1274 this->vo_driver.gui_data_exchange = xshm_gui_data_exchange;
1275 this->vo_driver.dispose = xshm_dispose;
1276 this->vo_driver.redraw_needed = xshm_redraw_needed;
1277
1278 LOCK_DISPLAY(this);
1279 XAllocNamedColor (this->display,
1280 DefaultColormap (this->display, this->screen),
1281 "black", &this->black, &dummy);
1282
1283 /*
1284 *
1285 * depth in X11 terminology land is the number of bits used to
1286 * actually represent the colour.
1287 *
1288 * bpp in X11 land means how many bits in the frame buffer per
1289 * pixel.
1290 *
1291 * ex. 15 bit color is 15 bit depth and 16 bpp. Also 24 bit
1292 * color is 24 bit depth, but can be 24 bpp or 32 bpp.
1293 */
1294
1295 XGetWindowAttributes(this->display, this->drawable, &attribs);
1296 UNLOCK_DISPLAY(this);
1297 this->visual = attribs.visual;
1298 this->depth = attribs.depth;
1299
1300 if (this->depth>16)
1301 xprintf(this->xine, XINE_VERBOSITY_LOG,
1302 _("\n\nWARNING: current display depth is %d. For better performance\n"
1303 "a depth of 16 bpp is recommended!\n\n"), this->depth);
1304
1305 /*
1306 * check for X shared memory support
1307 */
1308
1309 LOCK_DISPLAY(this);
1310 if (XShmQueryExtension(this->display)) {
1311 this->use_shm = 1;
1312 }
1313 else {
1314 xprintf(this->xine, XINE_VERBOSITY_LOG,
1315 _("%s: MIT shared memory extension not present on display.\n"), LOG_MODULE);
1316 this->use_shm = 0;
1317 }
1318
1319 /*
1320 * try to create a shared image
1321 * to find out if MIT shm really works
1322 * and what bpp it uses
1323 */
1324
1325 myimage = create_ximage (this, &myshminfo, 100, 100);
1326 dispose_ximage (this, &myshminfo, myimage);
1327 UNLOCK_DISPLAY(this);
1328
1329 /*
1330 * Is the same byte order in use on the X11 client and server?
1331 */
1332 cpu_byte_order = htonl(1) == 1 ? MSBFirst : LSBFirst;
1333 swapped = cpu_byte_order != this->image_byte_order;
1334
1335 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
1336 LOG_MODULE ": video mode depth is %d (%d bpp), %s, %sswapped,\n"
1337 LOG_MODULE ": red: %08lx, green: %08lx, blue: %08lx\n",
1338 this->depth, this->bpp,
1339 visual_class_name(this->visual),
1340 swapped ? "" : "not ",
1341 this->visual->red_mask, this->visual->green_mask, this->visual->blue_mask);
1342
1343 mode = 0;
1344
1345 switch (this->visual->class) {
1346 case TrueColor:
1347 switch (this->depth) {
1348 case 24:
1349 case 32:
1350 if (this->bpp == 32) {
1351 if (this->visual->red_mask == 0x00ff0000)
1352 mode = MODE_32_RGB;
1353 else
1354 mode = MODE_32_BGR;
1355 } else {
1356 if (this->visual->red_mask == 0x00ff0000)
1357 mode = MODE_24_RGB;
1358 else
1359 mode = MODE_24_BGR;
1360 }
1361 break;
1362 case 16:
1363 if (this->visual->red_mask == 0xf800)
1364 mode = MODE_16_RGB;
1365 else
1366 mode = MODE_16_BGR;
1367 break;
1368 case 15:
1369 if (this->visual->red_mask == 0x7C00)
1370 mode = MODE_15_RGB;
1371 else
1372 mode = MODE_15_BGR;
1373 break;
1374 case 8:
1375 if (this->visual->red_mask == 0xE0)
1376 mode = MODE_8_RGB; /* Solaris x86: RGB332 */
1377 else
1378 mode = MODE_8_BGR; /* XFree86: BGR233 */
1379 break;
1380 }
1381 break;
1382
1383 case StaticGray:
1384 if (this->depth == 8)
1385 mode = MODE_8_GRAY;
1386 break;
1387
1388 case PseudoColor:
1389 case GrayScale:
1390 LOCK_DISPLAY(this);
1391 if (this->depth <= 8 && ImlibPaletteLUTGet(this))
1392 mode = MODE_PALETTE;
1393 UNLOCK_DISPLAY(this);
1394 break;
1395 }
1396
1397 if (!mode) {
1398 xprintf (this->xine, XINE_VERBOSITY_LOG,
1399 _("%s: your video mode was not recognized, sorry :-(\n"), LOG_MODULE);
1400 return NULL;
1401 }
1402
1403 cm_init (this);
1404
1405 this->brightness = 0;
1406 this->contrast = 128;
1407 this->saturation = 128;
1408
1409 this->yuv2rgb_factory = yuv2rgb_factory_init (mode, swapped, this->yuv2rgb_cmap);
1410 if (!this->yuv2rgb_factory) {
1411 xprintf (this->xine, XINE_VERBOSITY_LOG, LOG_MODULE ": yuv2rgb initialization failed\n");
1412 xshm_dispose(&this->vo_driver);
1413 return NULL;
1414 }
1415
1416 LOCK_DISPLAY(this);
1417 this->xoverlay = x11osd_create (this->xine, this->display, this->screen,
1418 this->drawable, X11OSD_SHAPED);
1419 UNLOCK_DISPLAY(this);
1420
1421 return &this->vo_driver;
1422 }
1423
xshm_open_plugin_old(video_driver_class_t * class_gen,const void * visual_gen)1424 static vo_driver_t *xshm_open_plugin_old (video_driver_class_t *class_gen, const void *visual_gen) {
1425 const x11_visual_t *old_visual = (const x11_visual_t *) visual_gen;
1426 x11_visual_t visual;
1427
1428 /* provides compatibility for XINE_VISUAL_TYPE_X11 */
1429 visual.display = old_visual->display;
1430 visual.screen = old_visual->screen;
1431 visual.d = old_visual->d;
1432 visual.user_data = old_visual->user_data;
1433 visual.dest_size_cb = old_visual->dest_size_cb;
1434 visual.frame_output_cb = old_visual->frame_output_cb;
1435 visual.lock_display = NULL;
1436 visual.unlock_display = NULL;
1437
1438 return xshm_open_plugin_2(class_gen, (void *)&visual);
1439 }
1440
1441 /*
1442 * class functions
1443 */
xshm_init_class(xine_t * xine,const void * visual_gen)1444 static void *xshm_init_class (xine_t *xine, const void *visual_gen) {
1445 xshm_class_t *this;
1446
1447 (void)visual_gen;
1448
1449 this = calloc(1, sizeof(*this));
1450 if (!this)
1451 return NULL;
1452
1453 this->driver_class.open_plugin = xshm_open_plugin_old;
1454 this->driver_class.identifier = "XShm";
1455 this->driver_class.description = N_("xine video output plugin using the MIT X shared memory extension");
1456 this->driver_class.dispose = default_video_driver_class_dispose;
1457 this->xine = xine;
1458
1459 return this;
1460 }
1461
xshm_init_class_2(xine_t * xine,const void * visual_gen)1462 static void *xshm_init_class_2 (xine_t *xine, const void *visual_gen) {
1463 xshm_class_t *this;
1464 this = xshm_init_class (xine, visual_gen);
1465 if (this) {
1466 this->driver_class.open_plugin = xshm_open_plugin_2;
1467 }
1468 return this;
1469 }
1470
1471
1472 static const vo_info_t vo_info_xshm = {
1473 .priority = 6,
1474 .visual_type = XINE_VISUAL_TYPE_X11,
1475 };
1476
1477 /* visual type with configurable X11 locking */
1478 static const vo_info_t vo_info_xshm_2 = {
1479 .priority = 6,
1480 .visual_type = XINE_VISUAL_TYPE_X11_2,
1481 };
1482
1483
1484 /*
1485 * exported plugin catalog entry
1486 */
1487
1488 const plugin_info_t xine_plugin_info[] EXPORTED = {
1489 /* type, API, "name", version, special_info, init_function */
1490 { PLUGIN_VIDEO_OUT, 22, "xshm", XINE_VERSION_CODE, &vo_info_xshm, xshm_init_class },
1491 { PLUGIN_VIDEO_OUT, 22, "xshm", XINE_VERSION_CODE, &vo_info_xshm_2, xshm_init_class_2 },
1492 { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
1493 };
1494