src/video/x11/SDL_x11yuv.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 06 Mar 2002 11:23:08 +0000
changeset 297 f6ffac90895c
parent 292 eadc0746dfaf
child 341 6ca967a46bf1
permissions -rw-r--r--
Updated copyright information for 2002
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 /* This is the XFree86 Xv extension implementation of YUV video overlays */
    29 
    30 #ifdef XFREE86_XV
    31 
    32 #include <stdlib.h>
    33 #include <string.h>
    34 #include <X11/Xlib.h>
    35 #include <sys/ipc.h>
    36 #include <sys/shm.h>
    37 #include <X11/extensions/XShm.h>
    38 #include <XFree86/extensions/Xvlib.h>
    39 
    40 #include "SDL_error.h"
    41 #include "SDL_video.h"
    42 #include "SDL_x11yuv_c.h"
    43 #include "SDL_yuvfuncs.h"
    44 
    45 #define XFREE86_REFRESH_HACK
    46 #ifdef XFREE86_REFRESH_HACK
    47 #include "SDL_x11image_c.h"
    48 #endif
    49 
    50 /* Workaround when pitch != width */
    51 #define PITCH_WORKAROUND
    52 
    53 /* Fix for the NVidia GeForce 2 - use the last available adaptor */
    54 #define USE_LAST_ADAPTOR
    55 
    56 /* The functions used to manipulate software video overlays */
    57 static struct private_yuvhwfuncs x11_yuvfuncs = {
    58 	X11_LockYUVOverlay,
    59 	X11_UnlockYUVOverlay,
    60 	X11_DisplayYUVOverlay,
    61 	X11_FreeYUVOverlay
    62 };
    63 
    64 struct private_yuvhwdata {
    65 	int port;
    66 	XShmSegmentInfo yuvshm;
    67 	SDL_NAME(XvImage) *image;
    68 };
    69 
    70 
    71 SDL_Overlay *X11_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display)
    72 {
    73 	SDL_Overlay *overlay;
    74 	struct private_yuvhwdata *hwdata;
    75 	int xv_port;
    76 	int i, j, k;
    77 	int adaptors;
    78 	SDL_NAME(XvAdaptorInfo) *ainfo;
    79 	XShmSegmentInfo *yuvshm;
    80 
    81 	/* Look for the XVideo extension with a valid port for this format */
    82 	xv_port = -1;
    83 	if ( (Success == SDL_NAME(XvQueryExtension)(GFX_Display, &j, &j, &j, &j, &j)) &&
    84 	     (Success == SDL_NAME(XvQueryAdaptors)(GFX_Display,
    85 	                                 RootWindow(GFX_Display, SDL_Screen),
    86 	                                 &adaptors, &ainfo)) ) {
    87 #ifdef USE_LAST_ADAPTOR
    88 		for ( i=0; i < adaptors; ++i ) {
    89 #else
    90 		for ( i=0; (i < adaptors) && (xv_port == -1); ++i ) {
    91 #endif /* USE_LAST_ADAPTOR */
    92 			/* Check to see if the visual can be used */
    93 			if ( BUGGY_XFREE86(<=, 4001) ) {
    94 				int visual_ok = 0;
    95 				for ( j=0; j<ainfo[i].num_formats; ++j ) {
    96 					if ( ainfo[i].formats[j].visual_id ==
    97 							SDL_Visual->visualid ) {
    98 						visual_ok = 1;
    99 						break;
   100 					}
   101 				}
   102 				if ( ! visual_ok ) {
   103 					continue;
   104 				}
   105 			}
   106 			if ( (ainfo[i].type & XvInputMask) &&
   107 			     (ainfo[i].type & XvImageMask) ) {
   108 				int num_formats;
   109 				SDL_NAME(XvImageFormatValues) *formats;
   110 				formats = SDL_NAME(XvListImageFormats)(GFX_Display,
   111 				              ainfo[i].base_id, &num_formats);
   112 #ifdef USE_LAST_ADAPTOR
   113 				for ( j=0; j < num_formats; ++j ) {
   114 #else
   115 				for ( j=0; (j < num_formats) && (xv_port == -1); ++j ) {
   116 #endif /* USE_LAST_ADAPTOR */
   117 					if ( (Uint32)formats[j].id == format ) {
   118 						for ( k=0; k < ainfo[i].num_ports; ++k ) {
   119 							if ( Success == SDL_NAME(XvGrabPort)(GFX_Display, ainfo[i].base_id+k, CurrentTime) ) {
   120 								xv_port = ainfo[i].base_id+k;
   121 								break;
   122 							}
   123 						}
   124 					}
   125 				}
   126 			}
   127 		}
   128 	}
   129 	if ( xv_port == -1 ) {
   130 		SDL_SetError("No available video ports for requested format");
   131 		return(NULL);
   132 	}
   133 
   134 	/* Create the overlay structure */
   135 	overlay = (SDL_Overlay *)malloc(sizeof *overlay);
   136 	if ( overlay == NULL ) {
   137 		SDL_NAME(XvUngrabPort)(GFX_Display, xv_port, CurrentTime);
   138 		SDL_OutOfMemory();
   139 		return(NULL);
   140 	}
   141 	memset(overlay, 0, (sizeof *overlay));
   142 
   143 	/* Fill in the basic members */
   144 	overlay->format = format;
   145 	overlay->w = width;
   146 	overlay->h = height;
   147 
   148 	/* Set up the YUV surface function structure */
   149 	overlay->hwfuncs = &x11_yuvfuncs;
   150 	overlay->hw_overlay = 1;
   151 
   152 	/* Create the pixel data and lookup tables */
   153 	hwdata = (struct private_yuvhwdata *)malloc(sizeof *hwdata);
   154 	overlay->hwdata = hwdata;
   155 	if ( hwdata == NULL ) {
   156 		SDL_NAME(XvUngrabPort)(GFX_Display, xv_port, CurrentTime);
   157 		SDL_OutOfMemory();
   158 		SDL_FreeYUVOverlay(overlay);
   159 		return(NULL);
   160 	}
   161 	yuvshm = &hwdata->yuvshm;
   162 	memset(yuvshm, 0, sizeof(*yuvshm));
   163 	hwdata->port = xv_port;
   164 	hwdata->image = SDL_NAME(XvShmCreateImage)(GFX_Display, xv_port, format,
   165 	                                 0, width, height, yuvshm);
   166 
   167 #ifdef PITCH_WORKAROUND
   168 	if ( hwdata->image != NULL && hwdata->image->pitches[0] != width )
   169 	{
   170 	  /* Ajust overlay width according to pitch */ 
   171 	  switch (format) {
   172 	    case SDL_YV12_OVERLAY:
   173 	    case SDL_IYUV_OVERLAY:
   174 	        width = hwdata->image->pitches[0];
   175 		break;
   176 	    case SDL_YUY2_OVERLAY:
   177 	    case SDL_UYVY_OVERLAY:
   178 	    case SDL_YVYU_OVERLAY:
   179 	        width = hwdata->image->pitches[0] / 2;
   180 		break;
   181 	    default:
   182 		/* We should never get here (caught above) */
   183 		return(NULL);
   184 	  }
   185 	  
   186 	  XFree(hwdata->image);
   187 	  hwdata->image = SDL_NAME(XvShmCreateImage)(GFX_Display, xv_port, format,
   188 					   0, width, height, yuvshm);
   189 	}
   190 #endif
   191 
   192 	if ( hwdata->image == NULL ) {
   193 		SDL_OutOfMemory();
   194 		SDL_FreeYUVOverlay(overlay);
   195 		return(NULL);
   196 	}
   197 	yuvshm->shmid = shmget(IPC_PRIVATE, hwdata->image->data_size,
   198 	                       IPC_CREAT | 0777);
   199 	if ( yuvshm->shmid < 0 ) {
   200 		SDL_SetError("Unable to get %d bytes shared memory",
   201 		             hwdata->image->data_size);
   202 		SDL_FreeYUVOverlay(overlay);
   203 		return(NULL);
   204 	}
   205 	yuvshm->shmaddr  = (char *) shmat(yuvshm->shmid, 0, 0);
   206 	yuvshm->readOnly = False;
   207 	hwdata->image->data = yuvshm->shmaddr;
   208 
   209 	XShmAttach(GFX_Display, yuvshm);
   210 	XSync(GFX_Display, False);
   211 	shmctl(yuvshm->shmid, IPC_RMID, 0);
   212 
   213 	/* Find the pitch and offset values for the overlay */
   214 	overlay->planes = hwdata->image->num_planes;
   215 	overlay->pitches = (Uint16 *)malloc(overlay->planes * sizeof(Uint16));
   216 	overlay->pixels = (Uint8 **)malloc(overlay->planes * sizeof(Uint8 *));
   217 	if ( !overlay->pitches || !overlay->pixels ) {
   218 		SDL_OutOfMemory();
   219 		SDL_FreeYUVOverlay(overlay);
   220 		return(NULL);
   221 	}
   222 	for ( i=0; i<overlay->planes; ++i ) {
   223 		overlay->pitches[i] = hwdata->image->pitches[i];
   224 		overlay->pixels[i] = (Uint8 *)hwdata->image->data +
   225 		                              hwdata->image->offsets[i];
   226 	}
   227 
   228 #ifdef XFREE86_REFRESH_HACK
   229 	/* Work around an XFree86 X server bug (?)
   230 	   We can't perform normal updates in windows that have video
   231 	   being output to them.  See SDL_x11image.c for more details.
   232 	 */
   233 	X11_DisableAutoRefresh(this);
   234 #endif
   235 
   236 	/* We're all done.. */
   237 	return(overlay);
   238 }
   239 
   240 int X11_LockYUVOverlay(_THIS, SDL_Overlay *overlay)
   241 {
   242 	return(0);
   243 }
   244 
   245 void X11_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay)
   246 {
   247 	return;
   248 }
   249 
   250 int X11_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect)
   251 {
   252 	struct private_yuvhwdata *hwdata;
   253 
   254 	hwdata = overlay->hwdata;
   255 	SDL_NAME(XvShmPutImage)(GFX_Display, hwdata->port, SDL_Window, SDL_GC,
   256 	              hwdata->image, 0, 0, overlay->w, overlay->h,
   257 	              dstrect->x, dstrect->y, dstrect->w, dstrect->h, False);
   258 	XSync(GFX_Display, False);
   259 	return(0);
   260 }
   261 
   262 void X11_FreeYUVOverlay(_THIS, SDL_Overlay *overlay)
   263 {
   264 	struct private_yuvhwdata *hwdata;
   265 
   266 	hwdata = overlay->hwdata;
   267 	if ( hwdata ) {
   268 		SDL_NAME(XvUngrabPort)(GFX_Display, hwdata->port, CurrentTime);
   269 		if ( hwdata->yuvshm.shmaddr ) {
   270 			XShmDetach(GFX_Display, &hwdata->yuvshm);
   271 			shmdt(hwdata->yuvshm.shmaddr);
   272 		}
   273 		if ( hwdata->image ) {
   274 			XFree(hwdata->image);
   275 		}
   276 		free(hwdata);
   277 	}
   278 	if ( overlay->pitches ) {
   279 		free(overlay->pitches);
   280 		overlay->pitches = NULL;
   281 	}
   282 	if ( overlay->pixels ) {
   283 		free(overlay->pixels);
   284 		overlay->pixels = NULL;
   285 	}
   286 #ifdef XFREE86_REFRESH_HACK
   287 	X11_EnableAutoRefresh(this);
   288 #endif
   289 }
   290 
   291 #endif /* XFREE86_XV */