8 #include "video_out_internal.h"
13 #include <X11/Xutil.h>
17 #include "x11_common.h"
22 #include <X11/extensions/XShm.h>
24 static int Shmem_Flag
;
26 //static int Quiet_Flag; Here also what is this for. It's used but isn't initialized?
27 static XShmSegmentInfo Shminfo
[1];
28 static int gXErrorFlag
;
29 static int CompletionType
= -1;
34 #include "libswscale/swscale.h"
35 #include "libmpcodecs/vf_scale.h"
43 #include "gui/interface.h"
47 static const vo_info_t info
= {
50 "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>",
54 const LIBVO_EXTERN(x11
)
55 /* private prototypes */
56 static void Display_Image(XImage
* myximage
, unsigned char *ImageData
);
57 static void (*draw_alpha_fnc
) (int x0
, int y0
, int w
, int h
,
58 unsigned char *src
, unsigned char *srca
,
62 static unsigned char *ImageData
;
63 //! original unaligned pointer for free
64 static unsigned char *ImageDataOrig
;
66 /* X11 related variables */
67 static XImage
*myximage
= NULL
;
68 static int depth
, bpp
;
69 static XWindowAttributes attribs
;
77 static uint32_t image_width
;
78 static uint32_t image_height
;
79 static uint32_t in_format
;
80 static uint32_t out_format
= 0;
81 static int out_offset
;
85 static int old_vo_dwidth
= -1;
86 static int old_vo_dheight
= -1;
88 static void check_events(void)
90 int ret
= vo_x11_check_events(mDisplay
);
92 /* clear left over borders and redraw frame if we are paused */
93 if (ret
& VO_EVENT_EXPOSE
&& int_pause
)
95 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
,
98 } else if ((ret
& VO_EVENT_RESIZE
) || (ret
& VO_EVENT_EXPOSE
))
99 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
,
100 myximage
->height
, 0);
104 static void draw_alpha_32(int x0
, int y0
, int w
, int h
, unsigned char *src
,
105 unsigned char *srca
, int stride
)
107 vo_draw_alpha_rgb32(w
, h
, src
, srca
, stride
,
108 ImageData
+ 4 * (y0
* image_width
+ x0
),
112 static void draw_alpha_24(int x0
, int y0
, int w
, int h
, unsigned char *src
,
113 unsigned char *srca
, int stride
)
115 vo_draw_alpha_rgb24(w
, h
, src
, srca
, stride
,
116 ImageData
+ 3 * (y0
* image_width
+ x0
),
120 static void draw_alpha_16(int x0
, int y0
, int w
, int h
, unsigned char *src
,
121 unsigned char *srca
, int stride
)
123 vo_draw_alpha_rgb16(w
, h
, src
, srca
, stride
,
124 ImageData
+ 2 * (y0
* image_width
+ x0
),
128 static void draw_alpha_15(int x0
, int y0
, int w
, int h
, unsigned char *src
,
129 unsigned char *srca
, int stride
)
131 vo_draw_alpha_rgb15(w
, h
, src
, srca
, stride
,
132 ImageData
+ 2 * (y0
* image_width
+ x0
),
136 static void draw_alpha_null(int x0
, int y0
, int w
, int h
,
137 unsigned char *src
, unsigned char *srca
,
142 static struct SwsContext
*swsContext
= NULL
;
143 static int dst_width
;
144 extern int sws_flags
;
146 static XVisualInfo vinfo
;
148 static void getMyXImage(void)
151 if (mLocalDisplay
&& XShmQueryExtension(mDisplay
))
156 mp_msg(MSGT_VO
, MSGL_WARN
,
157 "Shared memory not supported\nReverting to normal Xlib\n");
160 CompletionType
= XShmGetEventBase(mDisplay
) + ShmCompletion
;
165 XShmCreateImage(mDisplay
, vinfo
.visual
, depth
, ZPixmap
, NULL
,
166 &Shminfo
[0], image_width
, image_height
);
167 if (myximage
== NULL
)
169 mp_msg(MSGT_VO
, MSGL_WARN
,
170 "Shared memory error,disabling ( Ximage error )\n");
173 Shminfo
[0].shmid
= shmget(IPC_PRIVATE
,
174 myximage
->bytes_per_line
*
175 myximage
->height
, IPC_CREAT
| 0777);
176 if (Shminfo
[0].shmid
< 0)
178 XDestroyImage(myximage
);
179 mp_msg(MSGT_VO
, MSGL_V
, "%s\n", strerror(errno
));
180 //perror( strerror( errno ) );
181 mp_msg(MSGT_VO
, MSGL_WARN
,
182 "Shared memory error,disabling ( seg id error )\n");
185 Shminfo
[0].shmaddr
= (char *) shmat(Shminfo
[0].shmid
, 0, 0);
187 if (Shminfo
[0].shmaddr
== ((char *) -1))
189 XDestroyImage(myximage
);
190 if (Shminfo
[0].shmaddr
!= ((char *) -1))
191 shmdt(Shminfo
[0].shmaddr
);
192 mp_msg(MSGT_VO
, MSGL_WARN
,
193 "Shared memory error,disabling ( address error )\n");
196 myximage
->data
= Shminfo
[0].shmaddr
;
197 ImageData
= (unsigned char *) myximage
->data
;
198 Shminfo
[0].readOnly
= False
;
199 XShmAttach(mDisplay
, &Shminfo
[0]);
201 XSync(mDisplay
, False
);
205 XDestroyImage(myximage
);
206 shmdt(Shminfo
[0].shmaddr
);
207 mp_msg(MSGT_VO
, MSGL_WARN
, "Shared memory error,disabling.\n");
211 shmctl(Shminfo
[0].shmid
, IPC_RMID
, 0);
214 static int firstTime
= 1;
218 mp_msg(MSGT_VO
, MSGL_V
, "Sharing memory.\n");
227 myximage
= XCreateImage(mDisplay
, vinfo
.visual
, depth
, ZPixmap
,
228 0, NULL
, image_width
, image_height
, 8, 0);
229 ImageDataOrig
= malloc(myximage
->bytes_per_line
* image_height
+ 32);
230 myximage
->data
= ImageDataOrig
+ 16 - ((long)ImageDataOrig
& 15);
231 memset(myximage
->data
, 0, myximage
->bytes_per_line
* image_height
);
232 ImageData
= myximage
->data
;
238 static void freeMyXImage(void)
243 XShmDetach(mDisplay
, &Shminfo
[0]);
244 XDestroyImage(myximage
);
245 shmdt(Shminfo
[0].shmaddr
);
249 myximage
->data
= ImageDataOrig
;
250 XDestroyImage(myximage
);
251 ImageDataOrig
= NULL
;
257 #ifdef WORDS_BIGENDIAN
258 #define BO_NATIVE MSBFirst
259 #define BO_NONNATIVE LSBFirst
261 #define BO_NATIVE LSBFirst
262 #define BO_NONNATIVE MSBFirst
264 const struct fmt2Xfmtentry_s
{
271 {IMGFMT_RGB8
, BO_NATIVE
, 0x00000007, 0x00000038, 0x000000C0},
272 {IMGFMT_RGB8
, BO_NONNATIVE
, 0x00000007, 0x00000038, 0x000000C0},
273 {IMGFMT_BGR8
, BO_NATIVE
, 0x000000E0, 0x0000001C, 0x00000003},
274 {IMGFMT_BGR8
, BO_NONNATIVE
, 0x000000E0, 0x0000001C, 0x00000003},
275 {IMGFMT_RGB15
, BO_NATIVE
, 0x0000001F, 0x000003E0, 0x00007C00},
276 {IMGFMT_BGR15
, BO_NATIVE
, 0x00007C00, 0x000003E0, 0x0000001F},
277 {IMGFMT_RGB16
, BO_NATIVE
, 0x0000001F, 0x000007E0, 0x0000F800},
278 {IMGFMT_BGR16
, BO_NATIVE
, 0x0000F800, 0x000007E0, 0x0000001F},
279 {IMGFMT_RGB24
, MSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
280 {IMGFMT_RGB24
, LSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
281 {IMGFMT_BGR24
, MSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
282 {IMGFMT_BGR24
, LSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
283 {IMGFMT_RGB32
, BO_NATIVE
, 0x000000FF, 0x0000FF00, 0x00FF0000},
284 {IMGFMT_RGB32
, BO_NONNATIVE
, 0xFF000000, 0x00FF0000, 0x0000FF00},
285 {IMGFMT_BGR32
, BO_NATIVE
, 0x00FF0000, 0x0000FF00, 0x000000FF},
286 {IMGFMT_BGR32
, BO_NONNATIVE
, 0x0000FF00, 0x00FF0000, 0xFF000000},
287 {IMGFMT_ARGB
, MSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
288 {IMGFMT_ARGB
, LSBFirst
, 0x0000FF00, 0x00FF0000, 0xFF000000},
289 {IMGFMT_ABGR
, MSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
290 {IMGFMT_ABGR
, LSBFirst
, 0xFF000000, 0x00FF0000, 0x0000FF00},
291 {IMGFMT_RGBA
, MSBFirst
, 0xFF000000, 0x00FF0000, 0x0000FF00},
292 {IMGFMT_RGBA
, LSBFirst
, 0x000000FF, 0x0000FF00, 0x00FF0000},
293 {IMGFMT_BGRA
, MSBFirst
, 0x0000FF00, 0x00FF0000, 0xFF000000},
294 {IMGFMT_BGRA
, LSBFirst
, 0x00FF0000, 0x0000FF00, 0x000000FF},
298 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
299 uint32_t d_height
, uint32_t flags
, char *title
,
304 // int interval, prefer_blank, allow_exp, nothing;
307 XSetWindowAttributes xswa
;
308 unsigned long xswamask
;
309 const struct fmt2Xfmtentry_s
*fmte
= fmt2Xfmt
;
312 int vm
= flags
& VOFLAG_MODESWITCHING
;
314 Flip_Flag
= flags
& VOFLAG_FLIPPING
;
315 zoomFlag
= flags
& VOFLAG_SWSCALE
;
322 title
= "MPlayer X11 (XImage/Shm) render";
328 XGetWindowAttributes(mDisplay
, mRootWin
, &attribs
);
329 depth
= attribs
.depth
;
331 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
335 depth
= vo_find_depth_from_visuals(mDisplay
, mScreen
, &visual
);
337 if (!XMatchVisualInfo(mDisplay
, mScreen
, depth
, DirectColor
, &vinfo
) ||
339 && vinfo
.visualid
!= XVisualIDFromVisual(attribs
.visual
)))
340 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
342 /* set image size (which is indeed neither the input nor output size),
343 if zoom is on it will be changed during draw_slice anyway so we don't duplicate the aspect code here
345 image_width
= (width
+ 7) & (~7);
346 image_height
= height
;
350 guiGetEvent(guiSetShVideo
, 0); // the GUI will set up / resize the window
360 bg
= WhitePixel(mDisplay
, mScreen
);
361 fg
= BlackPixel(mDisplay
, mScreen
);
363 theCmap
= vo_x11_create_colormap(&vinfo
);
365 xswa
.background_pixel
= 0;
366 xswa
.border_pixel
= 0;
367 xswa
.colormap
= theCmap
;
368 xswamask
= CWBackPixel
| CWBorderPixel
| CWColormap
;
373 xswa
.override_redirect
= True
;
374 xswamask
|= CWOverrideRedirect
;
378 vo_x11_create_vo_window(&vinfo
, vo_dx
, vo_dy
, vo_dwidth
, vo_dheight
,
379 flags
, theCmap
, "x11", title
);
381 depth
= vo_x11_update_geometry();
386 /* Grab the mouse pointer in our window */
388 XGrabPointer(mDisplay
, vo_window
, True
, 0,
389 GrabModeAsync
, GrabModeAsync
,
390 vo_window
, None
, CurrentTime
);
391 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
399 sws_freeContext(swsContext
);
403 while (fmte
->mpfmt
) {
404 int depth
= IMGFMT_RGB_DEPTH(fmte
->mpfmt
);
405 /* bits_per_pixel in X seems to be set to 16 for 15 bit formats
406 => force depth to 16 so that only the color masks are used for the format check */
410 if (depth
== myximage
->bits_per_pixel
&&
411 fmte
->byte_order
== myximage
->byte_order
&&
412 fmte
->red_mask
== myximage
->red_mask
&&
413 fmte
->green_mask
== myximage
->green_mask
&&
414 fmte
->blue_mask
== myximage
->blue_mask
)
419 mp_msg(MSGT_VO
, MSGL_ERR
,
420 "X server image format not supported, please contact the developers\n");
423 out_format
= fmte
->mpfmt
;
424 switch ((bpp
= myximage
->bits_per_pixel
))
427 draw_alpha_fnc
= draw_alpha_24
;
430 draw_alpha_fnc
= draw_alpha_32
;
435 draw_alpha_fnc
= draw_alpha_15
;
437 draw_alpha_fnc
= draw_alpha_16
;
440 draw_alpha_fnc
= draw_alpha_null
;
443 // for these formats conversion is currently not support and
444 // we can easily "emulate" them.
445 if (out_format
& 64 && (IMGFMT_IS_RGB(out_format
) || IMGFMT_IS_BGR(out_format
))) {
447 #ifdef WORDS_BIGENDIAN
454 /* always allocate swsContext as size could change between frames */
456 sws_getContextFromCmdLine(width
, height
, in_format
, width
, height
,
462 //printf( "X11 bpp: %d color mask: R:%lX G:%lX B:%lX\n",bpp,myximage->red_mask,myximage->green_mask,myximage->blue_mask );
467 static void Display_Image(XImage
* myximage
, uint8_t * ImageData
)
469 int x
= (vo_dwidth
- dst_width
) / 2;
470 int y
= (vo_dheight
- myximage
->height
) / 2;
475 myximage
->data
+= out_offset
;
479 XShmPutImage(mDisplay
, vo_window
, vo_gc
, myximage
,
482 myximage
->height
, True
);
486 XPutImage(mDisplay
, vo_window
, vo_gc
, myximage
,
491 myximage
->data
-= out_offset
;
494 static void draw_osd(void)
496 vo_draw_text(image_width
, image_height
, draw_alpha_fnc
);
499 static void flip_page(void)
501 Display_Image(myximage
, ImageData
);
502 XSync(mDisplay
, False
);
505 static int draw_slice(uint8_t * src
[], int stride
[], int w
, int h
,
511 if ((old_vo_dwidth
!= vo_dwidth
512 || old_vo_dheight
!= vo_dheight
) /*&& y==0 */ && zoomFlag
)
514 int newW
= vo_dwidth
;
515 int newH
= vo_dheight
;
516 struct SwsContext
*oldContext
= swsContext
;
518 old_vo_dwidth
= vo_dwidth
;
519 old_vo_dheight
= vo_dheight
;
522 aspect(&newW
, &newH
, A_ZOOM
);
524 newW
&= (~31); // not needed but, if the user wants the FAST_BILINEAR SCALER, then its needed
526 swsContext
= sws_getContextFromCmdLine(srcW
, srcH
, in_format
,
527 newW
, newH
, out_format
);
530 image_width
= (newW
+ 7) & (~7);
535 sws_freeContext(oldContext
);
538 swsContext
= oldContext
;
542 dstStride
[1] = dstStride
[2] = 0;
543 dst
[1] = dst
[2] = NULL
;
545 dstStride
[0] = image_width
* ((bpp
+ 7) / 8);
549 dst
[0] += dstStride
[0] * (image_height
- 1);
550 dstStride
[0] = -dstStride
[0];
552 sws_scale_ordered(swsContext
, src
, stride
, y
, h
, dst
, dstStride
);
556 static int draw_frame(uint8_t * src
[])
561 static uint32_t get_image(mp_image_t
* mpi
)
564 !IMGFMT_IS_BGR(mpi
->imgfmt
) ||
565 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) != vo_depthonscreen
) ||
566 ((mpi
->type
!= MP_IMGTYPE_STATIC
)
567 && (mpi
->type
!= MP_IMGTYPE_TEMP
))
568 || (mpi
->flags
& MP_IMGFLAG_PLANAR
)
569 || (mpi
->flags
& MP_IMGFLAG_YUV
) || (mpi
->width
!= image_width
)
570 || (mpi
->height
!= image_height
))
575 mpi
->stride
[0] = -image_width
* ((bpp
+ 7) / 8);
576 mpi
->planes
[0] = ImageData
- mpi
->stride
[0] * (image_height
- 1);
579 mpi
->stride
[0] = image_width
* ((bpp
+ 7) / 8);
580 mpi
->planes
[0] = ImageData
;
582 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
587 static int query_format(uint32_t format
)
589 mp_msg(MSGT_VO
, MSGL_DBG2
,
590 "vo_x11: query_format was called: %x (%s)\n", format
,
591 vo_format_name(format
));
592 if (IMGFMT_IS_BGR(format
))
594 if (IMGFMT_BGR_DEPTH(format
) <= 8)
595 return 0; // TODO 8bpp not yet fully implemented
596 if (IMGFMT_BGR_DEPTH(format
) == vo_depthonscreen
)
597 return VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_FLIP
|
600 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_FLIP
|
607 // case IMGFMT_BGR15:
608 // case IMGFMT_BGR16:
609 // case IMGFMT_BGR24:
610 // case IMGFMT_BGR32:
616 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
;
622 static void uninit(void)
636 sws_freeContext(swsContext
);
639 static int preinit(const char *arg
)
643 mp_msg(MSGT_VO
, MSGL_ERR
, "vo_x11: Unknown subdevice: %s\n", arg
);
648 return -1; // Can't open X11
652 static int control(uint32_t request
, void *data
, ...)
657 return int_pause
= 1;
659 return int_pause
= 0;
660 case VOCTRL_QUERY_FORMAT
:
661 return query_format(*((uint32_t *) data
));
662 case VOCTRL_GET_IMAGE
:
663 return get_image(data
);
664 case VOCTRL_GUISUPPORT
:
666 case VOCTRL_FULLSCREEN
:
668 vo_x11_clearwindow(mDisplay
, vo_window
);
670 case VOCTRL_SET_EQUALIZER
:
676 value
= va_arg(ap
, int);
679 return vo_x11_set_equalizer(data
, value
);
681 case VOCTRL_GET_EQUALIZER
:
687 value
= va_arg(ap
, int *);
690 return vo_x11_get_equalizer(data
, value
);
695 case VOCTRL_UPDATE_SCREENINFO
:
696 update_xinerama_info();