1 /*
2  * Copyright (C) 2000-2018 the xine project
3  *
4  * This file is part of xine, a free video player.
5  *
6  * xine is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * xine is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19  *
20  * video_out_vidix.c
21  *
22  * xine video_out driver to vidix library by Miguel Freitas 30/05/2002
23  *
24  * based on video_out_xv.c, video_out_syncfb.c and video_out_pgx64.c
25  *
26  * some vidix specific code from mplayer (file vosub_vidix.c)
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <inttypes.h>
37 #include <unistd.h>
38 
39 #ifdef HAVE_X11
40 #include <X11/Xlib.h>
41 #endif
42 
43 #ifdef HAVE_FB
44 #include <fcntl.h>
45 #include <sys/ioctl.h>
46 #include <linux/fb.h>
47 #include <errno.h>
48 #endif
49 
50 #include "xine.h"
51 #include "vidixlib.h"
52 #include "fourcc.h"
53 
54 #define LOG_MODULE "video_out_vidix"
55 #define LOG_VERBOSE
56 /*
57 #define LOG
58 */
59 
60 #include <xine/video_out.h>
61 #include <xine/xine_internal.h>
62 #include <xine/xineutils.h>
63 #include <xine/vo_scale.h>
64 
65 #ifdef HAVE_X11
66 #include "x11osd.h"
67 #endif
68 
69 #define NUM_FRAMES 3
70 
71 typedef struct vidix_driver_s vidix_driver_t;
72 
73 
74 typedef struct vidix_property_s {
75   int                value;
76   int                min;
77   int                max;
78 
79   cfg_entry_t       *entry;
80 
81   vidix_driver_t       *this;
82 } vidix_property_t;
83 
84 
85 typedef struct vidix_frame_s {
86     vo_frame_t vo_frame;
87     int width, height, format;
88     double ratio;
89 } vidix_frame_t;
90 
91 
92 struct vidix_driver_s {
93 
94   vo_driver_t         vo_driver;
95 
96   config_values_t    *config;
97 
98   char               *vidix_name;
99   VDL_HANDLE          vidix_handler;
100   uint8_t            *vidix_mem;
101   vidix_capability_t  vidix_cap;
102   vidix_playback_t    vidix_play;
103   vidix_grkey_t       vidix_grkey;
104   vidix_video_eq_t    vidix_eq;
105   vidix_yuv_t         dstrides;
106   int                 vidix_started;
107   int                 next_frame;
108   int                 got_frame_data;
109 
110   uint32_t            colourkey;
111   int                 use_doublebuffer;
112 
113   int                 supports_yv12;
114 
115   pthread_mutex_t     mutex;
116 
117   vidix_property_t    props[VO_NUM_PROPERTIES];
118   uint32_t            capabilities;
119 
120   int                 visual_type;
121 
122   /* X11 related stuff */
123 #ifdef HAVE_X11
124   Display            *display;
125   int                 screen;
126   Drawable            drawable;
127   GC                  gc;
128   x11osd              *xoverlay;
129   int                  ovl_changed;
130 #endif
131 
132   /* fb related stuff */
133   int                 fb_width;
134   int                 fb_height;
135 
136   int                 depth;
137 
138   vo_scale_t          sc;
139 
140   int                 delivered_format;
141 
142   xine_t             *xine;
143 
144   alphablend_t        alphablend_extra_data;
145 };
146 
147 typedef struct vidix_class_s {
148   video_driver_class_t driver_class;
149 
150   VDL_HANDLE          vidix_handler;
151   vidix_capability_t  vidix_cap;
152 
153   xine_t             *xine;
154 } vidix_class_t;
155 
156 
free_framedata(vidix_frame_t * frame)157 static void free_framedata(vidix_frame_t* frame)
158 {
159    if(frame->vo_frame.base[0]) {
160       free(frame->vo_frame.base[0]);
161       frame->vo_frame.base[0] = NULL;
162    }
163 
164    if(frame->vo_frame.base[1]) {
165       free(frame->vo_frame.base[1]);
166       frame->vo_frame.base[1] = NULL;
167    }
168 
169    if(frame->vo_frame.base[2]) {
170       free(frame->vo_frame.base[2]);
171       frame->vo_frame.base[2] = NULL;
172    }
173 }
174 
write_frame_YUV420P2(vidix_driver_t * this,vidix_frame_t * frame)175 static void write_frame_YUV420P2(vidix_driver_t* this, vidix_frame_t* frame)
176 {
177    uint8_t* y    = frame->vo_frame.base[0] + this->sc.displayed_xoffset +
178                      this->sc.displayed_yoffset*frame->vo_frame.pitches[0];
179    uint8_t* cb   = frame->vo_frame.base[1] + this->sc.displayed_xoffset/2 +
180                      this->sc.displayed_yoffset*frame->vo_frame.pitches[1]/2;
181    uint8_t* cr   = frame->vo_frame.base[2]+this->sc.displayed_xoffset/2 +
182                      this->sc.displayed_yoffset*frame->vo_frame.pitches[2]/2;
183    uint8_t* dst8 = (this->vidix_mem +
184                     this->vidix_play.offsets[this->next_frame] +
185                     this->vidix_play.offset.y);
186    int h, w;
187 
188    for(h = 0; h < this->sc.displayed_height; h++) {
189       xine_fast_memcpy(dst8, y, this->sc.displayed_width);
190       y    += frame->vo_frame.pitches[0];
191       dst8 += this->dstrides.y;
192    }
193 
194    dst8 = (this->vidix_mem + this->vidix_play.offsets[this->next_frame] +
195            this->vidix_play.offset.v);
196 
197    for(h = 0; h < (this->sc.displayed_height / 2); h++) {
198      for(w = 0; w < (this->sc.displayed_height / 2); w++) {
199        dst8[2*w+0] = cb[w];
200        dst8[2*w+1] = cr[w];
201      }
202       cb += frame->vo_frame.pitches[2];
203       cr += frame->vo_frame.pitches[1];
204       dst8 += this->dstrides.y;
205    }
206 }
207 
write_frame_sfb(vidix_driver_t * this,vidix_frame_t * frame)208 static void write_frame_sfb(vidix_driver_t* this, vidix_frame_t* frame)
209 {
210   uint8_t *base = this->vidix_mem+this->vidix_play.offsets[this->next_frame];
211 
212   switch(frame->format) {
213     case XINE_IMGFMT_YUY2:
214       yuy2_to_yuy2(
215        /* src */
216         frame->vo_frame.base[0]+this->sc.displayed_xoffset*2+
217           this->sc.displayed_yoffset*frame->vo_frame.pitches[0],
218         frame->vo_frame.pitches[0],
219        /* dst */
220         base+this->vidix_play.offset.y, this->dstrides.y,
221        /* width x height */
222         this->sc.displayed_width, this->sc.displayed_height);
223       break;
224 
225     case XINE_IMGFMT_YV12: {
226       uint8_t* y  = frame->vo_frame.base[0] + this->sc.displayed_xoffset +
227                       this->sc.displayed_yoffset*frame->vo_frame.pitches[0];
228       uint8_t* cb = frame->vo_frame.base[1] + this->sc.displayed_xoffset/2 +
229                       this->sc.displayed_yoffset*frame->vo_frame.pitches[1]/2;
230       uint8_t* cr = frame->vo_frame.base[2] + this->sc.displayed_xoffset/2 +
231                       this->sc.displayed_yoffset*frame->vo_frame.pitches[2]/2;
232 
233       if(this->supports_yv12) {
234         if(this->vidix_play.flags & VID_PLAY_INTERLEAVED_UV)
235           write_frame_YUV420P2(this, frame);
236         else
237           yv12_to_yv12(
238            /* Y */
239             y, frame->vo_frame.pitches[0],
240             base+this->vidix_play.offset.y, this->dstrides.y,
241            /* U */
242             cr, frame->vo_frame.pitches[2],
243             base+this->vidix_play.offset.u, this->dstrides.u/2,
244            /* V */
245             cb, frame->vo_frame.pitches[1],
246             base+this->vidix_play.offset.v, this->dstrides.v/2,
247            /* width x height */
248             this->sc.displayed_width, this->sc.displayed_height);
249       } else
250           yv12_to_yuy2(
251            /* src */
252             y,  frame->vo_frame.pitches[0],
253             cb, frame->vo_frame.pitches[1],
254             cr, frame->vo_frame.pitches[2],
255            /* dst */
256             base+this->vidix_play.offset.y, this->dstrides.y,
257            /* width x height */
258             this->sc.displayed_width, this->sc.displayed_height,
259            /* progressive */
260             frame->vo_frame.progressive_frame);
261       break;
262     }
263 
264     default:
265       xprintf(this->xine, XINE_VERBOSITY_DEBUG,
266 	      "video_out_vidix: error. (unknown frame format %04x)\n", frame->format);
267       break;
268    }
269 }
270 
271 
vidix_clean_output_area(vidix_driver_t * this)272 static void vidix_clean_output_area(vidix_driver_t *this) {
273 
274   if(this->visual_type == XINE_VISUAL_TYPE_X11) {
275 #ifdef HAVE_X11
276     int i;
277 
278     XLockDisplay(this->display);
279 
280     XSetForeground(this->display, this->gc, BlackPixel(this->display, this->screen));
281 
282     for( i = 0; i < 4; i++ ) {
283       if( this->sc.border[i].w && this->sc.border[i].h ) {
284         XFillRectangle(this->display, this->drawable, this->gc,
285                       this->sc.border[i].x, this->sc.border[i].y,
286                       this->sc.border[i].w, this->sc.border[i].h);
287       }
288     }
289 
290     XSetForeground(this->display, this->gc, this->colourkey);
291     XFillRectangle(this->display, this->drawable, this->gc, this->sc.output_xoffset, this->sc.output_yoffset, this->sc.output_width, this->sc.output_height);
292 
293     if (this->xoverlay) {
294       x11osd_resize (this->xoverlay, this->sc.gui_width, this->sc.gui_height);
295       this->ovl_changed = 1;
296     }
297 
298     XFlush(this->display);
299 
300     XUnlockDisplay(this->display);
301 #endif
302   }
303 }
304 
305 
vidix_update_colourkey(vidix_driver_t * this)306 static void vidix_update_colourkey(vidix_driver_t *this) {
307   switch(this->depth) {
308     case 15:
309       this->colourkey = ((this->vidix_grkey.ckey.red   & 0xF8) << 7) |
310                         ((this->vidix_grkey.ckey.green & 0xF8) << 2) |
311                         ((this->vidix_grkey.ckey.blue  & 0xF8) >> 3);
312       break;
313     case 16:
314       this->colourkey = ((this->vidix_grkey.ckey.red   & 0xF8) << 8) |
315                         ((this->vidix_grkey.ckey.green & 0xFC) << 3) |
316                         ((this->vidix_grkey.ckey.blue  & 0xF8) >> 3);
317       break;
318     case 24:
319     case 32:
320       this->colourkey = ((this->vidix_grkey.ckey.red   & 0xFF) << 16) |
321                         ((this->vidix_grkey.ckey.green & 0xFF) << 8) |
322                         ((this->vidix_grkey.ckey.blue  & 0xFF));
323       break;
324     default:
325       break;
326   }
327 
328   vidix_clean_output_area(this);
329 
330   vdlSetGrKeys(this->vidix_handler, &this->vidix_grkey);
331 }
332 
333 
vidix_get_capabilities(vo_driver_t * this_gen)334 static uint32_t vidix_get_capabilities (vo_driver_t *this_gen) {
335 
336   vidix_driver_t *this = (vidix_driver_t *) this_gen;
337 
338   return this->capabilities;
339 }
340 
341 #ifdef HAVE_FB
vidixfb_frame_output_cb(void * user_data,int video_width,int video_height,double video_pixel_aspect,int * dest_x,int * dest_y,int * dest_width,int * dest_height,double * dest_pixel_aspect,int * win_x,int * win_y)342 static void vidixfb_frame_output_cb(void *user_data, int video_width, int video_height, double video_pixel_aspect, int *dest_x, int *dest_y, int *dest_width, int *dest_height, double *dest_pixel_aspect, int *win_x, int *win_y) {
343   vidix_driver_t *this = (vidix_driver_t *) user_data;
344 
345   (void)video_width;
346   (void)video_height;
347   (void)video_pixel_aspect;
348   *dest_x            = 0;
349   *dest_y            = 0;
350   *dest_width        = this->fb_width;
351   *dest_height       = this->fb_height;
352   *dest_pixel_aspect = 1.0;
353   *win_x             = 0;
354   *win_y             = 0;
355 }
356 #endif
357 
vidix_frame_field(vo_frame_t * vo_img,int which_field)358 static void vidix_frame_field (vo_frame_t *vo_img, int which_field) {
359   /* not needed for vidix */
360   (void)vo_img;
361   (void)which_field;
362 }
363 
vidix_frame_dispose(vo_frame_t * vo_img)364 static void vidix_frame_dispose (vo_frame_t *vo_img) {
365 
366   vidix_frame_t  *frame = (vidix_frame_t *) vo_img ;
367 
368   free_framedata(frame);
369   free (frame);
370 }
371 
vidix_alloc_frame(vo_driver_t * this_gen)372 static vo_frame_t *vidix_alloc_frame (vo_driver_t *this_gen) {
373   /* vidix_driver_t  *this = (vidix_driver_t *) this_gen; */
374   vidix_frame_t   *frame ;
375 
376   (void)this_gen;
377   frame = (vidix_frame_t *) calloc(1, sizeof(vidix_frame_t));
378   if (!frame)
379     return NULL;
380 
381   pthread_mutex_init (&frame->vo_frame.mutex, NULL);
382 
383   frame->vo_frame.base[0] = NULL;
384   frame->vo_frame.base[1] = NULL;
385   frame->vo_frame.base[2] = NULL;
386 
387   /*
388    * supply required functions
389    */
390 
391   frame->vo_frame.proc_slice = NULL;
392   frame->vo_frame.proc_frame = NULL;
393   frame->vo_frame.field      = vidix_frame_field;
394   frame->vo_frame.dispose    = vidix_frame_dispose;
395 
396   return (vo_frame_t *) frame;
397 }
398 
399 
vidix_compute_ideal_size(vidix_driver_t * this)400 static void vidix_compute_ideal_size (vidix_driver_t *this) {
401 
402   _x_vo_scale_compute_ideal_size( &this->sc );
403 
404 }
405 
406 /*
407  * Configure vidix device
408  */
409 
vidix_config_playback(vidix_driver_t * this)410 static void vidix_config_playback (vidix_driver_t *this) {
411 
412   uint32_t apitch;
413   int err;
414   unsigned int i;
415 
416   _x_vo_scale_compute_output_size( &this->sc );
417 
418   /* We require that the displayed xoffset and width are even.
419    * To prevent displaying more than we're supposed to we round the
420    * xoffset up and the width down */
421   this->sc.displayed_xoffset = (this->sc.displayed_xoffset+1) & ~1;
422   this->sc.displayed_width = this->sc.displayed_width & ~1;
423 
424   /* For yv12 source displayed yoffset and height need to be even too */
425   if(this->delivered_format == XINE_IMGFMT_YV12) {
426     this->sc.displayed_yoffset = (this->sc.displayed_yoffset+1) & ~1;
427     this->sc.displayed_height = this->sc.displayed_height & ~1;
428   }
429 
430   if( this->vidix_started > 0 ) {
431     lprintf("video_out_vidix: overlay off\n");
432     vdlPlaybackOff(this->vidix_handler);
433   }
434 
435   memset(&this->vidix_play,0,sizeof(vidix_playback_t));
436 
437   if(this->delivered_format == XINE_IMGFMT_YV12 && this->supports_yv12)
438     this->vidix_play.fourcc = IMGFMT_YV12;
439   else
440     this->vidix_play.fourcc = IMGFMT_YUY2;
441 
442   this->vidix_play.capability = this->vidix_cap.flags; /* every ;) */
443   this->vidix_play.blend_factor = 0; /* for now */
444   this->vidix_play.src.x = 0;
445   this->vidix_play.src.y = 0;
446   this->vidix_play.src.w = this->sc.displayed_width;
447   this->vidix_play.src.h = this->sc.displayed_height;
448   this->vidix_play.dest.x = this->sc.gui_win_x+this->sc.output_xoffset;
449   this->vidix_play.dest.y = this->sc.gui_win_y+this->sc.output_yoffset;
450   this->vidix_play.dest.w = this->sc.output_width;
451   this->vidix_play.dest.h = this->sc.output_height;
452   this->vidix_play.num_frames= this->use_doublebuffer ? NUM_FRAMES : 1;
453   this->vidix_play.src.pitch.y = this->vidix_play.src.pitch.u = this->vidix_play.src.pitch.v = 0;
454 
455   if((err=vdlConfigPlayback(this->vidix_handler,&this->vidix_play))!=0)
456   {
457      xprintf(this->xine, XINE_VERBOSITY_DEBUG,
458 	     "video_out_vidix: Can't configure playback: %s\n",strerror(err));
459      this->vidix_started = -1;
460      return;
461   }
462 
463   lprintf("video_out_vidix: dga_addr = %p frame_size = %u frames = %u\n",
464 	  this->vidix_play.dga_addr, this->vidix_play.frame_size,
465 	  this->vidix_play.num_frames );
466 
467   lprintf("video_out_vidix: offsets[0..2] = %u %u %u\n",
468 	  this->vidix_play.offsets[0], this->vidix_play.offsets[1],
469 	  this->vidix_play.offsets[2] );
470 
471   lprintf("video_out_vidix: offset.y/u/v = %u/%u/%u\n",
472 	  this->vidix_play.offset.y, this->vidix_play.offset.u,
473 	  this->vidix_play.offset.v );
474 
475   lprintf("video_out_vidix: src.x/y/w/h = %u/%u/%u/%u\n",
476 	  this->vidix_play.src.x, this->vidix_play.src.y,
477 	  this->vidix_play.src.w, this->vidix_play.src.h );
478 
479   lprintf("video_out_vidix: dest.x/y/w/h = %u/%u/%u/%u\n",
480 	  this->vidix_play.dest.x, this->vidix_play.dest.y,
481 	  this->vidix_play.dest.w, this->vidix_play.dest.h );
482 
483   lprintf("video_out_vidix: dest.pitch.y/u/v = %u/%u/%u\n",
484 	  this->vidix_play.dest.pitch.y, this->vidix_play.dest.pitch.u,
485 	  this->vidix_play.dest.pitch.v );
486 
487   this->vidix_mem = this->vidix_play.dga_addr;
488 
489   this->next_frame = 0;
490 
491   /* clear every frame with correct address and frame_size */
492   for (i = 0; i < this->vidix_play.num_frames; i++)
493     memset(this->vidix_mem + this->vidix_play.offsets[i], 0x80,
494            this->vidix_play.frame_size);
495 
496   switch(this->vidix_play.fourcc) {
497     case IMGFMT_YV12:
498       apitch = this->vidix_play.dest.pitch.y-1;
499       this->dstrides.y = (this->sc.displayed_width + apitch) & ~apitch;
500       apitch = this->vidix_play.dest.pitch.v-1;
501       this->dstrides.v = (this->sc.displayed_width + apitch) & ~apitch;
502       apitch = this->vidix_play.dest.pitch.u-1;
503       this->dstrides.u = (this->sc.displayed_width + apitch) & ~apitch;
504       break;
505     case IMGFMT_YUY2:
506       apitch = this->vidix_play.dest.pitch.y-1;
507       this->dstrides.y = (this->sc.displayed_width*2 + apitch) & ~apitch;
508       break;
509     default:
510       xprintf(this->xine, XINE_VERBOSITY_DEBUG,
511 	      "video_out_vidix: error. (unknown frame format: %04x)\n", this->delivered_format);
512  }
513 
514   lprintf("video_out_vidix: overlay on\n");
515   vdlPlaybackOn(this->vidix_handler);
516   this->vidix_started = 1;
517 }
518 
vidix_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)519 static void vidix_update_frame_format (vo_driver_t *this_gen,
520 				    vo_frame_t *frame_gen,
521 				    uint32_t width, uint32_t height,
522 				    double ratio, int format, int flags) {
523   vidix_driver_t  *this = (vidix_driver_t *) this_gen;
524   vidix_frame_t   *frame = (vidix_frame_t *) frame_gen;
525 
526   (void)flags;
527   if ((frame->width != (int)width)
528       || (frame->height != (int)height)
529       || (frame->format != format)) {
530 
531     /*
532      * (re-) allocate image
533      */
534 
535       free_framedata(frame);
536 
537       frame->width  = width;
538       frame->height = height;
539       frame->format = format;
540 
541       switch(format) {
542        case XINE_IMGFMT_YV12:
543 	 frame->vo_frame.pitches[0] = 8*((width + 7) / 8);
544 	 frame->vo_frame.pitches[1] = 8*((width + 15) / 16);
545 	 frame->vo_frame.pitches[2] = 8*((width + 15) / 16);
546 	 frame->vo_frame.base[0] = malloc(frame->vo_frame.pitches[0] * height);
547          frame->vo_frame.base[1] = malloc(frame->vo_frame.pitches[1] * ((height+1)/2));
548 	 frame->vo_frame.base[2] = malloc(frame->vo_frame.pitches[2] * ((height+1)/2));
549 	 break;
550        case XINE_IMGFMT_YUY2:
551 	 frame->vo_frame.pitches[0] = 8*((width + 3) / 4);
552 	 frame->vo_frame.base[0] = malloc(frame->vo_frame.pitches[0] * height);
553 	 frame->vo_frame.base[1] = NULL;
554 	 frame->vo_frame.base[2] = NULL;
555 	 break;
556        default:
557 	 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
558 		 "video_out_vidix: error. (unknown frame format: %04x)\n", format);
559       }
560 
561       if((format == XINE_IMGFMT_YV12 && (frame->vo_frame.base[0] == NULL || frame->vo_frame.base[1] == NULL || frame->vo_frame.base[2] == NULL))
562 	 || (format == XINE_IMGFMT_YUY2 && frame->vo_frame.base[0] == NULL)) {
563 	 xprintf(this->xine, XINE_VERBOSITY_DEBUG,
564 		 "video_out_vidix: error. (framedata allocation failed: out of memory)\n");
565 
566 	 free_framedata(frame);
567       }
568    }
569 
570   frame->ratio = ratio;
571 }
572 
vidix_overlay_begin(vo_driver_t * this_gen,vo_frame_t * frame_gen,int changed)573 static void vidix_overlay_begin (vo_driver_t *this_gen,
574 			      vo_frame_t *frame_gen, int changed) {
575   vidix_driver_t  *this = (vidix_driver_t *) this_gen;
576 
577 #ifdef HAVE_X11
578   this->ovl_changed += changed;
579 
580   if( this->ovl_changed && this->xoverlay ) {
581     XLockDisplay (this->display);
582     x11osd_clear(this->xoverlay);
583     XUnlockDisplay (this->display);
584   }
585 #endif
586 
587   this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x;
588   this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y;
589 }
590 
vidix_overlay_end(vo_driver_t * this_gen,vo_frame_t * vo_img)591 static void vidix_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img) {
592 #ifdef HAVE_X11
593   vidix_driver_t  *this = (vidix_driver_t *) this_gen;
594 
595   (void)vo_img;
596   if( this->ovl_changed && this->xoverlay ) {
597     XLockDisplay (this->display);
598     x11osd_expose(this->xoverlay);
599     XUnlockDisplay (this->display);
600   }
601 
602   this->ovl_changed = 0;
603 #endif
604 }
605 
606 /*
607  *
608  */
vidix_overlay_blend(vo_driver_t * this_gen,vo_frame_t * frame_gen,vo_overlay_t * overlay)609 static void vidix_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay) {
610 
611   vidix_frame_t   *frame = (vidix_frame_t *) frame_gen;
612   vidix_driver_t  *this = (vidix_driver_t *) this_gen;
613 
614   if (overlay->rle) {
615     if( overlay->unscaled ) {
616 #ifdef HAVE_X11
617       if( this->ovl_changed && this->xoverlay ) {
618         XLockDisplay (this->display);
619         x11osd_blend(this->xoverlay, overlay);
620         XUnlockDisplay (this->display);
621       }
622 #endif
623     } else {
624       if( frame->format == XINE_IMGFMT_YV12 )
625         _x_blend_yuv( frame->vo_frame.base, overlay, frame->width, frame->height, frame->vo_frame.pitches, &this->alphablend_extra_data);
626       else
627         _x_blend_yuy2( frame->vo_frame.base[0], overlay, frame->width, frame->height, frame->vo_frame.pitches[0], &this->alphablend_extra_data);
628     }
629   }
630 }
631 
632 
vidix_redraw_needed(vo_driver_t * this_gen)633 static int vidix_redraw_needed (vo_driver_t *this_gen) {
634   vidix_driver_t  *this = (vidix_driver_t *) this_gen;
635   int ret = 0;
636 
637   if(_x_vo_scale_redraw_needed(&this->sc)) {
638     if(this->got_frame_data) {
639       vidix_config_playback(this);
640       vidix_clean_output_area(this);
641 
642       ret = 1;
643     }
644   }
645 
646   return ret;
647 }
648 
649 
vidix_display_frame(vo_driver_t * this_gen,vo_frame_t * frame_gen)650 static void vidix_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) {
651 
652   vidix_driver_t  *this = (vidix_driver_t *) this_gen;
653   vidix_frame_t   *frame = (vidix_frame_t *) frame_gen;
654 
655   pthread_mutex_lock(&this->mutex);
656 
657   if ( (frame->width != this->sc.delivered_width)
658        || (frame->height != this->sc.delivered_height)
659        || (frame->ratio != this->sc.delivered_ratio)
660        || (frame->format != this->delivered_format )
661        || (frame->vo_frame.crop_left != this->sc.crop_left)
662        || (frame->vo_frame.crop_right != this->sc.crop_right)
663        || (frame->vo_frame.crop_top != this->sc.crop_top)
664        || (frame->vo_frame.crop_bottom != this->sc.crop_bottom) ) {
665     lprintf("video_out_vidix: change frame format\n");
666 
667     this->sc.delivered_width  = frame->width;
668     this->sc.delivered_height = frame->height;
669     this->sc.delivered_ratio  = frame->ratio;
670     this->delivered_format    = frame->format;
671 
672     this->sc.crop_left        = frame->vo_frame.crop_left;
673     this->sc.crop_right       = frame->vo_frame.crop_right;
674     this->sc.crop_top         = frame->vo_frame.crop_top;
675     this->sc.crop_bottom      = frame->vo_frame.crop_bottom;
676 
677     vidix_compute_ideal_size( this );
678     this->sc.force_redraw = 1;
679   }
680 
681   /*
682    * check if we have to reconfigure vidix because of
683    * format/window position change
684    */
685   this->got_frame_data = 1;
686   vidix_redraw_needed(this_gen);
687 
688   if(this->vidix_started > 0) {
689     write_frame_sfb(this, frame);
690 
691     if( this->vidix_play.num_frames > 1 ) {
692       vdlPlaybackFrameSelect(this->vidix_handler,this->next_frame);
693       this->next_frame=(this->next_frame+1)%this->vidix_play.num_frames;
694     }
695   }
696 
697   frame->vo_frame.free(frame_gen);
698 
699   pthread_mutex_unlock(&this->mutex);
700 }
701 
702 
vidix_get_property(vo_driver_t * this_gen,int property)703 static int vidix_get_property (vo_driver_t *this_gen, int property) {
704 
705   vidix_driver_t *this = (vidix_driver_t *) this_gen;
706 
707   if ((property < 0) || (property >= VO_NUM_PROPERTIES)) return 0;
708 
709   switch (property) {
710     case VO_PROP_WINDOW_WIDTH:
711       this->props[property].value = this->sc.gui_width;
712       break;
713     case VO_PROP_WINDOW_HEIGHT:
714       this->props[property].value = this->sc.gui_height;
715       break;
716     case VO_PROP_OUTPUT_WIDTH:
717       this->props[property].value = this->sc.output_width;
718       break;
719     case VO_PROP_OUTPUT_HEIGHT:
720       this->props[property].value = this->sc.output_height;
721       break;
722     case VO_PROP_OUTPUT_XOFFSET:
723       this->props[property].value = this->sc.output_xoffset;
724       break;
725     case VO_PROP_OUTPUT_YOFFSET:
726       this->props[property].value = this->sc.output_yoffset;
727       break;
728   }
729 
730   lprintf ("video_out_vidix: property #%d = %d\n", property,
731 	   this->props[property].value);
732 
733   return this->props[property].value;
734 }
735 
736 
vidix_set_property(vo_driver_t * this_gen,int property,int value)737 static int vidix_set_property (vo_driver_t *this_gen,
738 			    int property, int value) {
739 
740   vidix_driver_t *this = (vidix_driver_t *) this_gen;
741   int err;
742 
743   if ((property < 0) || (property >= VO_NUM_PROPERTIES)) return 0;
744 
745   if ((value >= this->props[property].min) &&
746       (value <= this->props[property].max))
747   {
748   this->props[property].value = value;
749 
750   if ( property == VO_PROP_ASPECT_RATIO) {
751     if(value >= XINE_VO_ASPECT_NUM_RATIOS)
752       value = this->props[property].value = XINE_VO_ASPECT_AUTO;
753 
754     lprintf("video_out_vidix: aspect ratio changed to %s\n",
755 	    _x_vo_scale_aspect_ratio_name_table[value]);
756 
757     this->sc.user_ratio = value;
758     vidix_compute_ideal_size (this);
759     this->sc.force_redraw = 1;
760   }
761 
762   if ( property == VO_PROP_ZOOM_X ) {
763       this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP;
764 
765       vidix_compute_ideal_size (this);
766       this->sc.force_redraw = 1;
767   }
768 
769   if ( property == VO_PROP_ZOOM_Y ) {
770       this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP;
771 
772       vidix_compute_ideal_size (this);
773       this->sc.force_redraw = 1;
774   }
775 
776   if ( property == VO_PROP_HUE ) {
777     this->vidix_eq.cap = VEQ_CAP_HUE;
778     this->vidix_eq.hue = value;
779 
780     if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0)
781       xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_vidix: can't set hue: %s\n", strerror(err));
782   }
783 
784   if ( property == VO_PROP_SATURATION ) {
785     this->vidix_eq.cap = VEQ_CAP_SATURATION;
786     this->vidix_eq.saturation = value;
787 
788     if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0)
789       xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_vidix: can't set saturation: %s\n", strerror(err));
790   }
791 
792   if ( property == VO_PROP_BRIGHTNESS ) {
793     this->vidix_eq.cap = VEQ_CAP_BRIGHTNESS;
794     this->vidix_eq.brightness = value;
795 
796     if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0)
797       xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_vidix: can't set brightness: %s\n", strerror(err));
798   }
799 
800   if ( property == VO_PROP_CONTRAST ) {
801     this->vidix_eq.cap = VEQ_CAP_CONTRAST;
802     this->vidix_eq.contrast = value;
803 
804     if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)) != 0)
805       xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_vidix: can't set contrast: %s\n", strerror(err));
806   }
807   }
808 
809   return value;
810 }
811 
812 
vidix_ckey_callback(vo_driver_t * this_gen,xine_cfg_entry_t * entry)813 static void vidix_ckey_callback(vo_driver_t *this_gen, xine_cfg_entry_t *entry) {
814 
815   vidix_driver_t *this = (vidix_driver_t *) this_gen;
816 
817   if(strcmp(entry->key, "video.device.vidix_colour_key_red") == 0) {
818     this->vidix_grkey.ckey.red = entry->num_value;
819   }
820 
821   if(strcmp(entry->key, "video.device.vidix_colour_key_green") == 0) {
822     this->vidix_grkey.ckey.green = entry->num_value;
823   }
824 
825   if(strcmp(entry->key, "video.device.vidix_colour_key_blue") == 0) {
826     this->vidix_grkey.ckey.blue = entry->num_value;
827   }
828 
829   vidix_update_colourkey(this);
830   this->sc.force_redraw = 1;
831 }
832 
833 
vidix_db_callback(vo_driver_t * this_gen,xine_cfg_entry_t * entry)834 static void vidix_db_callback(vo_driver_t *this_gen, xine_cfg_entry_t *entry) {
835 
836   vidix_driver_t *this = (vidix_driver_t *) this_gen;
837 
838   this->use_doublebuffer = entry->num_value;
839   this->sc.force_redraw = 1;
840 }
841 
842 
vidix_rgb_callback(vo_driver_t * this_gen,xine_cfg_entry_t * entry)843 static void vidix_rgb_callback(vo_driver_t *this_gen, xine_cfg_entry_t *entry) {
844   int err;
845   vidix_driver_t *this = (vidix_driver_t *) this_gen;
846 
847   this->vidix_eq.cap = VEQ_CAP_RGB_INTENSITY;
848 
849   if(!strcmp(entry->key, "video.output.vidix_red_intensity")) {
850     this->vidix_eq.red_intensity = entry->num_value;
851   } else if(!strcmp(entry->key, "video.output.vidix_green_intensity")) {
852     this->vidix_eq.green_intensity = entry->num_value;
853   } else if(!strcmp(entry->key, "video.output.vidix_blue_intensity")) {
854     this->vidix_eq.blue_intensity = entry->num_value;
855   }
856 
857   if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)))
858     xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_vidix: can't set rgb intensity: %s\n", strerror(err));
859 }
860 
861 
vidix_get_property_min_max(vo_driver_t * this_gen,int property,int * min,int * max)862 static void vidix_get_property_min_max (vo_driver_t *this_gen,
863 				     int property, int *min, int *max) {
864 
865   vidix_driver_t *this = (vidix_driver_t *) this_gen;
866 
867   if ((property < 0) || (property >= VO_NUM_PROPERTIES)) {
868     *min = *max = 0;
869     return;
870   }
871   *min = this->props[property].min;
872   *max = this->props[property].max;
873 }
874 
vidix_gui_data_exchange(vo_driver_t * this_gen,int data_type,void * data)875 static int vidix_gui_data_exchange (vo_driver_t *this_gen,
876 				 int data_type, void *data) {
877 
878   int ret = 0;
879   vidix_driver_t     *this = (vidix_driver_t *) this_gen;
880 
881   pthread_mutex_lock(&this->mutex);
882 
883   switch (data_type) {
884 
885   case XINE_GUI_SEND_DRAWABLE_CHANGED:
886     lprintf ("video_out_vidix: GUI_DATA_EX_DRAWABLE_CHANGED\n");
887 
888     if(this->visual_type == XINE_VISUAL_TYPE_X11) {
889 #ifdef HAVE_X11
890       this->drawable = (Drawable) data;
891       XLockDisplay(this->display);
892       XFreeGC(this->display, this->gc);
893       this->gc = XCreateGC(this->display, this->drawable, 0, NULL);
894       if(this->xoverlay)
895         x11osd_drawable_changed(this->xoverlay, this->drawable);
896       this->ovl_changed = 1;
897       XUnlockDisplay(this->display);
898 #endif
899     }
900     break;
901 
902   case XINE_GUI_SEND_EXPOSE_EVENT:
903     lprintf ("video_out_vidix: GUI_DATA_EX_EXPOSE_EVENT\n");
904     vidix_clean_output_area(this);
905 #ifdef HAVE_X11
906     XLockDisplay (this->display);
907     if(this->xoverlay)
908       x11osd_expose(this->xoverlay);
909 
910     XSync(this->display, False);
911     XUnlockDisplay (this->display);
912 #endif
913     break;
914 
915   case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO:
916     {
917       int x1, y1, x2, y2;
918       x11_rectangle_t *rect = data;
919 
920       _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y,
921 			     &x1, &y1);
922       _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h,
923 			     &x2, &y2);
924       rect->x = x1;
925       rect->y = y1;
926       rect->w = x2-x1;
927       rect->h = y2-y1;
928     }
929     break;
930 
931   default:
932     ret = -1;
933   }
934   pthread_mutex_unlock(&this->mutex);
935 
936   return ret;
937 }
938 
vidix_exit(vo_driver_t * this_gen)939 static void vidix_exit (vo_driver_t *this_gen) {
940 
941   vidix_driver_t *this = (vidix_driver_t *) this_gen;
942 
943   if( this->vidix_started > 0 ) {
944     vdlPlaybackOff(this->vidix_handler);
945   }
946   vdlClose(this->vidix_handler);
947 
948 #ifdef HAVE_X11
949   XLockDisplay (this->display);
950   XFreeGC(this->display, this->gc);
951 
952   if( this->xoverlay )
953     x11osd_destroy (this->xoverlay);
954 
955   XUnlockDisplay (this->display);
956 #endif
957 
958   _x_alphablend_free(&this->alphablend_extra_data);
959   _x_vo_scale_cleanup (&this->sc, this->config);
960 
961   free (this);
962 }
963 
open_plugin(video_driver_class_t * class_gen)964 static vidix_driver_t *open_plugin (video_driver_class_t *class_gen) {
965   vidix_class_t        *class = (vidix_class_t *) class_gen;
966   config_values_t      *config = class->xine->config;
967   vidix_driver_t       *this;
968   int                   err;
969 
970   this = (vidix_driver_t *) calloc(1, sizeof(vidix_driver_t));
971   if (!this)
972     return NULL;
973 
974   _x_alphablend_init(&this->alphablend_extra_data, class->xine);
975 
976   pthread_mutex_init (&this->mutex, NULL);
977 
978   this->vidix_handler = class->vidix_handler;
979   this->vidix_cap = class->vidix_cap;
980 
981   _x_vo_scale_init( &this->sc, 1, /*this->vidix_cap.flags & FLAG_UPSCALER,*/ 0, config );
982 
983   this->xine              = class->xine;
984   this->config            = config;
985 
986   this->got_frame_data    = 0;
987   this->capabilities      = VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y;
988 
989   /* Find what equalizer flags are supported */
990   if(this->vidix_cap.flags & FLAG_EQUALIZER) {
991     if((err = vdlPlaybackGetEq(this->vidix_handler, &this->vidix_eq)) != 0) {
992       xprintf(this->xine, XINE_VERBOSITY_DEBUG,
993 	      "video_out_vidix: couldn't get equalizer capabilities: %s\n", strerror(err));
994     } else {
995       if(this->vidix_eq.cap & VEQ_CAP_BRIGHTNESS) {
996         this->capabilities |= VO_CAP_BRIGHTNESS;
997         this->props[VO_PROP_BRIGHTNESS].value = 0;
998         this->props[VO_PROP_BRIGHTNESS].min = -1000;
999         this->props[VO_PROP_BRIGHTNESS].max = 1000;
1000      }
1001 
1002       if(this->vidix_eq.cap & VEQ_CAP_CONTRAST) {
1003         this->capabilities |= VO_CAP_CONTRAST;
1004         this->props[VO_PROP_CONTRAST].value = 0;
1005         this->props[VO_PROP_CONTRAST].min = -1000;
1006         this->props[VO_PROP_CONTRAST].max = 1000;
1007       }
1008 
1009       if(this->vidix_eq.cap & VEQ_CAP_SATURATION) {
1010         this->capabilities |= VO_CAP_SATURATION;
1011         this->props[VO_PROP_SATURATION].value = 0;
1012         this->props[VO_PROP_SATURATION].min = -1000;
1013         this->props[VO_PROP_SATURATION].max = 1000;
1014       }
1015 
1016       if(this->vidix_eq.cap & VEQ_CAP_HUE) {
1017         this->capabilities |= VO_CAP_HUE;
1018         this->props[VO_PROP_HUE].value = 0;
1019         this->props[VO_PROP_HUE].min = -1000;
1020         this->props[VO_PROP_HUE].max = 1000;
1021       }
1022 
1023       if(this->vidix_eq.cap & VEQ_CAP_RGB_INTENSITY) {
1024         this->vidix_eq.red_intensity = config->register_range(config,
1025           "video.output.vidix_red_intensity", 0, -1000, 1000,
1026           _("red intensity"), _("The intensity of the red colour components."), 10,
1027           (void*) vidix_rgb_callback, this);
1028 
1029         this->vidix_eq.green_intensity = config->register_range(config,
1030           "video.output.vidix_green_intensity", 0, -1000, 1000,
1031           _("green intensity"), _("The intensity of the green colour components."), 10,
1032           (void*) vidix_rgb_callback, this);
1033 
1034         this->vidix_eq.blue_intensity = config->register_range(config,
1035           "video.output.vidix_blue_intensity", 0, -1000, 1000,
1036           _("blue intensity"), _("The intensity of the blue colour components."), 10,
1037           (void*) vidix_rgb_callback, this);
1038 
1039        if((err = vdlPlaybackSetEq(this->vidix_handler, &this->vidix_eq)))
1040          xprintf(this->xine, XINE_VERBOSITY_DEBUG,
1041 		 "video_out_vidix: can't set rgb intensity: %s\n", strerror(err));
1042       }
1043     }
1044   }
1045 
1046   /* Configuration for double buffering */
1047   this->use_doublebuffer = config->register_bool(config,
1048     "video.device.vidix_double_buffer", 1, _("enable double buffering"),
1049     _("Double buffering will synchronize the update of the video image to the repainting of the entire "
1050       "screen (\"vertical retrace\"). This eliminates flickering and tearing artifacts, but will use "
1051       "more graphics memory."), 20,
1052     (void*) vidix_db_callback, this);
1053 
1054   /* Set up remaining props */
1055   this->props[VO_PROP_ASPECT_RATIO].value = XINE_VO_ASPECT_AUTO;
1056   this->props[VO_PROP_ASPECT_RATIO].min = 0;
1057   this->props[VO_PROP_ASPECT_RATIO].max = XINE_VO_ASPECT_NUM_RATIOS;
1058 
1059   this->props[VO_PROP_ZOOM_X].value = 100;
1060   this->props[VO_PROP_ZOOM_X].min = XINE_VO_ZOOM_MIN;
1061   this->props[VO_PROP_ZOOM_X].max = XINE_VO_ZOOM_MAX;
1062 
1063   this->props[VO_PROP_ZOOM_Y].value = 100;
1064   this->props[VO_PROP_ZOOM_Y].min = XINE_VO_ZOOM_MIN;
1065   this->props[VO_PROP_ZOOM_Y].max = XINE_VO_ZOOM_MAX;
1066 
1067   this->vo_driver.get_capabilities     = vidix_get_capabilities;
1068   this->vo_driver.alloc_frame          = vidix_alloc_frame;
1069   this->vo_driver.update_frame_format  = vidix_update_frame_format;
1070   this->vo_driver.overlay_begin        = vidix_overlay_begin;
1071   this->vo_driver.overlay_blend        = vidix_overlay_blend;
1072   this->vo_driver.overlay_end          = vidix_overlay_end;
1073   this->vo_driver.display_frame        = vidix_display_frame;
1074   this->vo_driver.get_property         = vidix_get_property;
1075   this->vo_driver.set_property         = vidix_set_property;
1076   this->vo_driver.get_property_min_max = vidix_get_property_min_max;
1077   this->vo_driver.gui_data_exchange    = vidix_gui_data_exchange;
1078   this->vo_driver.dispose              = vidix_exit;
1079   this->vo_driver.redraw_needed        = vidix_redraw_needed;
1080 
1081   return this;
1082 }
1083 
query_fourccs(vidix_driver_t * this)1084 static void query_fourccs (vidix_driver_t *this) {
1085   vidix_fourcc_t        vidix_fourcc;
1086   int                   err;
1087 
1088   /* Detect if YUY2 is supported */
1089   memset(&vidix_fourcc, 0, sizeof(vidix_fourcc_t));
1090   vidix_fourcc.fourcc = IMGFMT_YUY2;
1091   vidix_fourcc.depth = this->depth;
1092 
1093   if((err = vdlQueryFourcc(this->vidix_handler, &vidix_fourcc)) == 0) {
1094     this->capabilities |= VO_CAP_YUY2;
1095     xprintf(this->xine, XINE_VERBOSITY_LOG,
1096 	    _("video_out_vidix: adaptor supports the yuy2 format\n"));
1097   }
1098 
1099   /* Detect if YV12 is supported - we always support yv12 but we need
1100      to know if we have to convert */
1101   this->capabilities |= VO_CAP_YV12;
1102   vidix_fourcc.fourcc = IMGFMT_YV12;
1103 
1104   if((err = vdlQueryFourcc(this->vidix_handler, &vidix_fourcc)) == 0) {
1105     this->supports_yv12 = 1;
1106     xprintf(this->xine, XINE_VERBOSITY_LOG,
1107 	    _("video_out_vidix: adaptor supports the yv12 format\n"));
1108   } else
1109     this->supports_yv12 = 0;
1110 }
1111 
init_class(xine_t * xine,const void * visual_gen)1112 static void *init_class (xine_t *xine, const void *visual_gen) {
1113   vidix_class_t        *this;
1114   int                   err;
1115 
1116   (void)visual_gen;
1117   this = (vidix_class_t *) calloc(1, sizeof(vidix_class_t));
1118   if (!this)
1119     return NULL;
1120 
1121   if(vdlGetVersion() != VIDIX_VERSION)
1122   {
1123     xprintf(xine, XINE_VERBOSITY_LOG,
1124 	    _("video_out_vidix: You have wrong version of VIDIX library\n"));
1125     free(this);
1126     return NULL;
1127   }
1128   this->vidix_handler = vdlOpen((XINE_PLUGINDIR"/vidix/"), NULL, TYPE_OUTPUT, 0);
1129   if(this->vidix_handler == NULL)
1130   {
1131     xprintf(xine, XINE_VERBOSITY_LOG,
1132 	    _("video_out_vidix: Couldn't find working VIDIX driver\n"));
1133     free(this);
1134     return NULL;
1135   }
1136   if((err=vdlGetCapability(this->vidix_handler,&this->vidix_cap)) != 0)
1137   {
1138     xprintf(xine, XINE_VERBOSITY_DEBUG,
1139 	    "video_out_vidix: Couldn't get capability: %s\n",strerror(err));
1140     free(this);
1141     return NULL;
1142   }
1143 
1144   xprintf(xine, XINE_VERBOSITY_LOG,
1145 	  _("video_out_vidix: using driver: %s by %s\n"), this->vidix_cap.name, this->vidix_cap.author);
1146 
1147   this->xine              = xine;
1148 
1149   return this;
1150 }
1151 
1152 #ifdef HAVE_X11
vidix_open_plugin(video_driver_class_t * class_gen,const void * visual_gen)1153 static vo_driver_t *vidix_open_plugin (video_driver_class_t *class_gen, const void *visual_gen) {
1154   vidix_driver_t       *this   = open_plugin(class_gen);
1155   config_values_t      *config = this->config;
1156   const x11_visual_t   *visual = (const x11_visual_t *) visual_gen;
1157   XWindowAttributes     window_attributes;
1158 
1159   (void)visual_gen;
1160   this->visual_type       = XINE_VISUAL_TYPE_X11;
1161 
1162   this->display           = visual->display;
1163   this->screen            = visual->screen;
1164   this->drawable          = visual->d;
1165   this->gc                = XCreateGC(this->display, this->drawable, 0, NULL);
1166   this->xoverlay          = NULL;
1167   this->ovl_changed       = 0;
1168 
1169   XGetWindowAttributes(this->display, this->drawable, &window_attributes);
1170   this->sc.gui_width      = window_attributes.width;
1171   this->sc.gui_height     = window_attributes.height;
1172   this->depth             = window_attributes.depth;
1173 
1174   this->sc.frame_output_cb   = visual->frame_output_cb;
1175   this->sc.user_data         = visual->user_data;
1176 
1177   /* We'll assume all drivers support colour keying (which they do
1178      at the moment) */
1179   this->vidix_grkey.ckey.op = CKEY_TRUE;
1180 
1181   /* Colour key components */
1182   this->vidix_grkey.ckey.red = config->register_range(config,
1183     "video.device.vidix_colour_key_red", 255, 0, 255,
1184     _("video overlay colour key red component"),
1185     _("The colour key is used to tell the graphics card where to overlay the video image. "
1186       "Try different values, if you experience windows becoming transparent."), 20,
1187     (void*) vidix_ckey_callback, this);
1188 
1189   this->vidix_grkey.ckey.green = config->register_range(config,
1190     "video.device.vidix_colour_key_green", 0, 0, 255,
1191     _("video overlay colour key green component"),
1192     _("The colour key is used to tell the graphics card where to overlay the video image. "
1193       "Try different values, if you experience windows becoming transparent."), 20,
1194     (void*) vidix_ckey_callback, this);
1195 
1196   this->vidix_grkey.ckey.blue = config->register_range(config,
1197     "video.device.vidix_colour_key_blue", 255, 0, 255,
1198     _("video overlay colour key blue component"),
1199     _("The colour key is used to tell the graphics card where to overlay the video image. "
1200       "Try different values, if you experience windows becoming transparent."), 20,
1201     (void*) vidix_ckey_callback, this);
1202 
1203   vidix_update_colourkey(this);
1204 
1205   query_fourccs(this);
1206 
1207   XLockDisplay (this->display);
1208   if(this->colourkey) {
1209     this->xoverlay = x11osd_create (this->xine, this->display, this->screen,
1210                                     this->drawable, X11OSD_COLORKEY);
1211     if(this->xoverlay)
1212       x11osd_colorkey(this->xoverlay, this->colourkey, &this->sc);
1213   } else {
1214     this->xoverlay = x11osd_create (this->xine, this->display, this->screen,
1215                                     this->drawable, X11OSD_SHAPED);
1216   }
1217   XUnlockDisplay (this->display);
1218 
1219   if( this->xoverlay )
1220     this->capabilities |= VO_CAP_UNSCALED_OVERLAY;
1221 
1222   return &this->vo_driver;
1223 }
1224 
vidix_init_class(xine_t * xine,const void * visual_gen)1225 static void *vidix_init_class (xine_t *xine, const void *visual_gen) {
1226 
1227   vidix_class_t *this = init_class (xine, visual_gen);
1228 
1229   if(this) {
1230     this->driver_class.open_plugin     = vidix_open_plugin;
1231     this->driver_class.identifier      = "vidix";
1232     this->driver_class.description     = N_("xine video output plugin using libvidix for x11");
1233     this->driver_class.dispose         = default_video_driver_class_dispose;
1234   }
1235 
1236   return this;
1237 }
1238 
1239 static const vo_info_t vo_info_vidix = {
1240   .priority    = 2,
1241   .visual_type = XINE_VISUAL_TYPE_X11,
1242 };
1243 #endif
1244 
1245 #ifdef HAVE_FB
vidixfb_open_plugin(video_driver_class_t * class_gen,const void * visual_gen)1246 static vo_driver_t *vidixfb_open_plugin (video_driver_class_t *class_gen, const void *visual_gen) {
1247   vidix_driver_t           *this = open_plugin(class_gen);
1248   config_values_t          *config = this->config;
1249   char                     *device;
1250   int                       fd;
1251   struct fb_var_screeninfo  fb_var;
1252 
1253   (void)visual_gen;
1254   this->visual_type = XINE_VISUAL_TYPE_FB;
1255 
1256   /* Register config option for fb device */
1257   device = config->register_filename(config, "video.device.vidixfb_device", "/dev/fb0", XINE_CONFIG_STRING_IS_DEVICE_NAME,
1258     _("framebuffer device name"),
1259     _("Specifies the file name for the framebuffer device to be used.\n"
1260       "This setting is security critical, because when changed to a different file, xine "
1261       "can be used to fill this file with arbitrary content. So you should be careful that "
1262       "the value you enter really is a proper framebuffer device."),
1263     XINE_CONFIG_SECURITY, NULL, NULL);
1264 
1265   /* Open fb device for reading */
1266   if((fd = xine_open_cloexec("/dev/fb0", O_RDONLY)) < 0) {
1267     xprintf(this->xine, XINE_VERBOSITY_DEBUG,
1268 	    "video_out_vidix: unable to open frame buffer device \"%s\": %s\n", device, strerror(errno));
1269     return NULL;
1270   }
1271 
1272   /* Read screen info */
1273   if(ioctl(fd, FBIOGET_VSCREENINFO, &fb_var) != 0) {
1274     xprintf(this->xine, XINE_VERBOSITY_DEBUG,
1275 	    "video_out_vidix: error in ioctl FBIOGET_VSCREENINFO: %s", strerror(errno));
1276     close(fd);
1277     return NULL;
1278   }
1279 
1280   /* Store screen bpp and dimensions */
1281   this->depth = fb_var.bits_per_pixel;
1282   this->fb_width = fb_var.xres;
1283   this->fb_height = fb_var.yres;
1284 
1285   /* Close device */
1286   close(fd);
1287 
1288   this->sc.frame_output_cb   = vidixfb_frame_output_cb;
1289   this->sc.user_data         = this;
1290 
1291   /* Make sure colour keying is turned off */
1292   this->vidix_grkey.ckey.op = CKEY_FALSE;
1293   vdlSetGrKeys(this->vidix_handler, &this->vidix_grkey);
1294 
1295   query_fourccs(this);
1296 
1297   return &this->vo_driver;
1298 }
1299 
vidixfb_init_class(xine_t * xine,const void * visual_gen)1300 static void *vidixfb_init_class (xine_t *xine, const void *visual_gen) {
1301 
1302   vidix_class_t *this = init_class (xine, visual_gen);
1303 
1304   if(this) {
1305     this->driver_class.open_plugin     = vidixfb_open_plugin;
1306     this->driver_class.identifier      = "vidixfb";
1307     this->driver_class.description     = N_("xine video output plugin using libvidix for linux frame buffer");
1308     this->driver_class.dispose         = default_video_driver_class_dispose;
1309   }
1310 
1311   return this;
1312 }
1313 
1314 static const vo_info_t vo_info_vidixfb = {
1315   .priority    = 2,
1316   .visual_type = XINE_VISUAL_TYPE_FB,
1317 };
1318 #endif
1319 
1320 /*
1321  * exported plugin catalog entry
1322  */
1323 
1324 const plugin_info_t xine_plugin_info[] EXPORTED = {
1325   /* type, API, "name", version, special_info, init_function */
1326 #ifdef HAVE_X11
1327   { PLUGIN_VIDEO_OUT, 22, "vidix", XINE_VERSION_CODE, &vo_info_vidix, vidix_init_class },
1328 #endif
1329 #ifdef HAVE_FB
1330   { PLUGIN_VIDEO_OUT, 22, "vidixfb", XINE_VERSION_CODE, &vo_info_vidixfb, vidixfb_init_class },
1331 #endif
1332   { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
1333 };
1334