21 # include <sys/time.h>
22 # include <sys/types.h>
23 # include <sys/stat.h>
30 #include "SDL_mixer.h"
34 #include "mve_audio.h"
40 #define MVE_OPCODE_ENDOFSTREAM 0x00
41 #define MVE_OPCODE_ENDOFCHUNK 0x01
42 #define MVE_OPCODE_CREATETIMER 0x02
43 #define MVE_OPCODE_INITAUDIOBUFFERS 0x03
44 #define MVE_OPCODE_STARTSTOPAUDIO 0x04
45 #define MVE_OPCODE_INITVIDEOBUFFERS 0x05
47 #define MVE_OPCODE_DISPLAYVIDEO 0x07
48 #define MVE_OPCODE_AUDIOFRAMEDATA 0x08
49 #define MVE_OPCODE_AUDIOFRAMESILENCE 0x09
50 #define MVE_OPCODE_INITVIDEOMODE 0x0A
52 #define MVE_OPCODE_SETPALETTE 0x0C
53 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
55 #define MVE_OPCODE_SETDECODINGMAP 0x0F
57 #define MVE_OPCODE_VIDEODATA 0x11
59 #define MVE_AUDIO_FLAGS_STEREO 1
60 #define MVE_AUDIO_FLAGS_16BIT 2
61 #define MVE_AUDIO_FLAGS_COMPRESSED 4
64 static int g_spdFactorDenom=10;
65 static int g_frameUpdated = 0;
67 static short get_short(unsigned char *data)
70 value = data[0] | (data[1] << 8);
74 static unsigned short get_ushort(unsigned char *data)
77 value = data[0] | (data[1] << 8);
81 static int get_int(unsigned char *data)
84 value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
88 static unsigned int unhandled_chunks[32*256];
90 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
92 unhandled_chunks[major<<8|minor]++;
93 //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
98 /*************************
100 *************************/
101 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
106 /*************************
108 *************************/
110 #if !defined(HAVE_STRUCT_TIMEVAL) || !HAVE_STRUCT_TIMEVAL // ifdef _WIN32_WCE
121 static int timer_created = 0;
122 static int micro_frame_delay=0;
123 static int timer_started=0;
124 static struct timeval timer_expire = {0, 0};
126 #if !defined(HAVE_STRUCT_TIMESPEC) || !HAVE_STRUCT_TIMESPEC
129 long int tv_sec; /* Seconds. */
130 long int tv_nsec; /* Nanoseconds. */
134 #if defined(_WIN32) || defined(macintosh)
135 int gettimeofday(struct timeval *tv, void *tz)
137 static int counter = 0;
139 DWORD now = GetTickCount();
141 long now = TickCount();
145 tv->tv_sec = now / 1000;
146 tv->tv_usec = (now % 1000) * 1000 + counter;
150 #endif // defined(_WIN32) || defined(macintosh)
153 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
156 #if !defined(_WIN32) && !defined(macintosh) // FIXME
157 __extension__ long long temp;
167 micro_frame_delay = get_int(data) * (int)get_short(data+4);
168 if (g_spdFactorNum != 0)
170 temp = micro_frame_delay;
171 temp *= g_spdFactorNum;
172 temp /= g_spdFactorDenom;
173 micro_frame_delay = (int)temp;
179 static void timer_stop(void)
181 timer_expire.tv_sec = 0;
182 timer_expire.tv_usec = 0;
186 static void timer_start(void)
189 gettimeofday(&timer_expire, NULL);
190 timer_expire.tv_usec += micro_frame_delay;
191 if (timer_expire.tv_usec > 1000000)
193 nsec = timer_expire.tv_usec / 1000000;
194 timer_expire.tv_sec += nsec;
195 timer_expire.tv_usec -= nsec*1000000;
200 static void do_timer_wait(void)
208 gettimeofday(&tv, NULL);
209 if (tv.tv_sec > timer_expire.tv_sec)
211 else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec)
214 ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
215 ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
218 ts.tv_nsec += 1000000000UL;
222 Sleep(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
223 #elif defined(macintosh)
224 Delay(ts.tv_sec * 1000 + ts.tv_nsec / 1000000, NULL);
226 if (nanosleep(&ts, NULL) == -1 && errno == EINTR)
231 timer_expire.tv_usec += micro_frame_delay;
232 if (timer_expire.tv_usec > 1000000)
234 nsec = timer_expire.tv_usec / 1000000;
235 timer_expire.tv_sec += nsec;
236 timer_expire.tv_usec -= nsec*1000000;
240 /*************************
242 *************************/
244 #define TOTAL_AUDIO_BUFFERS 64
246 static int audiobuf_created = 0;
247 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
248 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
249 static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
250 static int mve_audio_curbuf_curpos=0;
251 static int mve_audio_bufhead=0;
252 static int mve_audio_buftail=0;
253 static int mve_audio_playing=0;
254 static int mve_audio_canplay=0;
255 static int mve_audio_compressed=0;
256 static int mve_audio_enabled = 1;
259 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
263 if (mve_audio_bufhead == mve_audio_buftail)
266 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
268 while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */
269 && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */
271 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
272 memcpy(stream, /* cur output position */
273 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */
274 length); /* cur input length */
277 stream += length; /* advance output */
278 len -= length; /* decrement avail ospace */
279 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */
280 mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */
281 mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */
283 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
284 mve_audio_bufhead = 0;
285 mve_audio_curbuf_curpos = 0;
288 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
291 if (len != 0 /* ospace remaining */
292 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
294 memcpy(stream, /* dest */
295 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
298 mve_audio_curbuf_curpos += len; /* advance input */
299 stream += len; /* advance output (unnecessary) */
300 len -= len; /* advance output (unnecessary) */
302 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
304 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */
305 mve_audio_buffers[mve_audio_bufhead]=NULL;
306 mve_audio_buflens[mve_audio_bufhead]=0;
308 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
309 mve_audio_bufhead = 0;
310 mve_audio_curbuf_curpos = 0;
314 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
318 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
331 if (!mve_audio_enabled)
334 if (audiobuf_created)
337 audiobuf_created = 1;
339 flags = get_ushort(data + 2);
340 sample_rate = get_ushort(data + 4);
341 desired_buffer = get_int(data + 6);
343 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
344 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
347 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
352 mve_audio_compressed = compressed;
355 #ifdef WORDS_BIGENDIAN
356 format = AUDIO_S16MSB;
358 format = AUDIO_S16LSB;
364 fprintf(stderr, "creating audio buffers:\n");
365 fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
366 sample_rate, stereo, bitsize ? 16 : 8, compressed);
368 if (!Mix_OpenAudio(sample_rate, format, stereo ? 2 : 1, 4096) >= 0)
370 fprintf(stderr, " success\n");
371 mve_audio_canplay = 1;
375 fprintf(stderr, " failure : %s\n", Mix_GetError());
376 mve_audio_canplay = 0;
379 Mix_SetPostMix(mve_audio_callback, NULL);
380 mve_audio_canplay = 1;
382 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
383 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
389 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
392 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
395 mve_audio_playing = 1;
401 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
404 static const int selected_chan=1;
407 if (mve_audio_canplay)
409 chan = get_ushort(data + 2);
410 nsamp = get_ushort(data + 4);
411 if (chan & selected_chan)
413 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
414 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
415 if (mve_audio_compressed) {
418 mve_audio_buflens[mve_audio_buftail] = nsamp;
419 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
420 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
425 mve_audio_buflens[mve_audio_buftail] = nsamp;
426 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
427 memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
430 mve_audio_buflens[mve_audio_buftail] = nsamp;
431 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
433 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
436 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
437 mve_audio_buftail = 0;
439 if (mve_audio_buftail == mve_audio_bufhead)
440 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
448 /*************************
450 *************************/
452 static int videobuf_created = 0;
453 static int video_initialized = 0;
454 int g_width, g_height;
455 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
457 static int g_destX, g_destY;
458 static int g_screenWidth, g_screenHeight;
459 static unsigned char *g_pCurMap=NULL;
460 static int g_nMapLength=0;
461 static int g_truecolor;
463 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
466 short count, truecolor;
468 if (videobuf_created)
471 videobuf_created = 1;
474 h = get_short(data+2);
477 count = get_short(data+4);
483 truecolor = get_short(data+6);
491 /* TODO: * 4 causes crashes on some files */
492 /* only malloc once */
493 if (g_vBuffers == NULL)
494 g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
496 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
498 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
501 memset(g_vBackBuf1, 0, g_width * g_height * 4);
504 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
507 g_truecolor = truecolor;
512 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
514 if (g_destX == -1) // center it
515 g_destX = (g_screenWidth - g_width) >> 1;
516 if (g_destY == -1) // center it
517 g_destY = (g_screenHeight - g_height) >> 1;
519 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
520 g_width, g_height, g_destX, g_destY);
527 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
531 if (video_initialized)
532 return 1; /* maybe we actually need to change width/height here? */
534 video_initialized = 1;
536 width = get_short(data);
537 height = get_short(data+2);
538 g_screenWidth = width;
539 g_screenHeight = height;
544 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
549 start = get_short(data);
550 count = get_short(data+2);
554 mve_setpalette(p - 3*start, start, count);
559 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
566 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
568 short nFrameHot, nFrameCold;
569 short nXoffset, nYoffset;
570 short nXsize, nYsize;
571 unsigned short nFlags;
574 nFrameHot = get_short(data);
575 nFrameCold = get_short(data+2);
576 nXoffset = get_short(data+4);
577 nYoffset = get_short(data+6);
578 nXsize = get_short(data+8);
579 nYsize = get_short(data+10);
580 nFlags = get_ushort(data+12);
584 temp = (unsigned char *)g_vBackBuf1;
585 g_vBackBuf1 = g_vBackBuf2;
589 /* convert the frame */
591 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
593 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
599 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
606 static MVESTREAM *mve = NULL;
608 void MVE_ioCallbacks(mve_cb_Read io_read)
613 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
615 mve_alloc = mem_alloc;
619 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
621 mve_showframe = showframe;
624 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
626 mve_setpalette = setpalette;
629 int MVE_rmPrepMovie(void *src, int x, int y, int track)
646 for (i = 0; i < 32; i++)
647 mve_set_handler(mve, i, default_seg_handler);
649 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
650 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
651 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
652 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
653 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
654 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
656 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
657 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
658 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
659 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
661 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
662 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
664 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
666 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
668 mve_play_next_chunk(mve); /* video initialization chunk */
669 if (mve_audio_enabled)
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);
701 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;
737 audiobuf_created = 0;
740 mve_free(g_vBuffers);
744 videobuf_created = 0;
745 video_initialized = 0;
752 void MVE_rmHoldMovie()
758 void MVE_sndInit(int x)
762 mve_audio_enabled = 0;
764 mve_audio_enabled = 1;