2 XOver a general x11 vo for mplayer overlay drivers based on :
3 VIDIX accelerated overlay in a X window
5 (C) Alex Beregszaszi & Zoltan Ponekker & Nick Kurshev
7 WS window manager by Pontscho/Fresh!
9 Based on vo_gl.c and vo_vesa.c and vo_xmga.c (.so mastah! ;))
20 #include "video_out.h"
21 #include "video_out_internal.h"
24 #include <X11/Xutil.h>
25 //#include <X11/keysym.h>
28 #include <X11/extensions/Xinerama.h>
31 #include "x11_common.h"
36 #include "gui/interface.h"
40 static const vo_info_t info
=
42 "General X11 driver for overlay capable video output drivers",
50 #define UNUSED(x) ((void)(x)) /* Removes warning about unused arguments */
52 /* X11 related variables */
53 /* Colorkey handling */
54 static XGCValues mGCV
;
57 /* Image parameters */
58 static uint32_t image_width
;
59 static uint32_t image_height
;
60 static uint32_t image_format
;
62 /* Window parameters */
63 static uint32_t window_x
, window_y
;
64 static uint32_t window_width
, window_height
;
66 /* used by XGetGeometry & XTranslateCoordinates for moving/resizing window */
67 static uint32_t drwX
, drwY
, drwWidth
, drwHeight
, drwBorderWidth
,
68 drwDepth
, drwcX
, drwcY
, dwidth
, dheight
;
70 static const vo_functions_t
* sub_vo
= NULL
;
73 static void set_window(int force_update
)
78 XGetGeometry(mDisplay
, vo_window
, &mRoot
, &drwX
, &drwY
, &drwWidth
,
79 &drwHeight
, &drwBorderWidth
, &drwDepth
);
82 XTranslateCoordinates(mDisplay
, vo_window
, mRoot
, 0, 0,
83 &drwcX
, &drwcY
, &mRoot
);
84 aspect(&dwidth
,&dheight
,A_NOZOOM
);
86 mp_msg(MSGT_VO
, MSGL_V
, "[xvidix] dcx: %d dcy: %d dx: %d dy: %d dw: %d dh: %d\n",
87 drwcX
, drwcY
, drwX
, drwY
, drwWidth
, drwHeight
);
89 /* following stuff copied from vo_xmga.c */
93 aspect(&dwidth
,&dheight
,A_NOZOOM
);
94 drwcX
=drwX
=vo_dx
; drwcY
=drwY
=vo_dy
; drwWidth
=vo_dwidth
; drwHeight
=vo_dheight
;
100 aspect(&dwidth
,&dheight
,A_ZOOM
);
101 drwX
= (vo_screenwidth
- ((int)dwidth
> vo_screenwidth
? vo_screenwidth
: dwidth
)) / 2;
103 drwY
= (vo_screenheight
- ((int)dheight
> vo_screenheight
? vo_screenheight
: dheight
)) / 2;
105 drwWidth
= ((int)dwidth
> vo_screenwidth
? vo_screenwidth
: dwidth
);
106 drwHeight
= ((int)dheight
> vo_screenheight
? vo_screenheight
: dheight
);
107 mp_msg(MSGT_VO
, MSGL_V
, "[xvidix-fs] dcx: %d dcy: %d dx: %d dy: %d dw: %d dh: %d\n",
108 drwcX
, drwcY
, drwX
, drwY
, drwWidth
, drwHeight
);
112 vo_dwidth
=drwWidth
; vo_dheight
=drwHeight
;
115 if (XineramaIsActive(mDisplay
))
117 XineramaScreenInfo
*screens
;
121 screens
= XineramaQueryScreens(mDisplay
, &num_screens
);
123 /* find the screen we are on */
124 while (i
<num_screens
&&
125 ((screens
[i
].x_org
< (int)drwcX
) ||
126 (screens
[i
].y_org
< (int)drwcY
) ||
127 (screens
[i
].x_org
+ screens
[i
].width
>= (int)drwcX
) ||
128 (screens
[i
].y_org
+ screens
[i
].height
>= (int)drwcY
)))
135 /* save the screen we are on */
138 /* oops.. couldnt find the screen we are on
139 * because the upper left corner left the
140 * visual range. assume we are still on the
146 /* set drwcX and drwcY to the right values */
147 drwcX
= drwcX
- screens
[i
].x_org
;
148 drwcY
= drwcY
- screens
[i
].y_org
;
153 if ( vo_panscan
> 0.0f
&& vo_fs
)
155 drwcX
-=vo_panscan_x
>> 1;
156 drwcY
-=vo_panscan_y
>> 1;
157 drwX
-=vo_panscan_x
>> 1;
158 drwY
-=vo_panscan_y
>> 1;
159 drwWidth
+=vo_panscan_x
;
160 drwHeight
+=vo_panscan_y
;
163 /* set new values in VIDIX */
164 if (force_update
|| (window_x
!= drwcX
) || (window_y
!= drwcY
) ||
165 (window_width
!= drwWidth
) || (window_height
!= drwHeight
))
168 // do a backup of window coordinates
169 w
.x
= window_x
= drwcX
;
170 w
.y
= window_y
= drwcY
;
173 w
.w
= window_width
= drwWidth
;
174 w
.h
= window_height
= drwHeight
;
176 if(sub_vo
->control(VOCTRL_XOVERLAY_SET_WIN
,&w
) != VO_TRUE
)
177 mp_msg(MSGT_VO
, MSGL_ERR
, "xvidx: set_overlay failed\n");
179 mp_msg(MSGT_VO
, MSGL_V
, "[xvidix] window properties: pos: %dx%d, size: %dx%d\n", vo_dx
, vo_dy
, window_width
, window_height
);
184 /* fill drawable with specified color */
185 XSetBackground(mDisplay
, vo_gc
, 0L);
186 XClearWindow( mDisplay
,vo_window
);
187 XSetForeground(mDisplay
, vo_gc
, colorkey
);
188 XFillRectangle(mDisplay
, vo_window
, vo_gc
, drwX
, drwY
, drwWidth
,
189 (vo_fs
? drwHeight
- 1 : drwHeight
));
191 if (vo_ontop
) vo_x11_setlayer(mDisplay
, vo_window
, vo_ontop
);
193 /* flush, update drawable */
199 /* connect to server, create and map window,
200 * allocate colors and (shared) memory
202 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
203 uint32_t d_height
, uint32_t flags
, char *title
, uint32_t format
)
207 XSetWindowAttributes xswa
;
208 unsigned long xswamask
;
209 XWindowAttributes attribs
;
210 int window_depth
, r
, g
, b
;
211 mp_colorkey_t colork
;
214 sprintf(_title
,"MPlayer %s X11 Overlay",sub_vo
->info
->name
);
219 image_height
= height
;
221 image_format
= format
;
224 aspect_save_orig(width
, height
);
225 aspect_save_prescale(d_width
, d_height
);
226 update_xinerama_info();
228 window_width
= d_width
;
229 window_height
= d_height
;
231 r
= (vo_colorkey
& 0x00ff0000) >> 16;
232 g
= (vo_colorkey
& 0x0000ff00) >> 8;
233 b
= vo_colorkey
& 0x000000ff;
234 switch(vo_depthonscreen
)
237 colorkey
= vo_colorkey
;
240 colorkey
= vo_colorkey
& 0x00ffffff;
243 colorkey
= ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
246 colorkey
= ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
249 mp_msg(MSGT_VO
, MSGL_ERR
, "Sorry, this (%d) color depth is not supported\n",
252 mp_msg(MSGT_VO
, MSGL_V
, "Using colorkey: %x\n", colorkey
);
254 aspect(&d_width
, &d_height
, A_NOZOOM
);
256 vo_dx
=( vo_screenwidth
- d_width
) / 2; vo_dy
=( vo_screenheight
- d_height
) / 2;
259 vo_dwidth
=d_width
; vo_dheight
=d_height
;
262 if(use_gui
) guiGetEvent( guiSetShVideo
,0 ); // the GUI will set up / resize the window
267 #ifdef X11_FULLSCREEN
268 if ( ( flags
&VOFLAG_FULLSCREEN
)||(flags
& VOFLAG_SWSCALE
) ) aspect(&d_width
, &d_height
, A_ZOOM
);
272 /* Make the window */
273 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
), &attribs
);
276 window_depth
= attribs
.depth
;
277 if ((window_depth
!= 15) && (window_depth
!= 16) && (window_depth
!= 24)
278 && (window_depth
!= 32))
280 XMatchVisualInfo(mDisplay
, mScreen
, window_depth
, TrueColor
, &vinfo
);
282 xswa
.background_pixel
= BlackPixel(mDisplay
, mScreen
);
283 xswa
.border_pixel
= 0;
284 xswa
.colormap
= XCreateColormap(mDisplay
, RootWindow(mDisplay
, mScreen
),
285 vinfo
.visual
, AllocNone
);
286 xswa
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
| PropertyChangeMask
|
287 ((WinID
==0)?0:(ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
));
288 xswamask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
292 vo_window
= WinID
? ((Window
)WinID
) : RootWindow(mDisplay
, mScreen
);
295 XUnmapWindow(mDisplay
, vo_window
);
296 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
, &xswa
);
297 vo_x11_selectinput_witherr( mDisplay
,vo_window
,StructureNotifyMask
| KeyPressMask
| PropertyChangeMask
| PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask
| ExposureMask
);
298 XMapWindow(mDisplay
, vo_window
);
299 } else XSelectInput( mDisplay
,vo_window
,ExposureMask
);
303 vo_x11_create_vo_window(&vinfo
, vo_dx
, vo_dy
,
304 window_width
, window_height
, flags
,
305 xswa
.colormap
, "xvidix", title
);
306 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
, &xswa
);
309 if ( vo_gc
!= None
) XFreeGC( mDisplay
,vo_gc
);
310 vo_gc
= XCreateGC(mDisplay
, vo_window
, GCForeground
, &mGCV
);
315 if ( ( !WinID
)&&( flags
&VOFLAG_FULLSCREEN
) ) { vo_dx
=0; vo_dy
=0; vo_dwidth
=vo_screenwidth
; vo_dheight
=vo_screenheight
; vo_fs
=1; }
317 if(sub_vo
->config(image_width
,image_height
,vo_dwidth
,vo_dheight
,
318 flags
| VOFLAG_XOVERLAY_SUB_VO
,NULL
,format
)) {
319 mp_msg(MSGT_VO
, MSGL_ERR
, "xover: sub vo config failed\n");
322 colork
.x11
= colorkey
;
326 if(sub_vo
->control(VOCTRL_XOVERLAY_SET_COLORKEY
,&colork
) != VO_TRUE
)
327 mp_msg(MSGT_VO
, MSGL_WARN
, "xover: set_colorkey failed\n");
331 XSync(mDisplay
, False
);
338 static void check_events(void)
340 const int event
= vo_x11_check_events(mDisplay
);
342 if ((event
& VO_EVENT_RESIZE
) || (event
& VO_EVENT_EXPOSE
))
344 sub_vo
->check_events();
348 /* draw_osd, flip_page, draw_slice, draw_frame should be
349 overwritten with vidix functions (vosub_vidix.c) */
350 static void draw_osd(void)
352 mp_msg(MSGT_VO
, MSGL_FATAL
, "xover error: didn't used sub vo draw_osd!\n");
355 static void flip_page(void)
357 mp_msg(MSGT_VO
, MSGL_FATAL
, "xover error: didn't used sub vo flip_page!\n");
360 static int draw_slice(uint8_t *src
[], int stride
[],
361 int w
, int h
, int x
, int y
)
369 mp_msg(MSGT_VO
, MSGL_FATAL
, "xover error: didn't used sub vo draw_slice!\n");
373 static int draw_frame(uint8_t *src
[])
376 mp_msg(MSGT_VO
, MSGL_FATAL
, "xover error: didn't used sub vo draw_frame!\n");
380 static void uninit(void)
382 if(!vo_config_count
) return;
383 if(sub_vo
) sub_vo
->uninit();
386 // Restore our callbacks
387 video_out_xover
.draw_frame
= draw_frame
;
388 video_out_xover
.draw_slice
= draw_slice
;
389 video_out_xover
.flip_page
= flip_page
;
390 video_out_xover
.draw_osd
= draw_osd
;
393 static int preinit(const char *arg
)
398 mp_msg(MSGT_VO
, MSGL_ERR
, "VO XOverlay need a subdriver\n");
402 for(i
= 0 ; video_out_drivers
[i
] != NULL
; i
++) {
403 if(!strcmp(video_out_drivers
[i
]->info
->short_name
,arg
) &&
404 strcmp(video_out_drivers
[i
]->info
->short_name
,"xover"))
407 if(!video_out_drivers
[i
]) {
408 mp_msg(MSGT_VO
, MSGL_ERR
, "VO XOverlay: Subdriver %s not found\n", arg
);
411 if(video_out_drivers
[i
]->control(VOCTRL_XOVERLAY_SUPPORT
,NULL
) != VO_TRUE
) {
412 mp_msg(MSGT_VO
, MSGL_ERR
, "VO XOverlay: %s doesn't support XOverlay\n", arg
);
416 if (!vo_init()) return VO_FALSE
;
417 if(video_out_drivers
[i
]->preinit(NULL
)) {
418 mp_msg(MSGT_VO
, MSGL_ERR
, "VO XOverlay: Subvo init failed\n");
421 sub_vo
= video_out_drivers
[i
];
422 // Setup the sub vo callbacks
423 video_out_xover
.draw_frame
= sub_vo
->draw_frame
;
424 video_out_xover
.draw_slice
= sub_vo
->draw_slice
;
425 video_out_xover
.flip_page
= sub_vo
->flip_page
;
426 video_out_xover
.draw_osd
= sub_vo
->draw_osd
;
430 static int control(uint32_t request
, void *data
, ...)
432 if(!sub_vo
) return VO_ERROR
;
434 case VOCTRL_GUISUPPORT
:
436 case VOCTRL_GET_PANSCAN
:
437 if ( !vo_config_count
|| !vo_fs
) return VO_FALSE
;
442 case VOCTRL_FULLSCREEN
:
444 case VOCTRL_SET_PANSCAN
:
445 if ( vo_fs
&& ( vo_panscan
!= vo_panscan_amount
) )
452 // Safe atm bcs nothing use more than 1 arg
453 return sub_vo
->control(request
,data
);