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