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