1 /*******************************************************************************
2 * vout_x11.c: X11 video output display method
4 *******************************************************************************
5 * The X11 method for video output thread. It's properties (and the vout_x11_t
6 * type) are defined in vout.h. The functions declared here should not be
7 * needed by any other module than vout.c.
8 *******************************************************************************/
10 /*******************************************************************************
12 *******************************************************************************/
20 #include <netinet/in.h>
22 #include <sys/soundcard.h>
25 #include <X11/Xutil.h>
26 #include <X11/Xatom.h>
27 #include <X11/extensions/XShm.h>
32 #include "vlc_thread.h"
36 #include "input_vlan.h"
38 #include "audio_output.h"
41 #include "video_output.h"
42 #include "video_x11.h"
45 #include "interface.h"
49 /*******************************************************************************
50 * vout_sys_t: video output X11 method descriptor
51 *******************************************************************************
52 * This structure is part of the video output thread descriptor.
53 * It describes the X11 specific properties of an output thread. X11 video
54 * output is performed through regular resizable windows. Windows can be
55 * dynamically resized to adapt to the size of the streams.
56 *******************************************************************************/
57 typedef struct vout_sys_s
60 boolean_t b_shm; /* shared memory extension flag */
62 /* Internal settings and properties */
63 Display * p_display; /* display pointer */
64 int i_screen; /* screen number */
65 Window root_window; /* root window */
66 Window window; /* window instance handler */
67 GC gc; /* graphic context instance handler */
69 /* Color maps and translation tables - some of those tables are shifted,
70 * see x11.c for more informations. */
71 u8 * trans_16bpp_red; /* red (16 bpp) (SHIFTED !) */
72 u8 * trans_16bpp_green; /* green (16 bpp) (SHIFTED !) */
73 u8 * trans_16bpp_blue; /* blue (16 bpp) (SHIFTED !) */
75 /* Display buffers and shared memory information */
76 int i_buffer_index; /* buffer index */
77 XImage * p_ximage[2]; /* XImage pointer */
78 XShmSegmentInfo shm_info[2]; /* shared memory zone information */
80 int i_completion_type; /* ?? */
83 /*******************************************************************************
85 *******************************************************************************/
86 static int X11GetProperties ( vout_thread_t *p_vout );
87 static int X11CreateWindow ( vout_thread_t *p_vout );
88 static int X11CreateImages ( vout_thread_t *p_vout );
89 static void X11DestroyImages ( vout_thread_t *p_vout );
90 static void X11DestroyWindow ( vout_thread_t *p_vout );
91 static int X11CreateImage ( vout_thread_t *p_vout, XImage **pp_ximage );
92 static void X11DestroyImage ( XImage *p_ximage );
93 static int X11CreateShmImage ( vout_thread_t *p_vout, XImage **pp_ximage,
94 XShmSegmentInfo *p_shm_info );
95 static void X11DestroyShmImage ( vout_thread_t *p_vout, XImage *p_ximage,
96 XShmSegmentInfo *p_shm_info );
99 /*******************************************************************************
100 * vout_SysCreate: allocate X11 video thread output method
101 *******************************************************************************
102 * This function allocate and initialize a X11 vout method.
103 *******************************************************************************/
104 int vout_SysCreate( vout_thread_t *p_vout, Display *p_display, Window root_window )
106 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
107 if( p_vout->p_sys != NULL )
109 p_vout->p_sys->p_display = p_display;
110 p_vout->p_sys->root_window = root_window;
117 /*******************************************************************************
118 * vout_SysInit: initialize X11 video thread output method
119 *******************************************************************************
120 * This function create a X11 window according to the user configuration.
121 *******************************************************************************/
122 int vout_SysInit( vout_thread_t *p_vout )
124 if( X11GetProperties( p_vout ) ) /* get display properties */
128 if( X11CreateWindow( p_vout ) ) /* create window */
132 if( X11CreateImages( p_vout ) ) /* create images */
134 X11DestroyWindow( p_vout );
137 intf_DbgMsg("%p -> success, depth=%d bpp, Shm=%d\n",
138 p_vout, p_vout->i_screen_depth, p_vout->p_sys->b_shm );
142 /*******************************************************************************
143 * vout_SysEnd: terminate X11 video thread output method
144 *******************************************************************************
145 * Terminate an output method created by vout_X11CreateOutputMethod
146 *******************************************************************************/
147 void vout_SysEnd( vout_thread_t *p_vout )
149 X11DestroyImages( p_vout );
150 X11DestroyWindow( p_vout );
151 intf_DbgMsg("%p\n", p_vout );
154 /*******************************************************************************
155 * vout_SysDestroy: destroy X11 video thread output method
156 *******************************************************************************
157 * Terminate an output method created by vout_X11CreateOutputMethod
158 *******************************************************************************/
159 void vout_SysDestroy( vout_thread_t *p_vout )
161 free( p_vout->p_sys );
164 /*******************************************************************************
165 * vout_SysManage: handle X11 events
166 *******************************************************************************
167 * This function should be called regularly by video output thread. It manages
168 * X11 events and allows window resizing. It returns a negative value if
169 * something happened which does not allow the thread to continue, and a
170 * positive one if the thread can go on, but the images have been modified and
171 * therefore it is useless to display them.
172 *******************************************************************************
173 * Messages type: vout, major code: 103
174 *******************************************************************************/
175 int vout_SysManage( vout_thread_t *p_vout )
180 /* ?? this function should not receive any usefull X11 messages, since they
181 * have tobe treated by the main interface window - check it. */
185 /* If window has been resized, re-create images */
188 intf_DbgMsg("%p -> resizing window\n", p_vout);
189 X11DestroyImages( p_vout );
190 if( X11CreateImages( p_vout ) )
192 /* A fatal error occured: images could not be re-created. Note
193 * that in this case, the images pointers will be NULL, so the
194 * image destructor will know it does not need to destroy them. */
203 /*******************************************************************************
204 * vout_SysDisplay: displays previously rendered output
205 *******************************************************************************
206 * This function send the currently rendered image to X11 server, wait until
207 * it is displayed and switch the two rendering buffer, preparing next frame.
208 *******************************************************************************/
209 void vout_SysDisplay( vout_thread_t *p_vout )
211 if( p_vout->p_sys->b_shm) /* XShm is used */
213 /* Display rendered image using shared memory extension */
214 XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
215 p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ],
217 p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,
218 p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height, True);
220 /* Send the order to the X server */
221 XFlush(p_vout->p_sys->p_display);
223 /* ?? wait until effective display ? */
224 /* do XNextEvent(Display_Ptr, &xev);
225 while(xev.type!=CompletionType);*/
227 else /* regular X11 capabilities are used */
229 XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
230 p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ],
232 p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,
233 p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height);
235 /* Send the order to the X server */
236 XFlush(p_vout->p_sys->p_display); /* ?? not needed ? */
240 p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
243 /* following functions are local */
245 /*******************************************************************************
246 * X11GetProperties: get properties of a given display
247 *******************************************************************************
248 * Opens an X11 display and try to detect usable X extensions.
249 *******************************************************************************/
250 static int X11GetProperties( vout_thread_t *p_vout )
252 /* Check if extensions are supported */
253 p_vout->p_sys->b_shm = VOUT_XSHM && (XShmQueryExtension(p_vout->p_sys->p_display) == True);
255 /* Get the screen number and depth (bpp) - select functions depending
256 * of this value. i_bytes_per_pixel is required since on some hardware,
257 * depth as 15bpp are used, which can cause problems with later memory
259 p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
260 p_vout->i_screen_depth = DefaultDepth( p_vout->p_sys->p_display,
261 p_vout->p_sys->i_screen );
262 switch( p_vout->i_screen_depth )
264 case 15: /* 15 bpp (16bpp with a missing green bit) */
265 p_vout->i_bytes_per_pixel = 2;
270 case 16: /* 16 bpp (65536 colors) */
271 p_vout->i_bytes_per_pixel = 2;
273 Process_Frame=Translate_Frame;
274 Process_Top_Field=Translate_Top_Field;
275 Process_Bottom_Field=Translate_Bottom_Field;
276 Process_Top_Field420=Translate_Top_Field420;
277 Process_Bottom_Field420=Translate_Bottom_Field420; ?? */
280 case 24: /* 24 bpp (millions of colors) */
281 p_vout->i_bytes_per_pixel = 3;
284 Process_Frame=Translate_Frame;
285 Process_Top_Field=Translate_Top_Field;
286 Process_Bottom_Field=Translate_Bottom_Field;
287 Process_Top_Field420=Translate_Top_Field420;
288 Process_Bottom_Field420=Translate_Bottom_Field420; ?? */
291 case 32: /* 32 bpp (millions of colors) */
292 p_vout->i_bytes_per_pixel = 4;
294 Process_Frame=Translate_Frame;
295 Process_Top_Field=Translate_Top_Field;
296 Process_Bottom_Field=Translate_Bottom_Field;
297 Process_Top_Field420=Translate_Top_Field420;
298 Process_Bottom_Field420=Translate_Bottom_Field420; ?? */
301 default: /* unsupported screen depth */
302 intf_ErrMsg("vout error 106-2: screen depth %i is not supported\n",
303 p_vout->i_screen_depth);
310 /*******************************************************************************
311 * X11CreateWindow: create X11 vout window
312 *******************************************************************************
313 * The video output window will be created. Normally, this window is wether
314 * full screen or part of a parent window. Therefore, it does not need a
315 * title or other hints. Thery are still supplied in case the window would be
316 * spawned as a standalone one by the interface.
317 *******************************************************************************/
318 static int X11CreateWindow( vout_thread_t *p_vout )
320 XSetWindowAttributes xwindow_attributes;
324 boolean_t b_map_notify;
326 /* Prepare window attributes */
327 xwindow_attributes.backing_store = Always; /* save the hidden part */
329 /* Create the window and set hints - the window must receive ConfigureNotify
330 * events, and, until it is displayed, Expose and MapNotify events. */
331 p_vout->p_sys->window = XCreateSimpleWindow( p_vout->p_sys->p_display,
332 p_vout->p_sys->root_window,
334 p_vout->i_width, p_vout->i_height,
336 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
337 ExposureMask | StructureNotifyMask );
338 XChangeWindowAttributes( p_vout->p_sys->p_display, p_vout->p_sys->window,
339 CWBackingStore, &xwindow_attributes);
341 /* Creation of a graphic context that doesn't generate a GraphicsExpose event
342 when using functions like XCopyArea */
343 xgcvalues.graphics_exposures = False;
344 p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display, p_vout->p_sys->window,
345 GCGraphicsExposures, &xgcvalues);
347 /* Send orders to server, and wait until window is displayed - two events
348 * must be received: a MapNotify event, an Expose event allowing drawing in the
352 XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
355 XNextEvent( p_vout->p_sys->p_display, &xevent);
356 if( (xevent.type == Expose)
357 && (xevent.xexpose.window == p_vout->p_sys->window) )
361 else if( (xevent.type == MapNotify)
362 && (xevent.xmap.window == p_vout->p_sys->window) )
367 while( !( b_expose && b_map_notify ) );
368 XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 0 );
370 /* At this stage, the window is openned, displayed, and ready to receive data */
371 p_vout->b_active = 1;
375 /*******************************************************************************
376 * X11CreateImages: create X11 rendering buffers
377 *******************************************************************************
378 * Create two XImages which will be used as rendering buffers. On error, non 0
379 * will be returned and the images pointer will be set to NULL (see
380 * vout_X11ManageOutputMethod()).
381 *******************************************************************************
382 * Messages type: vout, major code: 108
383 *******************************************************************************/
384 static int X11CreateImages( vout_thread_t *p_vout )
388 /* Create XImages using XShm extension - on failure, fall back to regular
389 * way (and destroy the first image if it was created successfully) */
390 if( p_vout->p_sys->b_shm )
392 /* Create first image */
393 i_err = X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[0],
394 &p_vout->p_sys->shm_info[0] );
395 if( !i_err ) /* first image has been created */
397 /* Create second image */
398 if( X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[1],
399 &p_vout->p_sys->shm_info[1] ) )
400 { /* error creating the second image */
401 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
402 &p_vout->p_sys->shm_info[0] );
406 if( i_err ) /* an error occured */
408 intf_Msg("vout: XShm extension desactivated\n" );
409 p_vout->p_sys->b_shm = 0;
413 /* Create XImages without XShm extension */
414 if( !p_vout->p_sys->b_shm )
416 if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[0] ) )
418 intf_Msg("vout error 108-1: can't create images\n");
419 p_vout->p_sys->p_ximage[0] = NULL;
420 p_vout->p_sys->p_ximage[1] = NULL;
423 if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[1] ) )
425 intf_Msg("vout error 108-2: can't create images\n");
426 X11DestroyImage( p_vout->p_sys->p_ximage[0] );
427 p_vout->p_sys->p_ximage[0] = NULL;
428 p_vout->p_sys->p_ximage[1] = NULL;
433 /* Set buffer index to 0 */
434 p_vout->p_sys->i_buffer_index = 0;
439 /*******************************************************************************
440 * X11DestroyImages: destroy X11 rendering buffers
441 *******************************************************************************
442 * Destroy buffers created by vout_X11CreateImages().
443 *******************************************************************************
444 * Messages type: vout, major code: 109
445 *******************************************************************************/
446 static void X11DestroyImages( vout_thread_t *p_vout )
448 if( p_vout->p_sys->b_shm ) /* Shm XImages... */
450 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
451 &p_vout->p_sys->shm_info[0] );
452 X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[1],
453 &p_vout->p_sys->shm_info[1] );
455 else /* ...or regular XImages */
457 X11DestroyImage( p_vout->p_sys->p_ximage[0] );
458 X11DestroyImage( p_vout->p_sys->p_ximage[1] );
462 /*******************************************************************************
463 * X11DestroyWindow: destroy X11 window
464 *******************************************************************************
465 * Destroy an X11 window created by vout_X11CreateWindow
466 *******************************************************************************
467 * Messages type: vout, major code: 110
468 *******************************************************************************/
469 static void X11DestroyWindow( vout_thread_t *p_vout )
471 intf_DbgMsg("vout window: 0x%x\n", p_vout->p_sys->window );
472 XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
473 XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
474 XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
477 /*******************************************************************************
478 * X11CreateImage: create an XImage
479 *******************************************************************************
480 * Messages type: vout, major code 112
481 *******************************************************************************/
482 static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
484 byte_t * pb_data; /* image data storage zone */
485 int i_quantum; /* XImage quantum (see below) */
487 /* Allocate memory for image */
488 pb_data = (byte_t *) malloc( p_vout->i_bytes_per_pixel
490 * p_vout->i_height );
491 if( !pb_data ) /* error */
493 intf_ErrMsg("vout error 112-1: %s\n", strerror(ENOMEM));
497 /* Optimize the quantum of a scanline regarding its size - the quantum is
498 a diviser of the number of bits between the start of two scanlines. */
499 if( !(( p_vout->i_width * p_vout->i_bytes_per_pixel ) % 32) )
505 if( !(( p_vout->i_width * p_vout->i_bytes_per_pixel ) % 16) )
516 *pp_ximage = XCreateImage( p_vout->p_sys->p_display,
517 DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
518 p_vout->i_screen_depth, ZPixmap, 0, pb_data,
519 p_vout->i_width, p_vout->i_height, i_quantum, 0);
520 if(! *pp_ximage ) /* error */
522 intf_ErrMsg( "vout error 112-2: XCreateImage() failed\n" );
530 /*******************************************************************************
531 * X11CreateShmImage: create an XImage using shared memory extension
532 *******************************************************************************
533 * Prepare an XImage for DisplayX11ShmImage function.
534 * The order of the operations respects the recommandations of the mit-shm
535 * document by J.Corbet and K.Packard. Most of the parameters were copied from
537 * ?? error on failure:
538 * X Error of failed request: BadAccess (attempt to access private resource denied)
539 * Major opcode of failed request: 129 (MIT-SHM)
540 * Minor opcode of failed request: 1 (X_ShmAttach)
541 * Serial number of failed request: 17
542 * Current serial number in output stream: 18
543 *******************************************************************************
544 * Messages type: vout, major code 113
545 *******************************************************************************/
546 static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage,
547 XShmSegmentInfo *p_shm_info)
550 *pp_ximage = XShmCreateImage( p_vout->p_sys->p_display,
551 DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
552 p_vout->i_screen_depth, ZPixmap, 0,
553 p_shm_info, p_vout->i_width, p_vout->i_height );
554 if(! *pp_ximage ) /* error */
556 intf_ErrMsg("vout error 113-1: XShmCreateImage() failed\n");
560 /* Allocate shared memory segment - 0777 set the access permission
561 * rights (like umask), they are not yet supported by X servers */
562 p_shm_info->shmid = shmget( IPC_PRIVATE,
563 (*pp_ximage)->bytes_per_line * (*pp_ximage)->height,
565 if( p_shm_info->shmid < 0) /* error */
567 intf_ErrMsg("vout error 113-2: can't allocate shared image data (%s)\n",
569 XDestroyImage( *pp_ximage );
573 /* Attach shared memory segment to process (read/write) */
574 p_shm_info->shmaddr = (*pp_ximage)->data = shmat(p_shm_info->shmid, 0, 0);
575 if(! p_shm_info->shmaddr )
577 intf_ErrMsg("vout error 113-3: can't attach shared memory (%s)\n",
579 shmctl( p_shm_info->shmid, IPC_RMID, 0 ); /* free shared memory */
580 XDestroyImage( *pp_ximage );
584 /* Mark the shm segment to be removed when there will be no more
585 * attachements, so it is automatic on process exit or after shmdt */
586 shmctl( p_shm_info->shmid, IPC_RMID, 0 );
588 /* Attach shared memory segment to X server (read only) */
589 p_shm_info->readOnly = True;
590 if( XShmAttach( p_vout->p_sys->p_display, p_shm_info ) == False ) /* error */
592 intf_ErrMsg("vout error 113-4: can't attach shared memory to server\n");
593 shmdt( p_shm_info->shmaddr ); /* detach shared memory from process
594 * and automatic free */
595 XDestroyImage( *pp_ximage );
599 /* ?? don't know what it is. Function XShmGetEventBase prototype is defined
600 * in mit-shm document, but does not appears in any header. */
601 p_vout->p_sys->i_completion_type = XShmGetEventBase(p_vout->p_sys->p_display) + ShmCompletion;
606 /*******************************************************************************
607 * X11DestroyImage: destroy an XImage
608 *******************************************************************************
609 * Destroy XImage AND associated data. If pointer is NULL, the image won't be
610 * destroyed (see vout_X11ManageOutputMethod())
611 *******************************************************************************
612 * Messages type: vout, major code 114
613 *******************************************************************************/
614 static void X11DestroyImage( XImage *p_ximage )
616 if( p_ximage != NULL )
618 XDestroyImage( p_ximage ); /* no free() required */
622 /*******************************************************************************
624 *******************************************************************************
625 * Destroy XImage AND associated data. Detach shared memory segment from
626 * server and process, then free it. If pointer is NULL, the image won't be
627 * destroyed (see vout_X11ManageOutputMethod())
628 *******************************************************************************
629 * Messages type: vout, major code 115
630 *******************************************************************************/
631 static void X11DestroyShmImage( vout_thread_t *p_vout, XImage *p_ximage,
632 XShmSegmentInfo *p_shm_info )
634 /* If pointer is NULL, do nothing */
635 if( p_ximage == NULL )
640 XShmDetach( p_vout->p_sys->p_display, p_shm_info ); /* detach from server */
641 XDestroyImage( p_ximage );
642 if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
643 { /* also automatic freeing... */
644 intf_ErrMsg("vout error 115-1: can't detach shared memory (%s)\n",
649 /* following functions are local rendering functions */