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
*);
38 #include "fastmemcpy.h"
41 #include "postproc/swscale.h"
42 #include "postproc/swscale_internal.h" //FIXME
43 #include "postproc/rgb2rgb.h"
44 #include "libmpcodecs/vf_scale.h"
50 #include "Gui/interface.h"
54 static vo_info_t info
= {
57 "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>",
62 /* private prototypes */
63 static void Display_Image(XImage
* myximage
, unsigned char *ImageData
);
64 static void (*draw_alpha_fnc
) (int x0
, int y0
, int w
, int h
,
65 unsigned char *src
, unsigned char *srca
,
69 static unsigned char *ImageData
;
71 /* X11 related variables */
72 static XImage
*myximage
= NULL
;
73 static int depth
, bpp
, mode
;
74 static XWindowAttributes attribs
;
82 static uint32_t image_width
;
83 static uint32_t image_height
;
84 static uint32_t in_format
;
85 static uint32_t out_format
= 0;
88 static int aspect
; // 1<<16 based fixed point aspect, so that the aspect stays correct during resizing
90 static int old_vo_dwidth
= -1;
91 static int old_vo_dheight
= -1;
93 static void check_events()
95 int ret
= vo_x11_check_events(mDisplay
);
97 /* clear left over borders and redraw frame if we are paused */
98 if (ret
& VO_EVENT_EXPOSE
&& int_pause
)
100 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
,
101 myximage
->height
, 0);
103 } else if ((ret
& VO_EVENT_RESIZE
) || (ret
& VO_EVENT_EXPOSE
))
104 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
,
105 myximage
->height
, 0);
109 static void draw_alpha_32(int x0
, int y0
, int w
, int h
, unsigned char *src
,
110 unsigned char *srca
, int stride
)
112 vo_draw_alpha_rgb32(w
, h
, src
, srca
, stride
,
113 ImageData
+ 4 * (y0
* image_width
+ x0
),
117 static void draw_alpha_24(int x0
, int y0
, int w
, int h
, unsigned char *src
,
118 unsigned char *srca
, int stride
)
120 vo_draw_alpha_rgb24(w
, h
, src
, srca
, stride
,
121 ImageData
+ 3 * (y0
* image_width
+ x0
),
125 static void draw_alpha_16(int x0
, int y0
, int w
, int h
, unsigned char *src
,
126 unsigned char *srca
, int stride
)
128 vo_draw_alpha_rgb16(w
, h
, src
, srca
, stride
,
129 ImageData
+ 2 * (y0
* image_width
+ x0
),
133 static void draw_alpha_15(int x0
, int y0
, int w
, int h
, unsigned char *src
,
134 unsigned char *srca
, int stride
)
136 vo_draw_alpha_rgb15(w
, h
, src
, srca
, stride
,
137 ImageData
+ 2 * (y0
* image_width
+ x0
),
141 static void draw_alpha_null(int x0
, int y0
, int w
, int h
,
142 unsigned char *src
, unsigned char *srca
,
147 static SwsContext
*swsContext
= NULL
;
148 extern int sws_flags
;
150 static XVisualInfo vinfo
;
152 static void getMyXImage(void)
155 if (mLocalDisplay
&& XShmQueryExtension(mDisplay
))
160 mp_msg(MSGT_VO
, MSGL_WARN
,
161 "Shared memory not supported\nReverting to normal Xlib\n");
164 CompletionType
= XShmGetEventBase(mDisplay
) + ShmCompletion
;
169 XShmCreateImage(mDisplay
, vinfo
.visual
, depth
, ZPixmap
, NULL
,
170 &Shminfo
[0], image_width
, image_height
);
171 if (myximage
== NULL
)
173 if (myximage
!= NULL
)
174 XDestroyImage(myximage
);
175 mp_msg(MSGT_VO
, MSGL_WARN
,
176 "Shared memory error,disabling ( Ximage error )\n");
179 Shminfo
[0].shmid
= shmget(IPC_PRIVATE
,
180 myximage
->bytes_per_line
*
181 myximage
->height
, IPC_CREAT
| 0777);
182 if (Shminfo
[0].shmid
< 0)
184 XDestroyImage(myximage
);
185 mp_msg(MSGT_VO
, MSGL_V
, "%s\n", strerror(errno
));
186 //perror( strerror( errno ) );
187 mp_msg(MSGT_VO
, MSGL_WARN
,
188 "Shared memory error,disabling ( seg id error )\n");
191 Shminfo
[0].shmaddr
= (char *) shmat(Shminfo
[0].shmid
, 0, 0);
193 if (Shminfo
[0].shmaddr
== ((char *) -1))
195 XDestroyImage(myximage
);
196 if (Shminfo
[0].shmaddr
!= ((char *) -1))
197 shmdt(Shminfo
[0].shmaddr
);
198 mp_msg(MSGT_VO
, MSGL_WARN
,
199 "Shared memory error,disabling ( address error )\n");
202 myximage
->data
= Shminfo
[0].shmaddr
;
203 ImageData
= (unsigned char *) myximage
->data
;
204 Shminfo
[0].readOnly
= False
;
205 XShmAttach(mDisplay
, &Shminfo
[0]);
207 XSync(mDisplay
, False
);
211 XDestroyImage(myximage
);
212 shmdt(Shminfo
[0].shmaddr
);
213 mp_msg(MSGT_VO
, MSGL_WARN
, "Shared memory error,disabling.\n");
217 shmctl(Shminfo
[0].shmid
, IPC_RMID
, 0);
220 static int firstTime
= 1;
224 mp_msg(MSGT_VO
, MSGL_V
, "Sharing memory.\n");
233 myximage
= XGetImage(mDisplay
, vo_window
, 0, 0,
234 image_width
, image_height
, AllPlanes
,
236 ImageData
= myximage
->data
;
242 static void freeMyXImage(void)
247 XShmDetach(mDisplay
, &Shminfo
[0]);
248 XDestroyImage(myximage
);
249 shmdt(Shminfo
[0].shmaddr
);
253 XDestroyImage(myximage
);
258 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
259 uint32_t d_height
, uint32_t flags
, char *title
,
266 // int interval, prefer_blank, allow_exp, nothing;
271 XSetWindowAttributes xswa
;
272 unsigned long xswamask
;
275 unsigned int modeline_width
, modeline_height
;
276 static uint32_t vm_width
;
277 static uint32_t vm_height
;
280 vo_mouse_autohide
= 1;
285 title
= "MPlayer X11 (XImage/Shm) render";
290 update_xinerama_info();
291 vo_dx
= (vo_screenwidth
- d_width
) / 2;
292 vo_dy
= (vo_screenheight
- d_height
) / 2;
293 geometry(&vo_dx
, &vo_dy
, &d_width
, &d_height
, vo_screenwidth
,
298 vo_dheight
= d_height
;
300 if (flags
& (VOFLAG_FULLSCREEN
|VOFLAG_MODESWITCHING
))
302 if (flags
& VOFLAG_MODESWITCHING
)
304 if (flags
& VOFLAG_FLIPPING
)
306 zoomFlag
= flags
& VOFLAG_SWSCALE
;
309 // if(!fullscreen) zoomFlag=1; //it makes no sense to avoid zooming on windowd mode
311 //printf( "w: %d h: %d\n\n",vo_dwidth,vo_dheight );
313 XGetWindowAttributes(mDisplay
, mRootWin
, &attribs
);
314 depth
= attribs
.depth
;
316 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
320 depth
= vo_find_depth_from_visuals(mDisplay
, mScreen
, &visual
);
322 if (!XMatchVisualInfo(mDisplay
, mScreen
, depth
, DirectColor
, &vinfo
) ||
324 && vinfo
.visualid
!= XVisualIDFromVisual(attribs
.visual
)))
325 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
327 /* set image size (which is indeed neither the input nor output size),
328 if zoom is on it will be changed during draw_slice anyway so we don't duplicate the aspect code here
330 image_width
= (width
+ 7) & (~7);
331 image_height
= height
;
333 aspect
= ((1 << 16) * d_width
+ d_height
/ 2) / d_height
;
337 guiGetEvent(guiSetShVideo
, 0); // the GUI will set up / resize the window
344 if ((d_width
== 0) && (d_height
== 0))
346 vm_width
= image_width
;
347 vm_height
= image_height
;
351 vm_height
= d_height
;
353 vo_vm_switch(vm_width
, vm_height
, &modeline_width
,
355 vo_dx
= (vo_screenwidth
- modeline_width
) / 2;
356 vo_dy
= (vo_screenheight
- modeline_height
) / 2;
357 vo_dwidth
= modeline_width
;
358 vo_dheight
= modeline_height
;
361 bg
= WhitePixel(mDisplay
, mScreen
);
362 fg
= BlackPixel(mDisplay
, mScreen
);
364 theCmap
= vo_x11_create_colormap(&vinfo
);
366 xswa
.background_pixel
= 0;
367 xswa
.border_pixel
= 0;
368 xswa
.colormap
= theCmap
;
369 xswamask
= CWBackPixel
| CWBorderPixel
| CWColormap
;
374 xswa
.override_redirect
= True
;
375 xswamask
|= CWOverrideRedirect
;
381 vo_window
= WinID
? ((Window
) WinID
) : mRootWin
;
386 XUnmapWindow(mDisplay
, vo_window
);
387 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
,
389 vo_x11_selectinput_witherr(mDisplay
, vo_window
,
390 StructureNotifyMask
|
397 XMapWindow(mDisplay
, vo_window
);
398 XGetGeometry(mDisplay
, vo_window
, &mRootWin
,
399 &vo_dx
, &vo_dy
, &vo_dwidth
, &vo_dheight
,
402 XSelectInput(mDisplay
, vo_window
, ExposureMask
);
405 if (vo_window
== None
)
408 vo_x11_create_smooth_window(mDisplay
, mRootWin
,
409 vinfo
.visual
, vo_dx
, vo_dy
,
410 vo_dwidth
, vo_dheight
,
413 vo_x11_classhint(mDisplay
, vo_window
, "x11");
414 vo_hidecursor(mDisplay
, vo_window
);
415 vo_x11_sizehint(vo_dx
, vo_dy
, vo_dwidth
, vo_dheight
, 0);
416 XSelectInput(mDisplay
, vo_window
, StructureNotifyMask
);
417 XStoreName(mDisplay
, vo_window
, title
);
418 XMapWindow(mDisplay
, vo_window
);
422 XNextEvent(mDisplay
, &xev
);
424 while (xev
.type
!= MapNotify
425 || xev
.xmap
.event
!= vo_window
);
429 } else if (!fullscreen
)
430 XMoveResizeWindow(mDisplay
, vo_window
, vo_dx
, vo_dy
,
431 vo_dwidth
, vo_dheight
);
434 XSync(mDisplay
, False
);
436 // we cannot grab mouse events on root window :(
437 vo_x11_selectinput_witherr(mDisplay
, vo_window
,
438 StructureNotifyMask
| KeyPressMask
|
439 PropertyChangeMask
| ExposureMask
|
441 0) ? 0 : (ButtonPressMask
|
443 PointerMotionMask
)));
448 /* Grab the mouse pointer in our window */
450 XGrabPointer(mDisplay
, vo_window
, True
, 0,
451 GrabModeAsync
, GrabModeAsync
,
452 vo_window
, None
, CurrentTime
);
453 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
459 XFreeGC(mDisplay
, vo_gc
);
460 vo_gc
= XCreateGC(mDisplay
, vo_window
, 0L, &xgcv
);
465 sws_freeContext(swsContext
);
471 vo_dwidth
= vo_screenwidth
;
472 vo_dheight
= vo_screenheight
;
475 switch ((bpp
= myximage
->bits_per_pixel
))
478 draw_alpha_fnc
= draw_alpha_24
;
479 out_format
= IMGFMT_BGR24
;
482 draw_alpha_fnc
= draw_alpha_32
;
483 out_format
= IMGFMT_BGR32
;
489 draw_alpha_fnc
= draw_alpha_15
;
490 out_format
= IMGFMT_BGR15
;
493 draw_alpha_fnc
= draw_alpha_16
;
494 out_format
= IMGFMT_BGR16
;
498 draw_alpha_fnc
= draw_alpha_null
;
499 out_format
= IMGFMT_BGR8
;
502 draw_alpha_fnc
= draw_alpha_null
;
505 /* always allocate swsContext as size could change between frames */
507 sws_getContextFromCmdLine(width
, height
, in_format
, width
, height
,
512 //printf( "X11 bpp: %d color mask: R:%lX G:%lX B:%lX\n",bpp,myximage->red_mask,myximage->green_mask,myximage->blue_mask );
514 // If we have blue in the lowest bit then obviously RGB
515 mode
= ((myximage
->blue_mask
& 0x01) != 0) ? MODE_RGB
: MODE_BGR
;
516 #ifdef WORDS_BIGENDIAN
517 if (myximage
->byte_order
!= MSBFirst
)
519 if (myximage
->byte_order
!= LSBFirst
)
522 mode
= ((myximage
->blue_mask
& 0x01) != 0) ? MODE_BGR
: MODE_RGB
;
523 // printf( "No support for non-native XImage byte order!\n" );
526 #ifdef WORDS_BIGENDIAN
527 if (mode
== MODE_BGR
&& bpp
!= 32)
529 mp_msg(MSGT_VO
, MSGL_ERR
,
530 "BGR%d not supported, please contact the developers\n",
535 if (mode
== MODE_BGR
)
537 mp_msg(MSGT_VO
, MSGL_ERR
,
538 "BGR not supported, please contact the developers\n");
544 vo_x11_setlayer(mDisplay
, vo_window
, vo_ontop
);
549 static void Display_Image(XImage
* myximage
, uint8_t * ImageData
)
554 XShmPutImage(mDisplay
, vo_window
, vo_gc
, myximage
,
556 (vo_dwidth
- swsContext
->dstW
) / 2,
557 (vo_dheight
- myximage
->height
) / 2, swsContext
->dstW
,
558 myximage
->height
, True
);
562 XPutImage(mDisplay
, vo_window
, vo_gc
, myximage
,
564 (vo_dwidth
- swsContext
->dstW
) / 2,
565 (vo_dheight
- myximage
->height
) / 2, swsContext
->dstW
,
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 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
;
621 dstStride
[1] = dstStride
[2] = 0;
622 dst
[1] = dst
[2] = NULL
;
626 dstStride
[0] = -image_width
* ((bpp
+ 7) / 8);
627 dst
[0] = ImageData
- dstStride
[0] * (image_height
- 1);
628 sws_scale_ordered(swsContext
, src
, stride
, y
, h
, dst
, dstStride
);
631 dstStride
[0] = image_width
* ((bpp
+ 7) / 8);
633 sws_scale_ordered(swsContext
, src
, stride
, y
, h
, dst
, dstStride
);
638 static int draw_frame(uint8_t * src
[])
641 int stride
[3] = { 0, 0, 0 };
643 if (in_format
== IMGFMT_YUY2
)
644 stride
[0] = srcW
* 2;
645 else if (in_format
== IMGFMT_BGR8
)
647 else if (in_format
== IMGFMT_BGR15
)
648 stride
[0] = srcW
* 2;
649 else if (in_format
== IMGFMT_BGR16
)
650 stride
[0] = srcW
* 2;
651 else if (in_format
== IMGFMT_BGR24
)
652 stride
[0] = srcW
* 3;
653 else if (in_format
== IMGFMT_BGR32
)
654 stride
[0] = srcW
* 4;
656 return draw_slice(src
, stride
, srcW
, srcH
, 0, 0);
658 mp_msg(MSGT_VO
,MSGL_INFO
, MSGTR_LIBVO_X11_DrawFrameCalled
);
663 static uint32_t get_image(mp_image_t
* mpi
)
666 !IMGFMT_IS_BGR(mpi
->imgfmt
) ||
667 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) != vo_depthonscreen
) ||
668 ((mpi
->type
!= MP_IMGTYPE_STATIC
)
669 && (mpi
->type
!= MP_IMGTYPE_TEMP
))
670 || (mpi
->flags
& MP_IMGFLAG_PLANAR
)
671 || (mpi
->flags
& MP_IMGFLAG_YUV
) || (mpi
->width
!= image_width
)
672 || (mpi
->height
!= image_height
))
677 mpi
->stride
[0] = -image_width
* ((bpp
+ 7) / 8);
678 mpi
->planes
[0] = ImageData
- mpi
->stride
[0] * (image_height
- 1);
681 mpi
->stride
[0] = image_width
* ((bpp
+ 7) / 8);
682 mpi
->planes
[0] = ImageData
;
684 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
689 static int query_format(uint32_t format
)
691 mp_msg(MSGT_VO
, MSGL_DBG2
,
692 "vo_x11: query_format was called: %x (%s)\n", format
,
693 vo_format_name(format
));
694 if (IMGFMT_IS_BGR(format
))
696 if (IMGFMT_BGR_DEPTH(format
) <= 8)
697 return 0; // TODO 8bpp not yet fully implemented
698 if (IMGFMT_BGR_DEPTH(format
) == vo_depthonscreen
)
699 return VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_FLIP
|
702 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_FLIP
|
709 // case IMGFMT_BGR15:
710 // case IMGFMT_BGR16:
711 // case IMGFMT_BGR24:
712 // case IMGFMT_BGR32:
718 return VFCAP_CSP_SUPPORTED
| VFCAP_OSD
| VFCAP_SWSCALE
| VFCAP_ACCEPT_STRIDE
;
724 static void uninit(void)
732 vo_vm_close(mDisplay
);
738 sws_freeContext(swsContext
);
741 static int preinit(const char *arg
)
745 mp_msg(MSGT_VO
, MSGL_ERR
, "vo_x11: Unknown subdevice: %s\n", arg
);
750 return -1; // Can't open X11
754 static int control(uint32_t request
, void *data
, ...)
759 return (int_pause
= 1);
761 return (int_pause
= 0);
762 case VOCTRL_QUERY_FORMAT
:
763 return query_format(*((uint32_t *) data
));
764 case VOCTRL_GUISUPPORT
:
766 case VOCTRL_GET_IMAGE
:
767 return get_image(data
);
768 case VOCTRL_SET_EQUALIZER
:
774 value
= va_arg(ap
, int);
777 return vo_x11_set_equalizer(data
, value
);
779 case VOCTRL_GET_EQUALIZER
:
785 value
= va_arg(ap
, int *);
788 return vo_x11_get_equalizer(data
, value
);
793 case VOCTRL_FULLSCREEN
:
796 vo_x11_clearwindow(mDisplay
, vo_window
);