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_xvmc.c, X11 video motion compensation extension interface for xine
21  *
22  * based on mpeg2dec code from
23  * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
24  *
25  * XvMC image support by Jack Kelliher
26  *
27  * TODO:
28  *  - support non-XvMC output, probably falling back to Xv.
29  *  - support XvMC overlays for spu/osd
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 
36 #ifdef HAVE_XVMC
37 
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h>
42 #include <unistd.h>
43 #include <pthread.h>
44 
45 #if defined(__FreeBSD__)
46 #include <machine/param.h>
47 #endif
48 #include <sys/types.h>
49 #include <sys/ipc.h>
50 #include <sys/shm.h>
51 #include <sys/time.h>
52 
53 #include <X11/Xlib.h>
54 #include <X11/Xutil.h>
55 #include <X11/extensions/XShm.h>
56 #include <X11/extensions/Xv.h>
57 #include <X11/extensions/Xvlib.h>
58 
59 #include <X11/extensions/XvMClib.h>
60 #include <X11/extensions/XvMC.h>
61 
62 #define LOG_MODULE "video_out_xvmc"
63 #define LOG_VERBOSE
64 /*
65 #define LOG
66 */
67 
68 #include "xine.h"
69 #include <xine/video_out.h>
70 #include <xine/xine_internal.h>
71 #include "accel_xvmc.h"
72 
73 #include <xine/xineutils.h>
74 #include <xine/vo_scale.h>
75 #include "xv_common.h"
76 
77 /* #define LOG1 */
78 /* #define DLOG */
79 
80 /* #define PRINTDATA */
81 /* #define PRINTFRAME */
82 
83 #define MAX_NUM_FRAMES 8
84 
85 typedef struct {
86   xine_macroblocks_t   xine_mc;
87   XvMCBlockArray      *blocks;            /* pointer to memory for dct block array  */
88   int                  num_blocks;
89   XvMCMacroBlock      *macroblockptr;     /* pointer to current macro block         */
90   XvMCMacroBlock      *macroblockbaseptr; /* pointer to base MacroBlock in MB array */
91   XvMCMacroBlockArray *macro_blocks;      /* pointer to memory for macroblock array */
92   int                  slices;
93 } xvmc_macroblocks_t;
94 
95 typedef struct {
96   void *xid;
97 } cxid_t;
98 
99 typedef struct xvmc_driver_s xvmc_driver_t;
100 
101 typedef struct {
102   int                  value;
103   int                  min;
104   int                  max;
105   Atom                 atom;
106 
107   cfg_entry_t         *entry;
108 
109   xvmc_driver_t       *this;
110 } xvmc_property_t;
111 
112 
113 typedef struct {
114   vo_frame_t           vo_frame;
115 
116   int                  width, height, format;
117   double               ratio;
118 
119   XvMCSurface          surface;
120 
121   /* temporary Xv only storage */
122   xine_xvmc_t          xvmc_data;
123 } xvmc_frame_t;
124 
125 
126 struct xvmc_driver_s {
127 
128   vo_driver_t          vo_driver;
129 
130   config_values_t     *config;
131 
132   /* X11 / XvMC related stuff */
133   Display             *display;
134   int                  screen;
135   Drawable             drawable;
136   unsigned int         xvmc_format_yv12;
137   unsigned int         xvmc_format_yuy2;
138   XVisualInfo          vinfo;
139   GC                   gc;
140   XvPortID             xv_port;
141   XvMCContext          context;
142   xvmc_frame_t        *frames[MAX_NUM_FRAMES];
143 
144   int                  surface_type_id;
145   int                  max_surface_width;
146   int                  max_surface_height;
147   int                  num_frame_buffers;
148 
149   int                  surface_width;
150   int                  surface_height;
151   int                  surface_ratio;
152   int                  surface_format;
153   int                  surface_flags;
154   short                acceleration;
155 
156   cxid_t               context_id;
157   xvmc_macroblocks_t   macroblocks;
158 
159   /* all scaling information goes here */
160   vo_scale_t           sc;
161 
162 
163   XColor               black;
164 
165   /* display anatomy */
166   double               display_ratio;        /* given by visual parameter
167 						from init function            */
168 
169   xvmc_property_t      props[VO_NUM_PROPERTIES];
170   uint32_t             capabilities;
171 
172 
173   xvmc_frame_t        *recent_frames[VO_NUM_RECENT_FRAMES];
174   xvmc_frame_t        *cur_frame;
175   vo_overlay_t        *overlay;
176 
177   /* TODO CLEAN THIS UP all unused vars sizes moved to vo_scale */
178 
179   /* size / aspect ratio calculations */
180 
181   /*
182    * "delivered" size:
183    * frame dimension / aspect as delivered by the decoder
184    * used (among other things) to detect frame size changes
185    */
186 
187   int                  delivered_duration;
188 
189   /*
190    * "ideal" size :
191    * displayed width/height corrected by aspect ratio
192    */
193 
194   double               ratio_factor;         /* output frame must fullfill:
195 						height = width * ratio_factor  */
196 
197   /* gui callback */
198 
199   void               (*frame_output_cb) (void *user_data,
200 					 int video_width, int video_height,
201 					 int *dest_x, int *dest_y,
202 					 int *dest_height, int *dest_width,
203 					 int *win_x, int *win_y);
204 
205   int                  use_colorkey;
206   uint32_t             colorkey;
207 
208   void                *user_data;
209   xine_t              *xine;
210 
211   alphablend_t         alphablend_extra_data;
212 };
213 
214 
215 typedef struct {
216   video_driver_class_t driver_class;
217 
218   Display             *display;
219   XvPortID             xv_port;
220   XvAdaptorInfo       *adaptor_info;
221   unsigned int         adaptor_num;
222 
223   int                  surface_type_id;
224   unsigned int         max_surface_width;
225   unsigned int         max_surface_height;
226   short                acceleration;
227   xine_t              *xine;
228 } xvmc_class_t;
229 
230 static void xvmc_render_macro_blocks(vo_frame_t *current_image,
231 				     vo_frame_t *backward_ref_image,
232 				     vo_frame_t *forward_ref_image,
233 				     int picture_structure,
234 				     int second_field,
235 				     xvmc_macroblocks_t *macroblocks);
236 
237 /*********************** XVMC specific routines *********************/
238 
239 /**************************************************************************/
240 
241 /*
242  * dmvector: differential motion vector
243  * mvx, mvy: decoded mv components (always in field format)
244  */
calc_DMV(int DMV[][2],int * dmvector,int mvx,int mvy,int picture_structure,int top_field_first)245 static void calc_DMV(int DMV[][2], int *dmvector,
246 		     int mvx, int mvy, int picture_structure, int top_field_first) {
247 
248   if (picture_structure==VO_BOTH_FIELDS) {
249     if (top_field_first) {
250       /* vector for prediction of top field from bottom field */
251       DMV[0][0] = ((mvx  +(mvx>0))>>1) + dmvector[0];
252       DMV[0][1] = ((mvy  +(mvy>0))>>1) + dmvector[1] - 1;
253 
254       /* vector for prediction of bottom field from top field */
255       DMV[1][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0];
256       DMV[1][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] + 1;
257     }
258     else {
259       /* vector for prediction of top field from bottom field */
260       DMV[0][0] = ((3*mvx+(mvx>0))>>1) + dmvector[0];
261       DMV[0][1] = ((3*mvy+(mvy>0))>>1) + dmvector[1] - 1;
262 
263       /* vector for prediction of bottom field from top field */
264       DMV[1][0] = ((mvx  +(mvx>0))>>1) + dmvector[0];
265       DMV[1][1] = ((mvy  +(mvy>0))>>1) + dmvector[1] + 1;
266     }
267   }
268   else {
269     /* vector for prediction from field of opposite 'parity' */
270     DMV[0][0] = ((mvx+(mvx>0))>>1) + dmvector[0];
271     DMV[0][1] = ((mvy+(mvy>0))>>1) + dmvector[1];
272 
273     /* correct for vertical field shift */
274     if (picture_structure==VO_TOP_FIELD)
275       DMV[0][1]--;
276     else
277       DMV[0][1]++;
278   }
279 }
280 
xvmc_proc_macro_block(int x,int y,int mb_type,int motion_type,int (* mv_field_sel)[2],int * dmvector,int cbp,int dct_type,vo_frame_t * current_frame,vo_frame_t * forward_ref_frame,vo_frame_t * backward_ref_frame,int picture_structure,int second_field,int (* f_mot_pmv)[2],int (* b_mot_pmv)[2])281 static void xvmc_proc_macro_block(int x, int y, int mb_type, int motion_type,
282 				  int (*mv_field_sel)[2], int *dmvector, int cbp,
283 				  int dct_type, vo_frame_t *current_frame,
284 				  vo_frame_t *forward_ref_frame,
285 				  vo_frame_t *backward_ref_frame, int picture_structure,
286 				  int second_field, int (*f_mot_pmv)[2], int (*b_mot_pmv)[2]) {
287   xvmc_driver_t        *this                = (xvmc_driver_t *) current_frame->driver;
288   xvmc_macroblocks_t   *mbs                 = &this->macroblocks;
289   int                   top_field_first     = current_frame->top_field_first;
290   int                   picture_coding_type = current_frame->picture_coding_type;
291 
292   mbs->macroblockptr->x = x;
293   mbs->macroblockptr->y = y;
294 
295   if(mb_type & XINE_MACROBLOCK_INTRA) {
296     mbs->macroblockptr->macroblock_type = XVMC_MB_TYPE_INTRA;
297   }
298   else {
299     mbs->macroblockptr->macroblock_type = 0;
300     /* XvMC doesn't support skips */
301     if(!(mb_type & (XINE_MACROBLOCK_MOTION_BACKWARD | XINE_MACROBLOCK_MOTION_FORWARD))) {
302       mb_type |= XINE_MACROBLOCK_MOTION_FORWARD;
303       motion_type = (picture_structure == VO_BOTH_FIELDS) ? XINE_MC_FRAME : XINE_MC_FIELD;
304       mbs->macroblockptr->PMV[0][0][0] = 0;
305       mbs->macroblockptr->PMV[0][0][1] = 0;
306     }
307     else {
308       if(mb_type & XINE_MACROBLOCK_MOTION_BACKWARD) {
309 	mbs->macroblockptr->macroblock_type |= XVMC_MB_TYPE_MOTION_BACKWARD;
310 	mbs->macroblockptr->PMV[0][1][0]    = b_mot_pmv[0][0];
311 	mbs->macroblockptr->PMV[0][1][1]    = b_mot_pmv[0][1];
312 	mbs->macroblockptr->PMV[1][1][0]    = b_mot_pmv[1][0];
313 	mbs->macroblockptr->PMV[1][1][1]    = b_mot_pmv[1][1];
314 
315       }
316 
317       if(mb_type & XINE_MACROBLOCK_MOTION_FORWARD) {
318 	mbs->macroblockptr->macroblock_type |= XVMC_MB_TYPE_MOTION_FORWARD;
319 	mbs->macroblockptr->PMV[0][0][0]    = f_mot_pmv[0][0];
320 	mbs->macroblockptr->PMV[0][0][1]    = f_mot_pmv[0][1];
321 	mbs->macroblockptr->PMV[1][0][0]    = f_mot_pmv[1][0];
322 	mbs->macroblockptr->PMV[1][0][1]    = f_mot_pmv[1][1];
323       }
324     }
325 
326     if((mb_type & XINE_MACROBLOCK_PATTERN) && cbp)
327       mbs->macroblockptr->macroblock_type |= XVMC_MB_TYPE_PATTERN;
328 
329     mbs->macroblockptr->motion_type = motion_type;
330 
331     if(motion_type == XINE_MC_DMV) {
332       int DMV[2][2];
333 
334       if(picture_structure == VO_BOTH_FIELDS) {
335 	calc_DMV(DMV,dmvector, f_mot_pmv[0][0],
336 		 f_mot_pmv[0][1]>>1, picture_structure,
337 		 top_field_first);
338 
339 	mbs->macroblockptr->PMV[1][0][0] = DMV[0][0];
340 	mbs->macroblockptr->PMV[1][0][1] = DMV[0][1];
341 	mbs->macroblockptr->PMV[1][1][0] = DMV[1][0];
342 	mbs->macroblockptr->PMV[1][1][1] = DMV[1][1];
343       }
344       else {
345 	calc_DMV(DMV,dmvector, f_mot_pmv[0][0],
346 		 f_mot_pmv[0][1]>>1, picture_structure,
347 		 top_field_first);
348 
349 	mbs->macroblockptr->PMV[0][1][0] = DMV[0][0];
350 	mbs->macroblockptr->PMV[0][1][1] = DMV[0][1];
351       }
352     }
353 
354     if((motion_type == XINE_MC_FIELD) || (motion_type == XINE_MC_16X8)) {
355       mbs->macroblockptr->motion_vertical_field_select = 0;
356 
357       if(mv_field_sel[0][0])
358 	mbs->macroblockptr->motion_vertical_field_select |= 1;
359       if(mv_field_sel[0][1])
360 	mbs->macroblockptr->motion_vertical_field_select |= 2;
361       if(mv_field_sel[1][0])
362 	mbs->macroblockptr->motion_vertical_field_select |= 4;
363       if(mv_field_sel[1][1])
364 	mbs->macroblockptr->motion_vertical_field_select |= 8;
365     }
366   } /* else of if(mb_type & XINE_MACROBLOCK_INTRA) */
367 
368   mbs->macroblockptr->index = ((unsigned long)mbs->xine_mc.blockptr -
369 			       (unsigned long)mbs->xine_mc.blockbaseptr) >> 7;
370 
371   mbs->macroblockptr->dct_type = dct_type;
372   mbs->macroblockptr->coded_block_pattern = cbp;
373 
374   while(cbp) {
375     if(cbp & 1) mbs->macroblockptr->index--;
376     cbp >>= 1;
377   }
378 
379 #ifdef PRINTDATA
380   printf("\n");
381   printf("-- %04d %04d %02x %02x %02x %02x",mbs->macroblockptr->x,mbs->macroblockptr->y,mbs->macroblockptr->macroblock_type,
382 	 mbs->macroblockptr->motion_type,mbs->macroblockptr->motion_vertical_field_select,mbs->macroblockptr->dct_type);
383   printf(" [%04d %04d %04d %04d %04d %04d %04d %04d] ",
384 	 mbs->macroblockptr->PMV[0][0][0],mbs->macroblockptr->PMV[0][0][1],mbs->macroblockptr->PMV[0][1][0],mbs->macroblockptr->PMV[0][1][1],
385 	 mbs->macroblockptr->PMV[1][0][0],mbs->macroblockptr->PMV[1][0][1],mbs->macroblockptr->PMV[1][1][0],mbs->macroblockptr->PMV[1][1][1]);
386 
387   printf(" %04d %04x\n",mbs->macroblockptr->index,mbs->macroblockptr->coded_block_pattern);
388 #endif
389 
390   mbs->num_blocks++;
391   mbs->macroblockptr++;
392 
393   if(mbs->num_blocks == mbs->slices) {
394 #ifdef PRINTDATA
395     printf("macroblockptr %lx",  mbs->macroblockptr);
396     printf("** RenderSurface %04d %04x\n",picture_structure,
397 	   second_field ? XVMC_SECOND_FIELD : 0);
398     fflush(stdout);
399 #endif
400 #ifdef PRINTFRAME
401     printf("  target %08x past %08x future %08x\n",
402 	   current_frame,
403 	   forward_ref_frame,
404 	   backward_ref_frame);
405 #endif
406 #ifdef PRINTFRAME
407     if (picture_coding_type == XINE_PICT_P_TYPE)
408       printf(" coding type P_TYPE\n");
409     if (picture_coding_type == XINE_PICT_I_TYPE)
410       printf(" coding type I_TYPE\n");
411     if (picture_coding_type == XINE_PICT_B_TYPE)
412       printf(" coding type B_TYPE\n");
413     if (picture_coding_type == XINE_PICT_D_TYPE)
414       printf(" coding type D_TYPE\n");
415     fflush(stdout);
416 #endif
417 
418     if (picture_coding_type == XINE_PICT_B_TYPE)
419       xvmc_render_macro_blocks(
420 			  current_frame,
421 			  backward_ref_frame,
422 			  forward_ref_frame,
423 			  picture_structure,
424 			  second_field ? XVMC_SECOND_FIELD : 0,
425 			  mbs);
426     if (picture_coding_type == XINE_PICT_P_TYPE)
427       xvmc_render_macro_blocks(
428 			  current_frame,
429 			  NULL,
430 			  forward_ref_frame,
431 			  picture_structure,
432 			  second_field ? XVMC_SECOND_FIELD : 0,
433 			  mbs);
434     if (picture_coding_type == XINE_PICT_I_TYPE)
435       xvmc_render_macro_blocks(
436 			  current_frame,
437 			  NULL,
438 			  NULL,
439 			  picture_structure,
440 			  second_field ? XVMC_SECOND_FIELD : 0,
441 			  mbs);
442 
443     mbs->num_blocks       = 0;
444     mbs->macroblockptr    = mbs->macroblockbaseptr;
445     mbs->xine_mc.blockptr = mbs->xine_mc.blockbaseptr;
446   }
447 }
448 
xvmc_get_capabilities(vo_driver_t * this_gen)449 static uint32_t xvmc_get_capabilities (vo_driver_t *this_gen) {
450   xvmc_driver_t *this = (xvmc_driver_t *) this_gen;
451 
452   lprintf ("xvmc_get_capabilities\n");
453 
454   return this->capabilities;
455 }
456 
xvmc_frame_field(vo_frame_t * vo_img,int which_field)457 static void xvmc_frame_field (vo_frame_t *vo_img, int which_field) {
458   lprintf ("xvmc_frame_field\n");
459   (void)vo_img;
460   (void)which_field;
461 }
462 
xvmc_frame_dispose(vo_frame_t * vo_img)463 static void xvmc_frame_dispose (vo_frame_t *vo_img) {
464   xvmc_frame_t  *frame = (xvmc_frame_t *) vo_img ;
465 
466   lprintf ("xvmc_frame_dispose\n");
467 
468   /*
469    * TODO - clean up of images/surfaces and frames
470    * Note this function is not really needed
471    * set_context does the work
472    */
473 
474   free (frame);
475 }
476 
xvmc_render_macro_blocks(vo_frame_t * current_image,vo_frame_t * backward_ref_image,vo_frame_t * forward_ref_image,int picture_structure,int second_field,xvmc_macroblocks_t * macroblocks)477 static void xvmc_render_macro_blocks(vo_frame_t *current_image,
478 				     vo_frame_t *backward_ref_image,
479 				     vo_frame_t *forward_ref_image,
480 				     int picture_structure,
481 				     int second_field,
482 				     xvmc_macroblocks_t *macroblocks) {
483   xvmc_driver_t *this           = (xvmc_driver_t *) current_image->driver;
484   xvmc_frame_t  *current_frame  = XVMC_FRAME(current_image);
485   xvmc_frame_t  *forward_frame  = XVMC_FRAME(forward_ref_image);
486   xvmc_frame_t  *backward_frame = XVMC_FRAME(backward_ref_image);
487   int           flags;
488 
489   lprintf ("xvmc_render_macro_blocks\n");
490   lprintf ("slices %d %p %p %p\n",
491 	   macroblocks->slices,
492            (void *) current_frame, (void *) backward_frame,
493            (void *) forward_frame);
494   /* lprintf ("slices %d 0x%08lx 0x%08lx 0x%08lx\n",macroblocks->slices,
495 	   (long) current_frame->surface, (long) backward_frame->surface,
496 	   (long) forward_frame->surface);
497   */
498 
499   flags = second_field;
500 
501   if(forward_frame) {
502     if(backward_frame) {
503       XvMCRenderSurface(this->display, &this->context, picture_structure,
504 			&current_frame->surface,
505 			&forward_frame->surface,
506 			&backward_frame->surface,
507 			flags,
508 			macroblocks->slices, 0, macroblocks->macro_blocks,
509 			macroblocks->blocks);
510     }
511     else {
512       XvMCRenderSurface(this->display, &this->context, picture_structure,
513 			&current_frame->surface,
514 			&forward_frame->surface,
515 			NULL,
516 			flags,
517 			macroblocks->slices, 0, macroblocks->macro_blocks,
518 			macroblocks->blocks);
519     }
520   }
521   else {
522     if(backward_frame) {
523       XvMCRenderSurface(this->display, &this->context, picture_structure,
524 			&current_frame->surface,
525 			NULL,
526 			&backward_frame->surface,
527 			flags,
528 			macroblocks->slices, 0, macroblocks->macro_blocks,
529 			macroblocks->blocks);
530     }
531     else {
532       XvMCRenderSurface(this->display, &this->context, picture_structure,
533 			&current_frame->surface,
534 			NULL,
535 			NULL,
536 			flags,
537 			macroblocks->slices, 0, macroblocks->macro_blocks,
538 			macroblocks->blocks);
539     }
540   }
541 
542   XvMCFlushSurface(this->display, &current_frame->surface);
543 
544   lprintf ("xvmc_render_macro_blocks done\n");
545 }
546 
xvmc_alloc_frame(vo_driver_t * this_gen)547 static vo_frame_t *xvmc_alloc_frame (vo_driver_t *this_gen) {
548   xvmc_frame_t   *frame;
549   xvmc_driver_t  *this = (xvmc_driver_t *) this_gen;
550 
551   lprintf ("xvmc_alloc_frame\n");
552 
553   frame = calloc(1, sizeof (xvmc_frame_t));
554 
555   if (!frame)
556     return NULL;
557 
558   frame->vo_frame.accel_data = &frame->xvmc_data;
559   frame->xvmc_data.vo_frame = &frame->vo_frame;
560 
561   /* keep track of frames and how many frames alocated. */
562   this->frames[this->num_frame_buffers++] = frame;
563 
564   pthread_mutex_init (&frame->vo_frame.mutex, NULL);
565 
566   /*
567    * supply required functions
568    */
569 
570   frame->vo_frame.proc_slice       = NULL;
571   frame->vo_frame.proc_frame       = NULL;
572   frame->vo_frame.field            = xvmc_frame_field;
573   frame->vo_frame.dispose          = xvmc_frame_dispose;
574   frame->vo_frame.driver           = this_gen;
575   frame->xvmc_data.proc_macro_block            = xvmc_proc_macro_block;
576 
577   return (vo_frame_t *) frame;
578 }
579 
xvmc_set_context(xvmc_driver_t * this,uint32_t width,uint32_t height,double ratio,int format,int flags,xine_macroblocks_t * macro_blocks)580 static cxid_t *xvmc_set_context (xvmc_driver_t *this,
581 				 uint32_t width, uint32_t height,
582 				 double ratio, int format, int flags,
583 				 xine_macroblocks_t *macro_blocks) {
584   int                  i;
585   int                  result      = 0;
586   int                  slices      = 1;
587   xvmc_macroblocks_t  *macroblocks = (xvmc_macroblocks_t *) macro_blocks;
588 
589   lprintf ("xvmc_set_context %dx%d %04x\n",width,height,format);
590 
591   (void)ratio;
592   /* initialize block & macro block pointers first time */
593   if(macroblocks->blocks == NULL ||  macroblocks->macro_blocks == NULL) {
594     macroblocks->blocks       = calloc(1, sizeof(XvMCBlockArray));
595     macroblocks->macro_blocks = calloc(1, sizeof(XvMCMacroBlockArray));
596 
597     lprintf("macroblocks->blocks %p ->macro_blocks %p\n",
598             (void *)macroblocks->blocks, (void *)macroblocks->macro_blocks);
599   }
600 
601   if((this->context_id.xid != NULL)   &&
602      ((int)width  == this->surface_width)  &&
603      ((int)height == this->surface_height) &&
604      (format == this->surface_format) &&
605      (flags  == this->surface_flags)) {
606 
607     /* don't need to change  context */
608     lprintf ("didn't change context\n");
609 
610     return(&this->context_id);
611 
612   }
613   else {
614     if(this->context_id.xid != NULL) {
615 
616       /*
617        * flush any drawing and wait till we are done with the old stuff
618        * blow away the old stuff
619        */
620       lprintf ("freeing previous context\n");
621 
622       XvMCDestroyBlocks(this->display, macroblocks->blocks);
623       XvMCDestroyMacroBlocks(this->display, macroblocks->macro_blocks);
624 
625       for(i = 0; i < this->num_frame_buffers; i++) {
626 	XvMCFlushSurface(this->display, &this->frames[i]->surface);
627 	XvMCSyncSurface(this->display, &this->frames[i]->surface);
628 
629 	XvMCDestroySurface(this->display, &this->frames[i]->surface);
630       }
631       XvMCDestroyContext(this->display, &this->context);
632       this->context_id.xid = NULL;
633     }
634 
635     lprintf("CreateContext  w %d h %d id %x portNum %x\n",
636 	    width,height, this->surface_type_id, (int)this->xv_port);
637 
638     /* now create a new context */
639     result = XvMCCreateContext(this->display, this->xv_port,
640 			       this->surface_type_id,
641 			       width, height, XVMC_DIRECT, &this->context);
642 
643     if(result != Success) {
644       xprintf(this->xine, XINE_VERBOSITY_DEBUG, "set_context: couldn't create XvMCContext\n");
645       macroblocks->xine_mc.xvmc_accel = 0;
646       _x_abort();
647     }
648 
649     this->context_id.xid = (void *)this->context.context_id;
650 
651     for(i = 0; i < this->num_frame_buffers; i++) {
652       result = XvMCCreateSurface(this->display, &this->context,
653 				 &this->frames[i]->surface);
654       if(result != Success) {
655 	XvMCDestroyContext(this->display, &this->context);
656 	xprintf(this->xine, XINE_VERBOSITY_DEBUG, "set_context: couldn't create XvMCSurfaces\n");
657 	this->context_id.xid            = NULL;
658 	macroblocks->xine_mc.xvmc_accel = 0;
659 	_x_abort();
660       }
661 
662       lprintf ("  CreatedSurface %d 0x%lx\n",i,(long)&this->frames[i]->surface);
663     }
664 
665     slices = (slices * width/16);
666 
667     lprintf("CreateBlocks  slices %d\n",slices);
668 
669     result = XvMCCreateBlocks(this->display, &this->context, slices * 6,
670 			      macroblocks->blocks);
671     if(result != Success) {
672       xprintf(this->xine, XINE_VERBOSITY_DEBUG, "set_context: ERROR XvMCCreateBlocks failed\n");
673       macroblocks->xine_mc.xvmc_accel = 0;
674       _x_abort();
675     }
676     result =XvMCCreateMacroBlocks(this->display, &this->context, slices,
677 				  macroblocks->macro_blocks);
678     if(result != Success) {
679       xprintf(this->xine, XINE_VERBOSITY_DEBUG, "set_context: ERROR XvMCCreateMacroBlocks failed\n");
680       macroblocks->xine_mc.xvmc_accel = 0;
681       _x_abort();
682     }
683 
684     lprintf ("  Created bock and macro block arrays\n");
685 
686     macroblocks->xine_mc.blockbaseptr = macroblocks->blocks->blocks;
687     macroblocks->xine_mc.blockptr     = macroblocks->xine_mc.blockbaseptr;
688     macroblocks->num_blocks           = 0;
689     macroblocks->macroblockbaseptr    = macroblocks->macro_blocks->macro_blocks;
690     macroblocks->macroblockptr        = macroblocks->macroblockbaseptr;
691     macroblocks->slices               = slices;
692     macroblocks->xine_mc.xvmc_accel   = this->acceleration;
693     return(&this->context_id);
694   }
695 
696   return NULL;
697 }
698 
699 #if 0
700 static XvImage *create_ximage (xvmc_driver_t *this, XShmSegmentInfo *shminfo,
701 			       int width, int height, int format) {
702   unsigned int  xvmc_format;
703   XvImage      *image = NULL;
704 
705   lprintf ("create_ximage\n");
706 
707   switch (format) {
708   case XINE_IMGFMT_YV12:
709   case XINE_IMGFMT_XVMC:
710     xvmc_format = this->xvmc_format_yv12;
711     break;
712   case XINE_IMGFMT_YUY2:
713     xvmc_format = this->xvmc_format_yuy2;
714     break;
715   default:
716     xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unknown format %08x\n",format);
717     _x_abort();
718   }
719 
720   /*
721    *  plain Xv
722    */
723 
724   if (1) {
725     char *data;
726 
727     switch (format) {
728     case XINE_IMGFMT_YV12:
729     case XINE_IMGFMT_XVMC:
730       data = malloc (width * height * 3/2);
731       break;
732     case XINE_IMGFMT_YUY2:
733       data = malloc (width * height * 2);
734       break;
735     default:
736       xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unknown format %08x\n",format);
737       _x_abort();
738     }
739 
740     image = XvCreateImage (this->display, this->xv_port,
741 			   xvmc_format, data, width, height);
742   }
743 
744   return image;
745 }
746 
747 /* Already Xlocked */
748 static void dispose_ximage (xvmc_driver_t *this,
749 			    XShmSegmentInfo *shminfo,
750 			    XvImage *myimage) {
751 
752   lprintf ("dispose_ximage\n");
753   XFree(myimage);
754 }
755 #endif
756 
xvmc_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)757 static void xvmc_update_frame_format (vo_driver_t *this_gen,
758 				      vo_frame_t *frame_gen,
759 				      uint32_t width, uint32_t height,
760 				      double ratio, int format, int flags) {
761   xvmc_driver_t  *this  = (xvmc_driver_t *) this_gen;
762   xvmc_frame_t   *frame = (xvmc_frame_t *) frame_gen;
763   xine_xvmc_t *xvmc = (xine_xvmc_t *) frame_gen->accel_data;
764 
765   if (format != XINE_IMGFMT_XVMC) {
766     xprintf (this->xine, XINE_VERBOSITY_LOG, "xvmc_update_frame_format: frame format %08x not supported\n", format);
767     frame->vo_frame.width = frame->width = 0;
768     return;
769   }
770 
771   lprintf ("xvmc_update_frame_format\n");
772 
773   if ((frame->width != (int)width)
774       || (frame->height != (int)height)
775       || (frame->format != format)) {
776 
777     lprintf ("updating frame to %d x %d (ratio=%f, format=%08x)\n",
778 	     width, height, ratio, format);
779 
780     /* Note that since we are rendering in hardware, we do not need to
781      * allocate any ximage's for the software rendering buffers.
782      */
783     frame->width               = width;
784     frame->height              = height;
785     frame->format              = format;
786     frame->ratio               = ratio;
787   }
788 
789   xvmc->macroblocks = &this->macroblocks.xine_mc;
790   this->macroblocks.num_blocks = 0;
791   this->macroblocks.macroblockptr = this->macroblocks.macroblockbaseptr;
792   this->macroblocks.xine_mc.blockptr =
793     this->macroblocks.xine_mc.blockbaseptr;
794   if( flags & VO_NEW_SEQUENCE_FLAG ) {
795     xvmc_set_context (this, width, height, ratio, format, flags,
796                       xvmc->macroblocks);
797   }
798 }
799 
xvmc_clean_output_area(xvmc_driver_t * this)800 static void xvmc_clean_output_area (xvmc_driver_t *this) {
801   lprintf ("xvmc_clean_output_area\n");
802 
803   XLockDisplay (this->display);
804   XSetForeground (this->display, this->gc, this->black.pixel);
805   XFillRectangle (this->display, this->drawable, this->gc,
806 		  this->sc.gui_x, this->sc.gui_y, this->sc.gui_width, this->sc.gui_height);
807 
808   if (this->use_colorkey) {
809     XSetForeground (this->display, this->gc, this->colorkey);
810     XFillRectangle (this->display, this->drawable, this->gc,
811 		    this->sc.output_xoffset, this->sc.output_yoffset,
812 		    this->sc.output_width, this->sc.output_height);
813   }
814 
815   XUnlockDisplay (this->display);
816 }
817 
818 /*
819  * convert delivered height/width to ideal width/height
820  * taking into account aspect ratio and zoom factor
821  */
822 
xvmc_compute_ideal_size(xvmc_driver_t * this)823 static void xvmc_compute_ideal_size (xvmc_driver_t *this) {
824   _x_vo_scale_compute_ideal_size( &this->sc );
825 }
826 
827 /*
828  * make ideal width/height "fit" into the gui
829  */
830 
xvmc_compute_output_size(xvmc_driver_t * this)831 static void xvmc_compute_output_size (xvmc_driver_t *this) {
832  _x_vo_scale_compute_output_size( &this->sc );
833 }
834 
xvmc_overlay_blend(vo_driver_t * this_gen,vo_frame_t * frame_gen,vo_overlay_t * overlay)835 static void xvmc_overlay_blend (vo_driver_t *this_gen,
836 				vo_frame_t *frame_gen, vo_overlay_t *overlay) {
837   xvmc_driver_t  *this  = (xvmc_driver_t *) this_gen;
838   xvmc_frame_t   *frame = (xvmc_frame_t *) frame_gen;
839 
840   lprintf ("xvmc_overlay_blend\n");
841 
842   this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x;
843   this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y;
844 
845   /* Alpha Blend here
846    * As XV drivers improve to support Hardware overlay, we will change this function.
847    */
848 
849   if (overlay->rle) {
850     if (frame->format == XINE_IMGFMT_YV12)
851       _x_blend_yuv(frame->vo_frame.base, overlay,
852 		frame->width, frame->height, frame->vo_frame.pitches,
853                 &this->alphablend_extra_data);
854     else if (frame->format != XINE_IMGFMT_XVMC)
855       _x_blend_yuy2(frame->vo_frame.base[0], overlay,
856 		 frame->width, frame->height, frame->vo_frame.pitches[0],
857                  &this->alphablend_extra_data);
858     else
859       xprintf (this->xine, XINE_VERBOSITY_LOG, "xvmc_overlay_blend: overlay blending not supported for frame format %08x\n", frame->format);
860   }
861 }
862 
xvmc_add_recent_frame(xvmc_driver_t * this,xvmc_frame_t * frame)863 static void xvmc_add_recent_frame (xvmc_driver_t *this, xvmc_frame_t *frame) {
864   int i;
865 
866   lprintf ("xvmc_add_recent_frame\n");
867 
868   i = VO_NUM_RECENT_FRAMES-1;
869   if( this->recent_frames[i] )
870     this->recent_frames[i]->vo_frame.free
871        (&this->recent_frames[i]->vo_frame);
872 
873   for( ; i ; i-- )
874     this->recent_frames[i] = this->recent_frames[i-1];
875 
876   this->recent_frames[0] = frame;
877 }
878 
xv_flush_recent_frames(xvmc_driver_t * this)879 static int xv_flush_recent_frames (xvmc_driver_t *this) {
880   int i, n = 0;
881 
882   for (i = 0; i < VO_NUM_RECENT_FRAMES; i++) {
883     if (this->recent_frames[i]) {
884       this->recent_frames[i]->vo_frame.free (&this->recent_frames[i]->vo_frame);
885       this->recent_frames[i] = NULL;
886       n++;
887     }
888   }
889   return n;
890 }
891 
xvmc_redraw_needed(vo_driver_t * this_gen)892 static int xvmc_redraw_needed (vo_driver_t *this_gen) {
893   xvmc_driver_t  *this = (xvmc_driver_t *) this_gen;
894   int             ret  = 0;
895 
896   if(this->cur_frame) {
897 
898     this->sc.delivered_height   = this->cur_frame->height;
899     this->sc.delivered_width    = this->cur_frame->width;
900     this->sc.delivered_ratio    = this->cur_frame->ratio;
901 
902     this->sc.crop_left          = this->cur_frame->vo_frame.crop_left;
903     this->sc.crop_right         = this->cur_frame->vo_frame.crop_right;
904     this->sc.crop_top           = this->cur_frame->vo_frame.crop_top;
905     this->sc.crop_bottom        = this->cur_frame->vo_frame.crop_bottom;
906 
907     xvmc_compute_ideal_size(this);
908 
909     if(_x_vo_scale_redraw_needed(&this->sc)) {
910       xvmc_compute_output_size (this);
911       xvmc_clean_output_area (this);
912       ret = 1;
913     }
914   }
915   else
916     ret = 1;
917 
918   return ret;
919 }
920 
xvmc_display_frame(vo_driver_t * this_gen,vo_frame_t * frame_gen)921 static void xvmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) {
922   xvmc_driver_t  *this  = (xvmc_driver_t *) this_gen;
923   xvmc_frame_t   *frame = (xvmc_frame_t *) frame_gen;
924 
925   lprintf ("xvmc_display_frame %d %p\n", frame_gen->id, (void *)frame_gen);
926 
927   /*
928    * queue frames (deinterlacing)
929    * free old frames
930    */
931 
932   xvmc_add_recent_frame (this, frame); /* deinterlacing */
933 
934   this->cur_frame = frame;
935 
936   /*
937    * let's see if this frame is different in size / aspect
938    * ratio from the previous one
939    */
940 
941   if ( (frame->width != this->sc.delivered_width)
942        || (frame->height != this->sc.delivered_height)
943        || (frame->ratio != this->sc.delivered_ratio)
944        || (frame->vo_frame.crop_left != this->sc.crop_left)
945        || (frame->vo_frame.crop_right != this->sc.crop_right)
946        || (frame->vo_frame.crop_top != this->sc.crop_top)
947        || (frame->vo_frame.crop_bottom != this->sc.crop_bottom) ) {
948     lprintf("frame format changed\n");
949 
950     /*
951        this->delivered_width      = frame->width;
952        this->delivered_height     = frame->height;
953        this->delivered_ratio      = frame->ratio;
954        this->delivered_duration   = frame->vo_frame.duration;
955 
956        xvmc_compute_ideal_size (this);
957     */
958 
959     /* this->gui_width = 0; */ /* trigger re-calc of output size */
960     this->sc.force_redraw = 1;    /* trigger re-calc of output size */
961   }
962 
963   /*
964    * tell gui that we are about to display a frame,
965    * ask for offset and output size
966    */
967   xvmc_redraw_needed (this_gen);
968 
969   XLockDisplay (this->display);
970 
971   /* Make sure the surface has finished rendering before we display */
972   XvMCSyncSurface(this->display, &this->cur_frame->surface);
973 
974   XvMCPutSurface(this->display, &this->cur_frame->surface,
975 		 this->drawable,
976 		 this->sc.displayed_xoffset, this->sc.displayed_yoffset,
977 		 this->sc.displayed_width, this->sc.displayed_height,
978 		 this->sc.output_xoffset, this->sc.output_yoffset,
979 		 this->sc.output_width, this->sc.output_height,
980 		 XVMC_FRAME_PICTURE);
981 
982   XUnlockDisplay (this->display);
983 
984   /*
985   printf ("video_out_xvmc: xvmc_display_frame... done\n");
986   */
987 }
988 
xvmc_get_property(vo_driver_t * this_gen,int property)989 static int xvmc_get_property (vo_driver_t *this_gen, int property) {
990   xvmc_driver_t *this = (xvmc_driver_t *) this_gen;
991 
992   lprintf ("xvmc_get_property\n");
993 
994   if ((property < 0) || (property >= VO_NUM_PROPERTIES)) return 0;
995 
996   switch (property) {
997     case VO_PROP_WINDOW_WIDTH:
998       this->props[property].value = this->sc.gui_width;
999       break;
1000     case VO_PROP_WINDOW_HEIGHT:
1001       this->props[property].value = this->sc.gui_height;
1002       break;
1003     case VO_PROP_OUTPUT_WIDTH:
1004       this->props[property].value = this->sc.output_width;
1005       break;
1006     case VO_PROP_OUTPUT_HEIGHT:
1007       this->props[property].value = this->sc.output_height;
1008       break;
1009     case VO_PROP_OUTPUT_XOFFSET:
1010       this->props[property].value = this->sc.output_xoffset;
1011       break;
1012     case VO_PROP_OUTPUT_YOFFSET:
1013       this->props[property].value = this->sc.output_yoffset;
1014       break;
1015   }
1016 
1017   return this->props[property].value;
1018 }
1019 
xvmc_property_callback(void * property_gen,xine_cfg_entry_t * entry)1020 static void xvmc_property_callback (void *property_gen, xine_cfg_entry_t *entry) {
1021   xvmc_property_t *property = (xvmc_property_t *) property_gen;
1022   xvmc_driver_t   *this     = property->this;
1023 
1024   lprintf ("xvmc_property_callback\n");
1025 
1026   XLockDisplay(this->display);
1027   XvSetPortAttribute (this->display, this->xv_port,
1028 		      property->atom, entry->num_value);
1029   XUnlockDisplay(this->display);
1030 }
1031 
xvmc_set_property(vo_driver_t * this_gen,int property,int value)1032 static int xvmc_set_property (vo_driver_t *this_gen,
1033 			    int property, int value) {
1034   xvmc_driver_t *this = (xvmc_driver_t *) this_gen;
1035 
1036   lprintf ("xvmc_set_property %d value %d\n",property,value);
1037 
1038   if ((property < 0) || (property >= VO_NUM_PROPERTIES)) return 0;
1039 
1040   if (this->props[property].atom != None) {
1041     /* value is out of bound */
1042     if((value < this->props[property].min) || (value > this->props[property].max))
1043       value = (this->props[property].min + this->props[property].max) >> 1;
1044 
1045     XLockDisplay(this->display);
1046     XvSetPortAttribute (this->display, this->xv_port,
1047 			this->props[property].atom, value);
1048     XvGetPortAttribute (this->display, this->xv_port,
1049 			this->props[property].atom,
1050 			&this->props[property].value);
1051     XUnlockDisplay(this->display);
1052 
1053     if (this->props[property].entry)
1054       this->props[property].entry->num_value = this->props[property].value;
1055 
1056     return this->props[property].value;
1057   }
1058   else {
1059     switch (property) {
1060     case VO_PROP_DISCARD_FRAMES:
1061       if (value == -1)
1062         value = xv_flush_recent_frames (this);
1063       break;
1064 
1065     case VO_PROP_ASPECT_RATIO:
1066       if (value>=XINE_VO_ASPECT_NUM_RATIOS)
1067 	value = XINE_VO_ASPECT_AUTO;
1068 
1069       this->props[property].value = value;
1070       lprintf("VO_PROP_ASPECT_RATIO(%d)\n", this->props[property].value);
1071 
1072       xvmc_compute_ideal_size (this);
1073       xvmc_compute_output_size (this);
1074       xvmc_clean_output_area (this);
1075 
1076       break;
1077 
1078     case VO_PROP_ZOOM_X:
1079       if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
1080         this->props[property].value = value;
1081         xprintf (this->xine, XINE_VERBOSITY_DEBUG,
1082 		 "video_out_xvmc: VO_PROP_ZOOM_X = %d\n", this->props[property].value);
1083 
1084 	this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP;
1085 	xvmc_compute_ideal_size (this);
1086 	this->sc.force_redraw = 1;    /* trigger re-calc of output size */
1087       }
1088       break;
1089 
1090     case VO_PROP_ZOOM_Y:
1091       if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) {
1092         this->props[property].value = value;
1093         xprintf (this->xine, XINE_VERBOSITY_DEBUG,
1094 		 "video_out_xvmc: VO_PROP_ZOOM_Y = %d\n", this->props[property].value);
1095 
1096 	this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP;
1097 	xvmc_compute_ideal_size (this);
1098 	this->sc.force_redraw = 1;    /* trigger re-calc of output size */
1099       }
1100       break;
1101     }
1102   }
1103 
1104   return value;
1105 }
1106 
xvmc_get_property_min_max(vo_driver_t * this_gen,int property,int * min,int * max)1107 static void xvmc_get_property_min_max (vo_driver_t *this_gen,
1108 				     int property, int *min, int *max) {
1109   xvmc_driver_t *this = (xvmc_driver_t *) this_gen;
1110 
1111   lprintf ("xvmc_get_property_min_max\n");
1112 
1113   if ((property < 0) || (property >= VO_NUM_PROPERTIES)) {
1114     *min = *max = 0;
1115     return;
1116   }
1117   *min = this->props[property].min;
1118   *max = this->props[property].max;
1119 }
1120 
xvmc_gui_data_exchange(vo_driver_t * this_gen,int data_type,void * data)1121 static int xvmc_gui_data_exchange (vo_driver_t *this_gen,
1122 				   int data_type, void *data) {
1123   xvmc_driver_t     *this = (xvmc_driver_t *) this_gen;
1124 
1125   lprintf ("xvmc_gui_data_exchange\n");
1126 
1127   switch (data_type) {
1128   case XINE_GUI_SEND_EXPOSE_EVENT: {
1129     /* XExposeEvent * xev = (XExposeEvent *) data; */
1130 
1131     /* FIXME : take care of completion events */
1132     lprintf ("XINE_GUI_SEND_EXPOSE_EVENT\n");
1133 
1134     if (this->cur_frame) {
1135       int i;
1136 
1137       XLockDisplay (this->display);
1138 
1139       XSetForeground (this->display, this->gc, this->black.pixel);
1140 
1141       for( i = 0; i < 4; i++ ) {
1142         if( this->sc.border[i].w && this->sc.border[i].h )
1143           XFillRectangle(this->display, this->drawable, this->gc,
1144                          this->sc.border[i].x, this->sc.border[i].y,
1145                          this->sc.border[i].w, this->sc.border[i].h);
1146       }
1147 
1148       if (this->use_colorkey) {
1149 	XSetForeground (this->display, this->gc, this->colorkey);
1150 	XFillRectangle (this->display, this->drawable, this->gc,
1151 			this->sc.output_xoffset, this->sc.output_yoffset,
1152 			this->sc.output_width, this->sc.output_height);
1153       }
1154 
1155       XvMCPutSurface(this->display, &this->cur_frame->surface,
1156 		     this->drawable,
1157 		     this->sc.displayed_xoffset, this->sc.displayed_yoffset,
1158 		     this->sc.displayed_width, this->sc.displayed_height,
1159 		     this->sc.output_xoffset, this->sc.output_yoffset,
1160 		     this->sc.output_width, this->sc.output_height,
1161 		     XVMC_FRAME_PICTURE);
1162 
1163       XSync(this->display, False);
1164       XUnlockDisplay (this->display);
1165     }
1166   }
1167   break;
1168 
1169   case XINE_GUI_SEND_DRAWABLE_CHANGED:
1170     this->drawable = (Drawable) data;
1171     XLockDisplay(this->display);
1172     this->gc       = XCreateGC (this->display, this->drawable, 0, NULL);
1173     XUnlockDisplay(this->display);
1174     break;
1175 
1176   case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO:
1177     {
1178       int x1, y1, x2, y2;
1179       x11_rectangle_t *rect = data;
1180 
1181       /*
1182 	 xvmc_translate_gui2video(this, rect->x, rect->y,
1183 		                  &x1, &y1);
1184 	xvmc_translate_gui2video(this, rect->x + rect->w, rect->y + rect->h,
1185 				 &x2, &y2);
1186       */
1187 
1188       _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y,
1189 				   &x1, &y1);
1190       _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h,
1191 				   &x2, &y2);
1192 
1193       rect->x = x1;
1194       rect->y = y1;
1195       rect->w = x2-x1;
1196       rect->h = y2-y1;
1197     }
1198     break;
1199 
1200   default:
1201     return -1;
1202   }
1203 
1204   return 0;
1205 }
1206 
xvmc_dispose(vo_driver_t * this_gen)1207 static void xvmc_dispose (vo_driver_t *this_gen) {
1208   xvmc_driver_t *this = (xvmc_driver_t *) this_gen;
1209   int i;
1210 
1211   lprintf ("xvmc_dispose\n");
1212 
1213   if(this->context_id.xid) {
1214     XLockDisplay(this->display);
1215     for(i = 0; i < this->num_frame_buffers; i++) {
1216       /* if(useOverlay)  *//* only one is displaying but I don't want to keep track*/
1217       XvMCHideSurface(this->display, &this->frames[i]->surface);
1218       XvMCDestroySurface(this->display, &this->frames[i]->surface);
1219     }
1220     /* XvMCDestroyBlocks(this->display, &macroblocks->blocks); */
1221     /* XvMCDestroyMacroBlocks(this->display, &macroblocks->macro_blocks); */
1222     XvMCDestroyContext(this->display, &this->context);
1223     XUnlockDisplay(this->display);
1224   }
1225 
1226   XLockDisplay (this->display);
1227   XFreeGC(this->display, this->gc);
1228   if(XvUngrabPort (this->display, this->xv_port, CurrentTime) != Success) {
1229     lprintf ("xvmc_dispose: XvUngrabPort() failed.\n");
1230   }
1231   XUnlockDisplay (this->display);
1232 
1233   for( i=0; i < VO_NUM_RECENT_FRAMES; i++ ) {
1234     if(this->recent_frames[i])
1235       this->recent_frames[i]->vo_frame.dispose
1236 	(&this->recent_frames[i]->vo_frame);
1237     this->recent_frames[i] = NULL;
1238   }
1239 
1240   _x_alphablend_free(&this->alphablend_extra_data);
1241   _x_vo_scale_cleanup (&this->sc, this->xine->config);
1242 
1243   free (this);
1244 }
1245 
1246 /* called xlocked */
xvmc_check_capability(xvmc_driver_t * this,int property,XvAttribute attr,int base_id,const char * config_name,const char * config_desc,const char * config_help)1247 static void xvmc_check_capability (xvmc_driver_t *this,
1248 				   int property, XvAttribute attr, int base_id,
1249 				   const char *config_name,
1250 				   const char *config_desc,
1251 				   const char *config_help) {
1252   int          int_default;
1253   cfg_entry_t *entry;
1254   const char  *str_prop = attr.name;
1255 
1256   (void)base_id;
1257   /*
1258    * some Xv drivers (Gatos ATI) report some ~0 as max values, this is confusing.
1259    */
1260   if (attr.max_value == ~0)
1261     attr.max_value = 2147483615;
1262 
1263   this->props[property].min  = attr.min_value;
1264   this->props[property].max  = attr.max_value;
1265   this->props[property].atom = XInternAtom (this->display, str_prop, False);
1266 
1267   XvGetPortAttribute (this->display, this->xv_port,
1268 		      this->props[property].atom, &int_default);
1269 
1270   xprintf (this->xine, XINE_VERBOSITY_DEBUG,
1271 	   "video_out_xvmc: port attribute %s (%d) value is %d\n", str_prop, property, int_default);
1272 
1273   if (config_name) {
1274     /* is this a boolean property ? */
1275     if ((attr.min_value == 0) && (attr.max_value == 1)) {
1276       this->config->register_bool (this->config, config_name, int_default,
1277 				   config_desc,
1278 				   config_help, 20, xvmc_property_callback, &this->props[property]);
1279 
1280     } else {
1281       this->config->register_range (this->config, config_name, int_default,
1282 				    this->props[property].min, this->props[property].max,
1283 				    config_desc,
1284 				    config_help, 20, xvmc_property_callback, &this->props[property]);
1285     }
1286 
1287     entry = this->config->lookup_entry (this->config, config_name);
1288 
1289     this->props[property].entry = entry;
1290 
1291     xvmc_set_property (&this->vo_driver, property, entry->num_value);
1292 
1293     if (strcmp(str_prop,"XV_COLORKEY") == 0) {
1294       this->use_colorkey = 1;
1295       this->colorkey     = entry->num_value;
1296     }
1297   }
1298   else
1299     this->props[property].value  = int_default;
1300 }
1301 
xvmc_update_XV_DOUBLE_BUFFER(void * this_gen,xine_cfg_entry_t * entry)1302 static void xvmc_update_XV_DOUBLE_BUFFER(void *this_gen, xine_cfg_entry_t *entry)
1303 {
1304   xvmc_driver_t *this = (xvmc_driver_t *) this_gen;
1305   Atom           atom;
1306   int            xvmc_double_buffer;
1307 
1308   xvmc_double_buffer = entry->num_value;
1309 
1310   XLockDisplay(this->display);
1311   atom = XInternAtom (this->display, "XV_DOUBLE_BUFFER", False);
1312   XvSetPortAttribute (this->display, this->xv_port, atom, xvmc_double_buffer);
1313   XUnlockDisplay(this->display);
1314 
1315   lprintf("double buffering mode = %d\n",xvmc_double_buffer);
1316 }
1317 
open_plugin(video_driver_class_t * class_gen,const void * visual_gen)1318 static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *visual_gen) {
1319   xvmc_class_t         *class   = (xvmc_class_t *) class_gen;
1320   config_values_t      *config  = class->xine->config;
1321   xvmc_driver_t        *this    = NULL;
1322   unsigned int          i, formats;
1323   XvPortID              xv_port = class->xv_port;
1324   XvAttribute          *attr;
1325   XvImageFormatValues  *fo;
1326   int                   nattr;
1327   const x11_visual_t   *visual  = (const x11_visual_t *) visual_gen;
1328   XColor                dummy;
1329   XvAdaptorInfo        *adaptor_info = class->adaptor_info;
1330   unsigned int          adaptor_num  = class->adaptor_num;
1331   /* XvImage              *myimage; */
1332 
1333   lprintf ("open_plugin\n");
1334 
1335   /* TODO ???  */
1336   this = calloc(1, sizeof (xvmc_driver_t));
1337 
1338   if (!this)
1339     return NULL;
1340 
1341   _x_alphablend_init(&this->alphablend_extra_data, class->xine);
1342 
1343   this->display            = visual->display;
1344   this->overlay            = NULL;
1345   this->screen             = visual->screen;
1346   this->xv_port            = class->xv_port;
1347   this->config             = config;
1348   this->xine               = class->xine;
1349 
1350   _x_vo_scale_init (&this->sc, 1, 0, config );
1351 
1352   this->sc.frame_output_cb   = visual->frame_output_cb;
1353   this->sc.user_data         = visual->user_data;
1354 
1355   this->drawable           = visual->d;
1356   XLockDisplay(this->display);
1357   this->gc                 = XCreateGC(this->display, this->drawable, 0, NULL);
1358   XUnlockDisplay(this->display);
1359   this->capabilities       = VO_CAP_XVMC_MOCOMP | VO_CAP_CROP | VO_CAP_ZOOM_X | VO_CAP_ZOOM_Y;
1360 
1361   this->surface_type_id    = class->surface_type_id;
1362   this->max_surface_width  = class->max_surface_width;
1363   this->max_surface_height = class->max_surface_height;
1364   this->context_id.xid     = NULL;
1365   this->num_frame_buffers  = 0;
1366   this->acceleration       = class->acceleration;
1367 
1368   /* TODO CLEAN UP THIS */
1369   this->user_data          = visual->user_data;
1370 
1371   this->use_colorkey       = 0;
1372   this->colorkey           = 0;
1373 
1374   XLockDisplay(this->display);
1375   XAllocNamedColor(this->display,
1376 		   DefaultColormap(this->display, this->screen),
1377 		   "black", &this->black, &dummy);
1378   XUnlockDisplay(this->display);
1379 
1380   this->vo_driver.get_capabilities     = xvmc_get_capabilities;
1381   this->vo_driver.alloc_frame          = xvmc_alloc_frame;
1382   this->vo_driver.update_frame_format  = xvmc_update_frame_format;
1383   this->vo_driver.overlay_blend        = xvmc_overlay_blend;
1384   this->vo_driver.display_frame        = xvmc_display_frame;
1385   this->vo_driver.get_property         = xvmc_get_property;
1386   this->vo_driver.set_property         = xvmc_set_property;
1387   this->vo_driver.get_property_min_max = xvmc_get_property_min_max;
1388   this->vo_driver.gui_data_exchange    = xvmc_gui_data_exchange;
1389   this->vo_driver.dispose              = xvmc_dispose;
1390   this->vo_driver.redraw_needed        = xvmc_redraw_needed;
1391 
1392   /*
1393    * init properties
1394    */
1395   for (i=0; i<VO_NUM_PROPERTIES; i++) {
1396     this->props[i].value = 0;
1397     this->props[i].min   = 0;
1398     this->props[i].max   = 0;
1399     this->props[i].atom  = None;
1400     this->props[i].entry = NULL;
1401     this->props[i].this  = this;
1402   }
1403 
1404   this->props[VO_PROP_INTERLACED].value     = 0;
1405   this->props[VO_PROP_ASPECT_RATIO].value   = XINE_VO_ASPECT_AUTO;
1406   this->props[VO_PROP_ZOOM_X].value         = 100;
1407   this->props[VO_PROP_ZOOM_Y].value         = 100;
1408   this->props[VO_PROP_MAX_NUM_FRAMES].value = MAX_NUM_FRAMES;
1409 
1410   /*
1411    * check this adaptor's capabilities
1412    */
1413   if(this->acceleration&XINE_VO_IDCT_ACCEL)
1414     this->capabilities |= VO_CAP_XVMC_IDCT;
1415 
1416   XLockDisplay(this->display);
1417   attr = XvQueryPortAttributes(this->display, xv_port, &nattr);
1418   if(attr && nattr) {
1419     int k;
1420 
1421     for(k = 0; k < nattr; k++) {
1422       if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) {
1423 	const char *const name = attr[k].name;
1424 	if(!strcmp(name, "XV_HUE")) {
1425 	  if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) {
1426             xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n");
1427 	  } else {
1428 	    this->capabilities |= VO_CAP_HUE;
1429 	    xvmc_check_capability (this, VO_PROP_HUE, attr[k],
1430 				   adaptor_info[adaptor_num].base_id,
1431 				   NULL, NULL, NULL);
1432 	  }
1433 	} else if(!strcmp(name, "XV_SATURATION")) {
1434 	  this->capabilities |= VO_CAP_SATURATION;
1435 	  xvmc_check_capability (this, VO_PROP_SATURATION, attr[k],
1436 				 adaptor_info[adaptor_num].base_id,
1437 				 NULL, NULL, NULL);
1438 	} else if(!strcmp(attr[k].name, "XV_BRIGHTNESS")) {
1439 	  this->capabilities |= VO_CAP_BRIGHTNESS;
1440 	  xvmc_check_capability (this, VO_PROP_BRIGHTNESS, attr[k],
1441 				 adaptor_info[adaptor_num].base_id,
1442 				 NULL, NULL, NULL);
1443 	} else if(!strcmp(name, "XV_CONTRAST")) {
1444 	  this->capabilities |= VO_CAP_CONTRAST;
1445 	  xvmc_check_capability (this, VO_PROP_CONTRAST, attr[k],
1446 				 adaptor_info[adaptor_num].base_id,
1447 				 NULL, NULL, NULL);
1448 	} else if(!strcmp(name, "XV_GAMMA")) {
1449 	  this->capabilities |= VO_CAP_GAMMA;
1450 	  xvmc_check_capability (this, VO_PROP_GAMMA, attr[k],
1451 				 adaptor_info[adaptor_num].base_id,
1452 				 NULL, NULL, NULL);
1453 	} else if(!strcmp(name, "XV_COLORKEY")) {
1454 	  this->capabilities |= VO_CAP_COLORKEY;
1455 	  xvmc_check_capability (this, VO_PROP_COLORKEY, attr[k],
1456 				 adaptor_info[adaptor_num].base_id,
1457 				 "video.device.xv_colorkey",
1458 				 VIDEO_DEVICE_XV_COLORKEY_HELP);
1459 	} else if(!strcmp(name, "XV_AUTOPAINT_COLORKEY")) {
1460 	  this->capabilities |= VO_CAP_AUTOPAINT_COLORKEY;
1461 	  xvmc_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attr[k],
1462 				 adaptor_info[adaptor_num].base_id,
1463 				 "video.device.xv_autopaint_colorkey",
1464 				 VIDEO_DEVICE_XV_AUTOPAINT_COLORKEY_HELP);
1465 	} else if(!strcmp(name, "XV_DOUBLE_BUFFER")) {
1466 	  int xvmc_double_buffer = config->register_bool (config, "video.device.xv_double_buffer", 1,
1467 				   VIDEO_DEVICE_XV_DOUBLE_BUFFER_HELP,
1468 				   20, xvmc_update_XV_DOUBLE_BUFFER, this);
1469 	  config->update_num(config,"video.device.xv_double_buffer",xvmc_double_buffer);
1470 	}
1471       }
1472     }
1473     XFree(attr);
1474   }
1475   else {
1476     xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_xvmc: no port attributes defined.\n");
1477   }
1478 
1479 
1480   /*
1481    * check supported image formats
1482    */
1483   fo = XvListImageFormats(this->display, this->xv_port, (int*)&formats);
1484   XUnlockDisplay(this->display);
1485 
1486   this->xvmc_format_yv12 = 0;
1487   this->xvmc_format_yuy2 = 0;
1488 
1489   for(i = 0; i < formats; i++) {
1490     lprintf ("XvMC image format: 0x%x (%4.4s) %s\n",
1491 	     fo[i].id, (char*)&fo[i].id,
1492 	     (fo[i].format == XvPacked) ? "packed" : "planar");
1493 
1494     switch (fo[i].id) {
1495     case XINE_IMGFMT_YV12:
1496       this->xvmc_format_yv12 = fo[i].id;
1497       this->capabilities |= VO_CAP_YV12;
1498       xprintf(this->xine, XINE_VERBOSITY_LOG,
1499 	      _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YV12");
1500       break;
1501     case XINE_IMGFMT_YUY2:
1502       this->xvmc_format_yuy2 = fo[i].id;
1503       this->capabilities |= VO_CAP_YUY2;
1504       xprintf(this->xine, XINE_VERBOSITY_LOG,
1505 	      _("%s: this adaptor supports the %s format.\n"), LOG_MODULE, "YUY2");
1506       break;
1507     default:
1508       break;
1509     }
1510   }
1511 
1512   if(fo) {
1513     XLockDisplay(this->display);
1514     XFree(fo);
1515     XUnlockDisplay(this->display);
1516   }
1517 
1518   /*
1519    * try to create a shared image
1520    * to find out if MIT shm really works, using supported format
1521    */
1522   /*
1523     XLockDisplay(this->display);
1524     myimage = create_ximage (this, &myshminfo, 100, 100,
1525                              (this->xvmc_format_yv12 != 0) ? XINE_IMGFMT_YV12 : IMGFMT_YUY2);
1526     dispose_ximage (this, &myshminfo, myimage);
1527     XUnLockDisplay(this->display);
1528   */
1529 
1530   lprintf("initialization of plugin successful\n");
1531   return &this->vo_driver;
1532 }
1533 
1534 /*
1535  * class functions
1536  */
1537 
dispose_class(video_driver_class_t * this_gen)1538 static void dispose_class (video_driver_class_t *this_gen) {
1539   xvmc_class_t        *this = (xvmc_class_t *) this_gen;
1540 
1541   XLockDisplay(this->display);
1542   XvFreeAdaptorInfo (this->adaptor_info);
1543   XUnlockDisplay(this->display);
1544 
1545   free (this);
1546 }
1547 
init_class(xine_t * xine,const void * visual_gen)1548 static void *init_class (xine_t *xine, const void *visual_gen) {
1549   const x11_visual_t *visual = (const x11_visual_t *) visual_gen;
1550   xvmc_class_t      *this;
1551   Display           *display = NULL;
1552   unsigned int       adaptors, j = 0;
1553   unsigned int       ver,rel,req,ev,err;
1554   XvPortID           xv_port;
1555   XvAdaptorInfo     *adaptor_info;
1556   unsigned int       adaptor_num;
1557   /* XvMC */
1558   int                IDCTaccel = 0;
1559   int                useOverlay = 0;
1560   int                unsignedIntra = 0;
1561   unsigned int       surface_num, types;
1562   unsigned int       max_width=0, max_height=0;
1563   XvMCSurfaceInfo   *surfaceInfo;
1564   int                surface_type = 0;
1565 
1566   display = visual->display;
1567 
1568   /*
1569    * check for Xv and  XvMC video support
1570    */
1571   lprintf ("XvMC init_class\n");
1572 
1573   XLockDisplay(display);
1574   if (Success != XvQueryExtension(display, &ver, &rel, &req, &ev, &err)) {
1575     xprintf (xine, XINE_VERBOSITY_DEBUG, "video_out_xvmc: Xv extension not present.\n");
1576     XUnlockDisplay(display);
1577     return NULL;
1578   }
1579 
1580   if(!XvMCQueryExtension(display, &ev, &err)) {
1581     xprintf (xine, XINE_VERBOSITY_LOG, _("video_out_xvmc: XvMC extension not present.\n"));
1582     XUnlockDisplay(display);
1583     return 0;
1584   }
1585 
1586   /*
1587    * check adaptors, search for one that supports (at least) yuv12
1588    */
1589 
1590   if(Success != XvQueryAdaptors(display, DefaultRootWindow(display),
1591 				&adaptors, &adaptor_info))  {
1592     xprintf (xine, XINE_VERBOSITY_DEBUG, "video_out_xvmc: XvQueryAdaptors failed.\n");
1593     XUnlockDisplay(display);
1594     return 0;
1595   }
1596 
1597   xv_port = 0;
1598 
1599   for ( adaptor_num = 0; (adaptor_num < adaptors) && !xv_port; adaptor_num++ ) {
1600     xprintf (xine, XINE_VERBOSITY_DEBUG, "video_out_xvmc: checking adaptor %d\n",adaptor_num);
1601     if (adaptor_info[adaptor_num].type & XvImageMask) {
1602       surfaceInfo = XvMCListSurfaceTypes(display, adaptor_info[adaptor_num].base_id,
1603 					 &types);
1604       if(surfaceInfo) {
1605 	for(surface_num  = 0; surface_num < types; surface_num++) {
1606 	  if((surfaceInfo[surface_num].chroma_format == XVMC_CHROMA_FORMAT_420) &&
1607 	     (surfaceInfo[surface_num].mc_type == (XVMC_IDCT | XVMC_MPEG_2))) {
1608 
1609 	    max_width  = surfaceInfo[surface_num].max_width;
1610 	    max_height = surfaceInfo[surface_num].max_height;
1611 
1612 	    for(j = 0; j < adaptor_info[adaptor_num].num_ports; j++) {
1613 	      /* try to grab a port */
1614 	      if(Success == XvGrabPort(display,
1615 				       adaptor_info[adaptor_num].base_id + j, CurrentTime)) {
1616 		xv_port = adaptor_info[adaptor_num].base_id + j;
1617 		surface_type = surfaceInfo[surface_num].surface_type_id;
1618 		break;
1619 	      }
1620 	    }
1621 
1622 	    if(xv_port)
1623 	      break;
1624 	  }
1625 	}
1626 
1627 	if(!xv_port) { /* try for just XVMC_MOCOMP  */
1628 	  xprintf (xine, XINE_VERBOSITY_DEBUG, "didn't find XVMC_IDCT acceleration trying for MC\n");
1629 
1630 	  for(surface_num  = 0; surface_num < types; surface_num++) {
1631 	    if((surfaceInfo[surface_num].chroma_format == XVMC_CHROMA_FORMAT_420) &&
1632 	       ((surfaceInfo[surface_num].mc_type == (XVMC_MOCOMP | XVMC_MPEG_2)))) {
1633 
1634 	      xprintf (xine, XINE_VERBOSITY_DEBUG, "Found XVMC_MOCOMP\n");
1635 	      max_width = surfaceInfo[surface_num].max_width;
1636 	      max_height = surfaceInfo[surface_num].max_height;
1637 
1638 	      for(j = 0; j < adaptor_info[adaptor_num].num_ports; j++) {
1639 		/* try to grab a port */
1640 		if(Success == XvGrabPort(display,
1641 					 adaptor_info[adaptor_num].base_id + j, CurrentTime)) {
1642 		  xv_port = adaptor_info[adaptor_num].base_id + j;
1643 		  surface_type = surfaceInfo[surface_num].surface_type_id;
1644 		  break;
1645 		}
1646 	      }
1647 
1648 	      if(xv_port)
1649 		break;
1650 	    }
1651 	  }
1652 	}
1653 	if(xv_port) {
1654 	  lprintf ("port %ld surface %d\n",xv_port,j);
1655 
1656           IDCTaccel = 0;
1657 	  if(surfaceInfo[surface_num].flags & XVMC_OVERLAID_SURFACE)
1658 	    useOverlay = 1;
1659 	  if(surfaceInfo[surface_num].flags & XVMC_INTRA_UNSIGNED)
1660 	    unsignedIntra = 1;
1661 	  if(surfaceInfo[surface_num].mc_type == (XVMC_IDCT | XVMC_MPEG_2))
1662 	    IDCTaccel |= XINE_VO_IDCT_ACCEL | XINE_VO_MOTION_ACCEL;
1663 	  else if(surfaceInfo[surface_num].mc_type == (XVMC_MOCOMP | XVMC_MPEG_2)) {
1664 	    IDCTaccel |= XINE_VO_MOTION_ACCEL;
1665 	    if(!unsignedIntra)
1666 	      IDCTaccel |= XINE_VO_SIGNED_INTRA;
1667 	  }
1668 	  xprintf (xine, XINE_VERBOSITY_DEBUG, "video_out_xvmc: IDCTaccel %02x\n",IDCTaccel);
1669 	  break;
1670 	}
1671 	XFree(surfaceInfo);
1672       }
1673     }
1674   } /* outer for adaptor_num loop */
1675 
1676 
1677   if (!xv_port) {
1678     xprintf (xine, XINE_VERBOSITY_LOG,
1679 	     _("video_out_xvmc: Xv extension is present but I couldn't find a usable yuv12 port.\n"));
1680     xprintf (xine, XINE_VERBOSITY_LOG, "              Looks like your graphics hardware "
1681 	     "driver doesn't support Xv?!\n");
1682     /* XvFreeAdaptorInfo (adaptor_info); this crashed on me (gb)*/
1683     XUnlockDisplay(display);
1684     return NULL;
1685   }
1686   else {
1687     xprintf (xine, XINE_VERBOSITY_LOG,
1688 	     _("video_out_xvmc: using Xv port %ld from adaptor %s\n"
1689 	       "                for hardware colour space conversion and scaling\n"),
1690 	     xv_port, adaptor_info[adaptor_num].name);
1691 
1692     if(IDCTaccel&XINE_VO_IDCT_ACCEL)
1693       xprintf (xine, XINE_VERBOSITY_LOG, _("                idct and motion compensation acceleration \n"));
1694     else if (IDCTaccel&XINE_VO_MOTION_ACCEL)
1695       xprintf (xine, XINE_VERBOSITY_LOG, _("                motion compensation acceleration only\n"));
1696     else
1697       xprintf (xine, XINE_VERBOSITY_LOG, _("                no XvMC support \n"));
1698     xprintf (xine, XINE_VERBOSITY_LOG, _("                With Overlay = %d; UnsignedIntra = %d.\n"),
1699 	     useOverlay, unsignedIntra);
1700   }
1701 
1702   XUnlockDisplay(display);
1703 
1704   this = (xvmc_class_t *) malloc (sizeof (xvmc_class_t));
1705 
1706   if (!this)
1707     return NULL;
1708 
1709   this->driver_class.open_plugin     = open_plugin;
1710   this->driver_class.identifier      = "XvMC";
1711   this->driver_class.description     = N_("xine video output plugin using the XvMC X video extension");
1712   this->driver_class.dispose         = dispose_class;
1713 
1714   this->display                      = display;
1715   this->xv_port                      = xv_port;
1716   this->adaptor_info                 = adaptor_info;
1717   this->adaptor_num                  = adaptor_num;
1718   this->surface_type_id              = surface_type;
1719   this->max_surface_width            = max_width;
1720   this->max_surface_height           = max_height;
1721   this->acceleration                 = IDCTaccel;
1722 
1723   this->xine                         = xine;
1724 
1725   lprintf("init_class done\n");
1726 
1727   return this;
1728 }
1729 
1730 static const vo_info_t vo_info_xvmc = {
1731   /* priority must be low until it supports displaying non-accelerated stuff */
1732   .priority    = 0,
1733   .visual_type = XINE_VISUAL_TYPE_X11,
1734 };
1735 
1736 /*
1737  * exported plugin catalog entry
1738  */
1739 
1740 const plugin_info_t xine_plugin_info[] EXPORTED = {
1741   /* type, API, "name", version, special_info, init_function */
1742   { PLUGIN_VIDEO_OUT, 22, "xvmc", XINE_VERSION_CODE, &vo_info_xvmc, init_class },
1743   { PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
1744 };
1745 
1746 #endif
1747