1 /* $Id: mveplay.c,v 1.20 2004-10-21 16:33:11 schaffner Exp $ */
22 # include <sys/time.h>
23 # include <sys/types.h>
24 # include <sys/stat.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;
257 static SDL_AudioSpec *mve_audio_spec=NULL;
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 mve_audio_spec = (SDL_AudioSpec *)mve_alloc(sizeof(SDL_AudioSpec));
369 mve_audio_spec->freq = sample_rate;
370 mve_audio_spec->format = format;
371 mve_audio_spec->channels = (stereo) ? 2 : 1;
372 mve_audio_spec->samples = 4096;
373 mve_audio_spec->callback = mve_audio_callback;
374 mve_audio_spec->userdata = NULL;
375 if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
377 fprintf(stderr, " success\n");
378 mve_audio_canplay = 1;
382 fprintf(stderr, " failure : %s\n", SDL_GetError());
383 mve_audio_canplay = 0;
386 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
387 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
393 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
396 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
399 mve_audio_playing = 1;
405 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
408 static const int selected_chan=1;
411 if (mve_audio_canplay)
413 if (mve_audio_playing)
416 chan = get_ushort(data + 2);
417 nsamp = get_ushort(data + 4);
418 if (chan & selected_chan)
420 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
421 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
422 if (mve_audio_compressed) {
425 mve_audio_buflens[mve_audio_buftail] = nsamp;
426 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
427 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
432 mve_audio_buflens[mve_audio_buftail] = nsamp;
433 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
434 memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
437 mve_audio_buflens[mve_audio_buftail] = nsamp;
438 mve_audio_buffers[mve_audio_buftail] = (short *)mve_alloc(nsamp);
440 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
443 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
444 mve_audio_buftail = 0;
446 if (mve_audio_buftail == mve_audio_bufhead)
447 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
450 if (mve_audio_playing)
458 /*************************
460 *************************/
462 static int videobuf_created = 0;
463 static int video_initialized = 0;
464 int g_width, g_height;
465 void *g_vBuffers = NULL, *g_vBackBuf1, *g_vBackBuf2;
467 static int g_destX, g_destY;
468 static int g_screenWidth, g_screenHeight;
469 static unsigned char *g_pCurMap=NULL;
470 static int g_nMapLength=0;
471 static int g_truecolor;
473 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
476 short count, truecolor;
478 if (videobuf_created)
481 videobuf_created = 1;
484 h = get_short(data+2);
487 count = get_short(data+4);
493 truecolor = get_short(data+6);
501 /* TODO: * 4 causes crashes on some files */
502 /* only malloc once */
503 if (g_vBuffers == NULL)
504 g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
506 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
508 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
511 memset(g_vBackBuf1, 0, g_width * g_height * 4);
514 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
517 g_truecolor = truecolor;
522 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
524 if (g_destX == -1) // center it
525 g_destX = (g_screenWidth - g_width) >> 1;
526 if (g_destY == -1) // center it
527 g_destY = (g_screenHeight - g_height) >> 1;
529 mve_showframe(g_vBackBuf1, g_width, g_height, 0, 0,
530 g_width, g_height, g_destX, g_destY);
537 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
541 if (video_initialized)
542 return 1; /* maybe we actually need to change width/height here? */
544 video_initialized = 1;
546 width = get_short(data);
547 height = get_short(data+2);
548 g_screenWidth = width;
549 g_screenHeight = height;
554 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
559 start = get_short(data);
560 count = get_short(data+2);
564 mve_setpalette(p - 3*start, start, count);
569 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
576 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
578 short nFrameHot, nFrameCold;
579 short nXoffset, nYoffset;
580 short nXsize, nYsize;
581 unsigned short nFlags;
584 nFrameHot = get_short(data);
585 nFrameCold = get_short(data+2);
586 nXoffset = get_short(data+4);
587 nYoffset = get_short(data+6);
588 nXsize = get_short(data+8);
589 nYsize = get_short(data+10);
590 nFlags = get_ushort(data+12);
594 temp = (unsigned char *)g_vBackBuf1;
595 g_vBackBuf1 = g_vBackBuf2;
599 /* convert the frame */
601 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
603 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
609 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
616 static MVESTREAM *mve = NULL;
618 void MVE_ioCallbacks(mve_cb_Read io_read)
623 void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free)
625 mve_alloc = mem_alloc;
629 void MVE_sfCallbacks(mve_cb_ShowFrame showframe)
631 mve_showframe = showframe;
634 void MVE_palCallbacks(mve_cb_SetPalette setpalette)
636 mve_setpalette = setpalette;
639 int MVE_rmPrepMovie(void *src, int x, int y, int track)
656 for (i = 0; i < 32; i++)
657 mve_set_handler(mve, i, default_seg_handler);
659 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
660 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
661 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
662 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
663 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
664 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
666 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
667 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
668 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
669 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
671 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
672 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
674 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
676 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
678 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);
707 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;