test/testoverlay.c
author Patrice Mandin <patmandin@gmail.com>
Thu, 19 Jan 2006 21:28:52 +0000
changeset 1257 448a9a64537b
parent 1151 be9c9c8f6d53
child 1439 4d3bb026cd16
permissions -rw-r--r--
[PATCH] SDL_GetVideoMode() does not find best mode, part 2

Following commit 1.51, I come accross a problem when SDL must choose between
several video modes that could suit the one asked.

If I ask 320x240 with this list:
768x480 768x240 640x400 640x200 384x480 384x240 320x400 320x200

The smallest selectables modes are 384x240 and 320x400. And SDL choose the later
in this list, but 384x240 is more suitable. So I added a check to compare
the pixel count (surface) of modes, and select the one which has the smallest
pixel count.

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