Mercurial > sdl-ios-xcode
diff src/video/x11/SDL_x11yuv.c @ 0:74212992fb08
Initial revision
author | Sam Lantinga <slouken@lokigames.com> |
---|---|
date | Thu, 26 Apr 2001 16:45:43 +0000 |
parents | |
children | d4ebd1bbea9a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/x11/SDL_x11yuv.c Thu Apr 26 16:45:43 2001 +0000 @@ -0,0 +1,280 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +#ifdef SAVE_RCSID +static char rcsid = + "@(#) $Id$"; +#endif + +/* This is the XFree86 Xv extension implementation of YUV video overlays */ + +#ifdef XFREE86_XV + +#include <stdlib.h> +#include <string.h> +#include <X11/Xlib.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> +#include <X11/extensions/Xvlib.h> + +#include "SDL_error.h" +#include "SDL_video.h" +#include "SDL_x11yuv_c.h" +#include "SDL_yuvfuncs.h" + +#define XFREE86_REFRESH_HACK +#ifdef XFREE86_REFRESH_HACK +#include "SDL_x11image_c.h" +#endif + +/* Workaround when pitch != width */ +#define PITCH_WORKAROUND + +/* The functions used to manipulate software video overlays */ +static struct private_yuvhwfuncs x11_yuvfuncs = { + X11_LockYUVOverlay, + X11_UnlockYUVOverlay, + X11_DisplayYUVOverlay, + X11_FreeYUVOverlay +}; + +struct private_yuvhwdata { + int port; + XShmSegmentInfo yuvshm; + XvImage *image; +}; + + +SDL_Overlay *X11_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display) +{ + SDL_Overlay *overlay; + struct private_yuvhwdata *hwdata; + int xv_port; + int i, j, k; + int adaptors; + XvAdaptorInfo *ainfo; + XShmSegmentInfo *yuvshm; + + /* Look for the XVideo extension with a valid port for this format */ + xv_port = -1; + if ( (Success == XvQueryExtension(GFX_Display, &j, &j, &j, &j, &j)) && + (Success == XvQueryAdaptors(GFX_Display, + RootWindow(GFX_Display, SDL_Screen), + &adaptors, &ainfo)) ) { + for ( i=0; (i < adaptors) && (xv_port == -1); ++i ) { + /* Check to see if the visual can be used */ + if ( BUGGY_XFREE86(<=, 4001) ) { + int visual_ok = 0; + for ( j=0; j<ainfo[i].num_formats; ++j ) { + if ( ainfo[i].formats[j].visual_id == + SDL_Visual->visualid ) { + visual_ok = 1; + break; + } + } + if ( ! visual_ok ) { + continue; + } + } + if ( (ainfo[i].type & XvInputMask) && + (ainfo[i].type & XvImageMask) ) { + int num_formats; + XvImageFormatValues *formats; + formats = XvListImageFormats(GFX_Display, + ainfo[i].base_id, &num_formats); + for ( j=0; (j < num_formats) && (xv_port == -1); ++j ) { + if ( (Uint32)formats[j].id == format ) { + for ( k=0; k < ainfo[i].num_ports; ++k ) { + if ( Success == XvGrabPort(GFX_Display, ainfo[i].base_id+k, CurrentTime) ) { + xv_port = ainfo[i].base_id+k; + break; + } + } + } + } + } + } + } + if ( xv_port == -1 ) { + SDL_SetError("No available video ports for requested format"); + return(NULL); + } + + /* Create the overlay structure */ + overlay = (SDL_Overlay *)malloc(sizeof *overlay); + if ( overlay == NULL ) { + XvUngrabPort(GFX_Display, xv_port, CurrentTime); + SDL_OutOfMemory(); + return(NULL); + } + memset(overlay, 0, (sizeof *overlay)); + + /* Fill in the basic members */ + overlay->format = format; + overlay->w = width; + overlay->h = height; + + /* Set up the YUV surface function structure */ + overlay->hwfuncs = &x11_yuvfuncs; + overlay->hw_overlay = 1; + + /* Create the pixel data and lookup tables */ + hwdata = (struct private_yuvhwdata *)malloc(sizeof *hwdata); + overlay->hwdata = hwdata; + if ( hwdata == NULL ) { + XvUngrabPort(GFX_Display, xv_port, CurrentTime); + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + yuvshm = &hwdata->yuvshm; + memset(yuvshm, 0, sizeof(*yuvshm)); + hwdata->port = xv_port; + hwdata->image = XvShmCreateImage(GFX_Display, xv_port, format, + 0, width, height, yuvshm); + +#ifdef PITCH_WORKAROUND + if ( hwdata->image != NULL && hwdata->image->pitches[0] != width ) + { + /* Ajust overlay width according to pitch */ + switch (format) { + case SDL_YV12_OVERLAY: + case SDL_IYUV_OVERLAY: + width = hwdata->image->pitches[0]; + break; + case SDL_YUY2_OVERLAY: + case SDL_UYVY_OVERLAY: + case SDL_YVYU_OVERLAY: + width = hwdata->image->pitches[0] / 2; + break; + default: + /* We should never get here (caught above) */ + return(NULL); + } + + XFree(hwdata->image); + hwdata->image = XvShmCreateImage(GFX_Display, xv_port, format, + 0, width, height, yuvshm); + } +#endif + + if ( hwdata->image == NULL ) { + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + yuvshm->shmid = shmget(IPC_PRIVATE, hwdata->image->data_size, + IPC_CREAT | 0777); + if ( yuvshm->shmid < 0 ) { + SDL_SetError("Unable to get %d bytes shared memory", + hwdata->image->data_size); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + yuvshm->shmaddr = (char *) shmat(yuvshm->shmid, 0, 0); + yuvshm->readOnly = False; + hwdata->image->data = yuvshm->shmaddr; + + XShmAttach(GFX_Display, yuvshm); + XSync(GFX_Display, False); + shmctl(yuvshm->shmid, IPC_RMID, 0); + + /* Find the pitch and offset values for the overlay */ + overlay->planes = hwdata->image->num_planes; + overlay->pitches = (Uint16 *)malloc(overlay->planes * sizeof(Uint16)); + overlay->pixels = (Uint8 **)malloc(overlay->planes * sizeof(Uint8 *)); + if ( !overlay->pitches || !overlay->pixels ) { + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + for ( i=0; i<overlay->planes; ++i ) { + overlay->pitches[i] = hwdata->image->pitches[i]; + overlay->pixels[i] = (Uint8 *)hwdata->image->data + + hwdata->image->offsets[i]; + } + +#ifdef XFREE86_REFRESH_HACK + /* Work around an XFree86 X server bug (?) + We can't perform normal updates in windows that have video + being output to them. See SDL_x11image.c for more details. + */ + X11_DisableAutoRefresh(this); +#endif + + /* We're all done.. */ + return(overlay); +} + +int X11_LockYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + return(0); +} + +void X11_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + return; +} + +int X11_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect) +{ + struct private_yuvhwdata *hwdata; + + hwdata = overlay->hwdata; + XvShmPutImage(GFX_Display, hwdata->port, SDL_Window, SDL_GC, + hwdata->image, 0, 0, overlay->w, overlay->h, + dstrect->x, dstrect->y, dstrect->w, dstrect->h, False); + XSync(GFX_Display, False); + return(0); +} + +void X11_FreeYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + struct private_yuvhwdata *hwdata; + + hwdata = overlay->hwdata; + if ( hwdata ) { + XvUngrabPort(GFX_Display, hwdata->port, CurrentTime); + if ( hwdata->yuvshm.shmaddr ) { + XShmDetach(GFX_Display, &hwdata->yuvshm); + shmdt(hwdata->yuvshm.shmaddr); + } + if ( hwdata->image ) { + XFree(hwdata->image); + } + free(hwdata); + } + if ( overlay->pitches ) { + free(overlay->pitches); + overlay->pitches = NULL; + } + if ( overlay->pixels ) { + free(overlay->pixels); + overlay->pixels = NULL; + } +#ifdef XFREE86_REFRESH_HACK + X11_EnableAutoRefresh(this); +#endif +} + +#endif /* XFREE86_XV */