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