1 /* $Id: mveplay.c,v 1.17 2003-11-26 12:26:28 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 *************************/
116 static int timer_created = 0;
117 static int micro_frame_delay=0;
118 static int timer_started=0;
119 static struct timeval timer_expire = {0, 0};
121 #if !HAVE_STRUCT_TIMESPEC
124 long int tv_sec; /* Seconds. */
125 long int tv_nsec; /* Nanoseconds. */
130 int gettimeofday(struct timeval *tv, void *tz)
132 static int counter = 0;
136 now = GetTickCount();
138 tv->tv_sec = now / 1000;
139 tv->tv_usec = (now % 1000) * 1000 + counter;
146 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
149 #ifndef _WIN32 //FIXME
150 __extension__ long long temp;
160 micro_frame_delay = get_int(data) * (int)get_short(data+4);
161 if (g_spdFactorNum != 0)
163 temp = micro_frame_delay;
164 temp *= g_spdFactorNum;
165 temp /= g_spdFactorDenom;
166 micro_frame_delay = (int)temp;
172 static void timer_stop(void)
174 timer_expire.tv_sec = 0;
175 timer_expire.tv_usec = 0;
179 static void timer_start(void)
182 gettimeofday(&timer_expire, NULL);
183 timer_expire.tv_usec += micro_frame_delay;
184 if (timer_expire.tv_usec > 1000000)
186 nsec = timer_expire.tv_usec / 1000000;
187 timer_expire.tv_sec += nsec;
188 timer_expire.tv_usec -= nsec*1000000;
193 static void do_timer_wait(void)
201 gettimeofday(&tv, NULL);
202 if (tv.tv_sec > timer_expire.tv_sec)
204 else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec)
207 ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
208 ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
211 ts.tv_nsec += 1000000000UL;
215 Sleep(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
217 if (nanosleep(&ts, NULL) == -1 && errno == EINTR)
222 timer_expire.tv_usec += micro_frame_delay;
223 if (timer_expire.tv_usec > 1000000)
225 nsec = timer_expire.tv_usec / 1000000;
226 timer_expire.tv_sec += nsec;
227 timer_expire.tv_usec -= nsec*1000000;
231 /*************************
233 *************************/
235 #define TOTAL_AUDIO_BUFFERS 64
237 static int audiobuf_created = 0;
238 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
239 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
240 static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
241 static int mve_audio_curbuf_curpos=0;
242 static int mve_audio_bufhead=0;
243 static int mve_audio_buftail=0;
244 static int mve_audio_playing=0;
245 static int mve_audio_canplay=0;
246 static int mve_audio_compressed=0;
247 static int mve_audio_enabled = 1;
248 static SDL_AudioSpec *mve_audio_spec=NULL;
250 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
254 if (mve_audio_bufhead == mve_audio_buftail)
257 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
259 while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */
260 && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */
262 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
263 memcpy(stream, /* cur output position */
264 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */
265 length); /* cur input length */
268 stream += length; /* advance output */
269 len -= length; /* decrement avail ospace */
270 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */
271 mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */
272 mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */
274 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
275 mve_audio_bufhead = 0;
276 mve_audio_curbuf_curpos = 0;
279 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
282 if (len != 0 /* ospace remaining */
283 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
285 memcpy(stream, /* dest */
286 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
289 mve_audio_curbuf_curpos += len; /* advance input */
290 stream += len; /* advance output (unnecessary) */
291 len -= len; /* advance output (unnecessary) */
293 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
295 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */
296 mve_audio_buffers[mve_audio_bufhead]=NULL;
297 mve_audio_buflens[mve_audio_bufhead]=0;
299 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
300 mve_audio_bufhead = 0;
301 mve_audio_curbuf_curpos = 0;
305 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
309 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
322 if (!mve_audio_enabled)
325 if (audiobuf_created)
328 audiobuf_created = 1;
330 flags = get_ushort(data + 2);
331 sample_rate = get_ushort(data + 4);
332 desired_buffer = get_int(data + 6);
334 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
335 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
338 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
343 mve_audio_compressed = compressed;
346 #ifdef WORDS_BIGENDIAN
347 format = AUDIO_S16MSB;
349 format = AUDIO_S16LSB;
355 fprintf(stderr, "creating audio buffers:\n");
356 fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
357 sample_rate, stereo, bitsize ? 16 : 8, compressed);
359 mve_audio_spec = (SDL_AudioSpec *)mve_alloc(sizeof(SDL_AudioSpec));
360 mve_audio_spec->freq = sample_rate;
361 mve_audio_spec->format = format;
362 mve_audio_spec->channels = (stereo) ? 2 : 1;
363 mve_audio_spec->samples = 4096;
364 mve_audio_spec->callback = mve_audio_callback;
365 mve_audio_spec->userdata = NULL;
366 if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
368 fprintf(stderr, " success\n");
369 mve_audio_canplay = 1;
373 fprintf(stderr, " failure : %s\n", SDL_GetError());
374 mve_audio_canplay = 0;
377 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
378 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
384 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
387 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
390 mve_audio_playing = 1;
396 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
399 static const int selected_chan=1;
402 if (mve_audio_canplay)
404 if (mve_audio_playing)
407 chan = get_ushort(data + 2);
408 nsamp = get_ushort(data + 4);
409 if (chan & selected_chan)
411 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
412 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
413 if (mve_audio_compressed) {
416 mve_audio_buflens[mve_audio_buftail] = nsamp;
417 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
418 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
423 mve_audio_buflens[mve_audio_buftail] = nsamp;
424 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
425 memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
428 mve_audio_buflens[mve_audio_buftail] = nsamp;
429 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
431 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
434 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
435 mve_audio_buftail = 0;
437 if (mve_audio_buftail == mve_audio_bufhead)
438 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
441 if (mve_audio_playing)
449 /*************************
451 *************************/
453 static int videobuf_created = 0;
454 static int video_initialized = 0;
455 int g_width, g_height;
456 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
458 static int g_destX, g_destY;
459 static int g_screenWidth, g_screenHeight;
460 static unsigned char *g_pCurMap=NULL;
461 static int g_nMapLength=0;
462 static int g_truecolor;
464 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
467 short count, truecolor;
469 if (videobuf_created)
472 videobuf_created = 1;
475 h = get_short(data+2);
478 count = get_short(data+4);
484 truecolor = get_short(data+6);
492 /* TODO: * 4 causes crashes on some files */
493 /* only malloc once */
494 if (g_vBuffers == NULL)
495 g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
497 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
499 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
502 memset(g_vBackBuf1, 0, g_width * g_height * 4);
505 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
508 g_truecolor = truecolor;
513 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
515 if (g_destX == -1) // center it
516 g_destX = (g_screenWidth - g_width) >> 1;
517 if (g_destY == -1) // center it
518 g_destY = (g_screenHeight - g_height) >> 1;
520 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
521 g_width, g_height, g_destX, g_destY);
528 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
532 if (video_initialized)
533 return 1; /* maybe we actually need to change width/height here? */
535 video_initialized = 1;
537 width = get_short(data);
538 height = get_short(data+2);
539 g_screenWidth = width;
540 g_screenHeight = height;
545 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
550 start = get_short(data);
551 count = get_short(data+2);
555 mve_setpalette(p - 3*start, start, count);
560 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
567 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
569 short nFrameHot, nFrameCold;
570 short nXoffset, nYoffset;
571 short nXsize, nYsize;
572 unsigned short nFlags;
575 nFrameHot = get_short(data);
576 nFrameCold = get_short(data+2);
577 nXoffset = get_short(data+4);
578 nYoffset = get_short(data+6);
579 nXsize = get_short(data+8);
580 nYsize = get_short(data+10);
581 nFlags = get_ushort(data+12);
585 temp = (unsigned char *)g_vBackBuf1;
586 g_vBackBuf1 = g_vBackBuf2;
590 /* convert the frame */
592 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
594 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
600 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
607 static MVESTREAM *mve = NULL;
609 void MVE_ioCallbacks(mve_cb_Read io_read)
614 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
616 mve_alloc = mem_alloc;
620 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
622 mve_showframe = showframe;
625 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
627 mve_setpalette = setpalette;
630 int MVE_rmPrepMovie(void *src, int x, int y, int track)
647 for (i = 0; i < 32; i++)
648 mve_set_handler(mve, i, default_seg_handler);
650 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
651 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
652 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
653 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
654 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
655 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
657 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
658 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
659 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
660 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
662 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
663 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
665 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
667 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
669 mve_play_next_chunk(mve); /* video initialization chunk */
670 mve_play_next_chunk(mve); /* audio initialization chunk */
676 void MVE_getVideoSpec(MVE_videoSpec *vSpec)
678 vSpec->screenWidth = g_screenWidth;
679 vSpec->screenHeight = g_screenHeight;
680 vSpec->width = g_width;
681 vSpec->height = g_height;
682 vSpec->truecolor = g_truecolor;
686 int MVE_rmStepMovie()
688 static int init_timer=0;
694 while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
695 cont = mve_play_next_chunk(mve);
698 if (micro_frame_delay && !init_timer) {
711 void MVE_rmEndMovie()
721 if (mve_audio_canplay) {
722 // only close audio if we opened it
724 mve_audio_canplay = 0;
726 for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
727 if (mve_audio_buffers[i] != NULL)
728 mve_free(mve_audio_buffers[i]);
729 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
730 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
731 mve_audio_curbuf_curpos=0;
736 mve_audio_compressed=0;
738 mve_free(mve_audio_spec);
740 audiobuf_created = 0;
743 mve_free(g_vBuffers);
747 videobuf_created = 0;
748 video_initialized = 0;
755 void MVE_rmHoldMovie()
761 void MVE_sndInit(int x)
765 mve_audio_enabled = 0;
767 mve_audio_enabled = 1;