Added support for remote XVideo (thanks Frederic!)
authorSam Lantinga <slouken@libsdl.org>
Thu, 12 Feb 2004 16:05:30 +0000
changeset 8136a2c6717b386
parent 812 d315a411d5b2
child 814 5a417d2a8603
Added support for remote XVideo (thanks Frederic!)
src/video/x11/SDL_x11yuv.c
     1.1 --- a/src/video/x11/SDL_x11yuv.c	Thu Feb 12 06:21:13 2004 +0000
     1.2 +++ b/src/video/x11/SDL_x11yuv.c	Thu Feb 12 16:05:30 2004 +0000
     1.3 @@ -32,9 +32,11 @@
     1.4  #include <stdlib.h>
     1.5  #include <string.h>
     1.6  #include <X11/Xlib.h>
     1.7 +#ifndef NO_SHARED_MEMORY
     1.8  #include <sys/ipc.h>
     1.9  #include <sys/shm.h>
    1.10  #include <X11/extensions/XShm.h>
    1.11 +#endif
    1.12  #include <XFree86/extensions/Xvlib.h>
    1.13  
    1.14  #include "SDL_error.h"
    1.15 @@ -63,11 +65,29 @@
    1.16  
    1.17  struct private_yuvhwdata {
    1.18  	int port;
    1.19 +#ifndef NO_SHARED_MEMORY
    1.20 +	int yuv_use_mitshm;
    1.21  	XShmSegmentInfo yuvshm;
    1.22 +#endif
    1.23  	SDL_NAME(XvImage) *image;
    1.24  };
    1.25  
    1.26  
    1.27 +#ifndef NO_SHARED_MEMORY
    1.28 +/* Shared memory error handler routine */
    1.29 +static int shm_error;
    1.30 +static int (*X_handler)(Display *, XErrorEvent *) = NULL;
    1.31 +static int shm_errhandler(Display *d, XErrorEvent *e)
    1.32 +{
    1.33 +        if ( e->error_code == BadAccess ) {
    1.34 +        	shm_error = True;
    1.35 +        	return(0);
    1.36 +        } else
    1.37 +		return(X_handler(d,e));
    1.38 +}
    1.39 +#endif /* !NO_SHARED_MEMORY */
    1.40 +
    1.41 +
    1.42  SDL_Overlay *X11_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display)
    1.43  {
    1.44  	SDL_Overlay *overlay;
    1.45 @@ -76,7 +96,10 @@
    1.46  	int i, j, k;
    1.47  	int adaptors;
    1.48  	SDL_NAME(XvAdaptorInfo) *ainfo;
    1.49 +	int bpp;
    1.50 +#ifndef NO_SHARED_MEMORY
    1.51  	XShmSegmentInfo *yuvshm;
    1.52 +#endif
    1.53  
    1.54  	/* Look for the XVideo extension with a valid port for this format */
    1.55  	xv_port = -1;
    1.56 @@ -133,6 +156,19 @@
    1.57  		SDL_NAME(XvFreeAdaptorInfo)(ainfo);
    1.58  	}
    1.59  
    1.60 +	/* Precalculate the bpp for the pitch workaround below */
    1.61 +	switch (format) {
    1.62 +	    /* Add any other cases we need to support... */
    1.63 +	    case SDL_YUY2_OVERLAY:
    1.64 +	    case SDL_UYVY_OVERLAY:
    1.65 +	    case SDL_YVYU_OVERLAY:
    1.66 +		bpp = 2;
    1.67 +		break;
    1.68 +	    default:
    1.69 +		bpp = 1;
    1.70 +		break;
    1.71 +	}
    1.72 +
    1.73  #if 0
    1.74      /*
    1.75       * !!! FIXME:
    1.76 @@ -183,57 +219,77 @@
    1.77  		SDL_FreeYUVOverlay(overlay);
    1.78  		return(NULL);
    1.79  	}
    1.80 +	hwdata->port = xv_port;
    1.81 +#ifndef NO_SHARED_MEMORY
    1.82  	yuvshm = &hwdata->yuvshm;
    1.83  	memset(yuvshm, 0, sizeof(*yuvshm));
    1.84 -	hwdata->port = xv_port;
    1.85  	hwdata->image = SDL_NAME(XvShmCreateImage)(GFX_Display, xv_port, format,
    1.86 -	                                 0, width, height, yuvshm);
    1.87 +						   0, width, height, yuvshm);
    1.88 +#ifdef PITCH_WORKAROUND
    1.89 +	if ( hwdata->image != NULL && hwdata->image->pitches[0] != (width*bpp) ) {
    1.90 +		/* Ajust overlay width according to pitch */ 
    1.91 +		XFree(hwdata->image);
    1.92 +		width = hwdata->image->pitches[0] / bpp;
    1.93 +		hwdata->image = SDL_NAME(XvShmCreateImage)(GFX_Display, xv_port, format,
    1.94 +							   0, width, height, yuvshm);
    1.95 +	}
    1.96 +#endif /* PITCH_WORKAROUND */
    1.97 +	hwdata->yuv_use_mitshm = (hwdata->image != NULL);
    1.98 +	if ( hwdata->yuv_use_mitshm ) {
    1.99 +		yuvshm->shmid = shmget(IPC_PRIVATE, hwdata->image->data_size,
   1.100 +				       IPC_CREAT | 0777);
   1.101 +		if ( yuvshm->shmid >= 0 ) {
   1.102 +			yuvshm->shmaddr = (char *)shmat(yuvshm->shmid, 0, 0);
   1.103 +			yuvshm->readOnly = False;
   1.104 +			if ( yuvshm->shmaddr != (char *)-1 ) {
   1.105 +				shm_error = False;
   1.106 +				X_handler = XSetErrorHandler(shm_errhandler);
   1.107 +				XShmAttach(GFX_Display, yuvshm);
   1.108 +				XSync(GFX_Display, True);
   1.109 +				XSetErrorHandler(X_handler);
   1.110 +				if ( shm_error )
   1.111 +					shmdt(yuvshm->shmaddr);
   1.112 +			} else {
   1.113 +				shm_error = True;
   1.114 +			}
   1.115 +			shmctl(yuvshm->shmid, IPC_RMID, NULL);
   1.116 +		} else {
   1.117 +			shm_error = True;
   1.118 +		}
   1.119 +		if ( shm_error ) {
   1.120 +			XFree(hwdata->image);
   1.121 +			hwdata->yuv_use_mitshm = 0;
   1.122 +		} else {
   1.123 +			hwdata->image->data = yuvshm->shmaddr;
   1.124 +		}
   1.125 +	}
   1.126 +	if ( !hwdata->yuv_use_mitshm )
   1.127 +#endif /* NO_SHARED_MEMORY */
   1.128 +	{
   1.129 +		hwdata->image = SDL_NAME(XvCreateImage)(GFX_Display, xv_port, format,
   1.130 +							0, width, height);
   1.131  
   1.132  #ifdef PITCH_WORKAROUND
   1.133 -	if ( hwdata->image != NULL && hwdata->image->pitches[0] != width )
   1.134 -	{
   1.135 -	  /* Ajust overlay width according to pitch */ 
   1.136 -	  switch (format) {
   1.137 -	    case SDL_YV12_OVERLAY:
   1.138 -	    case SDL_IYUV_OVERLAY:
   1.139 -	        width = hwdata->image->pitches[0];
   1.140 -		break;
   1.141 -	    case SDL_YUY2_OVERLAY:
   1.142 -	    case SDL_UYVY_OVERLAY:
   1.143 -	    case SDL_YVYU_OVERLAY:
   1.144 -	        width = hwdata->image->pitches[0] / 2;
   1.145 -		break;
   1.146 -	    default:
   1.147 -		/* We should never get here (caught above) */
   1.148 -		return(NULL);
   1.149 -	  }
   1.150 -	  
   1.151 -	  XFree(hwdata->image);
   1.152 -	  hwdata->image = SDL_NAME(XvShmCreateImage)(GFX_Display, xv_port, format,
   1.153 -					   0, width, height, yuvshm);
   1.154 +		if ( hwdata->image != NULL && hwdata->image->pitches[0] != (width*bpp) ) {
   1.155 +			/* Ajust overlay width according to pitch */ 
   1.156 +			XFree(hwdata->image);
   1.157 +			width = hwdata->image->pitches[0] / bpp;
   1.158 +			hwdata->image = SDL_NAME(XvCreateImage)(GFX_Display, xv_port, format,
   1.159 +								0, width, height);
   1.160 +		}
   1.161 +#endif /* PITCH_WORKAROUND */
   1.162 +		if ( hwdata->image == NULL ) {
   1.163 +			SDL_SetError("Couldn't create XVideo image");
   1.164 +			SDL_FreeYUVOverlay(overlay);
   1.165 +			return(NULL);
   1.166 +		}
   1.167 +		hwdata->image->data = malloc(hwdata->image->data_size);
   1.168 +		if ( hwdata->image->data == NULL ) {
   1.169 +			SDL_OutOfMemory();
   1.170 +			SDL_FreeYUVOverlay(overlay);
   1.171 +			return(NULL);
   1.172 +		}
   1.173  	}
   1.174 -#endif
   1.175 -
   1.176 -	if ( hwdata->image == NULL ) {
   1.177 -		SDL_OutOfMemory();
   1.178 -		SDL_FreeYUVOverlay(overlay);
   1.179 -		return(NULL);
   1.180 -	}
   1.181 -	yuvshm->shmid = shmget(IPC_PRIVATE, hwdata->image->data_size,
   1.182 -	                       IPC_CREAT | 0777);
   1.183 -	if ( yuvshm->shmid < 0 ) {
   1.184 -		SDL_SetError("Unable to get %d bytes shared memory",
   1.185 -		             hwdata->image->data_size);
   1.186 -		SDL_FreeYUVOverlay(overlay);
   1.187 -		return(NULL);
   1.188 -	}
   1.189 -	yuvshm->shmaddr  = (char *) shmat(yuvshm->shmid, 0, 0);
   1.190 -	yuvshm->readOnly = False;
   1.191 -	hwdata->image->data = yuvshm->shmaddr;
   1.192 -
   1.193 -	XShmAttach(GFX_Display, yuvshm);
   1.194 -	XSync(GFX_Display, False);
   1.195 -	shmctl(yuvshm->shmid, IPC_RMID, 0);
   1.196  
   1.197  	/* Find the pitch and offset values for the overlay */
   1.198  	overlay->planes = hwdata->image->num_planes;
   1.199 @@ -277,9 +333,19 @@
   1.200  	struct private_yuvhwdata *hwdata;
   1.201  
   1.202  	hwdata = overlay->hwdata;
   1.203 -	SDL_NAME(XvShmPutImage)(GFX_Display, hwdata->port, SDL_Window, SDL_GC,
   1.204 +#ifndef NO_SHARED_MEMORY
   1.205 +	if ( hwdata->yuv_use_mitshm ) {
   1.206 +		SDL_NAME(XvShmPutImage)(GFX_Display, hwdata->port, SDL_Window, SDL_GC,
   1.207  	              hwdata->image, 0, 0, overlay->w, overlay->h,
   1.208  	              dstrect->x, dstrect->y, dstrect->w, dstrect->h, False);
   1.209 +	}
   1.210 +	else
   1.211 +#endif
   1.212 +	{
   1.213 +		SDL_NAME(XvPutImage)(GFX_Display, hwdata->port, SDL_Window, SDL_GC,
   1.214 +				     hwdata->image, 0, 0, overlay->w, overlay->h,
   1.215 +				     dstrect->x, dstrect->y, dstrect->w, dstrect->h);
   1.216 +	}
   1.217  	XSync(GFX_Display, False);
   1.218  	return(0);
   1.219  }
   1.220 @@ -291,10 +357,12 @@
   1.221  	hwdata = overlay->hwdata;
   1.222  	if ( hwdata ) {
   1.223  		SDL_NAME(XvUngrabPort)(GFX_Display, hwdata->port, CurrentTime);
   1.224 -		if ( hwdata->yuvshm.shmaddr ) {
   1.225 +#ifndef NO_SHARED_MEMORY
   1.226 +		if ( hwdata->yuv_use_mitshm ) {
   1.227  			XShmDetach(GFX_Display, &hwdata->yuvshm);
   1.228  			shmdt(hwdata->yuvshm.shmaddr);
   1.229  		}
   1.230 +#endif
   1.231  		if ( hwdata->image ) {
   1.232  			XFree(hwdata->image);
   1.233  		}