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