]> icculus.org git repositories - taylor/freespace2.git/blob - src/movie/mveplayer.cpp
Fix problem uno... now escape will skip movies
[taylor/freespace2.git] / src / movie / mveplayer.cpp
1 #include <string.h>
2 #include <errno.h>
3 #include <time.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6
7 #include "mvelib.h"
8 #include "bmpman.h"
9 #include "2d.h"
10 #include "mve_audio.h"
11 #include "key.h"
12 #include "osapi.h"
13
14 #ifndef MIN
15 #define MIN(a,b) ((a)<(b)?(a):(b))
16 #endif
17
18
19 static int g_spdFactorNum=0;
20 static int g_spdFactorDenom=10;
21 static int playing = 1;
22
23 void initializeMovie(MVESTREAM *mve);
24 void playMovie(MVESTREAM *mve);
25 void shutdownMovie(MVESTREAM *mve);
26
27 #if 0
28 static int doPlay(const char *filename)
29 {
30     MVESTREAM *mve = mve_open(filename);
31     if (mve == NULL)
32     {
33         fprintf(stderr, "can't open MVE file '%s'\n", filename);
34         return 1;
35     }
36
37     initializeMovie(mve);
38     playMovie(mve);
39     shutdownMovie(mve);
40
41     mve_close(mve);
42
43     return 0;
44 }
45 #endif
46
47 static short get_short(unsigned char *data)
48 {
49     short value;
50     value = data[0] | (data[1] << 8);
51     return value;
52 }
53
54 static unsigned short get_ushort(unsigned char *data)
55 {
56     unsigned short value;
57     value = data[0] | (data[1] << 8);
58     return value;
59 }
60
61 static int get_int(unsigned char *data)
62 {
63     int value;
64     value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
65     return value;
66 }
67
68 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
69 {
70 /*    fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor); */
71     return 1;
72 }
73
74 /*************************
75  * general handlers
76  *************************/
77 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
78 {
79     return 0;
80 }
81
82 /*************************
83  * timer handlers
84  *************************/
85
86 /*
87  * timer variables
88  */
89 static int micro_frame_delay=0;
90 static int timer_started=0;
91 static struct timeval timer_expire = {0, 0};
92
93 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
94 {
95     __extension__ long long temp;
96     micro_frame_delay = get_int(data) * (int)get_short(data+4);
97     if (g_spdFactorNum != 0)
98     {
99         temp = micro_frame_delay;
100         temp *= g_spdFactorNum;
101         temp /= g_spdFactorDenom;
102         micro_frame_delay = (int)temp;
103     }
104
105     return 1;
106 }
107
108 static void timer_start(void)
109 {
110     int nsec=0;
111     gettimeofday(&timer_expire, NULL);
112     timer_expire.tv_usec += micro_frame_delay;
113     if (timer_expire.tv_usec > 1000000)
114     {
115         nsec = timer_expire.tv_usec / 1000000;
116         timer_expire.tv_sec += nsec;
117         timer_expire.tv_usec -= nsec*1000000;
118     }
119     timer_started=1;
120 }
121
122 static void do_timer_wait(void)
123 {
124     int nsec=0;
125     struct timespec ts, tsRem;
126     struct timeval tv;
127     if (! timer_started)
128         return;
129
130     gettimeofday(&tv, NULL);
131     if (tv.tv_sec > timer_expire.tv_sec)
132         goto end;
133     else if (tv.tv_sec == timer_expire.tv_sec  &&  tv.tv_usec >= timer_expire.tv_usec)
134         goto end;
135
136     ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
137     ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
138     if (ts.tv_nsec < 0)
139     {
140         ts.tv_nsec += 1000000000UL;
141         --ts.tv_sec;
142     }
143     if (nanosleep(&ts, &tsRem) == -1  &&  errno == EINTR)
144        exit(1);
145
146 end:
147     timer_expire.tv_usec += micro_frame_delay;
148     if (timer_expire.tv_usec > 1000000)
149     {
150         nsec = timer_expire.tv_usec / 1000000;
151         timer_expire.tv_sec += nsec;
152         timer_expire.tv_usec -= nsec*1000000;
153     }
154 }
155
156 /*************************
157  * audio handlers
158  *************************/
159 static void mve_audio_callback(void *userdata, unsigned char *stream, int len); 
160 static short *mve_audio_buffers[64];
161 static int    mve_audio_buflens[64];
162 static int    mve_audio_curbuf_curpos=0;
163 static int mve_audio_bufhead=0;
164 static int mve_audio_buftail=0;
165 static int mve_audio_playing=0;
166 static int mve_audio_canplay=0;
167 #if 0
168 static SDL_AudioSpec *mve_audio_spec=NULL;
169 #endif
170 static int mve_audio_compressed = 0;
171
172 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
173 {
174 #if 0
175     int total=0;
176     int length;
177     if (mve_audio_bufhead == mve_audio_buftail)
178         return /* 0 */;
179
180 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
181
182     while (mve_audio_bufhead != mve_audio_buftail                                       /* while we have more buffers  */
183             &&  len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos))   /* and while we need more data */
184     {
185         length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
186         memcpy(stream,                                                        /* cur output position */
187                 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos,           /* cur input position  */
188                 length);                                                                /* cur input length    */
189
190         total += length;
191         stream += length;                                                               /* advance output */
192         len -= length;                                                                  /* decrement avail ospace */
193         free(mve_audio_buffers[mve_audio_bufhead]);                                     /* free the buffer */
194         mve_audio_buffers[mve_audio_bufhead]=NULL;                                      /* free the buffer */
195         mve_audio_buflens[mve_audio_bufhead]=0;                                         /* free the buffer */
196
197         if (++mve_audio_bufhead == 64)                                                  /* next buffer */
198             mve_audio_bufhead = 0;
199         mve_audio_curbuf_curpos = 0;
200     }
201
202 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
203 /*    return total; */
204
205     if (len != 0                                                                        /* ospace remaining  */
206             &&  mve_audio_bufhead != mve_audio_buftail)                                 /* buffers remaining */
207     {
208         memcpy(stream,                                                        /* dest */
209                 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos,         /* src */
210                 len);                                                                   /* length */
211
212         mve_audio_curbuf_curpos += len;                                                 /* advance input */
213         stream += len;                                                                  /* advance output (unnecessary) */
214         len -= len;                                                                     /* advance output (unnecessary) */
215
216         if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead])            /* if this ends the current chunk */
217         {
218             free(mve_audio_buffers[mve_audio_bufhead]);                                 /* free buffer */
219             mve_audio_buffers[mve_audio_bufhead]=NULL;
220             mve_audio_buflens[mve_audio_bufhead]=0;
221
222             if (++mve_audio_bufhead == 64)                                              /* next buffer */
223                 mve_audio_bufhead = 0;
224             mve_audio_curbuf_curpos = 0;
225         }
226     }
227
228 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
229 #endif
230 }
231
232 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
233 {
234 #if 0
235     int flags;
236     int sample_rate;
237     int desired_buffer;
238         
239     int stereo;
240     int bitsize;
241     int compressed;
242     
243     int format;
244     
245     flags = get_ushort(data + 2);
246     sample_rate = get_ushort(data + 4);
247     desired_buffer = get_int(data + 6);
248     
249     stereo = (flags & 0x0001) ? 1 : 0;
250     bitsize = (flags & 0x0002) ? 1 : 0;
251     
252     if (minor > 0) {
253         compressed = flags & 0x0004 ? 1 : 0;
254     } else {
255         compressed = 0;
256     }
257
258     mve_audio_compressed = compressed;
259         
260     if (bitsize == 1) {
261         format = AUDIO_S16LSB;
262     } else {
263         format = AUDIO_U8;
264     }
265     
266     fprintf(stderr, "creating audio buffers:\n");
267     fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n", 
268         sample_rate, stereo, bitsize ? 16 : 8, compressed);
269     
270     mve_audio_spec = (SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec));
271     mve_audio_spec->freq = sample_rate;
272     mve_audio_spec->format = format;
273     mve_audio_spec->channels = (stereo) ? 2 : 1;
274     mve_audio_spec->samples = 4096;
275     mve_audio_spec->callback = mve_audio_callback;
276     mve_audio_spec->userdata = NULL;
277     if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
278     {
279 fprintf(stderr, "   success\n");
280         mve_audio_canplay = 1;
281     }
282     else
283     {
284 fprintf(stderr, "   failure : %s\n", SDL_GetError());
285         mve_audio_canplay = 0;
286     }
287
288     memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
289     memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
290
291 #endif
292     return 1;
293 }
294
295 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
296 {
297 #if 0
298     if (mve_audio_canplay  &&  !mve_audio_playing  &&  mve_audio_bufhead != mve_audio_buftail)
299     {
300         SDL_PauseAudio(0);
301         mve_audio_playing = 1;
302     }
303 #endif
304     return 1;
305 }
306
307 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
308 {
309 #if 0
310     static const int selected_chan=1;
311     int chan;
312     int nsamp;
313     if (mve_audio_canplay)
314     {
315         if (mve_audio_playing)
316             SDL_LockAudio();
317
318         chan = get_ushort(data + 2);
319         nsamp = get_ushort(data + 4);
320         if (chan & selected_chan)
321         {
322             /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
323             if (major == 8) {
324                 if (mve_audio_compressed) {
325                         nsamp += 4;
326                         
327                         mve_audio_buflens[mve_audio_buftail] = nsamp;
328                         mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
329                         mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
330                 } else {
331                         nsamp -= 8;
332                         data += 8;
333                         
334                         mve_audio_buflens[mve_audio_buftail] = nsamp;
335                         mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
336                         memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
337                 }                     
338             } else {
339                 mve_audio_buflens[mve_audio_buftail] = nsamp;
340                 mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
341                 
342                 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
343             }
344             
345             if (++mve_audio_buftail == 64)
346                 mve_audio_buftail = 0;
347
348             if (mve_audio_buftail == mve_audio_bufhead)
349                 fprintf(stderr, "d'oh!  buffer ring overrun (%d)\n", mve_audio_bufhead);
350         }
351
352         if (mve_audio_playing)
353             SDL_UnlockAudio();
354     }
355 #endif
356
357     return 1;
358 }
359
360 /*************************
361  * video handlers
362  *************************/
363 int g_width, g_height;
364 void *g_vBackBuf1, *g_vBackBuf2;
365
366 #if 0
367 static SDL_Surface *g_screen;
368 #endif
369 static int g_screenWidth, g_screenHeight;
370 static unsigned char g_palette[768];
371 static unsigned char *g_pCurMap=NULL;
372 static int g_nMapLength=0;
373 static int g_truecolor;
374
375 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
376 {
377     short w, h;
378     short count, truecolor;
379     w = get_short(data);
380     h = get_short(data+2);
381     
382     if (minor > 0) {
383             count = get_short(data+4);
384     } else {
385         count = 1;
386     }
387     
388     if (minor > 1) {
389         truecolor = get_short(data+6);
390     } else {
391         truecolor = 0;
392     }
393     
394     g_width = w << 3;
395     g_height = h << 3;
396     
397     /* TODO: * 4 causes crashes on some files */
398     g_vBackBuf1 = malloc(g_width * g_height * 8);
399     if (truecolor) {
400         g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
401     } else {
402         g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
403     }
404         
405     memset(g_vBackBuf1, 0, g_width * g_height * 4);
406     
407     fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
408     
409     g_truecolor = truecolor;
410     
411     return 1;
412 }
413
414 #if 0
415 static int do_sdl_events()
416 {
417         SDL_Event event;
418         int retr = 0;
419         while (SDL_PollEvent(&event)) {
420                 switch(event.type) {
421                         case SDL_QUIT:
422                                 exit(0);
423                         case SDL_KEYDOWN:
424                                 if (event.key.keysym.sym == SDLK_ESCAPE)
425                                         exit(0);
426                                 break;
427                         case SDL_KEYUP:
428                                 retr = 1;
429                                 break;
430                         case SDL_MOUSEBUTTONDOWN:
431 /*
432                                 if (event.button.button == SDL_BUTTON_LEFT) {
433                                         printf("GRID: %d,%d (pix:%d,%d)\n", 
434                                         event.button.x / 16, event.button.y / 8,
435                                          event.button.x, event.button.y);
436                                 }
437 */
438                                 break;
439                         default:
440                                 break;
441                 }
442         }
443         
444         return retr;
445 }
446 #endif
447
448 static unsigned short stab[65536];
449 static unsigned int itab[65536];
450 static int table_inited;
451
452 unsigned short *pixelbuf;
453 static void ConvertAndDraw()
454 {
455     int i;
456     
457     unsigned short *pDests;
458     unsigned int *pDesti;
459     unsigned short *pSrcs;
460     unsigned char *pixels = (unsigned char *)g_vBackBuf1;
461     int x, y;
462
463 if (g_truecolor) {
464         pSrcs = (unsigned short *)pixels;
465         
466         /*
467         if (table_inited == 0) {
468                 int r, g, b;
469                 
470                 table_inited = 1;
471                 
472                 for (i = 0; i < 65536; i++) {
473                         r = (i & 0x7c00) >> 10;
474                         g = (i & 0x03e0) >> 5;
475                         b = (i & 0x001f) >> 0;
476                         
477                         stab[i]  = 1 << 15;
478                         stab[i] |= (r << 10)&0x7c00;
479                         stab[i] |= (g <<  5)&0x03e0;
480                         stab[i] |= (b <<  0)&0x001f;
481                 }
482         }
483         */
484         
485         pDests = pixelbuf;
486
487         if (g_screenWidth > g_width) {
488                 pDests += ((g_screenWidth - g_width) / 2) / 2;
489         }
490         if (g_screenHeight > g_height) {
491                 pDests += ((g_screenHeight - g_height) / 2) * g_screenWidth;
492         }
493
494         for (y=0; y<g_height; y++) {
495                 for (x = 0; x < g_width; x++) {
496                         //pDests[x] = stab[*pSrcs];
497                         pDests[x] = (1<<15)|*pSrcs;
498                 
499                         pSrcs++;
500                 }
501                 pDests += g_screenWidth;
502         }
503 } else {
504 #if 0
505 /* original slow 8 bit code */
506     int i;
507     unsigned char *pal = g_palette;
508     unsigned char *pDest;
509     unsigned char *pixels = g_vBackBuf1;
510     SDL_Surface *screenSprite, *initSprite;
511     SDL_Rect renderArea;
512     int x, y;
513
514        initSprite = SDL_CreateRGBSurface(SDL_SWSURFACE, g_width, g_height, 8, 0, 0, 0, 0);
515
516     if (!g_truecolor) {
517         for(i = 0; i < 256; i++)
518             {
519                 initSprite->format->palette->colors[i].r = (*pal++) << 2;
520                 initSprite->format->palette->colors[i].g = (*pal++) << 2;
521                 initSprite->format->palette->colors[i].b = (*pal++) << 2;
522                 initSprite->format->palette->colors[i].unused = 0;
523             }    
524     }
525     
526     pDest = initSprite->pixels;
527     for (i=0; i<g_height; i++)
528     {
529         memcpy(pDest, pixels, g_width * (g_truecolor?2:1));
530         pixels += g_width* (g_truecolor?2:1);
531         pDest += initSprite->pitch;
532     }
533
534     screenSprite = SDL_DisplayFormat(initSprite);
535     SDL_FreeSurface(initSprite);
536
537     if (g_screenWidth > screenSprite->w) x = (g_screenWidth - screenSprite->w) >> 1;
538     else x=0;
539     if (g_screenHeight > screenSprite->h) y = (g_screenHeight - screenSprite->h) >> 1;
540     else y=0;
541     renderArea.x = x;
542     renderArea.y = y;
543     renderArea.w = MIN(g_screenWidth  - x, screenSprite->w);
544     renderArea.h = MIN(g_screenHeight - y, screenSprite->h);
545     SDL_BlitSurface(screenSprite, NULL, g_screen, &renderArea);
546
547         SDL_FreeSurface(screenSprite);
548 #endif
549 }
550
551 }
552
553 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
554 {
555         ConvertAndDraw();
556 #if 0
557                 
558         SDL_Flip(g_screen);
559         
560         do_sdl_events();
561 #endif
562         /* DDOI - This is probably really fricking slow */
563         int bitmap = bm_create (16, g_screenWidth, g_screenHeight, pixelbuf, 0);
564         gr_set_bitmap (bitmap);
565         gr_bitmap (0, 0);
566         bm_release (bitmap);
567         gr_flip ();
568 #ifdef PLAT_UNIX
569         os_poll ();     /* DDOI - run event loop(s) */
570 #endif
571         if (key_check (KEY_ESC)) playing = 0;
572         
573         return 1;
574 }
575
576 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
577 {
578     short width, height;
579     width = get_short(data);
580     height = get_short(data+2);
581 #if 0
582     g_screen = SDL_SetVideoMode(width, height, 16, SDL_ANYFORMAT|SDL_DOUBLEBUF);
583 #endif
584     // DDOI - Allocate RGB565 pixel buffer
585     pixelbuf = (unsigned short *)malloc (width * height * 2);
586     g_screenWidth = width;
587     g_screenHeight = height;
588     memset(g_palette, 0, 768);
589     return 1;
590 }
591
592 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
593 {
594     short start, count;
595     start = get_short(data);
596     count = get_short(data+2);
597     memcpy(g_palette + 3*start, data+4, 3*count);
598     return 1;
599 }
600
601 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
602 {
603     g_pCurMap = data;
604     g_nMapLength = len;
605     return 1;
606 }
607
608 void decodeFrame16(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain);
609
610 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
611 {
612     short nFrameHot, nFrameCold;
613     short nXoffset, nYoffset;
614     short nXsize, nYsize;
615     unsigned short nFlags;
616     unsigned char *temp;
617
618     nFrameHot  = get_short(data);
619     nFrameCold = get_short(data+2);
620     nXoffset   = get_short(data+4);
621     nYoffset   = get_short(data+6);
622     nXsize     = get_short(data+8);
623     nYsize     = get_short(data+10);
624     nFlags     = get_ushort(data+12);
625
626     if (nFlags & 1)
627     {
628         temp = (unsigned char *)g_vBackBuf1;
629         g_vBackBuf1 = g_vBackBuf2;
630         g_vBackBuf2 = temp;
631     }
632
633     /* convert the frame */
634     if (g_truecolor) {
635         decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
636 #if 0
637     } else {
638         decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
639 #endif
640     }
641
642     return 1;
643 }
644
645 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
646 {
647     g_pCurMap=NULL;
648     return 1;
649 }
650
651 void initializeMovie(MVESTREAM *mve)
652 {
653     int i;
654     
655     for (i = 0; i < 32; i++) {
656         mve_set_handler(mve, i, default_seg_handler);
657     }
658     
659     mve_set_handler(mve, 0x00, end_movie_handler);
660     mve_set_handler(mve, 0x01, end_chunk_handler);
661     mve_set_handler(mve, 0x02, create_timer_handler);
662     mve_set_handler(mve, 0x03, create_audiobuf_handler);
663     mve_set_handler(mve, 0x04, play_audio_handler);
664     mve_set_handler(mve, 0x05, create_videobuf_handler);
665     mve_set_handler(mve, 0x07, display_video_handler);
666     mve_set_handler(mve, 0x08, audio_data_handler);
667     mve_set_handler(mve, 0x09, audio_data_handler);
668     mve_set_handler(mve, 0x0a, init_video_handler);
669     mve_set_handler(mve, 0x0c, video_palette_handler);
670     mve_set_handler(mve, 0x0f, video_codemap_handler);
671     mve_set_handler(mve, 0x11, video_data_handler);
672 }
673
674 void playMovie(MVESTREAM *mve)
675 {
676     int init_timer=0;
677     int cont=1;
678     while (cont && playing)
679     {
680         cont = mve_play_next_chunk(mve);
681         if (micro_frame_delay  &&  !init_timer)
682         {
683             timer_start();
684             init_timer = 1;
685         }
686
687         do_timer_wait();
688     }
689 }
690
691 void shutdownMovie(MVESTREAM *mve)
692 {
693         free (pixelbuf);
694 }