Document lmin and lmax lavcopts; mpeg vrc_buf_size values
[mplayer/greg.git] / libvo / vo_x11.c
blob07b1c9045a8cb912d6b3dbbad53118c59aa84f9d
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <signal.h>
7 #include "config.h"
8 #include "video_out.h"
9 #include "video_out_internal.h"
12 #include <X11/Xlib.h>
13 #include <X11/Xutil.h>
15 #ifdef HAVE_XF86VM
16 #include <X11/extensions/xf86vmode.h>
17 #endif
18 #include <errno.h>
20 #include "x11_common.h"
22 #include "fastmemcpy.h"
23 #include "sub.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"
32 #ifdef HAVE_NEW_GUI
33 #include "../Gui/interface.h"
34 #include "../mplayer.h"
35 #endif
37 static vo_info_t info =
39 "X11 ( XImage/Shm )",
40 "x11",
41 "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>",
45 LIBVO_EXTERN( x11 )
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);
51 /* local data */
52 static unsigned char *ImageData;
54 /* X11 related variables */
55 static XImage *myximage = NULL;
56 static int depth,bpp,mode;
57 static XWindowAttributes attribs;
59 static int int_pause;
61 static int Flip_Flag;
62 static int zoomFlag;
64 #ifdef HAVE_SHM
65 #include <sys/ipc.h>
66 #include <sys/shm.h>
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* );
77 #endif
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;
83 static int srcW=-1;
84 static int srcH=-1;
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);
97 flip_page();
98 } else
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()
130 #ifdef HAVE_SHM
131 if ( mLocalDisplay && XShmQueryExtension( mDisplay ) ) Shmem_Flag=1;
132 else
134 Shmem_Flag=0;
135 mp_msg(MSGT_VO,MSGL_WARN, "Shared memory not supported\nReverting to normal Xlib\n" );
137 if ( Shmem_Flag ) CompletionType=XShmGetEventBase( mDisplay ) + ShmCompletion;
139 if ( Shmem_Flag )
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" );
146 goto shmemerror;
148 Shminfo[0].shmid=shmget( IPC_PRIVATE,
149 myximage->bytes_per_line * myximage->height ,
150 IPC_CREAT | 0777 );
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" );
157 goto shmemerror;
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" );
166 goto shmemerror;
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 );
175 if ( gXErrorFlag )
177 XDestroyImage( myximage );
178 shmdt( Shminfo[0].shmaddr );
179 mp_msg(MSGT_VO,MSGL_WARN, "Shared memory error,disabling.\n" );
180 gXErrorFlag=0;
181 goto shmemerror;
183 else
184 shmctl( Shminfo[0].shmid,IPC_RMID,0 );
187 static int firstTime=1;
188 if ( firstTime){
189 mp_msg(MSGT_VO,MSGL_V, "Sharing memory.\n" );
190 firstTime=0;
194 else
196 shmemerror:
197 Shmem_Flag=0;
198 #endif
199 myximage=XGetImage( mDisplay,vo_window,0,0,
200 image_width,image_height,AllPlanes,ZPixmap );
201 ImageData=myximage->data;
202 #ifdef HAVE_SHM
204 #endif
207 static void freeMyXImage()
209 #ifdef HAVE_SHM
210 if ( Shmem_Flag )
212 XShmDetach( mDisplay,&Shminfo[0] );
213 XDestroyImage( myximage );
214 shmdt( Shminfo[0].shmaddr );
216 else
217 #endif
219 XDestroyImage( myximage );
221 myximage=NULL;
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)
226 // int screen;
227 int fullscreen=0;
228 int vm=0;
229 // int interval, prefer_blank, allow_exp, nothing;
230 unsigned int fg,bg;
231 XEvent xev;
232 XGCValues xgcv;
233 Colormap theCmap;
234 XSetWindowAttributes xswa;
235 unsigned long xswamask;
236 #ifdef HAVE_XF86VM
237 unsigned int modeline_width, modeline_height;
238 static uint32_t vm_width;
239 static uint32_t vm_height;
240 #endif
242 vo_mouse_autohide=1;
243 old_vo_dwidth=-1;
244 old_vo_dheight=-1;
246 if (!title)
247 title = strdup("MPlayer X11 (XImage/Shm) render");
249 in_format=format;
250 srcW= width;
251 srcH= height;
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;
261 int_pause = 0;
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 );
267 depth=attribs.depth;
269 if ( depth != 15 && depth != 16 && depth != 24 && depth != 32 ) {
270 Visual *visual;
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);
281 image_height=height;
283 aspect= ((1<<16)*d_width + d_height/2)/d_height;
285 #ifdef HAVE_NEW_GUI
286 if(use_gui) guiGetEvent( guiSetShVideo,0 ); // the GUI will set up / resize the window
287 else
288 #endif
290 #ifdef HAVE_XF86VM
291 if ( vm )
293 if ((d_width==0) && (d_height==0))
294 { vm_width=image_width; vm_height=image_height; }
295 else
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;
303 #endif
304 bg=WhitePixel( mDisplay,mScreen );
305 fg=BlackPixel( mDisplay,mScreen );
307 theCmap=vo_x11_create_colormap(&vinfo);
309 xswa.background_pixel=0;
310 xswa.border_pixel=0;
311 xswa.colormap=theCmap;
312 xswamask=CWBackPixel | CWBorderPixel | CWColormap;
314 #ifdef HAVE_XF86VM
315 if ( vm )
317 xswa.override_redirect=True;
318 xswamask|=CWOverrideRedirect;
320 #endif
322 if ( WinID>=0 ){
323 vo_window = WinID ? ((Window)WinID) : mRootWin;
324 if ( WinID )
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 );
332 else
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 );
344 // if(WinID!=0)
345 do { XNextEvent( mDisplay,&xev ); } while ( xev.type != MapNotify || xev.xmap.event != vo_window );
347 if ( fullscreen ) vo_x11_fullscreen();
348 #ifdef HAVE_XINERAMA
349 vo_x11_xinerama_move(mDisplay,vo_window);
350 #endif
351 } else if ( !fullscreen ) XMoveResizeWindow( mDisplay,vo_window,vo_dx,vo_dy,vo_dwidth,vo_dheight );
354 XFlush( mDisplay );
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)) );
361 #ifdef HAVE_XF86VM
362 if ( vm )
364 /* Grab the mouse pointer in our window */
365 if(vo_grabpointer)
366 XGrabPointer(mDisplay, vo_window, True, 0,
367 GrabModeAsync, GrabModeAsync,
368 vo_window, None, CurrentTime);
369 XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime);
371 #endif
374 if ( vo_gc != None ) XFreeGC( mDisplay,vo_gc );
375 vo_gc=XCreateGC( mDisplay,vo_window,0L,&xgcv );
377 if ( myximage )
379 freeMyXImage();
380 sws_freeContext(swsContext);
382 getMyXImage();
384 if ( !WinID )
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;
392 case 15:
393 case 16: if (depth==15){
394 draw_alpha_fnc=draw_alpha_15;
395 out_format= IMGFMT_BGR15;
396 }else{
397 draw_alpha_fnc=draw_alpha_16;
398 out_format= IMGFMT_BGR16;
399 }break;
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 );
407 if (!swsContext)
408 return -1;
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 )
416 #else
417 if ( myximage->byte_order != LSBFirst )
418 #endif
420 mode=( ( myximage->blue_mask & 0x01 ) != 0 ) ? MODE_BGR : MODE_RGB;
421 // printf( "No support for non-native XImage byte order!\n" );
422 // return -1;
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);
428 return -1;
430 #else
431 if(mode==MODE_BGR){
432 mp_msg(MSGT_VO,MSGL_ERR,"BGR not supported, please contact the developers\n");
433 return -1;
435 #endif
437 saver_off(mDisplay);
438 return 0;
441 static void Display_Image( XImage *myximage,uint8_t *ImageData )
443 #ifdef HAVE_SHM
444 if ( Shmem_Flag )
446 XShmPutImage( mDisplay,vo_window,vo_gc,myximage,
447 0,0,
448 ( vo_dwidth - swsContext->dstW ) / 2,( vo_dheight - myximage->height ) / 2,
449 swsContext->dstW,myximage->height,True );
451 else
452 #endif
454 XPutImage( mDisplay,vo_window,vo_gc,myximage,
455 0,0,
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 )
471 uint8_t *dst[3];
472 int dstStride[3];
474 if((old_vo_dwidth != vo_dwidth || old_vo_dheight != vo_dheight) /*&& y==0*/ && zoomFlag)
476 int newW= vo_dwidth;
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);
491 if(swsContext)
493 image_width= (newW+7)&(~7);
494 image_height= newH;
496 freeMyXImage();
497 getMyXImage();
498 sws_freeContext(oldContext);
500 else
502 swsContext= oldContext;
505 dstStride[1]=
506 dstStride[2]=0;
507 dst[1]=
508 dst[2]=NULL;
510 if(Flip_Flag)
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);
516 else
518 dstStride[0]=image_width*((bpp+7)/8);
519 dst[0]=ImageData;
520 sws_scale_ordered(swsContext,src,stride,y,h,dst, dstStride);
522 return 0;
525 static uint32_t draw_frame( uint8_t *src[] ){
526 #if 0
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);
537 #else
538 printf("draw_frame() called!!!!!!\n");
539 return -1;
540 #endif
543 static uint32_t get_image(mp_image_t *mpi)
545 if (zoomFlag ||
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)
554 return(VO_FALSE);
556 if (Flip_Flag)
558 mpi->stride[0] = -image_width*((bpp+7)/8);
559 mpi->planes[0] = ImageData - mpi->stride[0]*(image_height-1);
561 else
563 mpi->stride[0] = image_width*((bpp+7)/8);
564 mpi->planes[0] = ImageData;
566 mpi->flags |= MP_IMGFLAG_DIRECT;
568 return(VO_TRUE);
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;
580 else
581 return 1|VFCAP_OSD|VFCAP_SWSCALE|VFCAP_FLIP|VFCAP_ACCEPT_STRIDE;
584 switch( format )
586 // case IMGFMT_BGR8:
587 // case IMGFMT_BGR15:
588 // case IMGFMT_BGR16:
589 // case IMGFMT_BGR24:
590 // case IMGFMT_BGR32:
591 // return 0x2;
592 // case IMGFMT_YUY2:
593 case IMGFMT_I420:
594 case IMGFMT_IYUV:
595 case IMGFMT_YV12:
596 return 1|VFCAP_OSD|VFCAP_SWSCALE|VFCAP_ACCEPT_STRIDE;
598 return 0;
602 static void uninit(void)
604 if(!myximage) return;
606 freeMyXImage();
607 saver_on(mDisplay); // screen saver back on
609 #ifdef HAVE_XF86VM
610 vo_vm_close(mDisplay);
611 #endif
613 zoomFlag=0;
614 vo_x11_uninit();
616 sws_freeContext(swsContext);
619 static uint32_t preinit(const char *arg)
621 if(arg)
623 mp_msg(MSGT_VO,MSGL_ERR,"vo_x11: Unknown subdevice: %s\n",arg);
624 return ENOSYS;
627 if( !vo_init() ) return -1; // Can't open X11
628 return 0;
631 static uint32_t control(uint32_t request, void *data, ...)
633 switch (request) {
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:
639 return VO_TRUE;
640 case VOCTRL_GET_IMAGE:
641 return get_image(data);
642 case VOCTRL_SET_EQUALIZER:
644 va_list ap;
645 int value;
646 va_start(ap, data);
647 value = va_arg(ap, int);
648 va_end(ap);
649 return vo_x11_set_equalizer(data, value);
651 case VOCTRL_GET_EQUALIZER:
653 va_list ap;
654 int *value;
655 va_start(ap, data);
656 value = va_arg(ap, int *);
657 va_end(ap);
658 return vo_x11_get_equalizer(data, value);
660 case VOCTRL_FULLSCREEN:
662 vo_x11_fullscreen();
663 vo_x11_clearwindow(mDisplay, vo_window);
665 return VO_TRUE;
667 return VO_NOTIMPL;