Mercurial > sdl-ios-xcode
diff src/video/SDL_yuv_sw.c @ 1684:c4aa1a2f48f1 SDL-1.3
Software YUV texture support in progress...
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sun, 18 Jun 2006 06:35:41 +0000 |
parents | 9488fca10677 |
children |
line wrap: on
line diff
--- a/src/video/SDL_yuv_sw.c Sat Jun 17 06:45:14 2006 +0000 +++ b/src/video/SDL_yuv_sw.c Sun Jun 18 06:35:41 2006 +0000 @@ -21,8 +21,7 @@ */ #include "SDL_config.h" -#if 0 /* TODO */ -/* This is the software implementation of the YUV video overlay support */ +/* This is the software implementation of the YUV texture support */ /* This code was derived from code carrying the following copyright notices: @@ -87,22 +86,14 @@ #include "SDL_video.h" #include "SDL_cpuinfo.h" #include "SDL_stretch_c.h" -#include "SDL_yuvfuncs.h" #include "SDL_yuv_sw_c.h" -/* The functions used to manipulate software video overlays */ -static struct private_yuvhwfuncs sw_yuvfuncs = { - SDL_LockYUV_SW, - SDL_UnlockYUV_SW, - SDL_DisplayYUV_SW, - SDL_FreeYUV_SW -}; -/* RGB conversion lookup tables */ -struct private_yuvhwdata +struct SDL_SW_YUVTexture { - SDL_Surface *stretch; - SDL_Surface *display; + SDL_Texture *texture; + + Uint32 target_format; Uint8 *pixels; int *colortab; Uint32 *rgb_2_pix; @@ -118,9 +109,12 @@ /* These are just so we don't have to allocate them separately */ Uint16 pitches[3]; Uint8 *planes[3]; + + /* This is a temporary surface in case we have to stretch copy */ + SDL_Surface *stretch; + SDL_Surface *display; }; - /* The colorspace conversion functions */ #if 0 /*defined(__GNUC__) && defined(__i386__) && SDL_ASSEMBLY_ROUTINES */ @@ -918,105 +912,30 @@ return 1 + free_bits_at_bottom(a >> 1); } - -SDL_Overlay * -SDL_CreateYUV_SW(_THIS, int width, int height, Uint32 format, - SDL_Surface * display) +static int +SDL_SW_SetupYUVDisplay(SDL_SW_YUVTexture * swdata, Uint32 target_format) { - SDL_Overlay *overlay; - struct private_yuvhwdata *swdata; - int *Cr_r_tab; - int *Cr_g_tab; - int *Cb_g_tab; - int *Cb_b_tab; Uint32 *r_2_pix_alloc; Uint32 *g_2_pix_alloc; Uint32 *b_2_pix_alloc; int i; - int CR, CB; - Uint32 Rmask, Gmask, Bmask; - - /* Only RGB packed pixel conversion supported */ - if ((display->format->BytesPerPixel != 2) && - (display->format->BytesPerPixel != 3) && - (display->format->BytesPerPixel != 4)) { - SDL_SetError("Can't use YUV data on non 16/24/32 bit surfaces"); - return (NULL); - } + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; - /* Verify that we support the format */ - switch (format) { - case SDL_YV12_OVERLAY: - case SDL_IYUV_OVERLAY: - case SDL_YUY2_OVERLAY: - case SDL_UYVY_OVERLAY: - case SDL_YVYU_OVERLAY: - break; - default: - SDL_SetError("Unsupported YUV format"); - return (NULL); + if (!SDL_PixelFormatEnumToMasks + (target_format, &bpp, &Rmask, &Gmask, &Bmask, &Amask) || bpp < 15) { + SDL_SetError("Unsupported YUV destination format"); + return -1; } - /* Create the overlay structure */ - overlay = (SDL_Overlay *) SDL_malloc(sizeof *overlay); - if (overlay == NULL) { - SDL_OutOfMemory(); - return (NULL); - } - SDL_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 = &sw_yuvfuncs; - - /* Create the pixel data and lookup tables */ - swdata = (struct private_yuvhwdata *) SDL_malloc(sizeof *swdata); - overlay->hwdata = swdata; - if (swdata == NULL) { - SDL_OutOfMemory(); - SDL_FreeYUVOverlay(overlay); - return (NULL); - } - swdata->stretch = NULL; - swdata->display = display; - swdata->pixels = (Uint8 *) SDL_malloc(width * height * 2); - swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int)); - Cr_r_tab = &swdata->colortab[0 * 256]; - Cr_g_tab = &swdata->colortab[1 * 256]; - Cb_g_tab = &swdata->colortab[2 * 256]; - Cb_b_tab = &swdata->colortab[3 * 256]; - swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32)); + swdata->target_format = target_format; r_2_pix_alloc = &swdata->rgb_2_pix[0 * 768]; g_2_pix_alloc = &swdata->rgb_2_pix[1 * 768]; b_2_pix_alloc = &swdata->rgb_2_pix[2 * 768]; - if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) { - SDL_OutOfMemory(); - SDL_FreeYUVOverlay(overlay); - return (NULL); - } - - /* Generate the tables for the display surface */ - for (i = 0; i < 256; i++) { - /* Gamma correction (luminescence table) and chroma correction - would be done here. See the Berkeley mpeg_play sources. - */ - CB = CR = (i - 128); - Cr_r_tab[i] = (int) ((0.419 / 0.299) * CR); - Cr_g_tab[i] = (int) (-(0.299 / 0.419) * CR); - Cb_g_tab[i] = (int) (-(0.114 / 0.331) * CB); - Cb_b_tab[i] = (int) ((0.587 / 0.331) * CB); - } /* * Set up entries 0-255 in rgb-to-pixel value tables. */ - Rmask = display->format->Rmask; - Gmask = display->format->Gmask; - Bmask = display->format->Bmask; for (i = 0; i < 256; ++i) { r_2_pix_alloc[i + 256] = i >> (8 - number_of_bits_set(Rmask)); r_2_pix_alloc[i + 256] <<= free_bits_at_bottom(Rmask); @@ -1033,7 +952,7 @@ * harmless in the normal case as storing a 32-bit value * through a short pointer will lose the top bits anyway. */ - if (display->format->BytesPerPixel == 2) { + if (SDL_BYTESPERPIXEL(target_format) == 2) { for (i = 0; i < 256; ++i) { r_2_pix_alloc[i + 256] |= (r_2_pix_alloc[i + 256]) << 16; g_2_pix_alloc[i + 256] |= (g_2_pix_alloc[i + 256]) << 16; @@ -1055,10 +974,10 @@ } /* You have chosen wisely... */ - switch (format) { - case SDL_YV12_OVERLAY: - case SDL_IYUV_OVERLAY: - if (display->format->BytesPerPixel == 2) { + switch (swdata->texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + if (SDL_BYTESPERPIXEL(target_format) == 2) { #if 0 /*defined(__GNUC__) && defined(__i386__) && SDL_ASSEMBLY_ROUTINES */ /* inline assembly functions */ if (SDL_HasMMX() && (Rmask == 0xF800) && @@ -1074,11 +993,11 @@ #endif swdata->Display2X = Color16DitherYV12Mod2X; } - if (display->format->BytesPerPixel == 3) { + if (SDL_BYTESPERPIXEL(target_format) == 3) { swdata->Display1X = Color24DitherYV12Mod1X; swdata->Display2X = Color24DitherYV12Mod2X; } - if (display->format->BytesPerPixel == 4) { + if (SDL_BYTESPERPIXEL(target_format) == 4) { #if 0 /*defined(__GNUC__) && defined(__i386__) && SDL_ASSEMBLY_ROUTINES */ /* inline assembly functions */ if (SDL_HasMMX() && (Rmask == 0x00FF0000) && @@ -1096,18 +1015,18 @@ swdata->Display2X = Color32DitherYV12Mod2X; } break; - case SDL_YUY2_OVERLAY: - case SDL_UYVY_OVERLAY: - case SDL_YVYU_OVERLAY: - if (display->format->BytesPerPixel == 2) { + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + if (SDL_BYTESPERPIXEL(target_format) == 2) { swdata->Display1X = Color16DitherYUY2Mod1X; swdata->Display2X = Color16DitherYUY2Mod2X; } - if (display->format->BytesPerPixel == 3) { + if (SDL_BYTESPERPIXEL(target_format) == 3) { swdata->Display1X = Color24DitherYUY2Mod1X; swdata->Display2X = Color24DitherYUY2Mod2X; } - if (display->format->BytesPerPixel == 4) { + if (SDL_BYTESPERPIXEL(target_format) == 4) { swdata->Display1X = Color32DitherYUY2Mod1X; swdata->Display2X = Color32DitherYUY2Mod2X; } @@ -1117,28 +1036,88 @@ break; } + if (swdata->display) { + SDL_FreeSurface(swdata->display); + swdata->display = NULL; + } + return 0; +} + +SDL_SW_YUVTexture * +SDL_SW_CreateYUVTexture(SDL_Texture * texture) +{ + SDL_SW_YUVTexture *swdata; + int *Cr_r_tab; + int *Cr_g_tab; + int *Cb_g_tab; + int *Cb_b_tab; + int i; + int CR, CB; + + swdata = (SDL_SW_YUVTexture *) SDL_malloc(sizeof(*swdata)); + if (!swdata) { + SDL_OutOfMemory(); + return NULL; + } + SDL_zerop(swdata); + + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + break; + default: + SDL_SetError("Unsupported YUV format"); + return NULL; + } + + swdata->texture = texture; + swdata->target_format = SDL_PixelFormat_Unknown; + swdata->pixels = (Uint8 *) SDL_malloc(texture->w * texture->h * 2); + swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int)); + swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32)); + if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) { + SDL_OutOfMemory(); + SDL_SW_DestroyYUVTexture(swdata); + return NULL; + } + + /* Generate the tables for the display surface */ + Cr_r_tab = &swdata->colortab[0 * 256]; + Cr_g_tab = &swdata->colortab[1 * 256]; + Cb_g_tab = &swdata->colortab[2 * 256]; + Cb_b_tab = &swdata->colortab[3 * 256]; + for (i = 0; i < 256; i++) { + /* Gamma correction (luminescence table) and chroma correction + would be done here. See the Berkeley mpeg_play sources. + */ + CB = CR = (i - 128); + Cr_r_tab[i] = (int) ((0.419 / 0.299) * CR); + Cr_g_tab[i] = (int) (-(0.299 / 0.419) * CR); + Cb_g_tab[i] = (int) (-(0.114 / 0.331) * CB); + Cb_b_tab[i] = (int) ((0.587 / 0.331) * CB); + } + /* Find the pitch and offset values for the overlay */ - overlay->pitches = swdata->pitches; - overlay->pixels = swdata->planes; - switch (format) { - case SDL_YV12_OVERLAY: - case SDL_IYUV_OVERLAY: - overlay->pitches[0] = overlay->w; - overlay->pitches[1] = overlay->pitches[0] / 2; - overlay->pitches[2] = overlay->pitches[0] / 2; - overlay->pixels[0] = swdata->pixels; - overlay->pixels[1] = overlay->pixels[0] + - overlay->pitches[0] * overlay->h; - overlay->pixels[2] = overlay->pixels[1] + - overlay->pitches[1] * overlay->h / 2; - overlay->planes = 3; + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + swdata->pitches[0] = texture->w; + swdata->pitches[1] = swdata->pitches[0] / 2; + swdata->pitches[2] = swdata->pitches[0] / 2; + swdata->planes[0] = swdata->pixels; + swdata->planes[1] = + swdata->planes[0] + swdata->pitches[0] * texture->h; + swdata->planes[2] = + swdata->planes[1] + swdata->pitches[1] * texture->h / 2; break; - case SDL_YUY2_OVERLAY: - case SDL_UYVY_OVERLAY: - case SDL_YVYU_OVERLAY: - overlay->pitches[0] = overlay->w * 2; - overlay->pixels[0] = swdata->pixels; - overlay->planes = 1; + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + swdata->pitches[0] = texture->w * 2; + swdata->planes[0] = swdata->pixels; break; default: /* We should never get here (caught above) */ @@ -1146,146 +1125,210 @@ } /* We're all done.. */ - return (overlay); + return (swdata); } int -SDL_LockYUV_SW(_THIS, SDL_Overlay * overlay) +SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture * swdata, void **pixels, + int *pitch) { - return (0); -} - -void -SDL_UnlockYUV_SW(_THIS, SDL_Overlay * overlay) -{ - return; + *pixels = swdata->planes[0]; + *pitch = swdata->pitches[0]; + return 0; } int -SDL_DisplayYUV_SW(_THIS, SDL_Overlay * overlay, SDL_Rect * src, - SDL_Rect * dst) +SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, + const void *pixels, int pitch) { - struct private_yuvhwdata *swdata; + SDL_Texture *texture = swdata->texture; + + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + if (rect + && (rect->x != 0 || rect->y != 0 || rect->w != texture->w + || rect->h != texture->h)) { + SDL_SetError + ("YV12 and IYUV textures only support full surface updates"); + return -1; + } + SDL_memcpy(swdata->pixels, pixels, texture->h * texture->w * 2); + break; + case SDL_PixelFormat_YUY2: + case SDL_PixelFormat_UYVY: + case SDL_PixelFormat_YVYU: + { + Uint8 *src, *dst; + int row; + size_t length; + + src = (Uint8 *) pixels; + dst = + swdata->planes[0] + rect->y * swdata->pitches[0] + + rect->x * 2; + length = rect->w * 2; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += swdata->pitches[0]; + } + } + break; + } + return 0; +} + +int +SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, + int markDirty, void **pixels, int *pitch) +{ + SDL_Texture *texture = swdata->texture; + + switch (texture->format) { + case SDL_PixelFormat_YV12: + case SDL_PixelFormat_IYUV: + if (rect + && (rect->x != 0 || rect->y != 0 || rect->w != texture->w + || rect->h != texture->h)) { + SDL_SetError + ("YV12 and IYUV textures only support full surface locks"); + return -1; + } + break; + } + + *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2; + *pitch = swdata->pitches[0]; + return 0; +} + +void +SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture * swdata) +{ +} + +int +SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect, + Uint32 target_format, int w, int h, void *pixels, + int pitch) +{ + SDL_Texture *texture = swdata->texture; int stretch; int scale_2x; - SDL_Surface *display; Uint8 *lum, *Cr, *Cb; - Uint8 *dstp; int mod; - swdata = overlay->hwdata; + /* Make sure we're set up to display in the desired format */ + if (target_format != swdata->target_format) { + if (SDL_SW_SetupYUVDisplay(swdata, target_format) < 0) { + return -1; + } + } + stretch = 0; scale_2x = 0; - if (src->x || src->y || src->w < overlay->w || src->h < overlay->h) { + if (srcrect->x || srcrect->y || srcrect->w < texture->w + || srcrect->h < texture->h) { /* The source rectangle has been clipped. Using a scratch surface is easier than adding clipped source support to all the blitters, plus that would slow them down in the general unclipped case. */ stretch = 1; - } else if ((src->w != dst->w) || (src->h != dst->h)) { - if ((dst->w == 2 * src->w) && (dst->h == 2 * src->h)) { + } else if ((srcrect->w != w) || (srcrect->h != h)) { + if ((w == 2 * srcrect->w) && (h == 2 * srcrect->h)) { scale_2x = 1; } else { stretch = 1; } } if (stretch) { + int bpp; + Uint32 Rmask, Gmask, Bmask, Amask; + + if (swdata->display) { + swdata->display->w = w; + swdata->display->h = h; + swdata->display->pixels = pixels; + swdata->display->pitch = pitch; + } else { + /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */ + SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask, + &Bmask, &Amask); + swdata->display = + SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask, + Gmask, Bmask, Amask); + if (!swdata->display) { + return (-1); + } + } if (!swdata->stretch) { - display = swdata->display; - swdata->stretch = SDL_CreateRGBSurface(0, - overlay->w, - overlay->h, - display->format-> - BitsPerPixel, - display->format-> - Rmask, - display->format-> - Gmask, - display->format->Bmask, 0); + /* This must have succeeded in SDL_SW_SetupYUVDisplay() earlier */ + SDL_PixelFormatEnumToMasks(target_format, &bpp, &Rmask, &Gmask, + &Bmask, &Amask); + swdata->stretch = + SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, + Gmask, Bmask, Amask); if (!swdata->stretch) { return (-1); } } - display = swdata->stretch; - } else { - display = swdata->display; + pixels = swdata->stretch->pixels; + pitch = swdata->stretch->pitch; } - switch (overlay->format) { - case SDL_YV12_OVERLAY: - lum = overlay->pixels[0]; - Cr = overlay->pixels[1]; - Cb = overlay->pixels[2]; + switch (texture->format) { + case SDL_PixelFormat_YV12: + lum = swdata->planes[0]; + Cr = swdata->planes[1]; + Cb = swdata->planes[2]; break; - case SDL_IYUV_OVERLAY: - lum = overlay->pixels[0]; - Cr = overlay->pixels[2]; - Cb = overlay->pixels[1]; + case SDL_PixelFormat_IYUV: + lum = swdata->planes[0]; + Cr = swdata->planes[2]; + Cb = swdata->planes[1]; break; - case SDL_YUY2_OVERLAY: - lum = overlay->pixels[0]; + case SDL_PixelFormat_YUY2: + lum = swdata->planes[0]; Cr = lum + 3; Cb = lum + 1; break; - case SDL_UYVY_OVERLAY: - lum = overlay->pixels[0] + 1; + case SDL_PixelFormat_UYVY: + lum = swdata->planes[0] + 1; Cr = lum + 1; Cb = lum - 1; break; - case SDL_YVYU_OVERLAY: - lum = overlay->pixels[0]; + case SDL_PixelFormat_YVYU: + lum = swdata->planes[0]; Cr = lum + 1; Cb = lum + 3; break; default: - SDL_SetError("Unsupported YUV format in blit"); + SDL_SetError("Unsupported YUV format in copy"); return (-1); } - if (SDL_MUSTLOCK(display)) { - if (SDL_LockSurface(display) < 0) { - return (-1); - } - } - if (stretch) { - dstp = (Uint8 *) swdata->stretch->pixels; - } else { - dstp = (Uint8 *) display->pixels - + dst->x * display->format->BytesPerPixel - + dst->y * display->pitch; - } - mod = (display->pitch / display->format->BytesPerPixel); + mod = (pitch / SDL_BYTESPERPIXEL(target_format)); if (scale_2x) { - mod -= (overlay->w * 2); + mod -= (texture->w * 2); swdata->Display2X(swdata->colortab, swdata->rgb_2_pix, - lum, Cr, Cb, dstp, overlay->h, overlay->w, mod); + lum, Cr, Cb, pixels, texture->h, texture->w, mod); } else { - mod -= overlay->w; + mod -= texture->w; swdata->Display1X(swdata->colortab, swdata->rgb_2_pix, - lum, Cr, Cb, dstp, overlay->h, overlay->w, mod); - } - if (SDL_MUSTLOCK(display)) { - SDL_UnlockSurface(display); + lum, Cr, Cb, pixels, texture->h, texture->w, mod); } if (stretch) { - display = swdata->display; - SDL_SoftStretch(swdata->stretch, src, display, dst); + SDL_Rect rect = *srcrect; + SDL_SoftStretch(swdata->stretch, &rect, swdata->display, NULL); } - SDL_UpdateRects(display, 1, dst); - - return (0); + return 0; } void -SDL_FreeYUV_SW(_THIS, SDL_Overlay * overlay) +SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture * swdata) { - struct private_yuvhwdata *swdata; - - swdata = overlay->hwdata; if (swdata) { - if (swdata->stretch) { - SDL_FreeSurface(swdata->stretch); - } if (swdata->pixels) { SDL_free(swdata->pixels); } @@ -1295,9 +1338,14 @@ if (swdata->rgb_2_pix) { SDL_free(swdata->rgb_2_pix); } + if (swdata->stretch) { + SDL_FreeSurface(swdata->stretch); + } + if (swdata->display) { + SDL_FreeSurface(swdata->display); + } SDL_free(swdata); } } -#endif /* TODO */ /* vi: set ts=4 sw=4 expandtab: */