1 /* $Id: mveplay.c,v 1.15 2003-11-25 04:36:25 btb Exp $ */
16 #include <sys/types.h>
29 #include "mve_audio.h"
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
42 #define MVE_OPCODE_DISPLAYVIDEO 0x07
43 #define MVE_OPCODE_AUDIOFRAMEDATA 0x08
44 #define MVE_OPCODE_AUDIOFRAMESILENCE 0x09
45 #define MVE_OPCODE_INITVIDEOMODE 0x0A
47 #define MVE_OPCODE_SETPALETTE 0x0C
48 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
50 #define MVE_OPCODE_SETDECODINGMAP 0x0F
52 #define MVE_OPCODE_VIDEODATA 0x11
54 #define MVE_AUDIO_FLAGS_STEREO 1
55 #define MVE_AUDIO_FLAGS_16BIT 2
56 #define MVE_AUDIO_FLAGS_COMPRESSED 4
59 static int g_spdFactorDenom=10;
60 static int g_frameUpdated = 0;
62 static short get_short(unsigned char *data)
65 value = data[0] | (data[1] << 8);
69 static unsigned short get_ushort(unsigned char *data)
72 value = data[0] | (data[1] << 8);
76 static int get_int(unsigned char *data)
79 value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
83 static unsigned int unhandled_chunks[32*256];
85 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
87 unhandled_chunks[major<<8|minor]++;
88 //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
93 /*************************
95 *************************/
96 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
101 /*************************
103 *************************/
105 #if !HAVE_STRUCT_TIMEVAL
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};
120 #if !HAVE_STRUCT_TIMESPEC
123 long int tv_sec; /* Seconds. */
124 long int tv_nsec; /* Nanoseconds. */
128 #if defined(HAVE_DECL_NANOSLEEP) && !HAVE_DECL_NANOSLEEP
129 int nanosleep(struct timespec *ts, void *rem);
133 int gettimeofday(struct timeval *tv, void *tz)
135 static int counter = 0;
139 now = GetTickCount();
141 tv->tv_sec = now / 1000;
142 tv->tv_usec = (now % 1000) * 1000 + counter;
147 #elif defined(__WIN32)
148 #include <sys/timeb.h>
150 int gettimeofday(struct timeval *tv, void *tz)
152 static int counter = 0;
155 counter++; /* to avoid collisions */
157 tv->tv_sec = tm.time;
158 tv->tv_usec = (tm.millitm * 1000) + counter;
163 int nanosleep(struct timespec *ts, void *rem)
165 _sleep(ts->tv_sec * 1000 + ts->tv_nsec / 1000000);
171 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
175 __extension__ long long temp;
185 micro_frame_delay = get_int(data) * (int)get_short(data+4);
186 if (g_spdFactorNum != 0)
188 temp = micro_frame_delay;
189 temp *= g_spdFactorNum;
190 temp /= g_spdFactorDenom;
191 micro_frame_delay = (int)temp;
197 static void timer_stop(void)
199 timer_expire.tv_sec = 0;
200 timer_expire.tv_usec = 0;
204 static void timer_start(void)
207 gettimeofday(&timer_expire, NULL);
208 timer_expire.tv_usec += micro_frame_delay;
209 if (timer_expire.tv_usec > 1000000)
211 nsec = timer_expire.tv_usec / 1000000;
212 timer_expire.tv_sec += nsec;
213 timer_expire.tv_usec -= nsec*1000000;
218 static void do_timer_wait(void)
226 gettimeofday(&tv, NULL);
227 if (tv.tv_sec > timer_expire.tv_sec)
229 else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec)
232 ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
233 ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
236 ts.tv_nsec += 1000000000UL;
240 Sleep(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
241 #elif defined(__CYGWIN__)
242 usleep(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
244 if (nanosleep(&ts, NULL) == -1 && errno == EINTR)
249 timer_expire.tv_usec += micro_frame_delay;
250 if (timer_expire.tv_usec > 1000000)
252 nsec = timer_expire.tv_usec / 1000000;
253 timer_expire.tv_sec += nsec;
254 timer_expire.tv_usec -= nsec*1000000;
258 /*************************
260 *************************/
262 #define TOTAL_AUDIO_BUFFERS 64
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;
277 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
281 if (mve_audio_bufhead == mve_audio_buftail)
284 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
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 */
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 */
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 */
301 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
302 mve_audio_bufhead = 0;
303 mve_audio_curbuf_curpos = 0;
306 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
309 if (len != 0 /* ospace remaining */
310 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
312 memcpy(stream, /* dest */
313 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
316 mve_audio_curbuf_curpos += len; /* advance input */
317 stream += len; /* advance output (unnecessary) */
318 len -= len; /* advance output (unnecessary) */
320 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
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;
326 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
327 mve_audio_bufhead = 0;
328 mve_audio_curbuf_curpos = 0;
332 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
336 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
349 if (!mve_audio_enabled)
352 if (audiobuf_created)
355 audiobuf_created = 1;
357 flags = get_ushort(data + 2);
358 sample_rate = get_ushort(data + 4);
359 desired_buffer = get_int(data + 6);
361 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
362 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
365 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
370 mve_audio_compressed = compressed;
373 #ifdef WORDS_BIGENDIAN
374 format = AUDIO_S16MSB;
376 format = AUDIO_S16LSB;
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);
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)
395 fprintf(stderr, " success\n");
396 mve_audio_canplay = 1;
400 fprintf(stderr, " failure : %s\n", SDL_GetError());
401 mve_audio_canplay = 0;
404 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
405 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
411 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
414 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
417 mve_audio_playing = 1;
423 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
426 static const int selected_chan=1;
429 if (mve_audio_canplay)
431 if (mve_audio_playing)
434 chan = get_ushort(data + 2);
435 nsamp = get_ushort(data + 4);
436 if (chan & selected_chan)
438 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
439 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
440 if (mve_audio_compressed) {
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 */
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);
455 mve_audio_buflens[mve_audio_buftail] = nsamp;
456 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
458 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
461 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
462 mve_audio_buftail = 0;
464 if (mve_audio_buftail == mve_audio_bufhead)
465 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
468 if (mve_audio_playing)
476 /*************************
478 *************************/
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;
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;
491 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
494 short count, truecolor;
496 if (videobuf_created)
499 videobuf_created = 1;
502 h = get_short(data+2);
505 count = get_short(data+4);
511 truecolor = get_short(data+6);
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);
524 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
526 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
529 memset(g_vBackBuf1, 0, g_width * g_height * 4);
532 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
535 g_truecolor = truecolor;
540 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
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;
547 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
548 g_width, g_height, g_destX, g_destY);
555 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
559 if (video_initialized)
562 video_initialized = 1;
564 width = get_short(data);
565 height = get_short(data+2);
566 g_screenWidth = width;
567 g_screenHeight = height;
572 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
577 start = get_short(data);
578 count = get_short(data+2);
582 mve_setpalette(p - 3*start, start, count);
587 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
594 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
596 short nFrameHot, nFrameCold;
597 short nXoffset, nYoffset;
598 short nXsize, nYsize;
599 unsigned short nFlags;
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);
612 temp = (unsigned char *)g_vBackBuf1;
613 g_vBackBuf1 = g_vBackBuf2;
617 /* convert the frame */
619 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
621 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
627 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
634 static MVESTREAM *mve = NULL;
636 void MVE_ioCallbacks(mve_cb_Read io_read)
641 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
643 mve_alloc = mem_alloc;
647 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
649 mve_showframe = showframe;
652 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
654 mve_setpalette = setpalette;
657 int MVE_rmPrepMovie(void *src, int x, int y, int track)
674 for (i = 0; i < 32; i++)
675 mve_set_handler(mve, i, default_seg_handler);
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);
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);
689 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
690 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
692 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
694 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
696 mve_play_next_chunk(mve); /* video initialization chunk */
697 mve_play_next_chunk(mve); /* audio initialization chunk */
703 void MVE_getVideoSpec(MVE_videoSpec *vSpec)
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;
713 int MVE_rmStepMovie()
715 static int init_timer=0;
721 while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
722 cont = mve_play_next_chunk(mve);
725 if (micro_frame_delay && !init_timer) {
738 void MVE_rmEndMovie()
748 if (mve_audio_canplay) {
749 // only close audio if we opened it
751 mve_audio_canplay = 0;
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;
763 mve_audio_compressed=0;
765 mve_free(mve_audio_spec);
767 audiobuf_created = 0;
770 mve_free(g_vBuffers);
774 videobuf_created = 0;
775 video_initialized = 0;
782 void MVE_rmHoldMovie()
788 void MVE_sndInit(int x)
792 mve_audio_enabled = 0;
794 mve_audio_enabled = 1;