1 2 /* Bring up a window and play with it */ 3 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <string.h> 7 8 #define BENCHMARK_SDL 9 10 #define NOTICE(X) printf("%s", X); 11 12 #define WINDOW_WIDTH 640 13 #define WINDOW_HEIGHT 480 14 15 #include "SDL.h" 16 17 SDL_Surface *screen, *pic; 18 SDL_Overlay *overlay; 19 int scale; 20 int monochrome; 21 int luminance; 22 int w, h; 23 24 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 25 static void quit(int rc) 26 { 27 SDL_Quit(); 28 exit(rc); 29 } 30 31 /* NOTE: These RGB conversion functions are not intended for speed, 32 only as examples. 33 */ 34 35 void RGBtoYUV(Uint8 *rgb, int *yuv, int monochrome, int luminance) 36 { 37 if (monochrome) 38 { 39 #if 1 /* these are the two formulas that I found on the FourCC site... */ 40 yuv[0] = 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2]; 41 yuv[1] = 128; 42 yuv[2] = 128; 43 #else 44 yuv[0] = (0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16; 45 yuv[1] = 128; 46 yuv[2] = 128; 47 #endif 48 } 49 else 50 { 51 #if 1 /* these are the two formulas that I found on the FourCC site... */ 52 yuv[0] = 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2]; 53 yuv[1] = (rgb[2]-yuv[0])*0.565 + 128; 54 yuv[2] = (rgb[0]-yuv[0])*0.713 + 128; 55 #else 56 yuv[0] = (0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16; 57 yuv[1] = 128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]); 58 yuv[2] = 128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]); 59 #endif 60 } 61 62 if (luminance!=100) 63 { 64 yuv[0]=yuv[0]*luminance/100; 65 if (yuv[0]>255) 66 yuv[0]=255; 67 } 68 69 /* clamp values...if you need to, we don't seem to have a need */ 70 /* 71 for(i=0;i<3;i++) 72 { 73 if(yuv[i]<0) 74 yuv[i]=0; 75 if(yuv[i]>255) 76 yuv[i]=255; 77 } 78 */ 79 } 80 81 void ConvertRGBtoYV12(SDL_Surface *s, SDL_Overlay *o, int monochrome, int luminance) 82 { 83 int x,y; 84 int yuv[3]; 85 Uint8 *p,*op[3]; 86 87 SDL_LockSurface(s); 88 SDL_LockYUVOverlay(o); 89 90 /* Black initialization */ 91 /* 92 memset(o->pixels[0],0,o->pitches[0]*o->h); 93 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2)); 94 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2)); 95 */ 96 97 /* Convert */ 98 for(y=0; y<s->h && y<o->h; y++) 99 { 100 p=((Uint8 *) s->pixels)+s->pitch*y; 101 op[0]=o->pixels[0]+o->pitches[0]*y; 102 op[1]=o->pixels[1]+o->pitches[1]*(y/2); 103 op[2]=o->pixels[2]+o->pitches[2]*(y/2); 104 for(x=0; x<s->w && x<o->w; x++) 105 { 106 RGBtoYUV(p, yuv, monochrome, luminance); 107 *(op[0]++)=yuv[0]; 108 if(x%2==0 && y%2==0) 109 { 110 *(op[1]++)=yuv[2]; 111 *(op[2]++)=yuv[1]; 112 } 113 p+=s->format->BytesPerPixel; 114 } 115 } 116 117 SDL_UnlockYUVOverlay(o); 118 SDL_UnlockSurface(s); 119 } 120 121 void ConvertRGBtoIYUV(SDL_Surface *s, SDL_Overlay *o, int monochrome, int luminance) 122 { 123 int x,y; 124 int yuv[3]; 125 Uint8 *p,*op[3]; 126 127 SDL_LockSurface(s); 128 SDL_LockYUVOverlay(o); 129 130 /* Black initialization */ 131 /* 132 memset(o->pixels[0],0,o->pitches[0]*o->h); 133 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2)); 134 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2)); 135 */ 136 137 /* Convert */ 138 for(y=0; y<s->h && y<o->h; y++) 139 { 140 p=((Uint8 *) s->pixels)+s->pitch*y; 141 op[0]=o->pixels[0]+o->pitches[0]*y; 142 op[1]=o->pixels[1]+o->pitches[1]*(y/2); 143 op[2]=o->pixels[2]+o->pitches[2]*(y/2); 144 for(x=0; x<s->w && x<o->w; x++) 145 { 146 RGBtoYUV(p,yuv, monochrome, luminance); 147 *(op[0]++)=yuv[0]; 148 if(x%2==0 && y%2==0) 149 { 150 *(op[1]++)=yuv[1]; 151 *(op[2]++)=yuv[2]; 152 } 153 p+=s->format->BytesPerPixel; 154 } 155 } 156 157 SDL_UnlockYUVOverlay(o); 158 SDL_UnlockSurface(s); 159 } 160 161 void ConvertRGBtoUYVY(SDL_Surface *s, SDL_Overlay *o, int monochrome, int luminance) 162 { 163 int x,y; 164 int yuv[3]; 165 Uint8 *p,*op; 166 167 SDL_LockSurface(s); 168 SDL_LockYUVOverlay(o); 169 170 for(y=0; y<s->h && y<o->h; y++) 171 { 172 p=((Uint8 *) s->pixels)+s->pitch*y; 173 op=o->pixels[0]+o->pitches[0]*y; 174 for(x=0; x<s->w && x<o->w; x++) 175 { 176 RGBtoYUV(p, yuv, monochrome, luminance); 177 if(x%2==0) 178 { 179 *(op++)=yuv[1]; 180 *(op++)=yuv[0]; 181 *(op++)=yuv[2]; 182 } 183 else 184 *(op++)=yuv[0]; 185 186 p+=s->format->BytesPerPixel; 187 } 188 } 189 190 SDL_UnlockYUVOverlay(o); 191 SDL_UnlockSurface(s); 192 } 193 194 void ConvertRGBtoYVYU(SDL_Surface *s, SDL_Overlay *o, int monochrome, int luminance) 195 { 196 int x,y; 197 int yuv[3]; 198 Uint8 *p,*op; 199 200 SDL_LockSurface(s); 201 SDL_LockYUVOverlay(o); 202 203 for(y=0; y<s->h && y<o->h; y++) 204 { 205 p=((Uint8 *) s->pixels)+s->pitch*y; 206 op=o->pixels[0]+o->pitches[0]*y; 207 for(x=0; x<s->w && x<o->w; x++) 208 { 209 RGBtoYUV(p,yuv, monochrome, luminance); 210 if(x%2==0) 211 { 212 *(op++)=yuv[0]; 213 *(op++)=yuv[2]; 214 op[1]=yuv[1]; 215 } 216 else 217 { 218 *op=yuv[0]; 219 op+=2; 220 } 221 222 p+=s->format->BytesPerPixel; 223 } 224 } 225 226 SDL_UnlockYUVOverlay(o); 227 SDL_UnlockSurface(s); 228 } 229 230 void ConvertRGBtoYUY2(SDL_Surface *s, SDL_Overlay *o, int monochrome, int luminance) 231 { 232 int x,y; 233 int yuv[3]; 234 Uint8 *p,*op; 235 236 SDL_LockSurface(s); 237 SDL_LockYUVOverlay(o); 238 239 for(y=0; y<s->h && y<o->h; y++) 240 { 241 p=((Uint8 *) s->pixels)+s->pitch*y; 242 op=o->pixels[0]+o->pitches[0]*y; 243 for(x=0; x<s->w && x<o->w; x++) 244 { 245 RGBtoYUV(p,yuv, monochrome, luminance); 246 if(x%2==0) 247 { 248 *(op++)=yuv[0]; 249 *(op++)=yuv[1]; 250 op[1]=yuv[2]; 251 } 252 else 253 { 254 *op=yuv[0]; 255 op+=2; 256 } 257 258 p+=s->format->BytesPerPixel; 259 } 260 } 261 262 SDL_UnlockYUVOverlay(o); 263 SDL_UnlockSurface(s); 264 } 265 266 void Draw() 267 { 268 SDL_Rect rect; 269 int i; 270 int disp; 271 272 if(!scale) 273 { 274 rect.w=overlay->w; 275 rect.h=overlay->h; 276 for(i=0; i<h-rect.h && i<w-rect.w; i++) 277 { 278 rect.x=i; 279 rect.y=i; 280 SDL_DisplayYUVOverlay(overlay,&rect); 281 } 282 } 283 else 284 { 285 rect.w=overlay->w/2; 286 rect.h=overlay->h/2; 287 rect.x=(w-rect.w)/2; 288 rect.y=(h-rect.h)/2; 289 disp=rect.y-1; 290 for(i=0; i<disp; i++) 291 { 292 rect.w+=2; 293 rect.h+=2; 294 rect.x--; 295 rect.y--; 296 SDL_DisplayYUVOverlay(overlay,&rect); 297 } 298 } 299 printf("Displayed %d times.\n",i); 300 } 301 302 static void PrintUsage(char *argv0) 303 { 304 fprintf(stderr, "Usage: %s [arg] [arg] [arg] ...\n", argv0); 305 fprintf(stderr, "Where 'arg' is one of:\n"); 306 fprintf(stderr, " -delay <seconds>\n"); 307 fprintf(stderr, " -width <pixels>\n"); 308 fprintf(stderr, " -height <pixels>\n"); 309 fprintf(stderr, " -bpp <bits>\n"); 310 fprintf(stderr, " -format <fmt> (one of the: YV12, IYUV, YUY2, UYVY, YVYU)\n"); 311 fprintf(stderr, " -hw\n"); 312 fprintf(stderr, " -flip\n"); 313 fprintf(stderr, " -scale (test scaling features, from 50%% upto window size)\n"); 314 fprintf(stderr, " -mono (use monochromatic RGB2YUV conversion)\n"); 315 fprintf(stderr, " -lum <perc> (use luminance correction during RGB2YUV conversion,\n"); 316 fprintf(stderr, " from 0%% to unlimited, normal is 100%%)\n"); 317 fprintf(stderr, " -help (shows this help)\n"); 318 fprintf(stderr, " -fullscreen (test overlay in fullscreen mode)\n"); 319 } 320 321 int main(int argc, char **argv) 322 { 323 char *argv0 = argv[0]; 324 int flip; 325 int delay; 326 int desired_bpp; 327 Uint32 video_flags, overlay_format; 328 char *bmpfile; 329 #ifdef BENCHMARK_SDL 330 Uint32 then, now; 331 #endif 332 int i; 333 334 /* Set default options and check command-line */ 335 flip = 0; 336 scale=0; 337 monochrome=0; 338 luminance=100; 339 delay = 1; 340 w = WINDOW_WIDTH; 341 h = WINDOW_HEIGHT; 342 desired_bpp = 0; 343 video_flags = 0; 344 overlay_format = SDL_YV12_OVERLAY; 345 346 while ( argc > 1 ) { 347 if ( strcmp(argv[1], "-delay") == 0 ) { 348 if ( argv[2] ) { 349 delay = atoi(argv[2]); 350 argv += 2; 351 argc -= 2; 352 } else { 353 fprintf(stderr, 354 "The -delay option requires an argument\n"); 355 return(1); 356 } 357 } else 358 if ( strcmp(argv[1], "-width") == 0 ) { 359 if ( argv[2] && ((w = atoi(argv[2])) > 0) ) { 360 argv += 2; 361 argc -= 2; 362 } else { 363 fprintf(stderr, 364 "The -width option requires an argument\n"); 365 return(1); 366 } 367 } else 368 if ( strcmp(argv[1], "-height") == 0 ) { 369 if ( argv[2] && ((h = atoi(argv[2])) > 0) ) { 370 argv += 2; 371 argc -= 2; 372 } else { 373 fprintf(stderr, 374 "The -height option requires an argument\n"); 375 return(1); 376 } 377 } else 378 if ( strcmp(argv[1], "-bpp") == 0 ) { 379 if ( argv[2] ) { 380 desired_bpp = atoi(argv[2]); 381 argv += 2; 382 argc -= 2; 383 } else { 384 fprintf(stderr, 385 "The -bpp option requires an argument\n"); 386 return(1); 387 } 388 } else 389 if ( strcmp(argv[1], "-lum") == 0 ) { 390 if ( argv[2] ) { 391 luminance = atoi(argv[2]); 392 argv += 2; 393 argc -= 2; 394 } else { 395 fprintf(stderr, 396 "The -lum option requires an argument\n"); 397 return(1); 398 } 399 } else 400 if ( strcmp(argv[1], "-format") == 0 ) { 401 if ( argv[2] ) { 402 if(!strcmp(argv[2],"YV12")) 403 overlay_format = SDL_YV12_OVERLAY; 404 else if(!strcmp(argv[2],"IYUV")) 405 overlay_format = SDL_IYUV_OVERLAY; 406 else if(!strcmp(argv[2],"YUY2")) 407 overlay_format = SDL_YUY2_OVERLAY; 408 else if(!strcmp(argv[2],"UYVY")) 409 overlay_format = SDL_UYVY_OVERLAY; 410 else if(!strcmp(argv[2],"YVYU")) 411 overlay_format = SDL_YVYU_OVERLAY; 412 else 413 { 414 fprintf(stderr, "The -format option %s is not recognized\n",argv[2]); 415 return(1); 416 } 417 argv += 2; 418 argc -= 2; 419 } else { 420 fprintf(stderr, 421 "The -format option requires an argument\n"); 422 return(1); 423 } 424 } else 425 if ( strcmp(argv[1], "-hw") == 0 ) { 426 video_flags |= SDL_HWSURFACE; 427 argv += 1; 428 argc -= 1; 429 } else 430 if ( strcmp(argv[1], "-flip") == 0 ) { 431 video_flags |= SDL_DOUBLEBUF; 432 argv += 1; 433 argc -= 1; 434 } else 435 if ( strcmp(argv[1], "-scale") == 0 ) { 436 scale = 1; 437 argv += 1; 438 argc -= 1; 439 } else 440 if ( strcmp(argv[1], "-mono") == 0 ) { 441 monochrome = 1; 442 argv += 1; 443 argc -= 1; 444 } else 445 if (( strcmp(argv[1], "-help") == 0 ) || (strcmp(argv[1], "-h") == 0)) { 446 PrintUsage(argv0); 447 return(1); 448 } else 449 if ( strcmp(argv[1], "-fullscreen") == 0 ) { 450 video_flags |= SDL_FULLSCREEN; 451 argv += 1; 452 argc -= 1; 453 } else 454 break; 455 } 456 if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { 457 fprintf(stderr, 458 "Couldn't initialize SDL: %s\n", SDL_GetError()); 459 return(1); 460 } 461 462 /* Initialize the display */ 463 screen = SDL_SetVideoMode(w, h, desired_bpp, video_flags); 464 if ( screen == NULL ) { 465 fprintf(stderr, "Couldn't set %dx%dx%d video mode: %s\n", 466 w, h, desired_bpp, SDL_GetError()); 467 quit(1); 468 } 469 printf("Set%s %dx%dx%d mode\n", 470 screen->flags & SDL_FULLSCREEN ? " fullscreen" : "", 471 screen->w, screen->h, screen->format->BitsPerPixel); 472 printf("(video surface located in %s memory)\n", 473 (screen->flags&SDL_HWSURFACE) ? "video" : "system"); 474 if ( screen->flags & SDL_DOUBLEBUF ) { 475 printf("Double-buffering enabled\n"); 476 flip = 1; 477 } 478 479 /* Set the window manager title bar */ 480 SDL_WM_SetCaption("SDL test overlay", "testoverlay"); 481 482 /* Load picture */ 483 bmpfile=(argv[1]?argv[1]:"sample.bmp"); 484 pic = SDL_LoadBMP(bmpfile); 485 if ( pic == NULL ) { 486 fprintf(stderr, "Couldn't load %s: %s\n", bmpfile, 487 SDL_GetError()); 488 quit(1); 489 } 490 491 /* Convert the picture to 32bits, for easy conversion */ 492 { 493 SDL_Surface *newsurf; 494 SDL_PixelFormat format; 495 496 format.palette=NULL; 497 format.BitsPerPixel=32; 498 format.BytesPerPixel=4; 499 #if SDL_BYTEORDER == SDL_LIL_ENDIAN 500 format.Rshift=0; 501 format.Gshift=8; 502 format.Bshift=16; 503 #else 504 format.Rshift=24; 505 format.Gshift=16; 506 format.Bshift=8; 507 #endif 508 format.Ashift=0; 509 format.Rmask=0xff<<format.Rshift; 510 format.Gmask=0xff<<format.Gshift; 511 format.Bmask=0xff<<format.Bshift; 512 format.Amask=0; 513 format.Rloss=0; 514 format.Gloss=0; 515 format.Bloss=0; 516 format.Aloss=8; 517 format.colorkey=0; 518 format.alpha=0; 519 520 newsurf=SDL_ConvertSurface(pic, &format, SDL_SWSURFACE); 521 if(!newsurf) 522 { 523 fprintf(stderr, "Couldn't convert picture to 32bits RGB: %s\n", 524 SDL_GetError()); 525 quit(1); 526 } 527 SDL_FreeSurface(pic); 528 pic=newsurf; 529 } 530 531 /* Create the overlay */ 532 overlay = SDL_CreateYUVOverlay(pic->w, pic->h, overlay_format, screen); 533 if ( overlay == NULL ) { 534 fprintf(stderr, "Couldn't create overlay: %s\n", SDL_GetError()); 535 quit(1); 536 } 537 printf("Created %dx%dx%d %s %s overlay\n",overlay->w,overlay->h,overlay->planes, 538 overlay->hw_overlay?"hardware":"software", 539 overlay->format==SDL_YV12_OVERLAY?"YV12": 540 overlay->format==SDL_IYUV_OVERLAY?"IYUV": 541 overlay->format==SDL_YUY2_OVERLAY?"YUY2": 542 overlay->format==SDL_UYVY_OVERLAY?"UYVY": 543 overlay->format==SDL_YVYU_OVERLAY?"YVYU": 544 "Unknown"); 545 for(i=0; i<overlay->planes; i++) 546 { 547 printf(" plane %d: pitch=%d\n", i, overlay->pitches[i]); 548 } 549 550 /* Convert to YUV, and draw to the overlay */ 551 #ifdef BENCHMARK_SDL 552 then = SDL_GetTicks(); 553 #endif 554 switch(overlay->format) 555 { 556 case SDL_YV12_OVERLAY: 557 ConvertRGBtoYV12(pic,overlay,monochrome,luminance); 558 break; 559 case SDL_UYVY_OVERLAY: 560 ConvertRGBtoUYVY(pic,overlay,monochrome,luminance); 561 break; 562 case SDL_YVYU_OVERLAY: 563 ConvertRGBtoYVYU(pic,overlay,monochrome,luminance); 564 break; 565 case SDL_YUY2_OVERLAY: 566 ConvertRGBtoYUY2(pic,overlay,monochrome,luminance); 567 break; 568 case SDL_IYUV_OVERLAY: 569 ConvertRGBtoIYUV(pic,overlay,monochrome,luminance); 570 break; 571 default: 572 printf("cannot convert RGB picture to obtained YUV format!\n"); 573 quit(1); 574 break; 575 } 576 #ifdef BENCHMARK_SDL 577 now = SDL_GetTicks(); 578 printf("Conversion Time: %d milliseconds\n", now-then); 579 #endif 580 581 /* Do all the drawing work */ 582 #ifdef BENCHMARK_SDL 583 then = SDL_GetTicks(); 584 #endif 585 Draw(); 586 #ifdef BENCHMARK_SDL 587 now = SDL_GetTicks(); 588 printf("Time: %d milliseconds\n", now-then); 589 #endif 590 SDL_Delay(delay*1000); 591 SDL_Quit(); 592 return(0); 593 } 594 595