9 #include "video_out_internal.h"
13 #include <X11/Xutil.h>
16 #include <X11/extensions/xf86vmode.h>
20 #include "x11_common.h"
25 #include <X11/extensions/XShm.h>
27 static int Shmem_Flag
;
29 //static int Quiet_Flag; Here also what is this for. It's used but isn't inited ?
30 static XShmSegmentInfo Shminfo
[1];
31 static int gXErrorFlag
;
32 static int CompletionType
= -1;
34 /* since it doesn't seem to be defined on some platforms */
35 int XShmGetEventBase(Display
*);
40 #include "libswscale/swscale.h"
41 #include "libmpcodecs/vf_scale.h"
49 #include "gui/interface.h"
53 static const vo_info_t info
= {
56 "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>",
60 const LIBVO_EXTERN(x11
)
61 /* private prototypes */
62 static void Display_Image(XImage
* myximage
, unsigned char *ImageData
);
63 static void (*draw_alpha_fnc
) (int x0
, int y0
, int w
, int h
,
64 unsigned char *src
, unsigned char *srca
,
68 static unsigned char *ImageData
;
69 //! original unaligned pointer for free
70 static unsigned char *ImageDataOrig
;
72 /* X11 related variables */
73 static XImage
*myximage
= NULL
;
74 static int depth
, bpp
;
75 static XWindowAttributes attribs
;
83 static uint32_t image_width
;
84 static uint32_t image_height
;
85 static uint32_t in_format
;
86 static uint32_t out_format
= 0;
87 static int out_offset
;
90 static int aspect
; // 1<<16 based fixed point aspect, so that the aspect stays correct during resizing
92 static int old_vo_dwidth
= -1;
93 static int old_vo_dheight
= -1;
95 static void check_events(void)
97 int ret
= vo_x11_check_events(mDisplay
);
99 /* clear left over borders and redraw frame if we are paused */
100 if (ret
& VO_EVENT_EXPOSE
&& int_pause
)
102 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
,
103 myximage
->height
, 0);
105 } else if ((ret
& VO_EVENT_RESIZE
) || (ret
& VO_EVENT_EXPOSE
))
106 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
,
107 myximage
->height
, 0);
111 static void draw_alpha_32(int x0
, int y0
, int w
, int h
, unsigned char *src
,
112 unsigned char *srca
, int stride
)
114 vo_draw_alpha_rgb32(w
, h
, src
, srca
, stride
,
115 ImageData
+ 4 * (y0
* image_width
+ x0
),
119 static void draw_alpha_24(int x0
, int y0
, int w
, int h
, unsigned char *src
,
120 unsigned char *srca
, int stride
)
122 vo_draw_alpha_rgb24(w
, h
, src
, srca
, stride
,
123 ImageData
+ 3 * (y0
* image_width
+ x0
),
127 static void draw_alpha_16(int x0
, int y0
, int w
, int h
, unsigned char *src
,
128 unsigned char *srca
, int stride
)
130 vo_draw_alpha_rgb16(w
, h
, src
, srca
, stride
,
131 ImageData
+ 2 * (y0
* image_width
+ x0
),
135 static void draw_alpha_15(int x0
, int y0
, int w
, int h
, unsigned char *src
,
136 unsigned char *srca
, int stride
)
138 vo_draw_alpha_rgb15(w
, h
, src
, srca
, stride
,
139 ImageData
+ 2 * (y0
* image_width
+ x0
),
143 static void draw_alpha_null(int x0
, int y0
, int w
, int h
,
144 unsigned char *src
, unsigned char *srca
,
149 static struct SwsContext
*swsContext
= NULL
;
150 static int dst_width
;
151 extern int sws_flags
;
153 static XVisualInfo vinfo
;
155 static void getMyXImage(void)
158 if (mLocalDisplay
&& XShmQueryExtension(mDisplay
))
163 mp_msg(MSGT_VO
, MSGL_WARN
,
164 "Shared memory not supported\nReverting to normal Xlib\n");
167 CompletionType
= XShmGetEventBase(mDisplay
) + ShmCompletion
;
172 XShmCreateImage(mDisplay
, vinfo
.visual
, depth
, ZPixmap
, NULL
,
173 &Shminfo
[0], image_width
, image_height
);
174 if (myximage
== NULL
)
176 mp_msg(MSGT_VO
, MSGL_WARN
,
177 "Shared memory error,disabling ( Ximage error )\n");
180 Shminfo
[0].shmid
= shmget(IPC_PRIVATE
,
181 myximage
->bytes_per_line
*
182 myximage
->height
, IPC_CREAT
| 0777);
183 if (Shminfo
[0].shmid
< 0)
185 XDestroyImage(myximage
);
186 mp_msg(MSGT_VO
, MSGL_V
, "%s\n", strerror(errno
));
187 //perror( strerror( errno ) );
188 mp_msg(MSGT_VO
, MSGL_WARN
,
189 "Shared memory error,disabling ( seg id error )\n");
192 Shminfo
[0].shmaddr
= (char *) shmat(Shminfo
[0].shmid
, 0, 0);
194 if (Shminfo
[0].shmaddr
== ((char *) -1))
196 XDestroyImage(myximage
);
197 if (Shminfo
[0].shmaddr
!= ((char *) -1))
198 shmdt(Shminfo
[0].shmaddr
);
199 mp_msg(MSGT_VO
, MSGL_WARN
,
200 "Shared memory error,disabling ( address error )\n");
203 myximage
->data
= Shminfo
[0].shmaddr
;
204 ImageData
= (unsigned char *) myximage
->data
;
205 Shminfo
[0].readOnly
= False
;
206 XShmAttach(mDisplay
, &Shminfo
[0]);
208 XSync(mDisplay
, False
);
212 XDestroyImage(myximage
);
213 shmdt(Shminfo
[0].shmaddr
);
214 mp_msg(MSGT_VO
, MSGL_WARN
, "Shared memory error,disabling.\n");
218 shmctl(Shminfo
[0].shmid
, IPC_RMID
, 0);
221 static int firstTime
= 1;
225 mp_msg(MSGT_VO
, MSGL_V
, "Sharing memory.\n");
234 myximage
= XCreateImage(mDisplay
, vinfo
.visual
, depth
, ZPixmap
,
235 0, NULL
, image_width
, image_height
, 8, 0);
236 ImageDataOrig
= malloc(myximage
->bytes_per_line
* image_height
+ 32);
237 myximage
->data
= ImageDataOrig
+ 16 - ((long)ImageDataOrig
& 15);
238 memset(myximage
->data
, 0, myximage
->bytes_per_line
* image_height
);
239 ImageData
= myximage
->data
;
245 static void freeMyXImage(void)
250 XShmDetach(mDisplay
, &Shminfo
[0]);
251 XDestroyImage(myximage
);
252 shmdt(Shminfo
[0].shmaddr
);
256 myximage
->data
= ImageDataOrig
;
257 XDestroyImage(myximage
);
258 ImageDataOrig
= NULL
;
264 #ifdef WORDS_BIGENDIAN
265 #define BO_NATIVE MSBFirst
266 #define BO_NONNATIVE LSBFirst
268 #define BO_NATIVE LSBFirst
269 #define BO_NONNATIVE MSBFirst
271 const struct fmt2Xfmtentry_s
{
278 {IMGFMT_RGB8
, BO_NATIVE
, 0x00000007, 0x00000038, 0x000000C0},
279 {IMGFMT_RGB8
, BO_NONNATIVE
, 0x00000007, 0x00000038, 0x000000C0},
280 {IMGFMT_BGR8
, BO_NATIVE
, 0x000000E0, 0x0000001C, 0x00000003},
281 {IMGFMT_BGR8
, BO_NONNATIVE
, 0x000000E0, 0x0000001C, 0x00000003},
282 {IMGFMT_RGB15
, BO_NATIVE
, 0x0000001F, 0x000003E0, 0x00007C00},
283 {IMGFMT_BGR15
, BO_NATIVE
, 0x00007C00, 0x000003E0, 0x0000001F},
284 {IMGFMT_RGB16
, BO_NATIVE
, 0x0000001F, 0x000007E0, 0x0000F800},
285 {IMGFMT_BGR16
, BO_NATIVE
, 0x0000F800, 0x000007E0, 0x0000001F},
286 {IMGFMT_RGB24
, MSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
287 {IMGFMT_RGB24
, LSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
288 {IMGFMT_BGR24
, MSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
289 {IMGFMT_BGR24
, LSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
290 {IMGFMT_RGB32
, BO_NATIVE
, 0x000000FF, 0x0000FF00, 0x00FF0000},
291 {IMGFMT_RGB32
, BO_NONNATIVE
, 0xFF000000, 0x00FF0000, 0x0000FF00},
292 {IMGFMT_BGR32
, BO_NATIVE
, 0x00FF0000, 0x0000FF00, 0x000000FF},
293 {IMGFMT_BGR32
, BO_NONNATIVE
, 0x0000FF00, 0x00FF0000, 0xFF000000},
294 {IMGFMT_ARGB
, MSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
295 {IMGFMT_ARGB
, LSBFirst
, 0x0000FF00, 0x00FF0000, 0xFF000000},
296 {IMGFMT_ABGR
, MSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
297 {IMGFMT_ABGR
, LSBFirst
, 0xFF000000, 0x00FF0000, 0x0000FF00},
298 {IMGFMT_RGBA
, MSBFirst
, 0xFF000000, 0x00FF0000, 0x0000FF00},
299 {IMGFMT_RGBA
, LSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
300 {IMGFMT_BGRA
, MSBFirst
, 0x0000FF00, 0x00FF0000, 0xFF000000},
301 {IMGFMT_BGRA
, LSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
305 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
306 uint32_t d_height
, uint32_t flags
, char *title
,
313 // int interval, prefer_blank, allow_exp, nothing;
317 XSetWindowAttributes xswa
;
318 unsigned long xswamask
;
319 const struct fmt2Xfmtentry_s
*fmte
= fmt2Xfmt
;
322 unsigned int modeline_width
, modeline_height
;
323 static uint32_t vm_width
;
324 static uint32_t vm_height
;
327 vo_mouse_autohide
= 1;
332 title
= "MPlayer X11 (XImage/Shm) render";
338 if (flags
& (VOFLAG_FULLSCREEN
|VOFLAG_MODESWITCHING
))
340 if (flags
& VOFLAG_MODESWITCHING
)
342 if (flags
& VOFLAG_FLIPPING
)
344 zoomFlag
= flags
& VOFLAG_SWSCALE
;
347 // if(!fullscreen) zoomFlag=1; //it makes no sense to avoid zooming on windowd mode
349 //printf( "w: %d h: %d\n\n",vo_dwidth,vo_dheight );
351 XGetWindowAttributes(mDisplay
, mRootWin
, &attribs
);
352 depth
= attribs
.depth
;
354 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
358 depth
= vo_find_depth_from_visuals(mDisplay
, mScreen
, &visual
);
360 if (!XMatchVisualInfo(mDisplay
, mScreen
, depth
, DirectColor
, &vinfo
) ||
362 && vinfo
.visualid
!= XVisualIDFromVisual(attribs
.visual
)))
363 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
365 /* set image size (which is indeed neither the input nor output size),
366 if zoom is on it will be changed during draw_slice anyway so we don't duplicate the aspect code here
368 image_width
= (width
+ 7) & (~7);
369 image_height
= height
;
371 aspect
= ((1 << 16) * d_width
+ d_height
/ 2) / d_height
;
375 guiGetEvent(guiSetShVideo
, 0); // the GUI will set up / resize the window
382 if ((d_width
== 0) && (d_height
== 0))
384 vm_width
= image_width
;
385 vm_height
= image_height
;
389 vm_height
= d_height
;
391 vo_vm_switch(vm_width
, vm_height
, &modeline_width
,
393 vo_dx
= (vo_screenwidth
- modeline_width
) / 2;
394 vo_dy
= (vo_screenheight
- modeline_height
) / 2;
395 vo_dwidth
= modeline_width
;
396 vo_dheight
= modeline_height
;
399 bg
= WhitePixel(mDisplay
, mScreen
);
400 fg
= BlackPixel(mDisplay
, mScreen
);
402 theCmap
= vo_x11_create_colormap(&vinfo
);
404 xswa
.background_pixel
= 0;
405 xswa
.border_pixel
= 0;
406 xswa
.colormap
= theCmap
;
407 xswamask
= CWBackPixel
| CWBorderPixel
| CWColormap
;
412 xswa
.override_redirect
= True
;
413 xswamask
|= CWOverrideRedirect
;
419 vo_window
= WinID
? ((Window
) WinID
) : mRootWin
;
423 XUnmapWindow(mDisplay
, vo_window
);
424 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
,
426 vo_x11_selectinput_witherr(mDisplay
, vo_window
,
427 StructureNotifyMask
|
434 XMapWindow(mDisplay
, vo_window
);
435 XGetGeometry(mDisplay
, vo_window
, &mRootWin
,
436 &vo_dx
, &vo_dy
, &vo_dwidth
, &vo_dheight
,
439 XSelectInput(mDisplay
, vo_window
, ExposureMask
);
442 vo_x11_create_vo_window(&vinfo
, vo_dx
, vo_dy
, d_width
, d_height
,
443 flags
, theCmap
, "x11", title
);
446 XSync(mDisplay
, False
);
448 vo_x11_selectinput_witherr(mDisplay
, vo_window
,
449 StructureNotifyMask
| KeyPressMask
|
450 PropertyChangeMask
| ExposureMask
|
452 0) ? 0 : (ButtonPressMask
|
454 PointerMotionMask
)));
459 /* Grab the mouse pointer in our window */
461 XGrabPointer(mDisplay
, vo_window
, True
, 0,
462 GrabModeAsync
, GrabModeAsync
,
463 vo_window
, None
, CurrentTime
);
464 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
470 XFreeGC(mDisplay
, vo_gc
);
471 vo_gc
= XCreateGC(mDisplay
, vo_window
, 0L, &xgcv
);
476 sws_freeContext(swsContext
);
482 vo_dwidth
= vo_screenwidth
;
483 vo_dheight
= vo_screenheight
;
486 while (fmte
->mpfmt
) {
487 if (IMGFMT_RGB_DEPTH(fmte
->mpfmt
) == myximage
->bits_per_pixel
&&
488 fmte
->byte_order
== myximage
->byte_order
&&
489 fmte
->red_mask
== myximage
->red_mask
&&
490 fmte
->green_mask
== myximage
->green_mask
&&
491 fmte
->blue_mask
== myximage
->blue_mask
)
496 mp_msg(MSGT_VO
, MSGL_ERR
,
497 "X server image format not supported, please contact the developers\n");
500 out_format
= fmte
->mpfmt
;
501 switch ((bpp
= myximage
->bits_per_pixel
))
504 draw_alpha_fnc
= draw_alpha_24
;
507 draw_alpha_fnc
= draw_alpha_32
;
512 draw_alpha_fnc
= draw_alpha_15
;
514 draw_alpha_fnc
= draw_alpha_16
;
517 draw_alpha_fnc
= draw_alpha_null
;
520 // for these formats conversion is currently not support and
521 // we can easily "emulate" them.
522 if (out_format
& 64 && (IMGFMT_IS_RGB(out_format
) || IMGFMT_IS_BGR(out_format
))) {
524 #ifdef WORDS_BIGENDIAN
531 /* always allocate swsContext as size could change between frames */
533 sws_getContextFromCmdLine(width
, height
, in_format
, width
, height
,
539 //printf( "X11 bpp: %d color mask: R:%lX G:%lX B:%lX\n",bpp,myximage->red_mask,myximage->green_mask,myximage->blue_mask );
542 vo_x11_setlayer(mDisplay
, vo_window
, vo_ontop
);
547 static void Display_Image(XImage
* myximage
, uint8_t * ImageData
)
549 myximage
->data
+= out_offset
;
553 XShmPutImage(mDisplay
, vo_window
, vo_gc
, myximage
,
555 (vo_dwidth
- dst_width
) / 2,
556 (vo_dheight
- myximage
->height
) / 2, dst_width
,
557 myximage
->height
, True
);
561 XPutImage(mDisplay
, vo_window
, vo_gc
, myximage
,
563 (vo_dwidth
- dst_width
) / 2,
564 (vo_dheight
- myximage
->height
) / 2, dst_width
,
567 myximage
->data
-= out_offset
;
570 static void draw_osd(void)
572 vo_draw_text(image_width
, image_height
, draw_alpha_fnc
);
575 static void flip_page(void)
577 Display_Image(myximage
, ImageData
);
578 XSync(mDisplay
, False
);
581 static int draw_slice(uint8_t * src
[], int stride
[], int w
, int h
,
587 if ((old_vo_dwidth
!= vo_dwidth
588 || old_vo_dheight
!= vo_dheight
) /*&& y==0 */ && zoomFlag
)
590 int newW
= vo_dwidth
;
591 int newH
= vo_dheight
;
592 int newAspect
= (newW
* (1 << 16) + (newH
>> 1)) / newH
;
593 struct SwsContext
*oldContext
= swsContext
;
595 if (newAspect
> aspect
)
596 newW
= (newH
* aspect
+ (1 << 15)) >> 16;
598 newH
= ((newW
<< 16) + (aspect
>> 1)) / aspect
;
600 old_vo_dwidth
= vo_dwidth
;
601 old_vo_dheight
= vo_dheight
;
604 newW
&= (~31); // not needed but, if the user wants the FAST_BILINEAR SCALER, then its needed
606 swsContext
= sws_getContextFromCmdLine(srcW
, srcH
, in_format
,
607 newW
, newH
, out_format
);
610 image_width
= (newW
+ 7) & (~7);
615 sws_freeContext(oldContext
);
618 swsContext
= oldContext
;
622 dstStride
[1] = dstStride
[2] = 0;
623 dst
[1] = dst
[2] = NULL
;
625 dstStride
[0] = image_width
* ((bpp
+ 7) / 8);
629 dst
[0] += dstStride
[0] * (image_height
- 1);
630 dstStride
[0] = -dstStride
[0];
632 sws_scale_ordered(swsContext
, src
, stride
, y
, h
, dst
, dstStride
);
636 static int draw_frame(uint8_t * src
[])
639 int stride
[3] = { 0, 0, 0 };
641 if (in_format
== IMGFMT_YUY2
)
642 stride
[0] = srcW
* 2;
643 else if (in_format
== IMGFMT_BGR8
)
645 else if (in_format
== IMGFMT_BGR15
)
646 stride
[0] = srcW
* 2;
647 else if (in_format
== IMGFMT_BGR16
)
648 stride
[0] = srcW
* 2;
649 else if (in_format
== IMGFMT_BGR24
)
650 stride
[0] = srcW
* 3;
651 else if (in_format
== IMGFMT_BGR32
)
652 stride
[0] = srcW
* 4;
654 return draw_slice(src
, stride
, srcW
, srcH
, 0, 0);
656 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_X11_DrawFrameCalled
);
661 static uint32_t get_image(mp_image_t
* mpi
)
664 !IMGFMT_IS_BGR(mpi
->imgfmt
) ||
665 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) != vo_depthonscreen
) ||
666 ((mpi
->type
!= MP_IMGTYPE_STATIC
)
667 && (mpi
->type
!= MP_IMGTYPE_TEMP
))
668 || (mpi
->flags
& MP_IMGFLAG_PLANAR
)
669 || (mpi
->flags
& MP_IMGFLAG_YUV
) || (mpi
->width
!= image_width
)
670 || (mpi
->height
!= image_height
))
675 mpi
->stride
[0] = -image_width
* ((bpp
+ 7) / 8);
676 mpi
->planes
[0] = ImageData
- mpi
->stride
[0] * (image_height
- 1);
679 mpi
->stride
[0] = image_width
* ((bpp
+ 7) / 8);
680 mpi
->planes
[0] = ImageData
;
682 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
687 static int query_format(uint32_t format
)
689 mp_msg(MSGT_VO
, MSGL_DBG2
,
690 "vo_x11: query_format was called: %x (%s)\n", format
,
691 vo_format_name(format
));
692 if (IMGFMT_IS_BGR(format
))
694 if (IMGFMT_BGR_DEPTH(format
) <= 8)
695 return 0; // TODO 8bpp not yet fully implemented
696 if (IMGFMT_BGR_DEPTH(format
) == vo_depthonscreen
)
697 return VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_FLIP
|
700 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_FLIP
|
707 // case IMGFMT_BGR15:
708 // case IMGFMT_BGR16:
709 // case IMGFMT_BGR24:
710 // case IMGFMT_BGR32:
716 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
;
722 static void uninit(void)
730 vo_vm_close(mDisplay
);
736 sws_freeContext(swsContext
);
739 static int preinit(const char *arg
)
743 mp_msg(MSGT_VO
, MSGL_ERR
, "vo_x11: Unknown subdevice: %s\n", arg
);
748 return -1; // Can't open X11
752 static int control(uint32_t request
, void *data
, ...)
757 return (int_pause
= 1);
759 return (int_pause
= 0);
760 case VOCTRL_QUERY_FORMAT
:
761 return query_format(*((uint32_t *) data
));
762 case VOCTRL_GUISUPPORT
:
764 case VOCTRL_GET_IMAGE
:
765 return get_image(data
);
766 case VOCTRL_SET_EQUALIZER
:
772 value
= va_arg(ap
, int);
775 return vo_x11_set_equalizer(data
, value
);
777 case VOCTRL_GET_EQUALIZER
:
783 value
= va_arg(ap
, int *);
786 return vo_x11_get_equalizer(data
, value
);
791 case VOCTRL_FULLSCREEN
:
794 vo_x11_clearwindow(mDisplay
, vo_window
);
797 case VOCTRL_UPDATE_SCREENINFO
:
798 update_xinerama_info();