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