1 /* $Id: mveplay.c,v 1.15 2003-02-14 19:13:25 btb Exp $ */
15 #include <sys/types.h>
20 #if defined(STANDALONE) || defined(AUDIO)
25 #include "mve_audio.h"
36 #define MIN(a,b) ((a)<(b)?(a):(b))
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 playing = 1;
67 int g_sdlVidFlags = SDL_ANYFORMAT | SDL_DOUBLEBUF;
70 void initializeMovie(MVESTREAM *mve);
71 void playMovie(MVESTREAM *mve);
72 void shutdownMovie(MVESTREAM *mve);
74 static short get_short(unsigned char *data)
77 value = data[0] | (data[1] << 8);
81 static unsigned short get_ushort(unsigned char *data)
84 value = data[0] | (data[1] << 8);
88 static int get_int(unsigned char *data)
91 value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
95 static unsigned int unhandled_chunks[32*256];
97 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
99 unhandled_chunks[major<<8|minor]++;
100 //fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor);
104 /*************************
106 *************************/
107 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
112 /*************************
114 *************************/
119 static int micro_frame_delay=0;
120 static int timer_started=0;
121 static struct timeval timer_expire = {0, 0};
124 #include <sys/timeb.h>
128 long int tv_sec; /* Seconds. */
129 long int tv_nsec; /* Nanoseconds. */
132 int gettimeofday(struct timeval *tv, void *tz)
134 static int counter = 0;
137 counter++; /* to avoid collisions */
139 tv->tv_sec = tm.time;
140 tv->tv_usec = (tm.millitm * 1000) + counter;
145 int nanosleep(struct timespec *ts, void *rem)
147 sleep(ts->tv_sec * 1000 + ts->tv_nsec / 1000000);
153 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
155 __extension__ long long temp;
156 micro_frame_delay = get_int(data) * (int)get_short(data+4);
157 if (g_spdFactorNum != 0)
159 temp = micro_frame_delay;
160 temp *= g_spdFactorNum;
161 temp /= g_spdFactorDenom;
162 micro_frame_delay = (int)temp;
168 static void timer_stop(void)
170 timer_expire.tv_sec = 0;
171 timer_expire.tv_usec = 0;
175 static void timer_start(void)
178 gettimeofday(&timer_expire, NULL);
179 timer_expire.tv_usec += micro_frame_delay;
180 if (timer_expire.tv_usec > 1000000)
182 nsec = timer_expire.tv_usec / 1000000;
183 timer_expire.tv_sec += nsec;
184 timer_expire.tv_usec -= nsec*1000000;
189 static void do_timer_wait(void)
197 gettimeofday(&tv, NULL);
198 if (tv.tv_sec > timer_expire.tv_sec)
200 else if (tv.tv_sec == timer_expire.tv_sec && tv.tv_usec >= timer_expire.tv_usec)
203 ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
204 ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
207 ts.tv_nsec += 1000000000UL;
211 usleep(ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
213 if (nanosleep(&ts, NULL) == -1 && errno == EINTR)
218 timer_expire.tv_usec += micro_frame_delay;
219 if (timer_expire.tv_usec > 1000000)
221 nsec = timer_expire.tv_usec / 1000000;
222 timer_expire.tv_sec += nsec;
223 timer_expire.tv_usec -= nsec*1000000;
227 /*************************
229 *************************/
231 #define TOTAL_AUDIO_BUFFERS 64
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 SDL_AudioSpec *mve_audio_spec=NULL;
244 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
248 if (mve_audio_bufhead == mve_audio_buftail)
251 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
253 while (mve_audio_bufhead != mve_audio_buftail /* while we have more buffers */
254 && len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos)) /* and while we need more data */
256 length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
257 memcpy(stream, /* cur output position */
258 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos, /* cur input position */
259 length); /* cur input length */
262 stream += length; /* advance output */
263 len -= length; /* decrement avail ospace */
264 free(mve_audio_buffers[mve_audio_bufhead]); /* free the buffer */
265 mve_audio_buffers[mve_audio_bufhead]=NULL; /* free the buffer */
266 mve_audio_buflens[mve_audio_bufhead]=0; /* free the buffer */
268 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
269 mve_audio_bufhead = 0;
270 mve_audio_curbuf_curpos = 0;
273 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
276 if (len != 0 /* ospace remaining */
277 && mve_audio_bufhead != mve_audio_buftail) /* buffers remaining */
279 memcpy(stream, /* dest */
280 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos, /* src */
283 mve_audio_curbuf_curpos += len; /* advance input */
284 stream += len; /* advance output (unnecessary) */
285 len -= len; /* advance output (unnecessary) */
287 if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead]) /* if this ends the current chunk */
289 free(mve_audio_buffers[mve_audio_bufhead]); /* free buffer */
290 mve_audio_buffers[mve_audio_bufhead]=NULL;
291 mve_audio_buflens[mve_audio_bufhead]=0;
293 if (++mve_audio_bufhead == TOTAL_AUDIO_BUFFERS) /* next buffer */
294 mve_audio_bufhead = 0;
295 mve_audio_curbuf_curpos = 0;
299 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
303 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
317 if (FindArg("-nosound"))
321 flags = get_ushort(data + 2);
322 sample_rate = get_ushort(data + 4);
323 desired_buffer = get_int(data + 6);
325 stereo = (flags & MVE_AUDIO_FLAGS_STEREO) ? 1 : 0;
326 bitsize = (flags & MVE_AUDIO_FLAGS_16BIT) ? 1 : 0;
329 compressed = flags & MVE_AUDIO_FLAGS_COMPRESSED ? 1 : 0;
334 mve_audio_compressed = compressed;
337 format = AUDIO_S16LSB;
342 fprintf(stderr, "creating audio buffers:\n");
343 fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n",
344 sample_rate, stereo, bitsize ? 16 : 8, compressed);
346 mve_audio_spec = (SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec));
347 mve_audio_spec->freq = sample_rate;
348 mve_audio_spec->format = format;
349 mve_audio_spec->channels = (stereo) ? 2 : 1;
350 mve_audio_spec->samples = 4096;
351 mve_audio_spec->callback = mve_audio_callback;
352 mve_audio_spec->userdata = NULL;
353 if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
355 fprintf(stderr, " success\n");
356 mve_audio_canplay = 1;
360 fprintf(stderr, " failure : %s\n", SDL_GetError());
361 mve_audio_canplay = 0;
364 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
365 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
371 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
374 if (mve_audio_canplay && !mve_audio_playing && mve_audio_bufhead != mve_audio_buftail)
377 mve_audio_playing = 1;
383 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
386 static const int selected_chan=1;
389 if (mve_audio_canplay)
391 if (mve_audio_playing)
394 chan = get_ushort(data + 2);
395 nsamp = get_ushort(data + 4);
396 if (chan & selected_chan)
398 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
399 if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
400 if (mve_audio_compressed) {
403 mve_audio_buflens[mve_audio_buftail] = nsamp;
404 mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
405 mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
410 mve_audio_buflens[mve_audio_buftail] = nsamp;
411 mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
412 memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
415 mve_audio_buflens[mve_audio_buftail] = nsamp;
416 mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
418 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
421 if (++mve_audio_buftail == TOTAL_AUDIO_BUFFERS)
422 mve_audio_buftail = 0;
424 if (mve_audio_buftail == mve_audio_bufhead)
425 fprintf(stderr, "d'oh! buffer ring overrun (%d)\n", mve_audio_bufhead);
428 if (mve_audio_playing)
436 /*************************
438 *************************/
439 int g_width, g_height;
440 void *g_vBuffers, *g_vBackBuf1, *g_vBackBuf2;
443 static SDL_Surface *g_screen;
445 static grs_bitmap *g_screen;
447 static int g_screenWidth, g_screenHeight;
448 static unsigned char g_palette[768];
449 static unsigned char *g_pCurMap=NULL;
450 static int g_nMapLength=0;
451 static int g_truecolor;
452 static int g_palette_changed = 0;
454 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
457 short count, truecolor;
460 h = get_short(data+2);
463 count = get_short(data+4);
469 truecolor = get_short(data+6);
478 Assert((g_width <= g_screen->bm_w) && (g_height <= g_screen->bm_h));
481 /* TODO: * 4 causes crashes on some files */
482 g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 8);
484 g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
486 g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
489 memset(g_vBackBuf1, 0, g_width * g_height * 4);
491 fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
493 g_truecolor = truecolor;
499 static int do_sdl_events()
503 while (SDL_PollEvent(&event)) {
509 if (event.key.keysym.sym == SDLK_ESCAPE)
515 case SDL_MOUSEBUTTONDOWN:
517 if (event.button.button == SDL_BUTTON_LEFT) {
518 printf("GRID: %d,%d (pix:%d,%d)\n",
519 event.button.x / 16, event.button.y / 8,
520 event.button.x, event.button.y);
532 static void ConvertAndDraw()
535 unsigned char *pal = g_palette;
536 unsigned char *pDest;
537 unsigned char *pixels = g_vBackBuf1;
538 SDL_Surface *screenSprite, *initSprite;
542 initSprite = SDL_CreateRGBSurface(SDL_SWSURFACE, g_width, g_height, g_truecolor?16:8, 0x7C00, 0x03E0, 0x001F, 0);
545 for(i = 0; i < 256; i++) {
546 initSprite->format->palette->colors[i].r = (*pal++) << 2;
547 initSprite->format->palette->colors[i].g = (*pal++) << 2;
548 initSprite->format->palette->colors[i].b = (*pal++) << 2;
549 initSprite->format->palette->colors[i].unused = 0;
553 pDest = initSprite->pixels;
555 if (0 /*g_truecolor*/) {
557 unsigned short *pSrcs, *pDests;
559 pSrcs = (unsigned short *)pixels;
560 pDests = (unsigned short *)pDest;
562 for (y=0; y<g_height; y++) {
563 for (x = 0; x < g_width; x++) {
564 pDests[x] = (1<<15)|*pSrcs;
567 pDests += g_screenWidth;
572 for (i=0; i<g_height; i++) {
573 memcpy(pDest, pixels, g_width * (g_truecolor?2:1));
574 pixels += g_width* (g_truecolor?2:1);
575 pDest += initSprite->pitch;
579 screenSprite = SDL_DisplayFormat(initSprite);
580 SDL_FreeSurface(initSprite);
582 if (g_screenWidth > screenSprite->w)
583 x = (g_screenWidth - screenSprite->w) >> 1;
586 if (g_screenHeight > screenSprite->h)
587 y = (g_screenHeight - screenSprite->h) >> 1;
592 renderArea.w = MIN(g_screenWidth - x, screenSprite->w);
593 renderArea.h = MIN(g_screenHeight - y, screenSprite->h);
594 SDL_BlitSurface(screenSprite, NULL, g_screen, &renderArea);
596 SDL_FreeSurface(screenSprite);
600 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
609 if (g_palette_changed)
611 gr_palette_load(g_palette);
612 g_palette_changed = 0;
615 if (g_width == g_screen->bm_w && g_height >= g_screen->bm_h)
616 memcpy(g_screen->bm_data, g_vBackBuf1, g_width * g_height);
621 if (g_screen->bm_w > g_width)
622 x = (g_screen->bm_w - g_width) >> 1;
623 if (g_screen->bm_h > g_height)
624 y = (g_screen->bm_h - g_height) >> 1;
626 pDest = g_screen->bm_data + g_screen->bm_w * y + x;
627 for (i = 0; i < g_height; i++) {
628 memcpy(pDest, pSrc, g_width * (g_truecolor?2:1));
629 pSrc += g_width * (g_truecolor?2:1);
630 pDest += g_screen->bm_w * (g_truecolor?2:1);
638 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
641 width = get_short(data);
642 height = get_short(data+2);
644 g_screen = SDL_SetVideoMode(width, height, 16, g_sdlVidFlags);
646 g_screenWidth = width;
647 g_screenHeight = height;
648 memset(g_palette, 0, 765);
649 // 255 needs to default to white, for subtitles, etc
650 memset(g_palette + 765, 63, 3);
654 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
657 start = get_short(data);
658 count = get_short(data+2);
659 memcpy(g_palette + 3*start, data+4, 3*count);
660 g_palette_changed = 1;
665 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
672 void decodeFrame16(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain);
673 void decodeFrame8(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain);
675 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
677 short nFrameHot, nFrameCold;
678 short nXoffset, nYoffset;
679 short nXsize, nYsize;
680 unsigned short nFlags;
683 nFrameHot = get_short(data);
684 nFrameCold = get_short(data+2);
685 nXoffset = get_short(data+4);
686 nYoffset = get_short(data+6);
687 nXsize = get_short(data+8);
688 nYsize = get_short(data+10);
689 nFlags = get_ushort(data+12);
693 temp = (unsigned char *)g_vBackBuf1;
694 g_vBackBuf1 = g_vBackBuf2;
698 /* convert the frame */
700 decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
702 decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
708 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
714 void initializeMovie(MVESTREAM *mve)
718 for (i = 0; i < 32; i++)
719 mve_set_handler(mve, i, default_seg_handler);
721 memset(unhandled_chunks, 0, 32*256);
723 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
724 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
725 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
726 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
727 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
728 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
730 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
731 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
732 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
733 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
735 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
736 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, video_palette_handler);
737 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
739 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
742 void playMovie(MVESTREAM *mve)
746 while (cont && playing)
748 cont = mve_play_next_chunk(mve);
749 if (micro_frame_delay && !init_timer)
759 void shutdownMovie(MVESTREAM *mve)
765 for (i = 0; i < 32*256; i++) {
766 if (unhandled_chunks[i]) {
767 fprintf(stderr, "unhandled chunks of type %02x/%02x: %d\n", i>>8, i&0xFF, unhandled_chunks[i]);
773 void mveplay_initializeMovie(MVESTREAM *mve, grs_bitmap *mve_bitmap)
777 g_screen = mve_bitmap;
779 for (i = 0; i < 32; i++)
780 mve_set_handler(mve, i, default_seg_handler);
782 mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
783 mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
784 mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
785 mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
786 mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
787 mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
789 mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
790 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
791 mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
792 mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
794 mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
795 mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
797 mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
799 mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
803 int mveplay_stepMovie(MVESTREAM *mve)
805 static int init_timer=0;
811 cont = mve_play_next_chunk(mve);
812 if (micro_frame_delay && !init_timer) {
822 void mveplay_restartTimer(MVESTREAM *mve)
827 void mveplay_shutdownMovie(MVESTREAM *mve)
834 if (mve_audio_canplay) {
835 // only close audio if we opened it
836 mve_audio_canplay = 0;
838 for (i = 0; i < TOTAL_AUDIO_BUFFERS; i++)
839 if (mve_audio_buffers[i] != NULL)
840 free(mve_audio_buffers[i]);
841 memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
842 memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
843 mve_audio_curbuf_curpos=0;
848 mve_audio_compressed=0;
850 free(mve_audio_spec);