1 /* $Id: mveplay.c,v 1.16 2003-11-26 03:07:45 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 *************************/
108 static int timer_created = 0;
109 static int micro_frame_delay=0;
110 static int timer_started=0;
111 static struct timeval timer_expire = {0, 0};
113 #if !HAVE_STRUCT_TIMESPEC
116 long int tv_sec; /* Seconds. */
117 long int tv_nsec; /* Nanoseconds. */
121 #if defined(HAVE_DECL_NANOSLEEP) && !HAVE_DECL_NANOSLEEP
122 int nanosleep(struct timespec *ts, void *rem);
126 int gettimeofday(struct timeval *tv, void *tz)
128 static int counter = 0;
132 now = GetTickCount();
134 tv->tv_sec = now / 1000;
135 tv->tv_usec = (now % 1000) * 1000 + counter;
141 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
144 #ifndef _WIN32 //FIXME
145 __extension__ long long temp;
155 micro_frame_delay = get_int(data) * (int)get_short(data+4);
156 if (g_spdFactorNum != 0)
158 temp = micro_frame_delay;
159 temp *= g_spdFactorNum;
160 temp /= g_spdFactorDenom;
161 micro_frame_delay = (int)temp;
167 static void timer_stop(void)
169 timer_expire.tv_sec = 0;
170 timer_expire.tv_usec = 0;
174 static void timer_start(void)
177 gettimeofday(&timer_expire, NULL);
178 timer_expire.tv_usec += micro_frame_delay;
179 if (timer_expire.tv_usec > 1000000)
181 nsec = timer_expire.tv_usec / 1000000;
182 timer_expire.tv_sec += nsec;
183 timer_expire.tv_usec -= nsec*1000000;
188 static void do_timer_wait(void)
196 gettimeofday(&tv, NULL);
197 if (tv.tv_sec > timer_expire.tv_sec)
199 else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec)
202 ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
203 ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
206 ts.tv_nsec += 1000000000UL;
210 Sleep(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
212 if (nanosleep(&ts, NULL) == -1 && errno == EINTR)
217 timer_expire.tv_usec += micro_frame_delay;
218 if (timer_expire.tv_usec > 1000000)
220 nsec = timer_expire.tv_usec / 1000000;
221 timer_expire.tv_sec += nsec;
222 timer_expire.tv_usec -= nsec*1000000;
226 /*************************
228 *************************/
230 #define TOTAL_AUDIO_BUFFERS 64
232 static int audiobuf_created = 0;
233 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
234 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
235 static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
236 static int mve_audio_curbuf_curpos=0;
237 static int mve_audio_bufhead=0;
238 static int mve_audio_buftail=0;
239 static int mve_audio_playing=0;
240 static int mve_audio_canplay=0;
241 static int mve_audio_compressed=0;
242 static int mve_audio_enabled = 1;
243 static SDL_AudioSpec *mve_audio_spec=NULL;
245 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
249 if (mve_audio_bufhead == mve_audio_buftail)
252 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
254 while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */
255 && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */
257 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
258 memcpy(stream, /* cur output position */
259 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */
260 length); /* cur input length */
263 stream += length; /* advance output */
264 len -= length; /* decrement avail ospace */
265 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */
266 mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */
267 mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */
269 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
270 mve_audio_bufhead = 0;
271 mve_audio_curbuf_curpos = 0;
274 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
277 if (len != 0 /* ospace remaining */
278 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
280 memcpy(stream, /* dest */
281 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
284 mve_audio_curbuf_curpos += len; /* advance input */
285 stream += len; /* advance output (unnecessary) */
286 len -= len; /* advance output (unnecessary) */
288 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
290 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */
291 mve_audio_buffers[mve_audio_bufhead]=NULL;
292 mve_audio_buflens[mve_audio_bufhead]=0;
294 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
295 mve_audio_bufhead = 0;
296 mve_audio_curbuf_curpos = 0;
300 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
304 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
317 if (!mve_audio_enabled)
320 if (audiobuf_created)
323 audiobuf_created = 1;
325 flags = get_ushort(data + 2);
326 sample_rate = get_ushort(data + 4);
327 desired_buffer = get_int(data + 6);
329 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
330 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
333 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
338 mve_audio_compressed = compressed;
341 #ifdef WORDS_BIGENDIAN
342 format = AUDIO_S16MSB;
344 format = AUDIO_S16LSB;
350 fprintf(stderr, "creating audio buffers:\n");
351 fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
352 sample_rate, stereo, bitsize ? 16 : 8, compressed);
354 mve_audio_spec = (SDL_AudioSpec *)mve_alloc(sizeof(SDL_AudioSpec));
355 mve_audio_spec->freq = sample_rate;
356 mve_audio_spec->format = format;
357 mve_audio_spec->channels = (stereo) ? 2 : 1;
358 mve_audio_spec->samples = 4096;
359 mve_audio_spec->callback = mve_audio_callback;
360 mve_audio_spec->userdata = NULL;
361 if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
363 fprintf(stderr, " success\n");
364 mve_audio_canplay = 1;
368 fprintf(stderr, " failure : %s\n", SDL_GetError());
369 mve_audio_canplay = 0;
372 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
373 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
379 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
382 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
385 mve_audio_playing = 1;
391 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
394 static const int selected_chan=1;
397 if (mve_audio_canplay)
399 if (mve_audio_playing)
402 chan = get_ushort(data + 2);
403 nsamp = get_ushort(data + 4);
404 if (chan & selected_chan)
406 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
407 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
408 if (mve_audio_compressed) {
411 mve_audio_buflens[mve_audio_buftail] = nsamp;
412 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
413 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
418 mve_audio_buflens[mve_audio_buftail] = nsamp;
419 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
420 memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
423 mve_audio_buflens[mve_audio_buftail] = nsamp;
424 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
426 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
429 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
430 mve_audio_buftail = 0;
432 if (mve_audio_buftail == mve_audio_bufhead)
433 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
436 if (mve_audio_playing)
444 /*************************
446 *************************/
448 static int videobuf_created = 0;
449 static int video_initialized = 0;
450 int g_width, g_height;
451 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
453 static int g_destX, g_destY;
454 static int g_screenWidth, g_screenHeight;
455 static unsigned char *g_pCurMap=NULL;
456 static int g_nMapLength=0;
457 static int g_truecolor;
459 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
462 short count, truecolor;
464 if (videobuf_created)
467 videobuf_created = 1;
470 h = get_short(data+2);
473 count = get_short(data+4);
479 truecolor = get_short(data+6);
487 /* TODO: * 4 causes crashes on some files */
488 /* only malloc once */
489 if (g_vBuffers == NULL)
490 g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
492 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
494 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
497 memset(g_vBackBuf1, 0, g_width * g_height * 4);
500 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
503 g_truecolor = truecolor;
508 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
510 if (g_destX == -1) // center it
511 g_destX = (g_screenWidth - g_width) >> 1;
512 if (g_destY == -1) // center it
513 g_destY = (g_screenHeight - g_height) >> 1;
515 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
516 g_width, g_height, g_destX, g_destY);
523 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
527 if (video_initialized)
530 video_initialized = 1;
532 width = get_short(data);
533 height = get_short(data+2);
534 g_screenWidth = width;
535 g_screenHeight = height;
540 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
545 start = get_short(data);
546 count = get_short(data+2);
550 mve_setpalette(p - 3*start, start, count);
555 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
562 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
564 short nFrameHot, nFrameCold;
565 short nXoffset, nYoffset;
566 short nXsize, nYsize;
567 unsigned short nFlags;
570 nFrameHot = get_short(data);
571 nFrameCold = get_short(data+2);
572 nXoffset = get_short(data+4);
573 nYoffset = get_short(data+6);
574 nXsize = get_short(data+8);
575 nYsize = get_short(data+10);
576 nFlags = get_ushort(data+12);
580 temp = (unsigned char *)g_vBackBuf1;
581 g_vBackBuf1 = g_vBackBuf2;
585 /* convert the frame */
587 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
589 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
595 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
602 static MVESTREAM *mve = NULL;
604 void MVE_ioCallbacks(mve_cb_Read io_read)
609 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
611 mve_alloc = mem_alloc;
615 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
617 mve_showframe = showframe;
620 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
622 mve_setpalette = setpalette;
625 int MVE_rmPrepMovie(void *src, int x, int y, int track)
642 for (i = 0; i < 32; i++)
643 mve_set_handler(mve, i, default_seg_handler);
645 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
646 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
647 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
648 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
649 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
650 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
652 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
653 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
654 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
655 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
657 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
658 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
660 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
662 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
664 mve_play_next_chunk(mve); /* video initialization chunk */
665 mve_play_next_chunk(mve); /* audio initialization chunk */
671 void MVE_getVideoSpec(MVE_videoSpec *vSpec)
673 vSpec->screenWidth = g_screenWidth;
674 vSpec->screenHeight = g_screenHeight;
675 vSpec->width = g_width;
676 vSpec->height = g_height;
677 vSpec->truecolor = g_truecolor;
681 int MVE_rmStepMovie()
683 static int init_timer=0;
689 while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
690 cont = mve_play_next_chunk(mve);
693 if (micro_frame_delay && !init_timer) {
706 void MVE_rmEndMovie()
716 if (mve_audio_canplay) {
717 // only close audio if we opened it
719 mve_audio_canplay = 0;
721 for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
722 if (mve_audio_buffers[i] != NULL)
723 mve_free(mve_audio_buffers[i]);
724 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
725 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
726 mve_audio_curbuf_curpos=0;
731 mve_audio_compressed=0;
733 mve_free(mve_audio_spec);
735 audiobuf_created = 0;
738 mve_free(g_vBuffers);
742 videobuf_created = 0;
743 video_initialized = 0;
750 void MVE_rmHoldMovie()
756 void MVE_sndInit(int x)
760 mve_audio_enabled = 0;
762 mve_audio_enabled = 1;