9 #include "video_out_internal.h"
13 #include <X11/Xutil.h>
16 #include <X11/extensions/xf86vmode.h>
20 #include "x11_common.h"
22 #include "fastmemcpy.h"
25 #include "../postproc/swscale.h"
26 #include "../postproc/swscale_internal.h" //FIXME
27 #include "../postproc/rgb2rgb.h"
28 #include "../libmpcodecs/vf_scale.h"
30 #include "../mp_msg.h"
33 #include "../Gui/interface.h"
34 #include "../mplayer.h"
37 static vo_info_t info
=
41 "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>",
47 /* private prototypes */
48 static void Display_Image ( XImage
* myximage
,unsigned char *ImageData
);
49 static void (*draw_alpha_fnc
)(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
);
52 static unsigned char *ImageData
;
54 /* X11 related variables */
55 static XImage
*myximage
= NULL
;
56 static int depth
,bpp
,mode
;
57 static XWindowAttributes attribs
;
67 #include <X11/extensions/XShm.h>
69 static int Shmem_Flag
;
70 //static int Quiet_Flag; Here also what is this for. It's used but isn't inited ?
71 static XShmSegmentInfo Shminfo
[1];
72 static int gXErrorFlag
;
73 static int CompletionType
=-1;
75 /* since it doesn't seem to be defined on some platforms */
76 int XShmGetEventBase( Display
* );
79 static uint32_t image_width
;
80 static uint32_t image_height
;
81 static uint32_t in_format
;
82 static uint32_t out_format
=0;
85 static int aspect
; // 1<<16 based fixed point aspect, so that the aspect stays correct during resizing
87 static int old_vo_dwidth
=-1;
88 static int old_vo_dheight
=-1;
90 static void check_events(){
91 int ret
= vo_x11_check_events(mDisplay
);
93 /* clear left over borders and redraw frame if we are paused */
94 if ( ret
& VO_EVENT_EXPOSE
&& int_pause
)
96 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
, myximage
->height
, 0);
99 if ( (ret
& VO_EVENT_RESIZE
)||(ret
& VO_EVENT_EXPOSE
) )
100 vo_x11_clearwindow_part(mDisplay
, vo_window
, myximage
->width
, myximage
->height
, 0);
104 static void draw_alpha_32(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
105 vo_draw_alpha_rgb32(w
,h
,src
,srca
,stride
,ImageData
+4*(y0
*image_width
+x0
),4*image_width
);
108 static void draw_alpha_24(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
109 vo_draw_alpha_rgb24(w
,h
,src
,srca
,stride
,ImageData
+3*(y0
*image_width
+x0
),3*image_width
);
112 static void draw_alpha_16(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
113 vo_draw_alpha_rgb16(w
,h
,src
,srca
,stride
,ImageData
+2*(y0
*image_width
+x0
),2*image_width
);
116 static void draw_alpha_15(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
117 vo_draw_alpha_rgb15(w
,h
,src
,srca
,stride
,ImageData
+2*(y0
*image_width
+x0
),2*image_width
);
120 static void draw_alpha_null(int x0
,int y0
, int w
,int h
, unsigned char* src
, unsigned char *srca
, int stride
){
123 static SwsContext
*swsContext
=NULL
;
124 extern int sws_flags
;
126 static XVisualInfo vinfo
;
128 static void getMyXImage()
131 if ( mLocalDisplay
&& XShmQueryExtension( mDisplay
) ) Shmem_Flag
=1;
135 mp_msg(MSGT_VO
,MSGL_WARN
, "Shared memory not supported\nReverting to normal Xlib\n" );
137 if ( Shmem_Flag
) CompletionType
=XShmGetEventBase( mDisplay
) + ShmCompletion
;
141 myximage
=XShmCreateImage( mDisplay
,vinfo
.visual
,depth
,ZPixmap
,NULL
,&Shminfo
[0],image_width
,image_height
);
142 if ( myximage
== NULL
)
144 if ( myximage
!= NULL
) XDestroyImage( myximage
);
145 mp_msg(MSGT_VO
,MSGL_WARN
,"Shared memory error,disabling ( Ximage error )\n" );
148 Shminfo
[0].shmid
=shmget( IPC_PRIVATE
,
149 myximage
->bytes_per_line
* myximage
->height
,
151 if ( Shminfo
[0].shmid
< 0 )
153 XDestroyImage( myximage
);
154 mp_msg(MSGT_VO
,MSGL_V
, "%s\n",strerror( errno
) );
155 //perror( strerror( errno ) );
156 mp_msg(MSGT_VO
,MSGL_WARN
,"Shared memory error,disabling ( seg id error )\n" );
159 Shminfo
[0].shmaddr
=( char * ) shmat( Shminfo
[0].shmid
,0,0 );
161 if ( Shminfo
[0].shmaddr
== ( ( char * ) -1 ) )
163 XDestroyImage( myximage
);
164 if ( Shminfo
[0].shmaddr
!= ( ( char * ) -1 ) ) shmdt( Shminfo
[0].shmaddr
);
165 mp_msg(MSGT_VO
,MSGL_WARN
, "Shared memory error,disabling ( address error )\n" );
168 myximage
->data
=Shminfo
[0].shmaddr
;
169 ImageData
=( unsigned char * ) myximage
->data
;
170 Shminfo
[0].readOnly
=False
;
171 XShmAttach( mDisplay
,&Shminfo
[0] );
173 XSync( mDisplay
,False
);
177 XDestroyImage( myximage
);
178 shmdt( Shminfo
[0].shmaddr
);
179 mp_msg(MSGT_VO
,MSGL_WARN
, "Shared memory error,disabling.\n" );
184 shmctl( Shminfo
[0].shmid
,IPC_RMID
,0 );
187 static int firstTime
=1;
189 mp_msg(MSGT_VO
,MSGL_V
, "Sharing memory.\n" );
199 myximage
=XGetImage( mDisplay
,vo_window
,0,0,
200 image_width
,image_height
,AllPlanes
,ZPixmap
);
201 ImageData
=myximage
->data
;
207 static void freeMyXImage()
212 XShmDetach( mDisplay
,&Shminfo
[0] );
213 XDestroyImage( myximage
);
214 shmdt( Shminfo
[0].shmaddr
);
219 XDestroyImage( myximage
);
224 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
)
229 // int interval, prefer_blank, allow_exp, nothing;
234 XSetWindowAttributes xswa
;
235 unsigned long xswamask
;
237 unsigned int modeline_width
, modeline_height
;
238 static uint32_t vm_width
;
239 static uint32_t vm_height
;
247 title
= strdup("MPlayer X11 (XImage/Shm) render");
252 vo_dx
=( vo_screenwidth
- d_width
) / 2; vo_dy
=( vo_screenheight
- d_height
) / 2;
253 geometry(&vo_dx
, &vo_dy
, &d_width
, &d_height
, vo_screenwidth
, vo_screenheight
);
254 vo_dwidth
=d_width
; vo_dheight
=d_height
;
256 if( flags
&0x03 ) fullscreen
= 1;
257 if( flags
&0x02 ) vm
= 1;
258 if( flags
&0x08 ) Flip_Flag
= 1;
259 zoomFlag
= flags
&0x04;
262 // if(!fullscreen) zoomFlag=1; //it makes no sense to avoid zooming on windowd mode
264 //printf( "w: %d h: %d\n\n",vo_dwidth,vo_dheight );
266 XGetWindowAttributes( mDisplay
,mRootWin
,&attribs
);
269 if ( depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32 ) {
271 depth
= vo_find_depth_from_visuals(mDisplay
, mScreen
, &visual
);
273 if ( !XMatchVisualInfo( mDisplay
,mScreen
,depth
,DirectColor
,&vinfo
) ||
274 (WinID
> 0 && vinfo
.visualid
!= XVisualIDFromVisual(attribs
.visual
)))
275 XMatchVisualInfo( mDisplay
,mScreen
,depth
,TrueColor
,&vinfo
);
277 /* set image size (which is indeed neither the input nor output size),
278 if zoom is on it will be changed during draw_slice anyway so we don't duplicate the aspect code here
280 image_width
=(width
+ 7) & (~7);
283 aspect
= ((1<<16)*d_width
+ d_height
/2)/d_height
;
286 if(use_gui
) guiGetEvent( guiSetShVideo
,0 ); // the GUI will set up / resize the window
293 if ((d_width
==0) && (d_height
==0))
294 { vm_width
=image_width
; vm_height
=image_height
; }
296 { vm_width
=d_width
; vm_height
=d_height
; }
297 vo_vm_switch(vm_width
, vm_height
,&modeline_width
, &modeline_height
);
298 vo_dx
=(vo_screenwidth
-modeline_width
)/2;
299 vo_dy
=(vo_screenheight
-modeline_height
)/2;
300 vo_dwidth
=modeline_width
;
301 vo_dheight
=modeline_height
;
304 bg
=WhitePixel( mDisplay
,mScreen
);
305 fg
=BlackPixel( mDisplay
,mScreen
);
307 theCmap
=vo_x11_create_colormap(&vinfo
);
309 xswa
.background_pixel
=0;
311 xswa
.colormap
=theCmap
;
312 xswamask
=CWBackPixel
| CWBorderPixel
| CWColormap
;
317 xswa
.override_redirect
=True
;
318 xswamask
|=CWOverrideRedirect
;
323 vo_window
= WinID
? ((Window
)WinID
) : mRootWin
;
326 XUnmapWindow( mDisplay
,vo_window
);
327 XChangeWindowAttributes( mDisplay
,vo_window
,xswamask
,&xswa
);
328 vo_x11_selectinput_witherr( mDisplay
,vo_window
,StructureNotifyMask
| KeyPressMask
| PropertyChangeMask
| PointerMotionMask
| ButtonPressMask
| ButtonReleaseMask
| ExposureMask
);
329 XMapWindow( mDisplay
,vo_window
);
330 } else XSelectInput( mDisplay
,vo_window
,ExposureMask
);
334 if ( vo_window
== None
)
336 vo_window
=vo_x11_create_smooth_window( mDisplay
,mRootWin
,vinfo
.visual
, vo_dx
, vo_dy
, vo_dwidth
, vo_dheight
, depth
, theCmap
);
338 vo_x11_classhint( mDisplay
,vo_window
,"x11" );
339 vo_hidecursor(mDisplay
,vo_window
);
340 vo_x11_sizehint( vo_dx
,vo_dy
,vo_dwidth
,vo_dheight
,0 );
341 XSelectInput( mDisplay
,vo_window
,StructureNotifyMask
);
342 XStoreName( mDisplay
,vo_window
,title
);
343 XMapWindow( mDisplay
,vo_window
);
345 do { XNextEvent( mDisplay
,&xev
); } while ( xev
.type
!= MapNotify
|| xev
.xmap
.event
!= vo_window
);
347 if ( fullscreen
) vo_x11_fullscreen();
349 vo_x11_xinerama_move(mDisplay
,vo_window
);
351 } else if ( !fullscreen
) XMoveResizeWindow( mDisplay
,vo_window
,vo_dx
,vo_dy
,vo_dwidth
,vo_dheight
);
355 XSync( mDisplay
,False
);
357 // we cannot grab mouse events on root window :(
358 vo_x11_selectinput_witherr( mDisplay
,vo_window
,StructureNotifyMask
| KeyPressMask
| PropertyChangeMask
| ExposureMask
|
359 ((WinID
==0)?0:(ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
)) );
364 /* Grab the mouse pointer in our window */
366 XGrabPointer(mDisplay
, vo_window
, True
, 0,
367 GrabModeAsync
, GrabModeAsync
,
368 vo_window
, None
, CurrentTime
);
369 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
374 if ( vo_gc
!= None
) XFreeGC( mDisplay
,vo_gc
);
375 vo_gc
=XCreateGC( mDisplay
,vo_window
,0L,&xgcv
);
380 sws_freeContext(swsContext
);
385 { vo_dwidth
=vo_screenwidth
; vo_dheight
=vo_screenheight
; }
387 switch ((bpp
=myximage
->bits_per_pixel
)){
388 case 24: draw_alpha_fnc
=draw_alpha_24
;
389 out_format
= IMGFMT_BGR24
; break;
390 case 32: draw_alpha_fnc
=draw_alpha_32
;
391 out_format
= IMGFMT_BGR32
; break;
393 case 16: if (depth
==15){
394 draw_alpha_fnc
=draw_alpha_15
;
395 out_format
= IMGFMT_BGR15
;
397 draw_alpha_fnc
=draw_alpha_16
;
398 out_format
= IMGFMT_BGR16
;
400 case 8: draw_alpha_fnc
=draw_alpha_null
;
401 out_format
= IMGFMT_BGR8
; break;
402 default: draw_alpha_fnc
=draw_alpha_null
;
405 /* always allocate swsContext as size could change between frames */
406 swsContext
= sws_getContextFromCmdLine(width
, height
, in_format
, width
, height
, out_format
);
410 //printf( "X11 bpp: %d color mask: R:%lX G:%lX B:%lX\n",bpp,myximage->red_mask,myximage->green_mask,myximage->blue_mask );
412 // If we have blue in the lowest bit then obviously RGB
413 mode
=( ( myximage
->blue_mask
& 0x01 ) != 0 ) ? MODE_RGB
: MODE_BGR
;
414 #ifdef WORDS_BIGENDIAN
415 if ( myximage
->byte_order
!= MSBFirst
)
417 if ( myximage
->byte_order
!= LSBFirst
)
420 mode
=( ( myximage
->blue_mask
& 0x01 ) != 0 ) ? MODE_BGR
: MODE_RGB
;
421 // printf( "No support for non-native XImage byte order!\n" );
425 #ifdef WORDS_BIGENDIAN
426 if(mode
==MODE_BGR
&& bpp
!=32){
427 mp_msg(MSGT_VO
,MSGL_ERR
,"BGR%d not supported, please contact the developers\n", bpp
);
432 mp_msg(MSGT_VO
,MSGL_ERR
,"BGR not supported, please contact the developers\n");
441 static void Display_Image( XImage
*myximage
,uint8_t *ImageData
)
446 XShmPutImage( mDisplay
,vo_window
,vo_gc
,myximage
,
448 ( vo_dwidth
- swsContext
->dstW
) / 2,( vo_dheight
- myximage
->height
) / 2,
449 swsContext
->dstW
,myximage
->height
,True
);
454 XPutImage( mDisplay
,vo_window
,vo_gc
,myximage
,
456 ( vo_dwidth
- swsContext
->dstW
) / 2,( vo_dheight
- myximage
->height
) / 2,
457 swsContext
->dstW
,myximage
->height
);
461 static void draw_osd(void)
462 { vo_draw_text(image_width
,image_height
,draw_alpha_fnc
); }
464 static void flip_page( void ){
465 Display_Image( myximage
,ImageData
);
466 XSync(mDisplay
, False
);
469 static uint32_t draw_slice( uint8_t *src
[],int stride
[],int w
,int h
,int x
,int y
)
474 if((old_vo_dwidth
!= vo_dwidth
|| old_vo_dheight
!= vo_dheight
) /*&& y==0*/ && zoomFlag
)
477 int newH
= vo_dheight
;
478 int newAspect
= (newW
*(1<<16) + (newH
>>1))/newH
;
479 SwsContext
*oldContext
= swsContext
;
481 if(newAspect
>aspect
) newW
= (newH
*aspect
+ (1<<15))>>16;
482 else newH
= ((newW
<<16) + (aspect
>>1)) /aspect
;
484 old_vo_dwidth
= vo_dwidth
;
485 old_vo_dheight
= vo_dheight
;
487 if(sws_flags
==0) newW
&= (~31); // not needed but, if the user wants the FAST_BILINEAR SCALER, then its needed
489 swsContext
= sws_getContextFromCmdLine(srcW
, srcH
, in_format
,
490 newW
, newH
, out_format
);
493 image_width
= (newW
+7)&(~7);
498 sws_freeContext(oldContext
);
502 swsContext
= oldContext
;
512 dstStride
[0]= -image_width
*((bpp
+7)/8);
513 dst
[0]=ImageData
- dstStride
[0]*(image_height
-1);
514 sws_scale_ordered(swsContext
,src
,stride
,y
,h
,dst
, dstStride
);
518 dstStride
[0]=image_width
*((bpp
+7)/8);
520 sws_scale_ordered(swsContext
,src
,stride
,y
,h
,dst
, dstStride
);
525 static uint32_t draw_frame( uint8_t *src
[] ){
527 int stride
[3]= {0,0,0};
529 if (in_format
==IMGFMT_YUY2
) stride
[0]=srcW
*2;
530 else if(in_format
==IMGFMT_BGR8
) stride
[0]=srcW
;
531 else if(in_format
==IMGFMT_BGR15
) stride
[0]=srcW
*2;
532 else if(in_format
==IMGFMT_BGR16
) stride
[0]=srcW
*2;
533 else if(in_format
==IMGFMT_BGR24
) stride
[0]=srcW
*3;
534 else if(in_format
==IMGFMT_BGR32
) stride
[0]=srcW
*4;
536 return draw_slice(src
, stride
, srcW
, srcH
, 0, 0);
538 printf("draw_frame() called!!!!!!\n");
543 static uint32_t get_image(mp_image_t
*mpi
)
546 !IMGFMT_IS_BGR(mpi
->imgfmt
) ||
547 (IMGFMT_BGR_DEPTH(mpi
->imgfmt
) != vo_depthonscreen
) ||
548 ((mpi
->type
!= MP_IMGTYPE_STATIC
) && (mpi
->type
!= MP_IMGTYPE_TEMP
)) ||
549 (mpi
->flags
& MP_IMGFLAG_PLANAR
) ||
550 (mpi
->flags
& MP_IMGFLAG_YUV
) ||
551 (mpi
->width
!= image_width
) ||
552 (mpi
->height
!= image_height
)
558 mpi
->stride
[0] = -image_width
*((bpp
+7)/8);
559 mpi
->planes
[0] = ImageData
- mpi
->stride
[0]*(image_height
-1);
563 mpi
->stride
[0] = image_width
*((bpp
+7)/8);
564 mpi
->planes
[0] = ImageData
;
566 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
571 static uint32_t query_format( uint32_t format
)
573 mp_msg(MSGT_VO
,MSGL_DBG2
,"vo_x11: query_format was called: %x (%s)\n",format
,vo_format_name(format
));
574 if (IMGFMT_IS_BGR(format
))
576 if (IMGFMT_BGR_DEPTH(format
) <= 8)
577 return 0; // TODO 8bpp not yet fully implemented
578 if (IMGFMT_BGR_DEPTH(format
) == vo_depthonscreen
)
579 return 3|VFCAP_OSD
|VFCAP_SWSCALE
|VFCAP_FLIP
|VFCAP_ACCEPT_STRIDE
;
581 return 1|VFCAP_OSD
|VFCAP_SWSCALE
|VFCAP_FLIP
|VFCAP_ACCEPT_STRIDE
;
587 // case IMGFMT_BGR15:
588 // case IMGFMT_BGR16:
589 // case IMGFMT_BGR24:
590 // case IMGFMT_BGR32:
596 return 1|VFCAP_OSD
|VFCAP_SWSCALE
|VFCAP_ACCEPT_STRIDE
;
602 static void uninit(void)
604 if(!myximage
) return;
607 saver_on(mDisplay
); // screen saver back on
610 vo_vm_close(mDisplay
);
616 sws_freeContext(swsContext
);
619 static uint32_t preinit(const char *arg
)
623 mp_msg(MSGT_VO
,MSGL_ERR
,"vo_x11: Unknown subdevice: %s\n",arg
);
627 if( !vo_init() ) return -1; // Can't open X11
631 static uint32_t control(uint32_t request
, void *data
, ...)
634 case VOCTRL_PAUSE
: return (int_pause
=1);
635 case VOCTRL_RESUME
: return (int_pause
=0);
636 case VOCTRL_QUERY_FORMAT
:
637 return query_format(*((uint32_t*)data
));
638 case VOCTRL_GUISUPPORT
:
640 case VOCTRL_GET_IMAGE
:
641 return get_image(data
);
642 case VOCTRL_SET_EQUALIZER
:
647 value
= va_arg(ap
, int);
649 return vo_x11_set_equalizer(data
, value
);
651 case VOCTRL_GET_EQUALIZER
:
656 value
= va_arg(ap
, int *);
658 return vo_x11_get_equalizer(data
, value
);
660 case VOCTRL_FULLSCREEN
:
663 vo_x11_clearwindow(mDisplay
, vo_window
);