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)
25 #include "video_out.h"
26 #include "video_out_internal.h"
30 #include <X11/Xutil.h>
33 #include "x11_common.h"
35 #include "fastmemcpy.h"
39 #include "../postproc/rgb2rgb.h"
42 #include "../Gui/interface.h"
45 static vo_info_t info
=
49 "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others",
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
];
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
;
81 static uint32_t image_width
;
82 static uint32_t image_height
;
83 static uint32_t image_format
;
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 */
133 int hue
= 0,port_value
,port_min
,port_max
;
135 if(!strcmp(attributes
[i
].name
,"XV_BRIGHTNESS") &&
136 (!strcasecmp(name
, "brightness")))
139 if(!strcmp(attributes
[i
].name
,"XV_CONTRAST") &&
140 (!strcasecmp(name
, "contrast")))
143 if(!strcmp(attributes
[i
].name
,"XV_SATURATION") &&
144 (!strcasecmp(name
, "saturation")))
147 if(!strcmp(attributes
[i
].name
,"XV_HUE") &&
148 (!strcasecmp(name
, "hue")))
149 { port_value
= value
; hue
=1; }
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")))
156 if(!strcmp(attributes
[i
].name
,"XV_GREEN_INTENSITY") &&
157 (!strcasecmp(name
, "green_intensity")))
160 if(!strcmp(attributes
[i
].name
,"XV_BLUE_INTENSITY") &&
161 (!strcasecmp(name
, "blue_intensity")))
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);
176 port_value
= (port_value
+100)*(port_max
-port_min
)/200+port_min
;
177 XvSetPortAttribute(mDisplay
, xv_port
, xv_atom
, port_value
);
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 */
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")))
211 if(!strcmp(attributes
[i
].name
,"XV_CONTRAST") &&
212 (!strcasecmp(name
, "contrast")))
215 if(!strcmp(attributes
[i
].name
,"XV_SATURATION") &&
216 (!strcasecmp(name
, "saturation")))
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);
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")))
232 if(!strcmp(attributes
[i
].name
,"XV_GREEN_INTENSITY") &&
233 (!strcasecmp(name
, "green_intensity")))
236 if(!strcmp(attributes
[i
].name
,"XV_BLUE_INTENSITY") &&
237 (!strcasecmp(name
, "blue_intensity")))
241 mp_dbg(MSGT_VO
, MSGL_V
, "xv_get_eq called! (%s, %d)\n", name
, *value
);
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
)
257 char *hello
= (title
== NULL
) ? "Xv render" : title
;
258 // char *name = ":0.0";
262 XSetWindowAttributes xswa
;
263 XWindowAttributes attribs
;
264 unsigned long xswamask
;
268 unsigned int modeline_width
, modeline_height
;
269 static uint32_t vm_width
;
270 static uint32_t vm_height
;
275 aspect_save_orig(width
,height
);
276 aspect_save_prescale(d_width
,d_height
);
278 image_height
= height
;
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
;
289 if( flags
&0x02 ) vm
= 1;
292 num_buffers
=vo_doublebuffering
?(vo_directrendering
?NUM_BUFFERS
:2):1;
294 /* check image formats */
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
);
307 guiGetEvent( guiSetShVideo
,0 ); // let the GUI to setup/resize our window
313 hint
.width
= d_width
;
314 hint
.height
= d_height
;
315 aspect(&d_width
,&d_height
,A_NOZOOM
);
319 if ((d_width
==0) && (d_height
==0))
320 { vm_width
=image_width
; vm_height
=image_height
; }
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
);
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
);
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
);
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
;
360 vo_window
= WinID
? ((Window
)WinID
) : mRootWin
;
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
; }
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
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();
386 vo_x11_xinerama_move(mDisplay
,vo_window
);
388 vo_x11_sizehint( hint
.x
, hint
.y
, hint
.width
, hint
.height
,0 );
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
);
401 XSync(mDisplay
, False
);
405 /* Grab the mouse pointer in our window */
407 XGrabPointer(mDisplay
, vo_window
, True
, 0,
408 GrabModeAsync
, GrabModeAsync
,
409 vo_window
, None
, CurrentTime
);
410 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
415 mp_msg(MSGT_VO
,MSGL_V
, "using Xvideo port %d for hw scaling\n",xv_port
);
420 case IMGFMT_IYUV
: draw_alpha_fnc
=draw_alpha_yv12
; break;
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
);
438 set_gamma_correction();
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
);
454 XClearWindow(mDisplay
, vo_window
);
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
);
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
));
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
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
483 if ( mLocalDisplay
&& XShmQueryExtension( mDisplay
) ) Shmem_Flag
= 1;
487 mp_msg(MSGT_VO
,MSGL_INFO
, "Shared memory not supported\nReverting to normal Xv\n" );
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);
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
);
513 static void deallocate_xvimage(int foo
)
518 XShmDetach( mDisplay
,&Shminfo
[foo
] );
519 shmdt( Shminfo
[foo
].shmaddr
);
524 free(xvimage
[foo
]->data
);
529 XSync(mDisplay
, False
);
533 static void check_events(void)
535 int e
=vo_x11_check_events(mDisplay
);
536 if(e
&VO_EVENT_RESIZE
)
539 e
|= VO_EVENT_EXPOSE
;
540 XClearWindow(mDisplay
, vo_window
);
544 XGetGeometry( mDisplay
,vo_window
,&mRoot
,&drwX
,&drwY
,&vo_dwidth
,&vo_dheight
,&drwBorderWidth
,&drwDepth
);
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
);
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
)
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
);
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)
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
,
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
);
598 current_buf
=vo_directrendering
?0:((current_buf
+1)%num_buffers
);
601 XSync(mDisplay
, False
);
605 static uint32_t draw_slice(uint8_t *image
[], int stride
[], int w
,int h
,int x
,int y
)
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]);
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]);
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]);
627 memcpy_pic(dst
, image
[2], w
, h
, xvimage
[current_buf
]->pitches
[1], stride
[2]);
632 static uint32_t draw_frame(uint8_t *src
[]){
633 printf("draw_frame() called!!!!!!");
637 static uint32_t draw_image(mp_image_t
*mpi
){
638 if(mpi
->flags
&MP_IMGFLAG_DIRECT
){
640 current_buf
=(int)(mpi
->priv
); // hack!
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);
648 if(mpi
->flags
&MP_IMGFLAG_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]);
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]);
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
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
;
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]) ){
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
){
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];
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");
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;
727 static void uninit(void)
730 if ( !vo_config_count
) return;
732 saver_on(mDisplay
); // screen saver back on
733 for( i
=0;i
<num_buffers
;i
++ ) deallocate_xvimage( i
);
735 vo_vm_close(mDisplay
);
740 static uint32_t preinit(const char *arg
)
747 mp_msg(MSGT_VO
,MSGL_ERR
,"vo_xv: Unknown subdevice: %s\n",arg
);
750 if (!vo_init()) return -1;
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");
760 /* check for Xvideo support */
761 if (Success
!= XvQueryAdaptors(mDisplay
,DefaultRootWindow(mDisplay
), &adaptors
,&ai
)){
762 mp_msg(MSGT_VO
,MSGL_ERR
,"Xv: XvQueryAdaptors failed");
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
)) {
774 mp_msg(MSGT_VO
,MSGL_WARN
,"Xv: could not grab port %i\n", (int)xv_p
);
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");
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");
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);
804 fo
= XvListImageFormats(mDisplay
, xv_port
, (int*)&formats
);
809 static uint32_t control(uint32_t request
, void *data
, ...)
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
:
820 case VOCTRL_GET_PANSCAN
:
821 if ( !vo_config_count
|| !vo_fs
) return VO_FALSE
;
823 case VOCTRL_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
;
832 if(old_y
!= vo_panscan_y
)
834 XClearWindow(mDisplay
, vo_window
);
839 case VOCTRL_SET_EQUALIZER
:
845 value
= va_arg(ap
, int);
848 return(xv_set_eq(data
, value
));
850 case VOCTRL_GET_EQUALIZER
:
856 value
= va_arg(ap
, int*);
859 return(xv_get_eq(data
, value
));