e14743d1 |
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 | |