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