You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

737 lines
32 KiB

27 years ago
/*******************************************************************************
* vout_x11.c: X11 video output display method
* (c)1998 VideoLAN
*******************************************************************************/
/*******************************************************************************
* Preamble
*******************************************************************************/
27 years ago
27 years ago
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
27 years ago
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>
#include "config.h"
#include "common.h"
#include "mtime.h"
#include "vlc_thread.h"
27 years ago
#include "video.h"
#include "video_output.h"
#include "video_sys.h"
27 years ago
#include "intf_msg.h"
27 years ago
/*******************************************************************************
* vout_sys_t: video output X11 method descriptor
*******************************************************************************
* This structure is part of the video output thread descriptor.
* It describes the X11 specific properties of an output thread. X11 video
* output is performed through regular resizable windows. Windows can be
* dynamically resized to adapt to the size of the streams.
*******************************************************************************/
typedef struct vout_sys_s
{
/* User settings */
boolean_t b_shm; /* shared memory extension flag */
27 years ago
27 years ago
/* Internal settings and properties */
Display * p_display; /* display pointer */
int i_screen; /* screen number */
Window root_window; /* root window */
Window window; /* window instance handler */
GC gc; /* graphic context instance handler */
/* Font information */
int i_char_bytes_per_line; /* character width (bytes) */
int i_char_height; /* character height (lines) */
int i_char_interspacing; /* space between centers (pixels) */
byte_t * pi_font; /* pointer to font data */
27 years ago
/* Display buffers and shared memory information */
int i_buffer_index; /* buffer index */
XImage * p_ximage[2]; /* XImage pointer */
XShmSegmentInfo shm_info[2]; /* shared memory zone information */
} vout_sys_t;
/*******************************************************************************
* Local prototypes
*******************************************************************************/
static int X11OpenDisplay ( vout_thread_t *p_vout, char *psz_display, Window root_window );
static void X11CloseDisplay ( vout_thread_t *p_vout );
static int X11GetFont ( vout_thread_t *p_vout );
static int X11CreateWindow ( vout_thread_t *p_vout );
static void X11DestroyWindow ( vout_thread_t *p_vout );
static int X11CreateImage ( vout_thread_t *p_vout, XImage **pp_ximage );
static void X11DestroyImage ( XImage *p_ximage );
static int X11CreateShmImage ( vout_thread_t *p_vout, XImage **pp_ximage,
XShmSegmentInfo *p_shm_info );
static void X11DestroyShmImage ( vout_thread_t *p_vout, XImage *p_ximage,
XShmSegmentInfo *p_shm_info );
27 years ago
27 years ago
/*******************************************************************************
27 years ago
* vout_SysCreate: allocate X11 video thread output method
27 years ago
*******************************************************************************
* This function allocate and initialize a X11 vout method. It uses some of the
* vout properties to choose the window size, and change them according to the
* actual properties of the display.
27 years ago
*******************************************************************************/
int vout_SysCreate( vout_thread_t *p_vout, char *psz_display, Window root_window )
27 years ago
{
/* Allocate structure */
27 years ago
p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
if( p_vout->p_sys == NULL )
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM) );
return( 1 );
}
/* Open and initialize device. This function issues its own error messages.
* Since XLib is usually not thread-safe, we can't use the same display
* pointer than the interface or another thread. However, the root window
* id is still valid. */
if( X11OpenDisplay( p_vout, psz_display, root_window ) )
27 years ago
{
intf_ErrMsg("error: can't initialize X11 display\n" );
free( p_vout->p_sys );
return( 1 );
27 years ago
}
return( 0 );
27 years ago
}
/*******************************************************************************
27 years ago
* vout_SysInit: initialize X11 video thread output method
27 years ago
*******************************************************************************
* This function create the XImages needed by the output thread.
27 years ago
*******************************************************************************/
27 years ago
int vout_SysInit( vout_thread_t *p_vout )
{
int i_err;
/* Create XImages using XShm extension - on failure, fall back to regular
* way (and destroy the first image if it was created successfully) */
if( p_vout->p_sys->b_shm )
27 years ago
{
/* Create first image */
i_err = X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[0],
&p_vout->p_sys->shm_info[0] );
if( !i_err ) /* first image has been created */
{
/* Create second image */
if( X11CreateShmImage( p_vout, &p_vout->p_sys->p_ximage[1],
&p_vout->p_sys->shm_info[1] ) )
{ /* error creating the second image */
X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
&p_vout->p_sys->shm_info[0] );
i_err = 1;
}
}
if( i_err ) /* an error occured */
{
intf_Msg("warning: XShm video extension desactivated\n" );
p_vout->p_sys->b_shm = 0;
}
27 years ago
}
/* Create XImages without XShm extension */
if( !p_vout->p_sys->b_shm )
27 years ago
{
if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[0] ) )
{
intf_Msg("error: can't create images\n");
p_vout->p_sys->p_ximage[0] = NULL;
p_vout->p_sys->p_ximage[1] = NULL;
return( 1 );
}
if( X11CreateImage( p_vout, &p_vout->p_sys->p_ximage[1] ) )
{
intf_Msg("error: can't create images\n");
X11DestroyImage( p_vout->p_sys->p_ximage[0] );
p_vout->p_sys->p_ximage[0] = NULL;
p_vout->p_sys->p_ximage[1] = NULL;
return( 1 );
}
27 years ago
}
/* Set buffer index to 0 */
p_vout->p_sys->i_buffer_index = 0;
27 years ago
return( 0 );
}
/*******************************************************************************
27 years ago
* vout_SysEnd: terminate X11 video thread output method
27 years ago
*******************************************************************************
* Destroy the X11 XImages created by vout_SysInit.
27 years ago
*******************************************************************************/
27 years ago
void vout_SysEnd( vout_thread_t *p_vout )
27 years ago
{
if( p_vout->p_sys->b_shm ) /* Shm XImages... */
{
X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[0],
&p_vout->p_sys->shm_info[0] );
X11DestroyShmImage( p_vout, p_vout->p_sys->p_ximage[1],
&p_vout->p_sys->shm_info[1] );
}
else /* ...or regular XImages */
{
X11DestroyImage( p_vout->p_sys->p_ximage[0] );
X11DestroyImage( p_vout->p_sys->p_ximage[1] );
}
27 years ago
}
/*******************************************************************************
27 years ago
* vout_SysDestroy: destroy X11 video thread output method
*******************************************************************************
* Terminate an output method created by vout_X11CreateOutputMethod
*******************************************************************************/
void vout_SysDestroy( vout_thread_t *p_vout )
{
X11CloseDisplay( p_vout );
27 years ago
free( p_vout->p_sys );
}
/*******************************************************************************
* vout_SysManage: handle X11 events
27 years ago
*******************************************************************************
* This function should be called regularly by video output thread. It manages
* X11 events and allows window resizing. It returns a negative value if
* something happened which does not allow the thread to continue, and a
* positive one if the thread can go on, but the images have been modified and
* therefore it is useless to display them.
*******************************************************************************/
27 years ago
int vout_SysManage( vout_thread_t *p_vout )
27 years ago
{
27 years ago
//??
return 0;
27 years ago
// ?? if resized: end/init again, return >0
27 years ago
}
/*******************************************************************************
27 years ago
* vout_SysDisplay: displays previously rendered output
27 years ago
*******************************************************************************
* This function send the currently rendered image to X11 server, wait until
* it is displayed and switch the two rendering buffer, preparing next frame.
*******************************************************************************/
27 years ago
void vout_SysDisplay( vout_thread_t *p_vout )
27 years ago
{
if( p_vout->p_sys->b_shm) /* XShm is used */
27 years ago
{
/* Display rendered image using shared memory extension */
27 years ago
XShmPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ],
27 years ago
0, 0, 0, 0,
27 years ago
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height, True);
27 years ago
/* Send the order to the X server */
27 years ago
XFlush(p_vout->p_sys->p_display);
27 years ago
}
else /* regular X11 capabilities are used */
{
27 years ago
XPutImage(p_vout->p_sys->p_display, p_vout->p_sys->window, p_vout->p_sys->gc,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ],
27 years ago
0, 0, 0, 0,
27 years ago
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->width,
p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->height);
27 years ago
/* Send the order to the X server */
27 years ago
XFlush(p_vout->p_sys->p_display); /* ?? not needed ? */
27 years ago
}
/* Swap buffers */
27 years ago
p_vout->p_sys->i_buffer_index = ++p_vout->p_sys->i_buffer_index & 1;
27 years ago
}
/*******************************************************************************
* vout_SysGetPicture: get current display buffer informations
*******************************************************************************
* This function returns the address of the current display buffer.
*******************************************************************************/
byte_t * vout_SysGetPicture( vout_thread_t *p_vout )
{
return( p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data );
}
/*******************************************************************************
* vout_SysPrint: print simple text on a picture
*******************************************************************************
* This function will print a simple text on the picture. It is designed to
* print debugging or general informations, not to render subtitles.
* Since there is no way to print text on an Ximage directly, this function
* copy directly the pixels from a font.
*******************************************************************************/
void vout_SysPrint( vout_thread_t *p_vout, int i_x, int i_y, int i_halign,
int i_valign, unsigned char *psz_text )
{
int i_line; /* line in character matrix */
int i_byte; /* byte offset in character line */
int i_height; /* character height */
int i_char_bytes_per_line; /* total bytes per line */
byte_t * pi_pic; /* picture data */
byte_t * pi_char; /* character data */
/* Update upper left coordinates according to alignment */
switch( i_halign )
{
case 0: /* centered */
i_x -= p_vout->p_sys->i_char_interspacing * strlen( psz_text ) / 2;
break;
case 1: /* right aligned */
i_x -= p_vout->p_sys->i_char_interspacing * strlen( psz_text );
break;
}
switch( i_valign )
{
case 0: /* centered */
i_y -= p_vout->p_sys->i_char_height / 2;
break;
case 1: /* bottom aligned */
i_y -= p_vout->p_sys->i_char_height;
break;
}
/* Copy used variables to local */
i_height = p_vout->p_sys->i_char_height;
i_char_bytes_per_line = p_vout->p_sys->i_char_bytes_per_line;
/* Print text */
for( ; *psz_text != '\0'; psz_text++ )
{
if( (*psz_text >= VOUT_MIN_CHAR) && (*psz_text < VOUT_MAX_CHAR) )
{
/* Select character */
pi_char = p_vout->p_sys->pi_font + (*psz_text - VOUT_MIN_CHAR) *
i_height * i_char_bytes_per_line;
pi_pic = p_vout->p_sys->p_ximage[ p_vout->p_sys->i_buffer_index ]->data +
i_y * p_vout->i_bytes_per_line + i_x * p_vout->i_bytes_per_pixel;
/* Copy character */
for( i_line = 0; i_line < i_height; i_line++ )
{
/* Copy line */
for( i_byte = 0; i_byte < i_char_bytes_per_line; i_byte++ )
{
pi_pic[ i_byte ] = *pi_char++;
}
/* Go to next line */
pi_pic += p_vout->i_bytes_per_line;
}
}
/* Jump to next character */
i_x += p_vout->p_sys->i_char_interspacing;
}
}
27 years ago
/* following functions are local */
/*******************************************************************************
* X11OpenDisplay: open and initialize X11 device
27 years ago
*******************************************************************************
* Create a window according to video output given size, and set other
* properties according to the display properties.
27 years ago
*******************************************************************************/
static int X11OpenDisplay( vout_thread_t *p_vout, char *psz_display, Window root_window )
27 years ago
{
/* Open display */
p_vout->p_sys->p_display = XOpenDisplay( psz_display );
if( p_vout->p_sys->p_display == NULL )
{
intf_ErrMsg("error: can't open display %s\n", psz_display );
return( 1 );
}
/* Initialize structure */
p_vout->p_sys->root_window = root_window;
p_vout->p_sys->b_shm = VOUT_XSHM &&
(XShmQueryExtension(p_vout->p_sys->p_display) == True);
p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
/* Get the screen depth */
27 years ago
p_vout->i_screen_depth = DefaultDepth( p_vout->p_sys->p_display,
p_vout->p_sys->i_screen );
27 years ago
switch( p_vout->i_screen_depth )
{
case 15: /* 15 bpp (16bpp with a missing green bit) */
case 16: /* 16 bpp (65536 colors) */
p_vout->i_bytes_per_pixel = 2;
break;
case 24: /* 24 bpp (millions of colors) */
p_vout->i_bytes_per_pixel = 3;
break;
case 32: /* 32 bpp (millions of colors) */
p_vout->i_bytes_per_pixel = 4;
break;
default: /* unsupported screen depth */
intf_ErrMsg("error: screen depth %d is not supported\n",
p_vout->i_screen_depth);
XCloseDisplay( p_vout->p_sys->p_display );
27 years ago
return( 1 );
break;
}
/* Create a window and set line length */
if( X11CreateWindow( p_vout ) )
{
intf_ErrMsg("error: can't open a window\n");
XCloseDisplay( p_vout->p_sys->p_display );
return( 1 );
}
p_vout->i_bytes_per_line = p_vout->i_width * p_vout->i_bytes_per_pixel;
/* Get font information */
if( X11GetFont( p_vout ) )
{
intf_ErrMsg("error: can't read default font\n");
X11DestroyWindow( p_vout );
XCloseDisplay( p_vout->p_sys->p_display );
return( 1 );
}
return( 0 );
}
/*******************************************************************************
* X11CloseDisplay: close X11 device
*******************************************************************************
* Returns all resources allocated by X11OpenDisplay and restore the original
* state of the display.
*******************************************************************************/
static void X11CloseDisplay( vout_thread_t *p_vout )
{
// Free font info
free( p_vout->p_sys->pi_font );
// Destroy window and close display
X11DestroyWindow( p_vout );
XCloseDisplay( p_vout->p_sys->p_display );
27 years ago
}
/*******************************************************************************
* X11GetFont: get default font bitmap informations
*******************************************************************************
* This function will convert a font into a bitmap for later use by the
* vout_SysPrint function.
*******************************************************************************/
static int X11GetFont( vout_thread_t *p_vout )
{
XFontStruct * p_font_info; /* font information structure */
Pixmap pixmap; /* pixmap used to draw characters */
GC gc; /* graphic context */
XGCValues gc_values; /* graphic context properties */
XImage * p_ximage; /* ximage for character */
unsigned char i_char; /* character index */
int i_char_width; /* character width (pixels) */
int i_char_bytes; /* total character size */
/* Load font */
p_font_info = XLoadQueryFont( p_vout->p_sys->p_display, "fixed" );
if( p_font_info == NULL )
{
intf_ErrMsg("error: can't load 'fixed' font\n");
return( 1 );
}
/* Get character size */
i_char_width = p_font_info->max_bounds.lbearing +
p_font_info->max_bounds.rbearing;
p_vout->p_sys->i_char_bytes_per_line = i_char_width * p_vout->i_bytes_per_pixel;
p_vout->p_sys->i_char_height = p_font_info->max_bounds.ascent +
p_font_info->max_bounds.descent;
i_char_bytes = p_vout->p_sys->i_char_bytes_per_line *
p_vout->p_sys->i_char_height;
p_vout->p_sys->i_char_interspacing = p_font_info->max_bounds.width;
/* Allocate font descriptor */
p_vout->p_sys->pi_font = malloc( i_char_bytes * ( VOUT_MAX_CHAR - VOUT_MIN_CHAR ) );
if( p_vout->p_sys->pi_font == NULL )
{
intf_ErrMsg("error: %s\n", strerror( ENOMEM ) );
XFreeFont( p_vout->p_sys->p_display, p_font_info );
return( 1 );
}
/* Create drawable and graphic context */
gc_values.foreground = XBlackPixel( p_vout->p_sys->p_display,
p_vout->p_sys->i_screen );
gc_values.background = XBlackPixel( p_vout->p_sys->p_display,
p_vout->p_sys->i_screen );
gc_values.font = p_font_info->fid;
pixmap = XCreatePixmap( p_vout->p_sys->p_display, p_vout->p_sys->window,
i_char_width,
p_vout->p_sys->i_char_height *(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
p_vout->i_screen_depth );
gc = XCreateGC( p_vout->p_sys->p_display, pixmap,
GCForeground | GCBackground | GCFont, &gc_values );
/* Clear pixmap and invert graphic context */
XFillRectangle( p_vout->p_sys->p_display, pixmap, gc, 0, 0, i_char_width,
p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR) );
XSetForeground( p_vout->p_sys->p_display, gc,
XWhitePixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
XSetBackground( p_vout->p_sys->p_display, gc,
XBlackPixel( p_vout->p_sys->p_display, p_vout->p_sys->i_screen ) );
/* Copy characters bitmaps to font descriptor */
for( i_char = VOUT_MIN_CHAR; i_char < VOUT_MAX_CHAR; i_char++ )
{
XDrawString( p_vout->p_sys->p_display, pixmap, gc, 0,
p_font_info->max_bounds.ascent +
(i_char-VOUT_MIN_CHAR) * p_vout->p_sys->i_char_height,
&i_char, 1 );
}
p_ximage = XGetImage( p_vout->p_sys->p_display, pixmap, 0, 0, i_char_width,
p_vout->p_sys->i_char_height*(VOUT_MAX_CHAR-VOUT_MIN_CHAR),
-1, ZPixmap );
memcpy( p_vout->p_sys->pi_font, p_ximage->data,
i_char_bytes*(VOUT_MAX_CHAR-VOUT_MIN_CHAR));
/* Free resources, unload font and return */
XDestroyImage( p_ximage );
XFreeGC( p_vout->p_sys->p_display, gc );
XFreePixmap( p_vout->p_sys->p_display, pixmap );
XFreeFont( p_vout->p_sys->p_display, p_font_info );
return( 0 );
}
27 years ago
/*******************************************************************************
27 years ago
* X11CreateWindow: create X11 vout window
27 years ago
*******************************************************************************
27 years ago
* The video output window will be created. Normally, this window is wether
* full screen or part of a parent window. Therefore, it does not need a
* title or other hints. Thery are still supplied in case the window would be
* spawned as a standalone one by the interface.
27 years ago
*******************************************************************************/
static int X11CreateWindow( vout_thread_t *p_vout )
{
XSetWindowAttributes xwindow_attributes;
XGCValues xgcvalues;
XEvent xevent;
boolean_t b_expose;
boolean_t b_map_notify;
/* Prepare window attributes */
xwindow_attributes.backing_store = Always; /* save the hidden part */
27 years ago
/* Create the window and set hints */
27 years ago
p_vout->p_sys->window = XCreateSimpleWindow( p_vout->p_sys->p_display,
p_vout->p_sys->root_window,
0, 0,
p_vout->i_width, p_vout->i_height,
0, 0, 0);
XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window,
27 years ago
ExposureMask | StructureNotifyMask );
27 years ago
XChangeWindowAttributes( p_vout->p_sys->p_display, p_vout->p_sys->window,
27 years ago
CWBackingStore, &xwindow_attributes);
/* Creation of a graphic context that doesn't generate a GraphicsExpose event
when using functions like XCopyArea */
xgcvalues.graphics_exposures = False;
27 years ago
p_vout->p_sys->gc = XCreateGC( p_vout->p_sys->p_display, p_vout->p_sys->window,
27 years ago
GCGraphicsExposures, &xgcvalues);
27 years ago
/* Send orders to server, and wait until window is displayed - two events
27 years ago
* must be received: a MapNotify event, an Expose event allowing drawing in the
27 years ago
* window */
27 years ago
b_expose = 0;
b_map_notify = 0;
27 years ago
XMapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window);
27 years ago
do
{
27 years ago
XNextEvent( p_vout->p_sys->p_display, &xevent);
27 years ago
if( (xevent.type == Expose)
27 years ago
&& (xevent.xexpose.window == p_vout->p_sys->window) )
27 years ago
{
b_expose = 1;
}
else if( (xevent.type == MapNotify)
27 years ago
&& (xevent.xmap.window == p_vout->p_sys->window) )
27 years ago
{
b_map_notify = 1;
}
}
27 years ago
while( !( b_expose && b_map_notify ) );
XSelectInput( p_vout->p_sys->p_display, p_vout->p_sys->window, 0 );
27 years ago
/* At this stage, the window is openned, displayed, and ready to receive
* data */
27 years ago
return( 0 );
}
/*******************************************************************************
* X11DestroyWindow: destroy X11 window
*******************************************************************************
* Destroy an X11 window created by vout_X11CreateWindow
*******************************************************************************/
static void X11DestroyWindow( vout_thread_t *p_vout )
{
27 years ago
XUnmapWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
XFreeGC( p_vout->p_sys->p_display, p_vout->p_sys->gc );
XDestroyWindow( p_vout->p_sys->p_display, p_vout->p_sys->window );
27 years ago
}
/*******************************************************************************
* X11CreateImage: create an XImage
*******************************************************************************/
static int X11CreateImage( vout_thread_t *p_vout, XImage **pp_ximage )
{
byte_t * pb_data; /* image data storage zone */
int i_quantum; /* XImage quantum (see below) */
/* Allocate memory for image */
pb_data = (byte_t *) malloc( p_vout->i_bytes_per_line * p_vout->i_height );
27 years ago
if( !pb_data ) /* error */
{
intf_ErrMsg("error: %s\n", strerror(ENOMEM));
return( 1 );
27 years ago
}
/* Optimize the quantum of a scanline regarding its size - the quantum is
a diviser of the number of bits between the start of two scanlines. */
if( !(( p_vout->i_bytes_per_line ) % 32) )
27 years ago
{
i_quantum = 32;
}
else
{
if( !(( p_vout->i_bytes_per_line ) % 16) )
27 years ago
{
i_quantum = 16;
}
else
{
i_quantum = 8;
}
}
/* Create XImage */
27 years ago
*pp_ximage = XCreateImage( p_vout->p_sys->p_display,
DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
27 years ago
p_vout->i_screen_depth, ZPixmap, 0, pb_data,
p_vout->i_width, p_vout->i_height, i_quantum, 0);
if(! *pp_ximage ) /* error */
{
intf_ErrMsg( "error: XCreateImage() failed\n" );
27 years ago
free( pb_data );
return( 1 );
27 years ago
}
return 0;
}
/*******************************************************************************
* X11CreateShmImage: create an XImage using shared memory extension
*******************************************************************************
* Prepare an XImage for DisplayX11ShmImage function.
* The order of the operations respects the recommandations of the mit-shm
* document by J.Corbet and K.Packard. Most of the parameters were copied from
* there.
*******************************************************************************/
static int X11CreateShmImage( vout_thread_t *p_vout, XImage **pp_ximage,
XShmSegmentInfo *p_shm_info)
{
/* Create XImage */
27 years ago
*pp_ximage = XShmCreateImage( p_vout->p_sys->p_display,
DefaultVisual(p_vout->p_sys->p_display, p_vout->p_sys->i_screen),
27 years ago
p_vout->i_screen_depth, ZPixmap, 0,
p_shm_info, p_vout->i_width, p_vout->i_height );
if(! *pp_ximage ) /* error */
{
intf_ErrMsg("error: XShmCreateImage() failed\n");
return( 1 );
27 years ago
}
/* Allocate shared memory segment - 0777 set the access permission
* rights (like umask), they are not yet supported by X servers */
p_shm_info->shmid = shmget( IPC_PRIVATE,
(*pp_ximage)->bytes_per_line * (*pp_ximage)->height,
IPC_CREAT | 0777);
if( p_shm_info->shmid < 0) /* error */
{
intf_ErrMsg("error: can't allocate shared image data (%s)\n",
27 years ago
strerror(errno));
XDestroyImage( *pp_ximage );
return( 1 );
27 years ago
}
/* Attach shared memory segment to process (read/write) */
p_shm_info->shmaddr = (*pp_ximage)->data = shmat(p_shm_info->shmid, 0, 0);
if(! p_shm_info->shmaddr )
{ /* error */
intf_ErrMsg("error: can't attach shared memory (%s)\n",
27 years ago
strerror(errno));
shmctl( p_shm_info->shmid, IPC_RMID, 0 ); /* free shared memory */
XDestroyImage( *pp_ximage );
return( 1 );
27 years ago
}
/* Mark the shm segment to be removed when there will be no more
* attachements, so it is automatic on process exit or after shmdt */
shmctl( p_shm_info->shmid, IPC_RMID, 0 );
/* Attach shared memory segment to X server (read only) */
p_shm_info->readOnly = True;
27 years ago
if( XShmAttach( p_vout->p_sys->p_display, p_shm_info ) == False ) /* error */
27 years ago
{
intf_ErrMsg("error: can't attach shared memory to X11 server\n");
27 years ago
shmdt( p_shm_info->shmaddr ); /* detach shared memory from process
* and automatic free */
XDestroyImage( *pp_ximage );
return( 1 );
27 years ago
}
/* Send image to X server. This instruction is required, since having
* built a Shm XImage and not using it causes an error on XCloseDisplay */
XFlush( p_vout->p_sys->p_display );
27 years ago
return( 0 );
}
/*******************************************************************************
* X11DestroyImage: destroy an XImage
*******************************************************************************
* Destroy XImage AND associated data. If pointer is NULL, the image won't be
* destroyed (see vout_X11ManageOutputMethod())
*******************************************************************************/
static void X11DestroyImage( XImage *p_ximage )
{
if( p_ximage != NULL )
{
XDestroyImage( p_ximage ); /* no free() required */
}
}
/*******************************************************************************
* X11DestroyShmImage
*******************************************************************************
* Destroy XImage AND associated data. Detach shared memory segment from
* server and process, then free it. If pointer is NULL, the image won't be
* destroyed (see vout_X11ManageOutputMethod())
*******************************************************************************/
static void X11DestroyShmImage( vout_thread_t *p_vout, XImage *p_ximage,
XShmSegmentInfo *p_shm_info )
{
/* If pointer is NULL, do nothing */
if( p_ximage == NULL )
{
return;
}
27 years ago
XShmDetach( p_vout->p_sys->p_display, p_shm_info ); /* detach from server */
27 years ago
XDestroyImage( p_ximage );
if( shmdt( p_shm_info->shmaddr ) ) /* detach shared memory from process */
{ /* also automatic freeing... */
intf_ErrMsg("error: can't detach shared memory (%s)\n",
27 years ago
strerror(errno));
}
}