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