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