clean up of -geometry code.
[mplayer/glamo.git] / libvo / vo_xv.c
blobe8e905483341551adb36cb53047aab397ee6ad53
1 /* vo_xv.c, X11 Xv interface */
3 // Number of buffers _FOR_DOUBLEBUFFERING_MODE_
4 // Use option -double to enable double buffering! (default: single buffer)
5 #define NUM_BUFFERS 3
7 /*
8 Buffer allocation:
10 -nodr:
11 1: TEMP
12 2: 2*TEMP
14 -dr:
15 1: TEMP
16 3: 2*STATIC+TEMP
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "config.h"
24 #include "mp_msg.h"
25 #include "video_out.h"
26 #include "video_out_internal.h"
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <errno.h>
33 #include "x11_common.h"
35 #include "fastmemcpy.h"
36 #include "sub.h"
37 #include "aspect.h"
39 #include "../postproc/rgb2rgb.h"
41 #ifdef HAVE_NEW_GUI
42 #include "../Gui/interface.h"
43 #endif
45 static vo_info_t info =
47 "X11/Xv",
48 "xv",
49 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
53 LIBVO_EXTERN(xv)
55 #include <X11/extensions/Xv.h>
56 #include <X11/extensions/Xvlib.h>
57 // FIXME: dynamically allocate this stuff
58 static void allocate_xvimage(int);
59 static unsigned int ver,rel,req,ev,err;
60 static unsigned int formats, adaptors,i,xv_port,xv_format;
61 static XvAdaptorInfo *ai;
62 static XvImageFormatValues *fo;
64 static int current_buf=0;
65 static int current_ip_buf=0;
66 static int num_buffers=1; // default
67 static XvImage* xvimage[NUM_BUFFERS];
69 #ifdef HAVE_SHM
70 #include <sys/ipc.h>
71 #include <sys/shm.h>
72 #include <X11/extensions/XShm.h>
74 /* since it doesn't seem to be defined on some platforms */
75 int XShmGetEventBase(Display*);
77 static XShmSegmentInfo Shminfo[NUM_BUFFERS];
78 static int Shmem_Flag;
79 #endif
81 static uint32_t image_width;
82 static uint32_t image_height;
83 static uint32_t image_format;
84 static int flip_flag;
86 static Window mRoot;
87 static uint32_t drwX,drwY,drwBorderWidth,drwDepth;
88 static uint32_t dwidth,dheight;
90 static void (*draw_alpha_fnc)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride);
92 static void draw_alpha_yv12(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
93 x0+=image_width*(vo_panscan_x>>1)/(vo_dwidth+vo_panscan_x);
94 vo_draw_alpha_yv12(w,h,src,srca,stride,
95 xvimage[current_buf]->data+xvimage[current_buf]->offsets[0]+
96 xvimage[current_buf]->pitches[0]*y0+x0,xvimage[current_buf]->pitches[0]);
99 static void draw_alpha_yuy2(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
100 x0+=image_width*(vo_panscan_x>>1)/(vo_dwidth+vo_panscan_x);
101 vo_draw_alpha_yuy2(w,h,src,srca,stride,
102 xvimage[current_buf]->data+xvimage[current_buf]->offsets[0]+
103 xvimage[current_buf]->pitches[0]*y0+2*x0,xvimage[current_buf]->pitches[0]);
106 static void draw_alpha_uyvy(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
107 x0+=image_width*(vo_panscan_x>>1)/(vo_dwidth+vo_panscan_x);
108 vo_draw_alpha_yuy2(w,h,src,srca,stride,
109 xvimage[current_buf]->data+xvimage[current_buf]->offsets[0]+
110 xvimage[current_buf]->pitches[0]*y0+2*x0+1,xvimage[current_buf]->pitches[0]);
113 static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
116 static int xv_set_eq(char *name, int value)
118 XvAttribute *attributes;
119 int howmany, xv_atom;
121 mp_dbg(MSGT_VO, MSGL_V, "xv_set_eq called! (%s, %d)\n", name, value);
123 /* get available attributes */
124 attributes = XvQueryPortAttributes(mDisplay, xv_port, &howmany);
125 for (i = 0; i < howmany && attributes; i++)
126 if (attributes[i].flags & XvSettable)
128 xv_atom = XInternAtom(mDisplay, attributes[i].name, True);
129 /* since we have SET_DEFAULTS first in our list, we can check if it's available
130 then trigger it if it's ok so that the other values are at default upon query */
131 if (xv_atom != None)
133 int hue = 0,port_value,port_min,port_max;
135 if(!strcmp(attributes[i].name,"XV_BRIGHTNESS") &&
136 (!strcasecmp(name, "brightness")))
137 port_value = value;
138 else
139 if(!strcmp(attributes[i].name,"XV_CONTRAST") &&
140 (!strcasecmp(name, "contrast")))
141 port_value = value;
142 else
143 if(!strcmp(attributes[i].name,"XV_SATURATION") &&
144 (!strcasecmp(name, "saturation")))
145 port_value = value;
146 else
147 if(!strcmp(attributes[i].name,"XV_HUE") &&
148 (!strcasecmp(name, "hue")))
149 { port_value = value; hue=1; }
150 else
151 /* Note: since 22.01.2002 GATOS supports these attrs for radeons (NK) */
152 if(!strcmp(attributes[i].name,"XV_RED_INTENSITY") &&
153 (!strcasecmp(name, "red_intensity")))
154 port_value = value;
155 else
156 if(!strcmp(attributes[i].name,"XV_GREEN_INTENSITY") &&
157 (!strcasecmp(name, "green_intensity")))
158 port_value = value;
159 else
160 if(!strcmp(attributes[i].name,"XV_BLUE_INTENSITY") &&
161 (!strcasecmp(name, "blue_intensity")))
162 port_value = value;
163 else continue;
165 port_min = attributes[i].min_value;
166 port_max = attributes[i].max_value;
168 /* nvidia hue workaround */
169 if ( hue && port_min == 0 && port_max == 360 ){
170 port_value = (port_value>=0) ? (port_value-100) : (port_value+100);
173 // -100 -> min
174 // 0 -> (max+min)/2
175 // +100 -> max
176 port_value = (port_value+100)*(port_max-port_min)/200+port_min;
177 XvSetPortAttribute(mDisplay, xv_port, xv_atom, port_value);
178 return(VO_TRUE);
181 return(VO_FALSE);
184 static int xv_get_eq(char *name, int *value)
186 XvAttribute *attributes;
187 int howmany, xv_atom;
189 /* get available attributes */
190 attributes = XvQueryPortAttributes(mDisplay, xv_port, &howmany);
191 for (i = 0; i < howmany && attributes; i++)
192 if (attributes[i].flags & XvGettable)
194 xv_atom = XInternAtom(mDisplay, attributes[i].name, True);
195 /* since we have SET_DEFAULTS first in our list, we can check if it's available
196 then trigger it if it's ok so that the other values are at default upon query */
197 if (xv_atom != None)
199 int val, port_value=0, port_min, port_max;
201 XvGetPortAttribute(mDisplay, xv_port, xv_atom, &port_value);
203 port_min = attributes[i].min_value;
204 port_max = attributes[i].max_value;
205 val=(port_value-port_min)*200/(port_max-port_min)-100;
207 if(!strcmp(attributes[i].name,"XV_BRIGHTNESS") &&
208 (!strcasecmp(name, "brightness")))
209 *value = val;
210 else
211 if(!strcmp(attributes[i].name,"XV_CONTRAST") &&
212 (!strcasecmp(name, "contrast")))
213 *value = val;
214 else
215 if(!strcmp(attributes[i].name,"XV_SATURATION") &&
216 (!strcasecmp(name, "saturation")))
217 *value = val;
218 else
219 if(!strcmp(attributes[i].name,"XV_HUE") &&
220 (!strcasecmp(name, "hue"))){
221 /* nasty nvidia detect */
222 if (port_min == 0 && port_max == 360)
223 *value = (val>=0) ? (val-100) : (val+100);
224 else
225 *value = val;
226 } else
227 /* Note: since 22.01.2002 GATOS supports these attrs for radeons (NK) */
228 if(!strcmp(attributes[i].name,"XV_RED_INTENSITY") &&
229 (!strcasecmp(name, "red_intensity")))
230 *value = val;
231 else
232 if(!strcmp(attributes[i].name,"XV_GREEN_INTENSITY") &&
233 (!strcasecmp(name, "green_intensity")))
234 *value = val;
235 else
236 if(!strcmp(attributes[i].name,"XV_BLUE_INTENSITY") &&
237 (!strcasecmp(name, "blue_intensity")))
238 *value = val;
239 else continue;
241 mp_dbg(MSGT_VO, MSGL_V, "xv_get_eq called! (%s, %d)\n", name, *value);
242 return(VO_TRUE);
245 return(VO_FALSE);
248 static void deallocate_xvimage(int foo);
251 * connect to server, create and map window,
252 * allocate colors and (shared) memory
254 static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
256 // int screen;
257 char *hello = (title == NULL) ? "Xv render" : title;
258 // char *name = ":0.0";
259 XSizeHints hint;
260 XVisualInfo vinfo;
261 XGCValues xgcv;
262 XSetWindowAttributes xswa;
263 XWindowAttributes attribs;
264 unsigned long xswamask;
265 int depth;
266 #ifdef HAVE_XF86VM
267 int vm=0;
268 unsigned int modeline_width, modeline_height;
269 static uint32_t vm_width;
270 static uint32_t vm_height;
271 #endif
273 panscan_init();
275 aspect_save_orig(width,height);
276 aspect_save_prescale(d_width,d_height);
278 image_height = height;
279 image_width = width;
280 image_format=format;
282 vo_mouse_autohide=1;
284 vo_dx=( vo_screenwidth - d_width ) / 2; vo_dy=( vo_screenheight - d_height ) / 2;
285 geometry(&vo_dx, &vo_dy, &d_width, &d_height, vo_screenwidth, vo_screenheight);
286 vo_dwidth=d_width; vo_dheight=d_height;
288 #ifdef HAVE_XF86VM
289 if( flags&0x02 ) vm = 1;
290 #endif
291 flip_flag=flags&8;
292 num_buffers=vo_doublebuffering?(vo_directrendering?NUM_BUFFERS:2):1;
294 /* check image formats */
295 xv_format=0;
296 if(format==IMGFMT_BGR24) format=IMGFMT_YV12;
297 for(i = 0; i < formats; i++){
298 mp_msg(MSGT_VO,MSGL_V,"Xvideo image format: 0x%x (%4.4s) %s\n", fo[i].id,(char*)&fo[i].id, (fo[i].format == XvPacked) ? "packed" : "planar");
299 if (fo[i].id == format) xv_format = fo[i].id;
301 if (!xv_format) return -1;
303 aspect_save_screenres(vo_screenwidth,vo_screenheight);
305 #ifdef HAVE_NEW_GUI
306 if(use_gui)
307 guiGetEvent( guiSetShVideo,0 ); // let the GUI to setup/resize our window
308 else
309 #endif
311 hint.x = vo_dx;
312 hint.y = vo_dy;
313 hint.width = d_width;
314 hint.height = d_height;
315 aspect(&d_width,&d_height,A_NOZOOM);
316 #ifdef HAVE_XF86VM
317 if ( vm )
319 if ((d_width==0) && (d_height==0))
320 { vm_width=image_width; vm_height=image_height; }
321 else
322 { vm_width=d_width; vm_height=d_height; }
323 vo_vm_switch(vm_width, vm_height,&modeline_width, &modeline_height);
324 hint.x=(vo_screenwidth-modeline_width)/2;
325 hint.y=(vo_screenheight-modeline_height)/2;
326 hint.width=modeline_width;
327 hint.height=modeline_height;
328 aspect_save_screenres(modeline_width,modeline_height);
330 else
331 #endif
332 if ( vo_fs )
334 #ifdef X11_FULLSCREEN
335 /* this code replaces X11_FULLSCREEN hack in mplayer.c
336 * aspect() is available through aspect.h for all vos.
337 * besides zooming should only be done with -zoom,
338 * but I leave the old -fs behaviour so users don't get
339 * irritated for now (and send lots o' mails ;) ::atmos
342 aspect(&d_width,&d_height,A_ZOOM);
343 #endif
346 // dwidth=d_width; dheight=d_height; //XXX: what are the copy vars used for?
347 vo_dwidth=d_width; vo_dheight=d_height;
348 hint.flags = PPosition | PSize /* | PBaseSize */;
349 hint.base_width = hint.width; hint.base_height = hint.height;
350 XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), &attribs);
351 depth=attribs.depth;
352 if (depth != 15 && depth != 16 && depth != 24 && depth != 32) depth = 24;
353 XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &vinfo);
355 xswa.background_pixel = 0;
356 xswa.border_pixel = 0;
357 xswamask = CWBackPixel | CWBorderPixel;
359 if ( WinID>=0 ){
360 vo_window = WinID ? ((Window)WinID) : mRootWin;
361 if ( WinID )
363 XUnmapWindow( mDisplay,vo_window );
364 XChangeWindowAttributes( mDisplay,vo_window,xswamask,&xswa );
365 vo_x11_selectinput_witherr( mDisplay,vo_window,StructureNotifyMask | KeyPressMask | PropertyChangeMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | ExposureMask );
366 XMapWindow( mDisplay,vo_window );
367 } else { drwX=vo_dx; drwY=vo_dy; }
368 } else
369 if ( vo_window == None ){
370 vo_window = XCreateWindow(mDisplay, mRootWin,
371 hint.x, hint.y, hint.width, hint.height,
372 0, depth,CopyFromParent,vinfo.visual,xswamask,&xswa);
374 vo_x11_classhint( mDisplay,vo_window,"xv" );
375 vo_hidecursor(mDisplay,vo_window);
377 vo_x11_selectinput_witherr(mDisplay, vo_window, StructureNotifyMask | KeyPressMask | PropertyChangeMask |
378 ((WinID==0) ? 0 : (PointerMotionMask
379 | ButtonPressMask | ButtonReleaseMask
380 )));
381 XSetStandardProperties(mDisplay, vo_window, hello, hello, None, NULL, 0, &hint);
382 XSetWMNormalHints( mDisplay,vo_window,&hint );
383 XMapWindow(mDisplay, vo_window);
384 if ( flags&1 ) vo_x11_fullscreen();
385 #ifdef HAVE_XINERAMA
386 vo_x11_xinerama_move(mDisplay,vo_window);
387 #endif
388 vo_x11_sizehint( hint.x, hint.y, hint.width, hint.height,0 );
389 } else {
390 // vo_fs set means we were already at fullscreen
391 vo_x11_sizehint( hint.x, hint.y, hint.width, hint.height,0 );
392 if ( !vo_fs ) XMoveResizeWindow( mDisplay,vo_window,hint.x,hint.y,hint.width,hint.height );
393 if ( flags&1 && !vo_fs ) vo_x11_fullscreen(); // handle -fs on non-first file
396 // vo_x11_sizehint( hint.x, hint.y, hint.width, hint.height,0 );
398 if ( vo_gc != None ) XFreeGC( mDisplay,vo_gc );
399 vo_gc = XCreateGC(mDisplay, vo_window, 0L, &xgcv);
400 XFlush(mDisplay);
401 XSync(mDisplay, False);
402 #ifdef HAVE_XF86VM
403 if ( vm )
405 /* Grab the mouse pointer in our window */
406 if(vo_grabpointer)
407 XGrabPointer(mDisplay, vo_window, True, 0,
408 GrabModeAsync, GrabModeAsync,
409 vo_window, None, CurrentTime);
410 XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime);
412 #endif
415 mp_msg(MSGT_VO,MSGL_V, "using Xvideo port %d for hw scaling\n",xv_port );
417 switch (xv_format){
418 case IMGFMT_YV12:
419 case IMGFMT_I420:
420 case IMGFMT_IYUV: draw_alpha_fnc=draw_alpha_yv12; break;
421 case IMGFMT_YUY2:
422 case IMGFMT_YVYU: draw_alpha_fnc=draw_alpha_yuy2; break;
423 case IMGFMT_UYVY: draw_alpha_fnc=draw_alpha_uyvy; break;
424 default: draw_alpha_fnc=draw_alpha_null;
427 if ( vo_config_count )
428 for(current_buf=0;current_buf<num_buffers;++current_buf)
429 deallocate_xvimage(current_buf);
431 for(current_buf=0;current_buf<num_buffers;++current_buf)
432 allocate_xvimage(current_buf);
434 current_buf=0;
435 current_ip_buf=0;
437 #if 0
438 set_gamma_correction();
439 #endif
441 aspect(&vo_dwidth,&vo_dheight,A_NOZOOM);
442 if ( (( flags&1 )&&( WinID <= 0 )) || vo_fs )
444 aspect(&vo_dwidth,&vo_dheight,A_ZOOM);
445 drwX=( vo_screenwidth - (vo_dwidth > vo_screenwidth?vo_screenwidth:vo_dwidth) ) / 2;
446 drwY=( vo_screenheight - (vo_dheight > vo_screenheight?vo_screenheight:vo_dheight) ) / 2;
447 vo_dwidth=(vo_dwidth > vo_screenwidth?vo_screenwidth:vo_dwidth);
448 vo_dheight=(vo_dheight > vo_screenheight?vo_screenheight:vo_dheight);
449 mp_msg(MSGT_VO,MSGL_V, "[xv-fs] dx: %d dy: %d dw: %d dh: %d\n",drwX,drwY,vo_dwidth,vo_dheight );
452 panscan_calc();
454 XClearWindow(mDisplay, vo_window);
455 #if 0
456 #ifdef HAVE_SHM
457 if ( Shmem_Flag )
459 XvShmPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX, drwY, 1, 1, False);
460 XvShmPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX,drwY,vo_dwidth,(vo_fs?vo_dheight - 1:vo_dheight), False);
462 else
463 #endif
465 XvPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX, drwY, 1, 1);
466 XvPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX,drwY,vo_dwidth,(vo_fs?vo_dheight - 1:vo_dheight));
468 #endif
470 mp_msg(MSGT_VO,MSGL_V, "[xv] dx: %d dy: %d dw: %d dh: %d\n",drwX,drwY,vo_dwidth,vo_dheight );
472 saver_off(mDisplay); // turning off screen saver
473 return 0;
476 static void allocate_xvimage(int foo)
479 * allocate XvImages. FIXME: no error checking, without
480 * mit-shm this will bomb... trzing to fix ::atmos
482 #ifdef HAVE_SHM
483 if ( mLocalDisplay && XShmQueryExtension( mDisplay ) ) Shmem_Flag = 1;
484 else
486 Shmem_Flag = 0;
487 mp_msg(MSGT_VO,MSGL_INFO, "Shared memory not supported\nReverting to normal Xv\n" );
489 if ( Shmem_Flag )
491 xvimage[foo] = (XvImage *) XvShmCreateImage(mDisplay, xv_port, xv_format, NULL, image_width, image_height, &Shminfo[foo]);
493 Shminfo[foo].shmid = shmget(IPC_PRIVATE, xvimage[foo]->data_size, IPC_CREAT | 0777);
494 Shminfo[foo].shmaddr = (char *) shmat(Shminfo[foo].shmid, 0, 0);
495 Shminfo[foo].readOnly = False;
497 xvimage[foo]->data = Shminfo[foo].shmaddr;
498 XShmAttach(mDisplay, &Shminfo[foo]);
499 XSync(mDisplay, False);
500 shmctl(Shminfo[foo].shmid, IPC_RMID, 0);
502 else
503 #endif
505 xvimage[foo] = (XvImage *) XvCreateImage(mDisplay, xv_port, xv_format, NULL, image_width, image_height);
506 xvimage[foo]->data = malloc(xvimage[foo]->data_size);
507 XSync(mDisplay,False);
509 memset(xvimage[foo]->data,128,xvimage[foo]->data_size);
510 return;
513 static void deallocate_xvimage(int foo)
515 #ifdef HAVE_SHM
516 if ( Shmem_Flag )
518 XShmDetach( mDisplay,&Shminfo[foo] );
519 shmdt( Shminfo[foo].shmaddr );
521 else
522 #endif
524 free(xvimage[foo]->data);
526 XFree(xvimage[foo]);
528 XFlush( mDisplay );
529 XSync(mDisplay, False);
530 return;
533 static void check_events(void)
535 int e=vo_x11_check_events(mDisplay);
536 if(e&VO_EVENT_RESIZE)
538 if (vo_fs) {
539 e |= VO_EVENT_EXPOSE;
540 XClearWindow(mDisplay, vo_window);
541 XFlush(mDisplay);
544 XGetGeometry( mDisplay,vo_window,&mRoot,&drwX,&drwY,&vo_dwidth,&vo_dheight,&drwBorderWidth,&drwDepth );
545 drwX = drwY = 0;
546 mp_msg(MSGT_VO,MSGL_V, "[xv] dx: %d dy: %d dw: %d dh: %d\n",drwX,drwY,vo_dwidth,vo_dheight );
548 aspect(&dwidth,&dheight,A_NOZOOM);
549 if ( vo_fs )
551 aspect(&dwidth,&dheight,A_ZOOM);
552 drwX=( vo_screenwidth - (dwidth > vo_screenwidth?vo_screenwidth:dwidth) ) / 2;
553 drwY=( vo_screenheight - (dheight > vo_screenheight?vo_screenheight:dheight) ) / 2;
554 vo_dwidth=(dwidth > vo_screenwidth?vo_screenwidth:dwidth);
555 vo_dheight=(dheight > vo_screenheight?vo_screenheight:dheight);
556 mp_msg(MSGT_VO,MSGL_V, "[xv-fs] dx: %d dy: %d dw: %d dh: %d\n",drwX,drwY,vo_dwidth,vo_dheight );
559 if ( e & VO_EVENT_EXPOSE )
561 #ifdef HAVE_SHM
562 if ( Shmem_Flag )
564 XvShmPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX, drwY, 1, 1, False);
565 XvShmPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX,drwY,vo_dwidth,(vo_fs?vo_dheight - 1:vo_dheight), False);
567 else
568 #endif
570 XvPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX, drwY, 1, 1);
571 XvPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf], 0, 0, image_width, image_height, drwX,drwY,vo_dwidth,(vo_fs?vo_dheight - 1:vo_dheight));
576 static void draw_osd(void)
577 { vo_draw_text(image_width-image_width*vo_panscan_x/(vo_dwidth+vo_panscan_x),image_height,draw_alpha_fnc);}
579 static void flip_page(void)
582 #ifdef HAVE_SHM
583 if ( Shmem_Flag )
585 XvShmPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf],
586 0, 0, image_width, image_height,
587 drwX-(vo_panscan_x>>1),drwY-(vo_panscan_y>>1),vo_dwidth+vo_panscan_x,(vo_fs?vo_dheight - 1:vo_dheight)+vo_panscan_y,
588 False);
590 else
591 #endif
593 XvPutImage(mDisplay, xv_port, vo_window, vo_gc, xvimage[current_buf],
594 0, 0, image_width, image_height,
595 drwX-(vo_panscan_x>>1),drwY-(vo_panscan_y>>1),vo_dwidth+vo_panscan_x,(vo_fs?vo_dheight - 1:vo_dheight)+vo_panscan_y);
597 if (num_buffers>1){
598 current_buf=vo_directrendering?0:((current_buf+1)%num_buffers);
599 XFlush(mDisplay);
600 } else
601 XSync(mDisplay, False);
602 return;
605 static uint32_t draw_slice(uint8_t *image[], int stride[], int w,int h,int x,int y)
607 uint8_t *dst;
609 dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[0] +
610 xvimage[current_buf]->pitches[0]*y + x;
611 memcpy_pic(dst, image[0], w, h, xvimage[current_buf]->pitches[0], stride[0]);
613 x/=2;y/=2;w/=2;h/=2;
615 dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[1] +
616 xvimage[current_buf]->pitches[1]*y + x;
617 if(image_format!=IMGFMT_YV12)
618 memcpy_pic(dst, image[1], w, h, xvimage[current_buf]->pitches[1], stride[1]);
619 else
620 memcpy_pic(dst, image[2], w, h, xvimage[current_buf]->pitches[1], stride[2]);
622 dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[2] +
623 xvimage[current_buf]->pitches[2]*y + x;
624 if(image_format==IMGFMT_YV12)
625 memcpy_pic(dst, image[1], w, h, xvimage[current_buf]->pitches[1], stride[1]);
626 else
627 memcpy_pic(dst, image[2], w, h, xvimage[current_buf]->pitches[1], stride[2]);
629 return 0;
632 static uint32_t draw_frame(uint8_t *src[]){
633 printf("draw_frame() called!!!!!!");
634 return -1;
637 static uint32_t draw_image(mp_image_t *mpi){
638 if(mpi->flags&MP_IMGFLAG_DIRECT){
639 // direct rendering:
640 current_buf=(int)(mpi->priv); // hack!
641 return VO_TRUE;
643 if(mpi->flags&MP_IMGFLAG_DRAW_CALLBACK) return VO_TRUE; // done
644 if(mpi->flags&MP_IMGFLAG_PLANAR){
645 draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,0,0);
646 return VO_TRUE;
648 if(mpi->flags&MP_IMGFLAG_YUV){
649 // packed YUV:
650 memcpy_pic(xvimage[current_buf]->data+xvimage[current_buf]->offsets[0],
651 mpi->planes[0],mpi->w*(mpi->bpp/8),mpi->h,
652 xvimage[current_buf]->pitches[0], mpi->stride[0]);
653 return VO_TRUE;
655 if(mpi->imgfmt==IMGFMT_BGR24){
656 rgb24toyv12(mpi->planes[0]+(flip_flag ? 3*image_width*(image_height-1) : 0),
657 xvimage[current_buf]->data+xvimage[current_buf]->offsets[0],
658 xvimage[current_buf]->data+xvimage[current_buf]->offsets[2],
659 xvimage[current_buf]->data+xvimage[current_buf]->offsets[1],
660 image_width,image_height,
661 xvimage[current_buf]->pitches[0],
662 xvimage[current_buf]->pitches[1],
663 flip_flag ? -mpi->stride[0] : mpi->stride[0]);
664 return VO_TRUE;
666 return VO_FALSE; // not (yet) supported
669 static uint32_t get_image(mp_image_t *mpi){
670 int buf=current_buf; // we shouldn't change current_buf unless we do DR!
671 if(mpi->type==MP_IMGTYPE_STATIC && num_buffers>1) return VO_FALSE; // it is not static
672 if(mpi->imgfmt!=image_format || mpi->imgfmt==IMGFMT_BGR24) return VO_FALSE; // needs conversion :(
673 // if(mpi->flags&MP_IMGFLAG_READABLE) return VO_FALSE; // slow video ram
674 if(mpi->flags&MP_IMGFLAG_READABLE &&
675 (mpi->type==MP_IMGTYPE_IPB || mpi->type==MP_IMGTYPE_IP)){
676 // reference (I/P) frame of IP or IPB:
677 if(num_buffers<2) return VO_FALSE; // not enough
678 current_ip_buf^=1;
679 // for IPB with 2 buffers we can DR only one of the 2 P frames:
680 if(mpi->type==MP_IMGTYPE_IPB && num_buffers<3 && current_ip_buf) return VO_FALSE;
681 buf=current_ip_buf;
682 if(mpi->type==MP_IMGTYPE_IPB) ++buf; // preserve space for B
684 if(mpi->height > xvimage[buf]->height) return VO_FALSE; //buffer to small
685 if(mpi->width*(mpi->bpp/8) > xvimage[buf]->pitches[0]) return VO_FALSE; //buffer to small
686 if( (mpi->flags&(MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_ACCEPT_WIDTH)) ||
687 (mpi->width*(mpi->bpp/8)==xvimage[buf]->pitches[0]) ){
688 current_buf=buf;
689 mpi->planes[0]=xvimage[current_buf]->data+xvimage[current_buf]->offsets[0];
690 mpi->stride[0]=xvimage[current_buf]->pitches[0];
691 mpi->width=mpi->stride[0]/(mpi->bpp/8);
692 if(mpi->flags&MP_IMGFLAG_PLANAR){
693 if(mpi->flags&MP_IMGFLAG_SWAPPED){
694 // I420
695 mpi->planes[1]=xvimage[current_buf]->data+xvimage[current_buf]->offsets[1];
696 mpi->planes[2]=xvimage[current_buf]->data+xvimage[current_buf]->offsets[2];
697 mpi->stride[1]=xvimage[current_buf]->pitches[1];
698 mpi->stride[2]=xvimage[current_buf]->pitches[2];
699 } else {
700 // YV12
701 mpi->planes[1]=xvimage[current_buf]->data+xvimage[current_buf]->offsets[2];
702 mpi->planes[2]=xvimage[current_buf]->data+xvimage[current_buf]->offsets[1];
703 mpi->stride[1]=xvimage[current_buf]->pitches[2];
704 mpi->stride[2]=xvimage[current_buf]->pitches[1];
707 mpi->flags|=MP_IMGFLAG_DIRECT;
708 mpi->priv=(void*)current_buf;
709 // printf("mga: get_image() SUCCESS -> Direct Rendering ENABLED\n");
710 return VO_TRUE;
712 return VO_FALSE;
715 static uint32_t query_format(uint32_t format)
717 int flag=VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW|
718 VFCAP_HWSCALE_UP|VFCAP_HWSCALE_DOWN|VFCAP_OSD|VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN
719 /* check image formats */
720 if(format==IMGFMT_BGR24){ format=IMGFMT_YV12;flag&=~2;flag|=VFCAP_FLIP;} // conversion!
721 for(i = 0; i < formats; i++){
722 if (fo[i].id == format) return flag; //xv_format = fo[i].id;
724 return 0;
727 static void uninit(void)
729 int i;
730 if ( !vo_config_count ) return;
731 free( ai );
732 saver_on(mDisplay); // screen saver back on
733 for( i=0;i<num_buffers;i++ ) deallocate_xvimage( i );
734 #ifdef HAVE_XF86VM
735 vo_vm_close(mDisplay);
736 #endif
737 vo_x11_uninit();
740 static uint32_t preinit(const char *arg)
742 XvPortID xv_p;
743 int busy_ports=0;
745 if(arg)
747 mp_msg(MSGT_VO,MSGL_ERR,"vo_xv: Unknown subdevice: %s\n",arg);
748 return ENOSYS;
750 if (!vo_init()) return -1;
752 xv_port = 0;
753 /* check for Xvideo extension */
754 if (Success != XvQueryExtension(mDisplay,&ver,&rel,&req,&ev,&err)){
755 mp_msg(MSGT_VO,MSGL_ERR,"Sorry, Xv not supported by this X11 version/driver\n");
756 mp_msg(MSGT_VO,MSGL_ERR,"******** Try with -vo x11 or -vo sdl *********\n");
757 return -1;
760 /* check for Xvideo support */
761 if (Success != XvQueryAdaptors(mDisplay,DefaultRootWindow(mDisplay), &adaptors,&ai)){
762 mp_msg(MSGT_VO,MSGL_ERR,"Xv: XvQueryAdaptors failed");
763 return -1;
766 /* check adaptors */
767 for (i = 0; i < adaptors && xv_port == 0; i++){
768 if ((ai[i].type & XvInputMask) && (ai[i].type & XvImageMask)) {
769 for (xv_p = ai[i].base_id; xv_p < ai[i].base_id+ai[i].num_ports; ++xv_p)
770 if (!XvGrabPort(mDisplay, xv_p, CurrentTime)) {
771 xv_port = xv_p;
772 break;
773 } else {
774 mp_msg(MSGT_VO,MSGL_WARN,"Xv: could not grab port %i\n", (int)xv_p);
775 ++busy_ports;
779 if(!xv_port){
780 if(busy_ports)
781 mp_msg(MSGT_VO,MSGL_ERR,"Could not find free Xvideo port - maybe another process is already using it.\n"
782 "Close all video applications, and try again. If that does not help,\n"
783 "see 'mplayer -vo help' for other (non-xv) video out drivers.\n");
784 else
785 mp_msg(MSGT_VO,MSGL_ERR,"It seems there is no Xvideo support for your video card available.\n"
786 "Run 'xvinfo' to verify its Xv support, and read Xv section of DOCS/video.html !\n"
787 "See 'mplayer -vo help' for other (non-xv) video out drivers. Try -vo x11\n");
788 return -1;
792 int howmany, i;
793 const XvAttribute * const attributes = XvQueryPortAttributes(mDisplay, xv_port, &howmany);
795 for (i = 0; i < howmany && attributes; i++)
796 if (!strcmp(attributes[i].name, "XV_AUTOPAINT_COLORKEY"))
798 const Atom autopaint = XInternAtom(mDisplay, "XV_AUTOPAINT_COLORKEY", False);
799 XvSetPortAttribute(mDisplay, xv_port, autopaint, 1);
800 break;
804 fo = XvListImageFormats(mDisplay, xv_port, (int*)&formats);
806 return 0;
809 static uint32_t control(uint32_t request, void *data, ...)
811 switch (request) {
812 case VOCTRL_QUERY_FORMAT:
813 return query_format(*((uint32_t*)data));
814 case VOCTRL_GET_IMAGE:
815 return get_image(data);
816 case VOCTRL_DRAW_IMAGE:
817 return draw_image(data);
818 case VOCTRL_GUISUPPORT:
819 return VO_TRUE;
820 case VOCTRL_GET_PANSCAN:
821 if ( !vo_config_count || !vo_fs ) return VO_FALSE;
822 return VO_TRUE;
823 case VOCTRL_FULLSCREEN:
824 vo_x11_fullscreen();
825 /* indended, fallthrough to update panscan on fullscreen/windowed switch */
826 case VOCTRL_SET_PANSCAN:
827 if ( ( vo_fs && ( vo_panscan != vo_panscan_amount ) ) || ( !vo_fs && vo_panscan_amount ) )
829 int old_y = vo_panscan_y;
830 panscan_calc();
832 if(old_y != vo_panscan_y)
834 XClearWindow(mDisplay, vo_window);
835 XFlush(mDisplay);
838 return VO_TRUE;
839 case VOCTRL_SET_EQUALIZER:
841 va_list ap;
842 int value;
844 va_start(ap, data);
845 value = va_arg(ap, int);
846 va_end(ap);
848 return(xv_set_eq(data, value));
850 case VOCTRL_GET_EQUALIZER:
852 va_list ap;
853 int *value;
855 va_start(ap, data);
856 value = va_arg(ap, int*);
857 va_end(ap);
859 return(xv_get_eq(data, value));
862 return VO_NOTIMPL;