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