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