1 /* $Id: mveplay.c,v 1.14 2003-06-10 04:46:16 btb Exp $ */
15 #include <sys/types.h>
25 #include "mve_audio.h"
31 #define MVE_OPCODE_ENDOFSTREAM 0x00
32 #define MVE_OPCODE_ENDOFCHUNK 0x01
33 #define MVE_OPCODE_CREATETIMER 0x02
34 #define MVE_OPCODE_INITAUDIOBUFFERS 0x03
35 #define MVE_OPCODE_STARTSTOPAUDIO 0x04
36 #define MVE_OPCODE_INITVIDEOBUFFERS 0x05
38 #define MVE_OPCODE_DISPLAYVIDEO 0x07
39 #define MVE_OPCODE_AUDIOFRAMEDATA 0x08
40 #define MVE_OPCODE_AUDIOFRAMESILENCE 0x09
41 #define MVE_OPCODE_INITVIDEOMODE 0x0A
43 #define MVE_OPCODE_SETPALETTE 0x0C
44 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
46 #define MVE_OPCODE_SETDECODINGMAP 0x0F
48 #define MVE_OPCODE_VIDEODATA 0x11
50 #define MVE_AUDIO_FLAGS_STEREO 1
51 #define MVE_AUDIO_FLAGS_16BIT 2
52 #define MVE_AUDIO_FLAGS_COMPRESSED 4
55 static int g_spdFactorDenom=10;
56 static int g_frameUpdated = 0;
58 static short get_short(unsigned char *data)
61 value = data[0] | (data[1] << 8);
65 static unsigned short get_ushort(unsigned char *data)
68 value = data[0] | (data[1] << 8);
72 static int get_int(unsigned char *data)
75 value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
79 static unsigned int unhandled_chunks[32*256];
81 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
83 unhandled_chunks[major<<8|minor]++;
84 //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
89 /*************************
91 *************************/
92 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
97 /*************************
99 *************************/
101 #if !HAVE_STRUCT_TIMEVAL
111 static int timer_created = 0;
112 static int micro_frame_delay=0;
113 static int timer_started=0;
114 static struct timeval timer_expire = {0, 0};
116 #if !HAVE_STRUCT_TIMESPEC
119 long int tv_sec; /* Seconds. */
120 long int tv_nsec; /* Nanoseconds. */
124 #if defined(HAVE_DECL_NANOSLEEP) && !HAVE_DECL_NANOSLEEP
125 int nanosleep(struct timespec *ts, void *rem);
129 #include <sys/timeb.h>
131 int gettimeofday(struct timeval *tv, void *tz)
133 static int counter = 0;
136 counter++; /* to avoid collisions */
138 tv->tv_sec = tm.time;
139 tv->tv_usec = (tm.millitm * 1000) + counter;
144 int nanosleep(struct timespec *ts, void *rem)
146 _sleep(ts->tv_sec * 1000 + ts->tv_nsec / 1000000);
152 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
154 __extension__ long long temp;
161 micro_frame_delay = get_int(data) * (int)get_short(data+4);
162 if (g_spdFactorNum != 0)
164 temp = micro_frame_delay;
165 temp *= g_spdFactorNum;
166 temp /= g_spdFactorDenom;
167 micro_frame_delay = (int)temp;
173 static void timer_stop(void)
175 timer_expire.tv_sec = 0;
176 timer_expire.tv_usec = 0;
180 static void timer_start(void)
183 gettimeofday(&timer_expire, NULL);
184 timer_expire.tv_usec += micro_frame_delay;
185 if (timer_expire.tv_usec > 1000000)
187 nsec = timer_expire.tv_usec / 1000000;
188 timer_expire.tv_sec += nsec;
189 timer_expire.tv_usec -= nsec*1000000;
194 static void do_timer_wait(void)
202 gettimeofday(&tv, NULL);
203 if (tv.tv_sec > timer_expire.tv_sec)
205 else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec)
208 ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
209 ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
212 ts.tv_nsec += 1000000000UL;
216 usleep(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
218 if (nanosleep(&ts, NULL) == -1 && errno == EINTR)
223 timer_expire.tv_usec += micro_frame_delay;
224 if (timer_expire.tv_usec > 1000000)
226 nsec = timer_expire.tv_usec / 1000000;
227 timer_expire.tv_sec += nsec;
228 timer_expire.tv_usec -= nsec*1000000;
232 /*************************
234 *************************/
236 #define TOTAL_AUDIO_BUFFERS 64
238 static int audiobuf_created = 0;
239 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
240 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
241 static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
242 static int mve_audio_curbuf_curpos=0;
243 static int mve_audio_bufhead=0;
244 static int mve_audio_buftail=0;
245 static int mve_audio_playing=0;
246 static int mve_audio_canplay=0;
247 static int mve_audio_compressed=0;
248 static int mve_audio_enabled = 1;
249 static SDL_AudioSpec *mve_audio_spec=NULL;
251 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
255 if (mve_audio_bufhead == mve_audio_buftail)
258 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
260 while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */
261 && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */
263 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
264 memcpy(stream, /* cur output position */
265 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */
266 length); /* cur input length */
269 stream += length; /* advance output */
270 len -= length; /* decrement avail ospace */
271 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */
272 mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */
273 mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */
275 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
276 mve_audio_bufhead = 0;
277 mve_audio_curbuf_curpos = 0;
280 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
283 if (len != 0 /* ospace remaining */
284 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
286 memcpy(stream, /* dest */
287 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
290 mve_audio_curbuf_curpos += len; /* advance input */
291 stream += len; /* advance output (unnecessary) */
292 len -= len; /* advance output (unnecessary) */
294 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
296 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */
297 mve_audio_buffers[mve_audio_bufhead]=NULL;
298 mve_audio_buflens[mve_audio_bufhead]=0;
300 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
301 mve_audio_bufhead = 0;
302 mve_audio_curbuf_curpos = 0;
306 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
310 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
323 if (!mve_audio_enabled)
326 if (audiobuf_created)
329 audiobuf_created = 1;
331 flags = get_ushort(data + 2);
332 sample_rate = get_ushort(data + 4);
333 desired_buffer = get_int(data + 6);
335 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
336 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
339 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
344 mve_audio_compressed = compressed;
347 #ifdef WORDS_BIGENDIAN
348 format = AUDIO_S16MSB;
350 format = AUDIO_S16LSB;
356 fprintf(stderr, "creating audio buffers:\n");
357 fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
358 sample_rate, stereo, bitsize ? 16 : 8, compressed);
360 mve_audio_spec = (SDL_AudioSpec *)mve_alloc(sizeof(SDL_AudioSpec));
361 mve_audio_spec->freq = sample_rate;
362 mve_audio_spec->format = format;
363 mve_audio_spec->channels = (stereo) ? 2 : 1;
364 mve_audio_spec->samples = 4096;
365 mve_audio_spec->callback = mve_audio_callback;
366 mve_audio_spec->userdata = NULL;
367 if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
369 fprintf(stderr, " success\n");
370 mve_audio_canplay = 1;
374 fprintf(stderr, " failure : %s\n", SDL_GetError());
375 mve_audio_canplay = 0;
378 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
379 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
385 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
388 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
391 mve_audio_playing = 1;
397 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
400 static const int selected_chan=1;
403 if (mve_audio_canplay)
405 if (mve_audio_playing)
408 chan = get_ushort(data + 2);
409 nsamp = get_ushort(data + 4);
410 if (chan & selected_chan)
412 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
413 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
414 if (mve_audio_compressed) {
417 mve_audio_buflens[mve_audio_buftail] = nsamp;
418 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
419 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
424 mve_audio_buflens[mve_audio_buftail] = nsamp;
425 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
426 memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
429 mve_audio_buflens[mve_audio_buftail] = nsamp;
430 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
432 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
435 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
436 mve_audio_buftail = 0;
438 if (mve_audio_buftail == mve_audio_bufhead)
439 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
442 if (mve_audio_playing)
450 /*************************
452 *************************/
454 static int videobuf_created = 0;
455 static int video_initialized = 0;
456 int g_width, g_height;
457 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
459 static int g_destX, g_destY;
460 static int g_screenWidth, g_screenHeight;
461 static unsigned char *g_pCurMap=NULL;
462 static int g_nMapLength=0;
463 static int g_truecolor;
465 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
468 short count, truecolor;
470 if (videobuf_created)
473 videobuf_created = 1;
476 h = get_short(data+2);
479 count = get_short(data+4);
485 truecolor = get_short(data+6);
493 /* TODO: * 4 causes crashes on some files */
494 /* only malloc once */
495 if (g_vBuffers == NULL)
496 g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
498 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
500 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
503 memset(g_vBackBuf1, 0, g_width * g_height * 4);
506 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
509 g_truecolor = truecolor;
514 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
516 if (g_destX == -1) // center it
517 g_destX = (g_screenWidth - g_width) >> 1;
518 if (g_destY == -1) // center it
519 g_destY = (g_screenHeight - g_height) >> 1;
521 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
522 g_width, g_height, g_destX, g_destY);
529 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
533 if (video_initialized)
536 video_initialized = 1;
538 width = get_short(data);
539 height = get_short(data+2);
540 g_screenWidth = width;
541 g_screenHeight = height;
546 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
551 start = get_short(data);
552 count = get_short(data+2);
556 mve_setpalette(p - 3*start, start, count);
561 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
568 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
570 short nFrameHot, nFrameCold;
571 short nXoffset, nYoffset;
572 short nXsize, nYsize;
573 unsigned short nFlags;
576 nFrameHot = get_short(data);
577 nFrameCold = get_short(data+2);
578 nXoffset = get_short(data+4);
579 nYoffset = get_short(data+6);
580 nXsize = get_short(data+8);
581 nYsize = get_short(data+10);
582 nFlags = get_ushort(data+12);
586 temp = (unsigned char *)g_vBackBuf1;
587 g_vBackBuf1 = g_vBackBuf2;
591 /* convert the frame */
593 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
595 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
601 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
608 static MVESTREAM *mve = NULL;
610 void MVE_ioCallbacks(mve_cb_Read io_read)
615 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
617 mve_alloc = mem_alloc;
621 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
623 mve_showframe = showframe;
626 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
628 mve_setpalette = setpalette;
631 int MVE_rmPrepMovie(void *src, int x, int y, int track)
648 for (i = 0; i < 32; i++)
649 mve_set_handler(mve, i, default_seg_handler);
651 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
652 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
653 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
654 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
655 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
656 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
658 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
659 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
660 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
661 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
663 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
664 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
666 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
668 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
670 mve_play_next_chunk(mve); /* video initialization chunk */
671 mve_play_next_chunk(mve); /* audio initialization chunk */
677 void MVE_getVideoSpec(MVE_videoSpec *vSpec)
679 vSpec->screenWidth = g_screenWidth;
680 vSpec->screenHeight = g_screenHeight;
681 vSpec->width = g_width;
682 vSpec->height = g_height;
683 vSpec->truecolor = g_truecolor;
687 int MVE_rmStepMovie()
689 static int init_timer=0;
695 while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
696 cont = mve_play_next_chunk(mve);
699 if (micro_frame_delay && !init_timer) {
712 void MVE_rmEndMovie()
722 if (mve_audio_canplay) {
723 // only close audio if we opened it
725 mve_audio_canplay = 0;
727 for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
728 if (mve_audio_buffers[i] != NULL)
729 mve_free(mve_audio_buffers[i]);
730 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
731 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
732 mve_audio_curbuf_curpos=0;
737 mve_audio_compressed=0;
739 mve_free(mve_audio_spec);
741 audiobuf_created = 0;
744 mve_free(g_vBuffers);
748 videobuf_created = 0;
749 video_initialized = 0;
756 void MVE_rmHoldMovie()
762 void MVE_sndInit(int x)
766 mve_audio_enabled = 0;
768 mve_audio_enabled = 1;