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 ¤t_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 ¤t_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 ¤t_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 ¤t_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, ¤t_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, ¯oblocks->blocks); */
1221 /* XvMCDestroyMacroBlocks(this->display, ¯oblocks->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