test/testoverlay.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 03 Jun 2011 16:03:10 -0400
changeset 5547 4ccecd0901e2
parent 5535 96594ac5fd1a
permissions -rw-r--r--
Assert code's stdio interface was reading from the wrong variable.

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