21 # include <sys/time.h>
22 # include <sys/types.h>
23 # include <sys/stat.h>
33 #include "mve_audio.h"
39 #define MVE_OPCODE_ENDOFSTREAM 0x00
40 #define MVE_OPCODE_ENDOFCHUNK 0x01
41 #define MVE_OPCODE_CREATETIMER 0x02
42 #define MVE_OPCODE_INITAUDIOBUFFERS 0x03
43 #define MVE_OPCODE_STARTSTOPAUDIO 0x04
44 #define MVE_OPCODE_INITVIDEOBUFFERS 0x05
46 #define MVE_OPCODE_DISPLAYVIDEO 0x07
47 #define MVE_OPCODE_AUDIOFRAMEDATA 0x08
48 #define MVE_OPCODE_AUDIOFRAMESILENCE 0x09
49 #define MVE_OPCODE_INITVIDEOMODE 0x0A
51 #define MVE_OPCODE_SETPALETTE 0x0C
52 #define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D
54 #define MVE_OPCODE_SETDECODINGMAP 0x0F
56 #define MVE_OPCODE_VIDEODATA 0x11
58 #define MVE_AUDIO_FLAGS_STEREO 1
59 #define MVE_AUDIO_FLAGS_16BIT 2
60 #define MVE_AUDIO_FLAGS_COMPRESSED 4
63 static int g_spdFactorDenom=10;
64 static int g_frameUpdated = 0;
66 static short get_short(unsigned char *data)
69 value = data[0] | (data[1] << 8);
73 static unsigned short get_ushort(unsigned char *data)
76 value = data[0] | (data[1] << 8);
80 static int get_int(unsigned char *data)
83 value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
87 static unsigned int unhandled_chunks[32*256];
89 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
91 unhandled_chunks[major<<8|minor]++;
92 //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
97 /*************************
99 *************************/
100 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
105 /*************************
107 *************************/
109 #if !defined(HAVE_STRUCT_TIMEVAL) || !HAVE_STRUCT_TIMEVAL // ifdef _WIN32_WCE
120 static int timer_created = 0;
121 static int micro_frame_delay=0;
122 static int timer_started=0;
123 static struct timeval timer_expire = {0, 0};
125 #if !defined(HAVE_STRUCT_TIMESPEC) || !HAVE_STRUCT_TIMESPEC
128 long int tv_sec; /* Seconds. */
129 long int tv_nsec; /* Nanoseconds. */
133 #if defined(_WIN32) || defined(macintosh)
134 int gettimeofday(struct timeval *tv, void *tz)
136 static int counter = 0;
138 DWORD now = GetTickCount();
140 long now = TickCount();
144 tv->tv_sec = now / 1000;
145 tv->tv_usec = (now % 1000) * 1000 + counter;
149 #endif // defined(_WIN32) || defined(macintosh)
152 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
155 #if !defined(_WIN32) && !defined(macintosh) // FIXME
156 __extension__ long long temp;
166 micro_frame_delay = get_int(data) * (int)get_short(data+4);
167 if (g_spdFactorNum != 0)
169 temp = micro_frame_delay;
170 temp *= g_spdFactorNum;
171 temp /= g_spdFactorDenom;
172 micro_frame_delay = (int)temp;
178 static void timer_stop(void)
180 timer_expire.tv_sec = 0;
181 timer_expire.tv_usec = 0;
185 static void timer_start(void)
188 gettimeofday(&timer_expire, NULL);
189 timer_expire.tv_usec += micro_frame_delay;
190 if (timer_expire.tv_usec > 1000000)
192 nsec = timer_expire.tv_usec / 1000000;
193 timer_expire.tv_sec += nsec;
194 timer_expire.tv_usec -= nsec*1000000;
199 static void do_timer_wait(void)
207 gettimeofday(&tv, NULL);
208 if (tv.tv_sec > timer_expire.tv_sec)
210 else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec)
213 ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
214 ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
217 ts.tv_nsec += 1000000000UL;
221 Sleep(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
222 #elif defined(macintosh)
223 Delay(ts.tv_sec * 1000 + ts.tv_nsec / 1000000, NULL);
225 if (nanosleep(&ts, NULL) == -1 && errno == EINTR)
230 timer_expire.tv_usec += micro_frame_delay;
231 if (timer_expire.tv_usec > 1000000)
233 nsec = timer_expire.tv_usec / 1000000;
234 timer_expire.tv_sec += nsec;
235 timer_expire.tv_usec -= nsec*1000000;
239 /*************************
241 *************************/
243 #define TOTAL_AUDIO_BUFFERS 64
245 static int audiobuf_created = 0;
246 static void mve_audio_callback(void *userdata, unsigned char *stream, int len);
247 static short *mve_audio_buffers[TOTAL_AUDIO_BUFFERS];
248 static int mve_audio_buflens[TOTAL_AUDIO_BUFFERS];
249 static int mve_audio_curbuf_curpos=0;
250 static int mve_audio_bufhead=0;
251 static int mve_audio_buftail=0;
252 static int mve_audio_playing=0;
253 static int mve_audio_canplay=0;
254 static int mve_audio_compressed=0;
255 static int mve_audio_enabled = 1;
256 static SDL_AudioSpec *mve_audio_spec=NULL;
258 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
262 if (mve_audio_bufhead == mve_audio_buftail)
265 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
267 while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */
268 && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */
270 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
271 memcpy(stream, /* cur output position */
272 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */
273 length); /* cur input length */
276 stream += length; /* advance output */
277 len -= length; /* decrement avail ospace */
278 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */
279 mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */
280 mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */
282 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
283 mve_audio_bufhead = 0;
284 mve_audio_curbuf_curpos = 0;
287 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
290 if (len != 0 /* ospace remaining */
291 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
293 memcpy(stream, /* dest */
294 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
297 mve_audio_curbuf_curpos += len; /* advance input */
298 stream += len; /* advance output (unnecessary) */
299 len -= len; /* advance output (unnecessary) */
301 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
303 mve_free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */
304 mve_audio_buffers[mve_audio_bufhead]=NULL;
305 mve_audio_buflens[mve_audio_bufhead]=0;
307 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
308 mve_audio_bufhead = 0;
309 mve_audio_curbuf_curpos = 0;
313 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
317 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
330 if (!mve_audio_enabled)
333 if (audiobuf_created)
336 audiobuf_created = 1;
338 flags = get_ushort(data + 2);
339 sample_rate = get_ushort(data + 4);
340 desired_buffer = get_int(data + 6);
342 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
343 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
346 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
351 mve_audio_compressed = compressed;
354 #ifdef WORDS_BIGENDIAN
355 format = AUDIO_S16MSB;
357 format = AUDIO_S16LSB;
363 fprintf(stderr, "creating audio buffers:\n");
364 fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
365 sample_rate, stereo, bitsize ? 16 : 8, compressed);
367 mve_audio_spec = (SDL_AudioSpec *)mve_alloc(sizeof(SDL_AudioSpec));
368 mve_audio_spec->freq = sample_rate;
369 mve_audio_spec->format = format;
370 mve_audio_spec->channels = (stereo) ? 2 : 1;
371 mve_audio_spec->samples = 4096;
372 mve_audio_spec->callback = mve_audio_callback;
373 mve_audio_spec->userdata = NULL;
374 if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
376 fprintf(stderr, " success\n");
377 mve_audio_canplay = 1;
381 fprintf(stderr, " failure : %s\n", SDL_GetError());
382 mve_audio_canplay = 0;
385 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
386 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
392 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
395 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
398 mve_audio_playing = 1;
404 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
407 static const int selected_chan=1;
410 if (mve_audio_canplay)
412 if (mve_audio_playing)
415 chan = get_ushort(data + 2);
416 nsamp = get_ushort(data + 4);
417 if (chan & selected_chan)
419 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
420 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
421 if (mve_audio_compressed) {
424 mve_audio_buflens[mve_audio_buftail] = nsamp;
425 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
426 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
431 mve_audio_buflens[mve_audio_buftail] = nsamp;
432 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
433 memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
436 mve_audio_buflens[mve_audio_buftail] = nsamp;
437 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
439 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
442 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
443 mve_audio_buftail = 0;
445 if (mve_audio_buftail == mve_audio_bufhead)
446 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
449 if (mve_audio_playing)
457 /*************************
459 *************************/
461 static int videobuf_created = 0;
462 static int video_initialized = 0;
463 int g_width, g_height;
464 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
466 static int g_destX, g_destY;
467 static int g_screenWidth, g_screenHeight;
468 static unsigned char *g_pCurMap=NULL;
469 static int g_nMapLength=0;
470 static int g_truecolor;
472 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
475 short count, truecolor;
477 if (videobuf_created)
480 videobuf_created = 1;
483 h = get_short(data+2);
486 count = get_short(data+4);
492 truecolor = get_short(data+6);
500 /* TODO: * 4 causes crashes on some files */
501 /* only malloc once */
502 if (g_vBuffers == NULL)
503 g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
505 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
507 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
510 memset(g_vBackBuf1, 0, g_width * g_height * 4);
513 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
516 g_truecolor = truecolor;
521 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
523 if (g_destX == -1) // center it
524 g_destX = (g_screenWidth - g_width) >> 1;
525 if (g_destY == -1) // center it
526 g_destY = (g_screenHeight - g_height) >> 1;
528 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
529 g_width, g_height, g_destX, g_destY);
536 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
540 if (video_initialized)
541 return 1; /* maybe we actually need to change width/height here? */
543 video_initialized = 1;
545 width = get_short(data);
546 height = get_short(data+2);
547 g_screenWidth = width;
548 g_screenHeight = height;
553 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
558 start = get_short(data);
559 count = get_short(data+2);
563 mve_setpalette(p - 3*start, start, count);
568 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
575 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
577 short nFrameHot, nFrameCold;
578 short nXoffset, nYoffset;
579 short nXsize, nYsize;
580 unsigned short nFlags;
583 nFrameHot = get_short(data);
584 nFrameCold = get_short(data+2);
585 nXoffset = get_short(data+4);
586 nYoffset = get_short(data+6);
587 nXsize = get_short(data+8);
588 nYsize = get_short(data+10);
589 nFlags = get_ushort(data+12);
593 temp = (unsigned char *)g_vBackBuf1;
594 g_vBackBuf1 = g_vBackBuf2;
598 /* convert the frame */
600 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
602 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
608 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
615 static MVESTREAM *mve = NULL;
617 void MVE_ioCallbacks(mve_cb_Read io_read)
622 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
624 mve_alloc = mem_alloc;
628 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
630 mve_showframe = showframe;
633 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
635 mve_setpalette = setpalette;
638 int MVE_rmPrepMovie(void *src, int x, int y, int track)
655 for (i = 0; i < 32; i++)
656 mve_set_handler(mve, i, default_seg_handler);
658 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
659 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
660 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
661 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
662 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
663 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
665 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
666 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
667 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
668 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
670 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
671 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
673 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
675 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
677 mve_play_next_chunk(mve); /* video initialization chunk */
679 mve_play_next_chunk(mve); /* audio initialization chunk */
685 void MVE_getVideoSpec(MVE_videoSpec *vSpec)
687 vSpec->screenWidth = g_screenWidth;
688 vSpec->screenHeight = g_screenHeight;
689 vSpec->width = g_width;
690 vSpec->height = g_height;
691 vSpec->truecolor = g_truecolor;
695 int MVE_rmStepMovie()
697 static int init_timer=0;
703 while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
704 cont = mve_play_next_chunk(mve);
710 if (micro_frame_delay && !init_timer) {
720 void MVE_rmEndMovie()
730 if (mve_audio_canplay) {
731 // only close audio if we opened it
733 mve_audio_canplay = 0;
735 for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
736 if (mve_audio_buffers[i] != NULL)
737 mve_free(mve_audio_buffers[i]);
738 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
739 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
740 mve_audio_curbuf_curpos=0;
745 mve_audio_compressed=0;
747 mve_free(mve_audio_spec);
749 audiobuf_created = 0;
752 mve_free(g_vBuffers);
756 videobuf_created = 0;
757 video_initialized = 0;
764 void MVE_rmHoldMovie()
770 void MVE_sndInit(int x)
774 mve_audio_enabled = 0;
776 mve_audio_enabled = 1;