typo
[btb/d2x.git] / main / mveplay.c
1 /* $Id: mveplay.c,v 1.15 2003-02-14 19:13:25 btb Exp $ */
2 #ifdef HAVE_CONFIG_H
3 #include <conf.h>
4 #endif
5
6 #ifndef __MSDOS__
7 #define AUDIO
8 #endif
9 //#define DEBUG
10
11 #include <string.h>
12 #include <errno.h>
13 #include <time.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19
20 #if defined(STANDALONE) || defined(AUDIO)
21 #include <SDL.h>
22 #endif
23
24 #include "mvelib.h"
25 #include "mve_audio.h"
26
27 #ifndef STANDALONE
28 #include "mveplay.h"
29 #include "error.h"
30 #include "u_mem.h"
31 #include "gr.h"
32 #include "palette.h"
33 #endif
34
35 #ifndef MIN
36 #define MIN(a,b) ((a)<(b)?(a):(b))
37 #endif
38
39 #define MVE_OPCODE_ENDOFSTREAM          0x00
40 #define MVE_OPCODE_ENDOFCHUNK           0x01
41 #define MVE_OPCODE_CREATETIMER          0x02
42 #define MVE_OPCODE_INITAUDIOBUFFERS     0x03
43 #define MVE_OPCODE_STARTSTOPAUDIO       0x04
44 #define MVE_OPCODE_INITVIDEOBUFFERS     0x05
45
46 #define MVE_OPCODE_DISPLAYVIDEO         0x07
47 #define MVE_OPCODE_AUDIOFRAMEDATA       0x08
48 #define MVE_OPCODE_AUDIOFRAMESILENCE    0x09
49 #define MVE_OPCODE_INITVIDEOMODE        0x0A
50
51 #define MVE_OPCODE_SETPALETTE           0x0C
52 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
53
54 #define MVE_OPCODE_SETDECODINGMAP       0x0F
55
56 #define MVE_OPCODE_VIDEODATA            0x11
57
58 #define MVE_AUDIO_FLAGS_STEREO     1
59 #define MVE_AUDIO_FLAGS_16BIT      2
60 #define MVE_AUDIO_FLAGS_COMPRESSED 4
61
62 int g_spdFactorNum=0;
63 static int g_spdFactorDenom=10;
64 static int playing = 1;
65
66 #ifdef STANDALONE
67 int g_sdlVidFlags = SDL_ANYFORMAT | SDL_DOUBLEBUF;
68 #endif
69
70 void initializeMovie(MVESTREAM *mve);
71 void playMovie(MVESTREAM *mve);
72 void shutdownMovie(MVESTREAM *mve);
73
74 static short get_short(unsigned char *data)
75 {
76         short value;
77         value = data[0] | (data[1] << 8);
78         return value;
79 }
80
81 static unsigned short get_ushort(unsigned char *data)
82 {
83         unsigned short value;
84         value = data[0] | (data[1] << 8);
85         return value;
86 }
87
88 static int get_int(unsigned char *data)
89 {
90         int value;
91         value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
92         return value;
93 }
94
95 static unsigned int unhandled_chunks[32*256];
96
97 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
98 {
99         unhandled_chunks[major<<8|minor]++;
100         //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
101         return 1;
102 }
103
104 /*************************
105  * general handlers
106  *************************/
107 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
108 {
109         return 0;
110 }
111
112 /*************************
113  * timer handlers
114  *************************/
115
116 /*
117  * timer variables
118  */
119 static int micro_frame_delay=0;
120 static int timer_started=0;
121 static struct timeval timer_expire = {0, 0};
122
123 #ifdef __WIN32
124 #include <sys/timeb.h>
125
126 struct timespec
127 {
128         long int tv_sec;            /* Seconds.  */
129         long int tv_nsec;           /* Nanoseconds.  */
130 };
131
132 int gettimeofday(struct timeval *tv, void *tz)
133 {
134         static int counter = 0;
135         struct timeb tm;
136
137         counter++; /* to avoid collisions */
138         ftime(&tm);
139         tv->tv_sec  = tm.time;
140         tv->tv_usec = (tm.millitm * 1000) + counter;
141
142         return 0;
143 }
144
145 int nanosleep(struct timespec *ts, void *rem)
146 {
147         sleep(ts->tv_sec * 1000 + ts->tv_nsec / 1000000);
148
149         return 0;
150 }
151 #endif
152
153 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
154 {
155         __extension__ long long temp;
156         micro_frame_delay = get_int(data) * (int)get_short(data+4);
157         if (g_spdFactorNum != 0)
158         {
159                 temp = micro_frame_delay;
160                 temp *= g_spdFactorNum;
161                 temp /= g_spdFactorDenom;
162                 micro_frame_delay = (int)temp;
163         }
164
165         return 1;
166 }
167
168 static void timer_stop(void)
169 {
170         timer_expire.tv_sec = 0;
171         timer_expire.tv_usec = 0;
172         timer_started = 0;
173 }
174
175 static void timer_start(void)
176 {
177         int nsec=0;
178         gettimeofday(&timer_expire, NULL);
179         timer_expire.tv_usec += micro_frame_delay;
180         if (timer_expire.tv_usec > 1000000)
181         {
182                 nsec = timer_expire.tv_usec / 1000000;
183                 timer_expire.tv_sec += nsec;
184                 timer_expire.tv_usec -= nsec*1000000;
185         }
186         timer_started=1;
187 }
188
189 static void do_timer_wait(void)
190 {
191         int nsec=0;
192         struct timespec ts;
193         struct timeval tv;
194         if (! timer_started)
195                 return;
196
197         gettimeofday(&tv, NULL);
198         if (tv.tv_sec > timer_expire.tv_sec)
199                 goto end;
200         else if (tv.tv_sec == timer_expire.tv_sec  &&  tv.tv_usec >= timer_expire.tv_usec)
201                 goto end;
202
203         ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
204         ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
205         if (ts.tv_nsec < 0)
206         {
207                 ts.tv_nsec += 1000000000UL;
208                 --ts.tv_sec;
209         }
210 #ifdef __CYGWIN__
211         usleep(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
212 #else
213         if (nanosleep(&ts, NULL) == -1  &&  errno == EINTR)
214                 exit(1);
215 #endif
216
217  end:
218         timer_expire.tv_usec += micro_frame_delay;
219         if (timer_expire.tv_usec > 1000000)
220         {
221                 nsec = timer_expire.tv_usec / 1000000;
222                 timer_expire.tv_sec += nsec;
223                 timer_expire.tv_usec -= nsec*1000000;
224         }
225 }
226
227 /*************************
228  * audio handlers
229  *************************/
230 #ifdef AUDIO
231 #define TOTAL_AUDIO_BUFFERS 64
232
233 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
234 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
235 static int    mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
236 static int    mve_audio_curbuf_curpos=0;
237 static int mve_audio_bufhead=0;
238 static int mve_audio_buftail=0;
239 static int mve_audio_playing=0;
240 static int mve_audio_canplay=0;
241 static int mve_audio_compressed=0;
242 static SDL_AudioSpec *mve_audio_spec=NULL;
243
244 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
245 {
246         int total=0;
247         int length;
248         if (mve_audio_bufhead == mve_audio_buftail)
249                 return /* 0 */;
250
251         //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
252
253         while (mve_audio_bufhead != mve_audio_buftail                                           /* while we have more buffers  */
254                    &&  len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos))        /* and while we need more data */
255         {
256                 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
257                 memcpy(stream,                                                                  /* cur output position */
258                            ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos,           /* cur input position  */
259                            length);                                                                 /* cur input length    */
260
261                 total += length;
262                 stream += length;                                                               /* advance output */
263                 len -= length;                                                                  /* decrement avail ospace */
264                 free(mve_audio_buffers[mve_audio_bufhead]);                                     /* free the buffer */
265                 mve_audio_buffers[mve_audio_bufhead]=NULL;                                      /* free the buffer */
266                 mve_audio_buflens[mve_audio_bufhead]=0;                                         /* free the buffer */
267
268                 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS)                                 /* next buffer */
269                         mve_audio_bufhead = 0;
270                 mve_audio_curbuf_curpos = 0;
271         }
272
273         //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
274         /*    return total; */
275
276         if (len != 0                                                                            /* ospace remaining  */
277                 &&  mve_audio_bufhead != mve_audio_buftail)                                         /* buffers remaining */
278         {
279                 memcpy(stream,                                                                  /* dest */
280                            ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos,         /* src */
281                            len);                                                                    /* length */
282
283                 mve_audio_curbuf_curpos += len;                                                 /* advance input */
284                 stream += len;                                                                  /* advance output (unnecessary) */
285                 len -= len;                                                                     /* advance output (unnecessary) */
286
287                 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead])            /* if this ends the current chunk */
288                 {
289                         free(mve_audio_buffers[mve_audio_bufhead]);                             /* free buffer */
290                         mve_audio_buffers[mve_audio_bufhead]=NULL;
291                         mve_audio_buflens[mve_audio_bufhead]=0;
292
293                         if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS)                         /* next buffer */
294                                 mve_audio_bufhead = 0;
295                         mve_audio_curbuf_curpos = 0;
296                 }
297         }
298
299         //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
300 }
301 #endif
302
303 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
304 {
305 #ifdef AUDIO
306         int flags;
307         int sample_rate;
308         int desired_buffer;
309
310         int stereo;
311         int bitsize;
312         int compressed;
313
314         int format;
315
316 #ifndef STANDALONE
317         if (FindArg("-nosound"))
318                 return 1;
319 #endif
320
321         flags = get_ushort(data + 2);
322         sample_rate = get_ushort(data + 4);
323         desired_buffer = get_int(data + 6);
324
325         stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
326         bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
327
328         if (minor > 0) {
329                 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
330         } else {
331                 compressed = 0;
332         }
333
334         mve_audio_compressed = compressed;
335
336         if (bitsize == 1) {
337                 format = AUDIO_S16LSB;
338         } else {
339                 format = AUDIO_U8;
340         }
341
342         fprintf(stderr, "creating audio buffers:\n");
343         fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
344                         sample_rate, stereo, bitsize ? 16 : 8, compressed);
345
346         mve_audio_spec = (SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec));
347         mve_audio_spec->freq = sample_rate;
348         mve_audio_spec->format = format;
349         mve_audio_spec->channels = (stereo) ? 2 : 1;
350         mve_audio_spec->samples = 4096;
351         mve_audio_spec->callback = mve_audio_callback;
352         mve_audio_spec->userdata = NULL;
353         if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
354         {
355                 fprintf(stderr, "   success\n");
356                 mve_audio_canplay = 1;
357         }
358         else
359         {
360                 fprintf(stderr, "   failure : %s\n", SDL_GetError());
361                 mve_audio_canplay = 0;
362         }
363
364         memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
365         memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
366
367 #endif
368         return 1;
369 }
370
371 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
372 {
373 #ifdef AUDIO
374         if (mve_audio_canplay  &&  !mve_audio_playing  &&  mve_audio_bufhead != mve_audio_buftail)
375         {
376                 SDL_PauseAudio(0);
377                 mve_audio_playing = 1;
378         }
379 #endif
380         return 1;
381 }
382
383 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
384 {
385 #ifdef AUDIO
386         static const int selected_chan=1;
387         int chan;
388         int nsamp;
389         if (mve_audio_canplay)
390         {
391                 if (mve_audio_playing)
392                         SDL_LockAudio();
393
394                 chan = get_ushort(data + 2);
395                 nsamp = get_ushort(data + 4);
396                 if (chan & selected_chan)
397                 {
398                         /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
399                         if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
400                                 if (mve_audio_compressed) {
401                                         nsamp += 4;
402
403                                         mve_audio_buflens[mve_audio_buftail] = nsamp;
404                                         mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
405                                         mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
406                                 } else {
407                                         nsamp -= 8;
408                                         data += 8;
409
410                                         mve_audio_buflens[mve_audio_buftail] = nsamp;
411                                         mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
412                                         memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
413                                 }
414                         } else {
415                                 mve_audio_buflens[mve_audio_buftail] = nsamp;
416                                 mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
417
418                                 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
419                         }
420
421                         if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
422                                 mve_audio_buftail = 0;
423
424                         if (mve_audio_buftail == mve_audio_bufhead)
425                                 fprintf(stderr, "d'oh!  buffer ring overrun (%d)\n", mve_audio_bufhead);
426                 }
427
428                 if (mve_audio_playing)
429                         SDL_UnlockAudio();
430         }
431 #endif
432
433         return 1;
434 }
435
436 /*************************
437  * video handlers
438  *************************/
439 int g_width, g_height;
440 void *g_vBuffers, *g_vBackBuf1, *g_vBackBuf2;
441
442 #ifdef STANDALONE
443 static SDL_Surface *g_screen;
444 #else
445 static grs_bitmap *g_screen;
446 #endif
447 static int g_screenWidth, g_screenHeight;
448 static unsigned char g_palette[768];
449 static unsigned char *g_pCurMap=NULL;
450 static int g_nMapLength=0;
451 static int g_truecolor;
452 static int g_palette_changed = 0;
453
454 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
455 {
456         short w, h;
457         short count, truecolor;
458
459         w = get_short(data);
460         h = get_short(data+2);
461
462         if (minor > 0) {
463                 count = get_short(data+4);
464         } else {
465                 count = 1;
466         }
467
468         if (minor > 1) {
469                 truecolor = get_short(data+6);
470         } else {
471                 truecolor = 0;
472         }
473
474         g_width = w << 3;
475         g_height = h << 3;
476
477 #ifndef STANDALONE
478         Assert((g_width <= g_screen->bm_w) && (g_height <= g_screen->bm_h));
479 #endif
480
481         /* TODO: * 4 causes crashes on some files */
482         g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 8);
483         if (truecolor) {
484                 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
485         } else {
486                 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
487         }
488
489         memset(g_vBackBuf1, 0, g_width * g_height * 4);
490
491         fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
492
493         g_truecolor = truecolor;
494
495         return 1;
496 }
497
498 #ifdef STANDALONE
499 static int do_sdl_events()
500 {
501         SDL_Event event;
502         int retr = 0;
503         while (SDL_PollEvent(&event)) {
504                 switch(event.type) {
505                 case SDL_QUIT:
506                         playing=0;
507                         break;
508                 case SDL_KEYDOWN:
509                         if (event.key.keysym.sym == SDLK_ESCAPE)
510                                 playing=0;
511                         break;
512                 case SDL_KEYUP:
513                         retr = 1;
514                         break;
515                 case SDL_MOUSEBUTTONDOWN:
516                         /*
517                           if (event.button.button == SDL_BUTTON_LEFT) {
518                           printf("GRID: %d,%d (pix:%d,%d)\n", 
519                           event.button.x / 16, event.button.y / 8,
520                           event.button.x, event.button.y);
521                           }
522                         */
523                         break;
524                 default:
525                         break;
526                 }
527         }
528
529         return retr;
530 }
531
532 static void ConvertAndDraw()
533 {
534         int i;
535         unsigned char *pal = g_palette;
536         unsigned char *pDest;
537         unsigned char *pixels = g_vBackBuf1;
538         SDL_Surface *screenSprite, *initSprite;
539         SDL_Rect renderArea;
540         int x, y;
541
542         initSprite = SDL_CreateRGBSurface(SDL_SWSURFACE, g_width, g_height, g_truecolor?16:8, 0x7C00, 0x03E0, 0x001F, 0);
543
544         if (!g_truecolor) {
545                 for(i = 0; i < 256; i++) {
546                         initSprite->format->palette->colors[i].r = (*pal++) << 2;
547                         initSprite->format->palette->colors[i].g = (*pal++) << 2;
548                         initSprite->format->palette->colors[i].b = (*pal++) << 2;
549                         initSprite->format->palette->colors[i].unused = 0;
550                 }
551         }
552
553         pDest = initSprite->pixels;
554
555         if (0 /*g_truecolor*/) {
556
557                 unsigned short *pSrcs, *pDests;
558
559                 pSrcs = (unsigned short *)pixels;
560                 pDests = (unsigned short *)pDest;
561
562                 for (y=0; y<g_height; y++) {
563                         for (x = 0; x < g_width; x++) {
564                                 pDests[x] = (1<<15)|*pSrcs;
565                                 pSrcs++;
566                         }
567                         pDests += g_screenWidth;
568                 }
569
570         } else {
571
572                 for (i=0; i<g_height; i++) {
573                         memcpy(pDest, pixels, g_width * (g_truecolor?2:1));
574                         pixels += g_width* (g_truecolor?2:1);
575                         pDest += initSprite->pitch;
576                 }
577         }
578
579         screenSprite = SDL_DisplayFormat(initSprite);
580         SDL_FreeSurface(initSprite);
581
582         if (g_screenWidth > screenSprite->w)
583                 x = (g_screenWidth - screenSprite->w) >> 1;
584         else
585                 x=0;
586         if (g_screenHeight > screenSprite->h)
587                 y = (g_screenHeight - screenSprite->h) >> 1;
588         else
589                 y=0;
590         renderArea.x = x;
591         renderArea.y = y;
592         renderArea.w = MIN(g_screenWidth  - x, screenSprite->w);
593         renderArea.h = MIN(g_screenHeight - y, screenSprite->h);
594         SDL_BlitSurface(screenSprite, NULL, g_screen, &renderArea);
595
596         SDL_FreeSurface(screenSprite);
597 }
598 #endif
599
600 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
601 {
602 #ifdef STANDALONE
603         ConvertAndDraw();
604
605         SDL_Flip(g_screen);
606
607         do_sdl_events();
608 #else
609         if (g_palette_changed)
610         {
611                 gr_palette_load(g_palette);
612                 g_palette_changed = 0;
613         }
614
615         if (g_width == g_screen->bm_w && g_height >= g_screen->bm_h)
616                 memcpy(g_screen->bm_data, g_vBackBuf1, g_width * g_height);
617         else {
618                 int i, x = 0, y = 0;
619                 char *pSrc, *pDest;
620
621                 if (g_screen->bm_w > g_width)
622                         x = (g_screen->bm_w - g_width) >> 1;
623                 if (g_screen->bm_h > g_height)
624                         y = (g_screen->bm_h - g_height) >> 1;
625                 pSrc = g_vBackBuf1;
626                 pDest = g_screen->bm_data + g_screen->bm_w * y + x;
627                 for (i = 0; i < g_height; i++) {
628                         memcpy(pDest, pSrc, g_width * (g_truecolor?2:1));
629                         pSrc += g_width * (g_truecolor?2:1);
630                         pDest += g_screen->bm_w * (g_truecolor?2:1);
631                 }
632         }
633 #endif
634
635         return 1;
636 }
637
638 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
639 {
640         short width, height;
641         width = get_short(data);
642         height = get_short(data+2);
643 #ifdef STANDALONE
644         g_screen = SDL_SetVideoMode(width, height, 16, g_sdlVidFlags);
645 #endif
646         g_screenWidth = width;
647         g_screenHeight = height;
648         memset(g_palette, 0, 765);
649         // 255 needs to default to white, for subtitles, etc
650         memset(g_palette + 765, 63, 3);
651         return 1;
652 }
653
654 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
655 {
656         short start, count;
657         start = get_short(data);
658         count = get_short(data+2);
659         memcpy(g_palette + 3*start, data+4, 3*count);
660         g_palette_changed = 1;
661
662         return 1;
663 }
664
665 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
666 {
667         g_pCurMap = data;
668         g_nMapLength = len;
669         return 1;
670 }
671
672 void decodeFrame16(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain);
673 void decodeFrame8(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain);
674
675 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
676 {
677         short nFrameHot, nFrameCold;
678         short nXoffset, nYoffset;
679         short nXsize, nYsize;
680         unsigned short nFlags;
681         unsigned char *temp;
682
683         nFrameHot  = get_short(data);
684         nFrameCold = get_short(data+2);
685         nXoffset   = get_short(data+4);
686         nYoffset   = get_short(data+6);
687         nXsize     = get_short(data+8);
688         nYsize     = get_short(data+10);
689         nFlags     = get_ushort(data+12);
690
691         if (nFlags & 1)
692         {
693                 temp = (unsigned char *)g_vBackBuf1;
694                 g_vBackBuf1 = g_vBackBuf2;
695                 g_vBackBuf2 = temp;
696         }
697
698         /* convert the frame */
699         if (g_truecolor) {
700                 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
701         } else {
702                 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
703         }
704
705         return 1;
706 }
707
708 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
709 {
710         g_pCurMap=NULL;
711         return 1;
712 }
713
714 void initializeMovie(MVESTREAM *mve)
715 {
716         int i;
717
718         for (i = 0; i < 32; i++)
719                 mve_set_handler(mve, i, default_seg_handler);
720
721         memset(unhandled_chunks, 0, 32*256);
722
723         mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
724         mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
725         mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
726         mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
727         mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
728         mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
729
730         mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
731         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
732         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
733         mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
734
735         mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
736         mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, video_palette_handler);
737         mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
738
739         mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
740 }
741
742 void playMovie(MVESTREAM *mve)
743 {
744         int init_timer=0;
745         int cont=1;
746         while (cont && playing)
747         {
748                 cont = mve_play_next_chunk(mve);
749                 if (micro_frame_delay  &&  !init_timer)
750                 {
751                         timer_start();
752                         init_timer = 1;
753                 }
754
755                 do_timer_wait();
756         }
757 }
758
759 void shutdownMovie(MVESTREAM *mve)
760 {
761         int i;
762
763         timer_stop();
764
765         for (i = 0; i < 32*256; i++) {
766                 if (unhandled_chunks[i]) {
767                         fprintf(stderr, "unhandled chunks of type %02x/%02x: %d\n", i>>8, i&0xFF, unhandled_chunks[i]);
768                 }
769         }
770 }
771
772 #ifndef STANDALONE
773 void mveplay_initializeMovie(MVESTREAM *mve, grs_bitmap *mve_bitmap)
774 {
775         int i;
776
777         g_screen = mve_bitmap;
778
779         for (i = 0; i < 32; i++)
780                 mve_set_handler(mve, i, default_seg_handler);
781
782         mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM,          end_movie_handler);
783         mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK,           end_chunk_handler);
784         mve_set_handler(mve, MVE_OPCODE_CREATETIMER,          create_timer_handler);
785         mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS,     create_audiobuf_handler);
786         mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO,       play_audio_handler);
787         mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS,     create_videobuf_handler);
788
789         mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO,         display_video_handler);
790         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA,       audio_data_handler);
791         mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE,    audio_data_handler);
792         mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE,        init_video_handler);
793
794         mve_set_handler(mve, MVE_OPCODE_SETPALETTE,           video_palette_handler);
795         mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
796
797         mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP,       video_codemap_handler);
798
799         mve_set_handler(mve, MVE_OPCODE_VIDEODATA,            video_data_handler);
800
801 }
802
803 int mveplay_stepMovie(MVESTREAM *mve)
804 {
805         static int init_timer=0;
806         int cont=1;
807
808         if (!timer_started)
809                 timer_start();
810
811         cont = mve_play_next_chunk(mve);
812         if (micro_frame_delay  && !init_timer) {
813                 timer_start();
814                 init_timer = 1;
815         }
816
817         do_timer_wait();
818
819         return cont;
820 }
821
822 void mveplay_restartTimer(MVESTREAM *mve)
823 {
824         timer_start();
825 }
826
827 void mveplay_shutdownMovie(MVESTREAM *mve)
828 {
829         int i;
830
831         timer_stop();
832
833         SDL_CloseAudio();
834         if (mve_audio_canplay) {
835                 // only close audio if we opened it
836                 mve_audio_canplay = 0;
837         }
838         for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
839                 if (mve_audio_buffers[i] != NULL)
840                         free(mve_audio_buffers[i]);
841         memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
842         memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
843         mve_audio_curbuf_curpos=0;
844         mve_audio_bufhead=0;
845         mve_audio_buftail=0;
846         mve_audio_playing=0;
847         mve_audio_canplay=0;
848         mve_audio_compressed=0;
849         if (mve_audio_spec)
850                 free(mve_audio_spec);
851         mve_audio_spec=NULL;
852
853         free(g_vBuffers);
854         g_vBuffers = NULL;
855         g_pCurMap=NULL;
856         g_nMapLength=0;
857 }
858 #endif