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