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