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