📄 sdl_yuv_sw.c
字号:
unsigned char *cb, unsigned char *out,
int rows, int cols, int mod )
{
unsigned int* row = (unsigned int*) out;
const int next_row = cols*2+mod;
int x, y;
int cr_r;
int crb_g;
int cb_b;
int cols_2 = cols / 2;
mod+=mod;
y = rows;
while( y-- )
{
x = cols_2;
while( x-- )
{
register int L;
cr_r = 0*768+256 + colortab[ *cr + 0*256 ];
crb_g = 1*768+256 + colortab[ *cr + 1*256 ]
+ colortab[ *cb + 2*256 ];
cb_b = 2*768+256 + colortab[ *cb + 3*256 ];
cr += 4; cb += 4;
L = *lum; lum += 2;
row[0] = row[1] = row[next_row] = row[next_row+1] =
(rgb_2_pix[ L + cr_r ] |
rgb_2_pix[ L + crb_g ] |
rgb_2_pix[ L + cb_b ]);
row += 2;
L = *lum; lum += 2;
row[0] = row[1] = row[next_row] = row[next_row+1] =
(rgb_2_pix[ L + cr_r ] |
rgb_2_pix[ L + crb_g ] |
rgb_2_pix[ L + cb_b ]);
row += 2;
}
row += next_row;
}
}
/*
* How many 1 bits are there in the Uint32.
* Low performance, do not call often.
*/
static int number_of_bits_set( Uint32 a )
{
if(!a) return 0;
if(a & 1) return 1 + number_of_bits_set(a >> 1);
return(number_of_bits_set(a >> 1));
}
/*
* How many 0 bits are there at least significant end of Uint32.
* Low performance, do not call often.
*/
static int free_bits_at_bottom( Uint32 a )
{
/* assume char is 8 bits */
if(!a) return sizeof(Uint32) * 8;
if(((Sint32)a) & 1l) return 0;
return 1 + free_bits_at_bottom ( a >> 1);
}
SDL_Overlay *SDL_CreateYUV_SW(_THIS, int width, int height, Uint32 format, SDL_Surface *display)
{
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, cpu_mmx;
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);
}
/* 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);
}
/* Create the overlay structure */
overlay = (SDL_Overlay *)malloc(sizeof *overlay);
if ( overlay == NULL ) {
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 = &sw_yuvfuncs;
/* Create the pixel data and lookup tables */
swdata = (struct private_yuvhwdata *)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 *) malloc(width*height*2);
swdata->colortab = (int *)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 *)malloc(3*768*sizeof(Uint32));
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);
g_2_pix_alloc[i+256] = i >> (8 - number_of_bits_set(Gmask));
g_2_pix_alloc[i+256] <<= free_bits_at_bottom(Gmask);
b_2_pix_alloc[i+256] = i >> (8 - number_of_bits_set(Bmask));
b_2_pix_alloc[i+256] <<= free_bits_at_bottom(Bmask);
}
/*
* If we have 16-bit output depth, then we double the value
* in the top word. This means that we can write out both
* pixels in the pixel doubling mode with one op. It is
* 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 ) {
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;
b_2_pix_alloc[i+256] |= (b_2_pix_alloc[i+256]) << 16;
}
}
/*
* Spread out the values we have to the rest of the array so that
* we do not need to check for overflow.
*/
for ( i=0; i<256; ++i ) {
r_2_pix_alloc[i] = r_2_pix_alloc[256];
r_2_pix_alloc[i+512] = r_2_pix_alloc[511];
g_2_pix_alloc[i] = g_2_pix_alloc[256];
g_2_pix_alloc[i+512] = g_2_pix_alloc[511];
b_2_pix_alloc[i] = b_2_pix_alloc[256];
b_2_pix_alloc[i+512] = b_2_pix_alloc[511];
}
/* You have chosen wisely... */
switch (format) {
case SDL_YV12_OVERLAY:
case SDL_IYUV_OVERLAY:
cpu_mmx = CPU_Flags() & MMX_CPU;
if ( display->format->BytesPerPixel == 2 ) {
#if defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
/* inline assembly functions */
if ( cpu_mmx && (Rmask == 0xF800) &&
(Gmask == 0x07E0) &&
(Bmask == 0x001F) &&
(width & 15) == 0) {
/*printf("Using MMX 16-bit 565 dither\n");*/
swdata->Display1X = Color565DitherYV12MMX1X;
} else {
/*printf("Using C 16-bit dither\n");*/
swdata->Display1X = Color16DitherYV12Mod1X;
}
#else
swdata->Display1X = Color16DitherYV12Mod1X;
#endif
swdata->Display2X = Color16DitherYV12Mod2X;
}
if ( display->format->BytesPerPixel == 3 ) {
swdata->Display1X = Color24DitherYV12Mod1X;
swdata->Display2X = Color24DitherYV12Mod2X;
}
if ( display->format->BytesPerPixel == 4 ) {
#if defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
/* inline assembly functions */
if ( cpu_mmx && (Rmask == 0x00FF0000) &&
(Gmask == 0x0000FF00) &&
(Bmask == 0x000000FF) &&
(width & 15) == 0) {
/*printf("Using MMX 32-bit dither\n");*/
swdata->Display1X = ColorRGBDitherYV12MMX1X;
} else {
/*printf("Using C 32-bit dither\n");*/
swdata->Display1X = Color32DitherYV12Mod1X;
}
#else
swdata->Display1X = Color32DitherYV12Mod1X;
#endif
swdata->Display2X = Color32DitherYV12Mod2X;
}
break;
case SDL_YUY2_OVERLAY:
case SDL_UYVY_OVERLAY:
case SDL_YVYU_OVERLAY:
if ( display->format->BytesPerPixel == 2 ) {
swdata->Display1X = Color16DitherYUY2Mod1X;
swdata->Display2X = Color16DitherYUY2Mod2X;
}
if ( display->format->BytesPerPixel == 3 ) {
swdata->Display1X = Color24DitherYUY2Mod1X;
swdata->Display2X = Color24DitherYUY2Mod2X;
}
if ( display->format->BytesPerPixel == 4 ) {
swdata->Display1X = Color32DitherYUY2Mod1X;
swdata->Display2X = Color32DitherYUY2Mod2X;
}
break;
default:
/* We should never get here (caught above) */
break;
}
/* 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;
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;
break;
default:
/* We should never get here (caught above) */
break;
}
/* We're all done.. */
return(overlay);
}
int SDL_LockYUV_SW(_THIS, SDL_Overlay *overlay)
{
return(0);
}
void SDL_UnlockYUV_SW(_THIS, SDL_Overlay *overlay)
{
return;
}
int SDL_DisplayYUV_SW(_THIS, SDL_Overlay *overlay, SDL_Rect *dstrect)
{
struct private_yuvhwdata *swdata;
SDL_Surface *stretch;
SDL_Surface *display;
int scale_2x;
Uint8 *lum, *Cr, *Cb;
Uint8 *dst;
int mod;
swdata = overlay->hwdata;
scale_2x = 0;
stretch = 0;
if ( (overlay->w != dstrect->w) || (overlay->h != dstrect->h) ) {
if ( (dstrect->w == 2*overlay->w) &&
(dstrect->h == 2*overlay->h) ) {
scale_2x = 1;
} else {
if ( ! swdata->stretch ) {
display = swdata->display;
swdata->stretch = SDL_CreateRGBSurface(
SDL_SWSURFACE,
overlay->w, overlay->h,
display->format->BitsPerPixel,
display->format->Rmask,
display->format->Gmask,
display->format->Bmask, 0);
if ( ! swdata->stretch ) {
return(-1);
}
}
stretch = swdata->stretch;
}
}
if ( stretch ) {
display = stretch;
} else {
display = swdata->display;
}
switch (overlay->format) {
case SDL_YV12_OVERLAY:
lum = overlay->pixels[0];
Cr = overlay->pixels[1];
Cb = overlay->pixels[2];
break;
case SDL_IYUV_OVERLAY:
lum = overlay->pixels[0];
Cr = overlay->pixels[2];
Cb = overlay->pixels[1];
break;
case SDL_YUY2_OVERLAY:
lum = overlay->pixels[0];
Cr = lum + 3;
Cb = lum + 1;
break;
case SDL_UYVY_OVERLAY:
lum = overlay->pixels[0]+1;
Cr = lum + 1;
Cb = lum - 1;
break;
case SDL_YVYU_OVERLAY:
lum = overlay->pixels[0];
Cr = lum + 1;
Cb = lum + 3;
break;
default:
SDL_SetError("Unsupported YUV format in blit");
return(-1);
}
if ( SDL_MUSTLOCK(display) ) {
if ( SDL_LockSurface(display) < 0 ) {
return(-1);
}
}
if ( stretch ) {
dst = (Uint8 *)stretch->pixels;
} else {
dst = (Uint8 *)display->pixels
+ dstrect->x * display->format->BytesPerPixel
+ dstrect->y * display->pitch;
}
mod = (display->pitch / display->format->BytesPerPixel);
if ( scale_2x ) {
mod -= (overlay->w * 2);
swdata->Display2X(swdata->colortab, swdata->rgb_2_pix,
lum, Cr, Cb, dst, overlay->h, overlay->w,mod);
} else {
mod -= overlay->w;
swdata->Display1X(swdata->colortab, swdata->rgb_2_pix,
lum, Cr, Cb, dst, overlay->h, overlay->w,mod);
}
if ( SDL_MUSTLOCK(display) ) {
SDL_UnlockSurface(display);
}
if ( stretch ) {
display = swdata->display;
SDL_SoftStretch(stretch, NULL, display, dstrect);
}
SDL_UpdateRects(display, 1, dstrect);
return(0);
}
void SDL_FreeYUV_SW(_THIS, SDL_Overlay *overlay)
{
struct private_yuvhwdata *swdata;
swdata = overlay->hwdata;
if ( swdata ) {
if ( swdata->stretch ) {
SDL_FreeSurface(swdata->stretch);
}
if ( swdata->pixels ) {
free(swdata->pixels);
}
if ( swdata->colortab ) {
free(swdata->colortab);
}
if ( swdata->rgb_2_pix ) {
free(swdata->rgb_2_pix);
}
free(swdata);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -