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