]> icculus.org git repositories - taylor/freespace2.git/blob - src/movie/mveplayer.cpp
Preliminary MVE code (Where's the soup now?!)
[taylor/freespace2.git] / src / movie / mveplayer.cpp
1 #include <string.h>
2 #include <errno.h>
3 #include <time.h>
4 #include <unistd.h>
5 #include <sys/time.h>
6
7 #include "mvelib.h"                                             /* next buffer */
8 #include "bmpman.h"
9 #include "2d.h"
10 #include "mve_audio.h"
11
12 #ifndef MIN
13 #define MIN(a,b) ((a)<(b)?(a):(b))
14 #endif
15
16
17 static int g_spdFactorNum=0;
18 static int g_spdFactorDenom=10;
19
20 void initializeMovie(MVESTREAM *mve);
21 void playMovie(MVESTREAM *mve);
22 void shutdownMovie(MVESTREAM *mve);
23
24 #if 0
25 static int doPlay(const char *filename)
26 {
27     MVESTREAM *mve = mve_open(filename);
28     if (mve == NULL)
29     {
30         fprintf(stderr, "can't open MVE file '%s'\n", filename);
31         return 1;
32     }
33
34     initializeMovie(mve);
35     playMovie(mve);
36     shutdownMovie(mve);
37
38     mve_close(mve);
39
40     return 0;
41 }
42 #endif
43
44 static short get_short(unsigned char *data)
45 {
46     short value;
47     value = data[0] | (data[1] << 8);
48     return value;
49 }
50
51 static unsigned short get_ushort(unsigned char *data)
52 {
53     unsigned short value;
54     value = data[0] | (data[1] << 8);
55     return value;
56 }
57
58 static int get_int(unsigned char *data)
59 {
60     int value;
61     value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
62     return value;
63 }
64
65 static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
66 {
67 /*    fprintf(stderr, "unknown chunk type %02x/%02x\n", major, minor); */
68     return 1;
69 }
70
71 /*************************
72  * general handlers
73  *************************/
74 static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
75 {
76     return 0;
77 }
78
79 /*************************
80  * timer handlers
81  *************************/
82
83 /*
84  * timer variables
85  */
86 static int micro_frame_delay=0;
87 static int timer_started=0;
88 static struct timeval timer_expire = {0, 0};
89
90 static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
91 {
92     __extension__ long long temp;
93     micro_frame_delay = get_int(data) * (int)get_short(data+4);
94     if (g_spdFactorNum != 0)
95     {
96         temp = micro_frame_delay;
97         temp *= g_spdFactorNum;
98         temp /= g_spdFactorDenom;
99         micro_frame_delay = (int)temp;
100     }
101
102     return 1;
103 }
104
105 static void timer_start(void)
106 {
107     int nsec=0;
108     gettimeofday(&timer_expire, NULL);
109     timer_expire.tv_usec += micro_frame_delay;
110     if (timer_expire.tv_usec > 1000000)
111     {
112         nsec = timer_expire.tv_usec / 1000000;
113         timer_expire.tv_sec += nsec;
114         timer_expire.tv_usec -= nsec*1000000;
115     }
116     timer_started=1;
117 }
118
119 static void do_timer_wait(void)
120 {
121     int nsec=0;
122     struct timespec ts, tsRem;
123     struct timeval tv;
124     if (! timer_started)
125         return;
126
127     gettimeofday(&tv, NULL);
128     if (tv.tv_sec > timer_expire.tv_sec)
129         goto end;
130     else if (tv.tv_sec == timer_expire.tv_sec  &&  tv.tv_usec >= timer_expire.tv_usec)
131         goto end;
132
133     ts.tv_sec = timer_expire.tv_sec - tv.tv_sec;
134     ts.tv_nsec = 1000 * (timer_expire.tv_usec - tv.tv_usec);
135     if (ts.tv_nsec < 0)
136     {
137         ts.tv_nsec += 1000000000UL;
138         --ts.tv_sec;
139     }
140     if (nanosleep(&ts, &tsRem) == -1  &&  errno == EINTR)
141        exit(1);
142
143 end:
144     timer_expire.tv_usec += micro_frame_delay;
145     if (timer_expire.tv_usec > 1000000)
146     {
147         nsec = timer_expire.tv_usec / 1000000;
148         timer_expire.tv_sec += nsec;
149         timer_expire.tv_usec -= nsec*1000000;
150     }
151 }
152
153 /*************************
154  * audio handlers
155  *************************/
156 static void mve_audio_callback(void *userdata, unsigned char *stream, int len); 
157 static short *mve_audio_buffers[64];
158 static int    mve_audio_buflens[64];
159 static int    mve_audio_curbuf_curpos=0;
160 static int mve_audio_bufhead=0;
161 static int mve_audio_buftail=0;
162 static int mve_audio_playing=0;
163 static int mve_audio_canplay=0;
164 #if 0
165 static SDL_AudioSpec *mve_audio_spec=NULL;
166 #endif
167 static int mve_audio_compressed = 0;
168
169 static void mve_audio_callback(void *userdata, unsigned char *stream, int len)
170 {
171 #if 0
172     int total=0;
173     int length;
174     if (mve_audio_bufhead == mve_audio_buftail)
175         return /* 0 */;
176
177 //fprintf(stderr, "+ <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
178
179     while (mve_audio_bufhead != mve_audio_buftail                                       /* while we have more buffers  */
180             &&  len > (mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos))   /* and while we need more data */
181     {
182         length = mve_audio_buflens[mve_audio_bufhead]-mve_audio_curbuf_curpos;
183         memcpy(stream,                                                        /* cur output position */
184                 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead])+mve_audio_curbuf_curpos,           /* cur input position  */
185                 length);                                                                /* cur input length    */
186
187         total += length;
188         stream += length;                                                               /* advance output */
189         len -= length;                                                                  /* decrement avail ospace */
190         free(mve_audio_buffers[mve_audio_bufhead]);                                     /* free the buffer */
191         mve_audio_buffers[mve_audio_bufhead]=NULL;                                      /* free the buffer */
192         mve_audio_buflens[mve_audio_bufhead]=0;                                         /* free the buffer */
193
194         if (++mve_audio_bufhead == 64)                                                  /* next buffer */
195             mve_audio_bufhead = 0;
196         mve_audio_curbuf_curpos = 0;
197     }
198
199 //fprintf(stderr, "= <%d (%d), %d, %d>: %d\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len, total);
200 /*    return total; */
201
202     if (len != 0                                                                        /* ospace remaining  */
203             &&  mve_audio_bufhead != mve_audio_buftail)                                 /* buffers remaining */
204     {
205         memcpy(stream,                                                        /* dest */
206                 ((unsigned char *)mve_audio_buffers[mve_audio_bufhead]) + mve_audio_curbuf_curpos,         /* src */
207                 len);                                                                   /* length */
208
209         mve_audio_curbuf_curpos += len;                                                 /* advance input */
210         stream += len;                                                                  /* advance output (unnecessary) */
211         len -= len;                                                                     /* advance output (unnecessary) */
212
213         if (mve_audio_curbuf_curpos >= mve_audio_buflens[mve_audio_bufhead])            /* if this ends the current chunk */
214         {
215             free(mve_audio_buffers[mve_audio_bufhead]);                                 /* free buffer */
216             mve_audio_buffers[mve_audio_bufhead]=NULL;
217             mve_audio_buflens[mve_audio_bufhead]=0;
218
219             if (++mve_audio_bufhead == 64)                                              /* next buffer */
220                 mve_audio_bufhead = 0;
221             mve_audio_curbuf_curpos = 0;
222         }
223     }
224
225 //fprintf(stderr, "- <%d (%d), %d, %d>\n", mve_audio_bufhead, mve_audio_curbuf_curpos, mve_audio_buftail, len);
226 #endif
227 }
228
229 static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
230 {
231 #if 0
232     int flags;
233     int sample_rate;
234     int desired_buffer;
235         
236     int stereo;
237     int bitsize;
238     int compressed;
239     
240     int format;
241     
242     flags = get_ushort(data + 2);
243     sample_rate = get_ushort(data + 4);
244     desired_buffer = get_int(data + 6);
245     
246     stereo = (flags & 0x0001) ? 1 : 0;
247     bitsize = (flags & 0x0002) ? 1 : 0;
248     
249     if (minor > 0) {
250         compressed = flags & 0x0004 ? 1 : 0;
251     } else {
252         compressed = 0;
253     }
254
255     mve_audio_compressed = compressed;
256         
257     if (bitsize == 1) {
258         format = AUDIO_S16LSB;
259     } else {
260         format = AUDIO_U8;
261     }
262     
263     fprintf(stderr, "creating audio buffers:\n");
264     fprintf(stderr, "sample rate = %d, stereo = %d, bitsize = %d, compressed = %d\n", 
265         sample_rate, stereo, bitsize ? 16 : 8, compressed);
266     
267     mve_audio_spec = (SDL_AudioSpec *)malloc(sizeof(SDL_AudioSpec));
268     mve_audio_spec->freq = sample_rate;
269     mve_audio_spec->format = format;
270     mve_audio_spec->channels = (stereo) ? 2 : 1;
271     mve_audio_spec->samples = 4096;
272     mve_audio_spec->callback = mve_audio_callback;
273     mve_audio_spec->userdata = NULL;
274     if (SDL_OpenAudio(mve_audio_spec, NULL) >= 0)
275     {
276 fprintf(stderr, "   success\n");
277         mve_audio_canplay = 1;
278     }
279     else
280     {
281 fprintf(stderr, "   failure : %s\n", SDL_GetError());
282         mve_audio_canplay = 0;
283     }
284
285     memset(mve_audio_buffers, 0, sizeof(mve_audio_buffers));
286     memset(mve_audio_buflens, 0, sizeof(mve_audio_buflens));
287
288 #endif
289     return 1;
290 }
291
292 static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
293 {
294 #if 0
295     if (mve_audio_canplay  &&  !mve_audio_playing  &&  mve_audio_bufhead != mve_audio_buftail)
296     {
297         SDL_PauseAudio(0);
298         mve_audio_playing = 1;
299     }
300 #endif
301     return 1;
302 }
303
304 static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
305 {
306 #if 0
307     static const int selected_chan=1;
308     int chan;
309     int nsamp;
310     if (mve_audio_canplay)
311     {
312         if (mve_audio_playing)
313             SDL_LockAudio();
314
315         chan = get_ushort(data + 2);
316         nsamp = get_ushort(data + 4);
317         if (chan & selected_chan)
318         {
319             /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
320             if (major == 8) {
321                 if (mve_audio_compressed) {
322                         nsamp += 4;
323                         
324                         mve_audio_buflens[mve_audio_buftail] = nsamp;
325                         mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
326                         mveaudio_uncompress(mve_audio_buffers[mve_audio_buftail], data, -1); /* XXX */
327                 } else {
328                         nsamp -= 8;
329                         data += 8;
330                         
331                         mve_audio_buflens[mve_audio_buftail] = nsamp;
332                         mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
333                         memcpy(mve_audio_buffers[mve_audio_buftail], data, nsamp);
334                 }                     
335             } else {
336                 mve_audio_buflens[mve_audio_buftail] = nsamp;
337                 mve_audio_buffers[mve_audio_buftail] = (short *)malloc(nsamp);
338                 
339                 memset(mve_audio_buffers[mve_audio_buftail], 0, nsamp); /* XXX */
340             }
341             
342             if (++mve_audio_buftail == 64)
343                 mve_audio_buftail = 0;
344
345             if (mve_audio_buftail == mve_audio_bufhead)
346                 fprintf(stderr, "d'oh!  buffer ring overrun (%d)\n", mve_audio_bufhead);
347         }
348
349         if (mve_audio_playing)
350             SDL_UnlockAudio();
351     }
352 #endif
353
354     return 1;
355 }
356
357 /*************************
358  * video handlers
359  *************************/
360 int g_width, g_height;
361 void *g_vBackBuf1, *g_vBackBuf2;
362
363 #if 0
364 static SDL_Surface *g_screen;
365 #endif
366 static int g_screenWidth, g_screenHeight;
367 static unsigned char g_palette[768];
368 static unsigned char *g_pCurMap=NULL;
369 static int g_nMapLength=0;
370 static int g_truecolor;
371
372 static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
373 {
374     short w, h;
375     short count, truecolor;
376     w = get_short(data);
377     h = get_short(data+2);
378     
379     if (minor > 0) {
380             count = get_short(data+4);
381     } else {
382         count = 1;
383     }
384     
385     if (minor > 1) {
386         truecolor = get_short(data+6);
387     } else {
388         truecolor = 0;
389     }
390     
391     g_width = w << 3;
392     g_height = h << 3;
393     
394     /* TODO: * 4 causes crashes on some files */
395     g_vBackBuf1 = malloc(g_width * g_height * 8);
396     if (truecolor) {
397         g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
398     } else {
399         g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
400     }
401         
402     memset(g_vBackBuf1, 0, g_width * g_height * 4);
403     
404     fprintf(stderr, "DEBUG: w,h=%d,%d count=%d, tc=%d\n", w, h, count, truecolor);
405     
406     g_truecolor = truecolor;
407     
408     return 1;
409 }
410
411 #if 0
412 static int do_sdl_events()
413 {
414         SDL_Event event;
415         int retr = 0;
416         while (SDL_PollEvent(&event)) {
417                 switch(event.type) {
418                         case SDL_QUIT:
419                                 exit(0);
420                         case SDL_KEYDOWN:
421                                 if (event.key.keysym.sym == SDLK_ESCAPE)
422                                         exit(0);
423                                 break;
424                         case SDL_KEYUP:
425                                 retr = 1;
426                                 break;
427                         case SDL_MOUSEBUTTONDOWN:
428 /*
429                                 if (event.button.button == SDL_BUTTON_LEFT) {
430                                         printf("GRID: %d,%d (pix:%d,%d)\n", 
431                                         event.button.x / 16, event.button.y / 8,
432                                          event.button.x, event.button.y);
433                                 }
434 */
435                                 break;
436                         default:
437                                 break;
438                 }
439         }
440         
441         return retr;
442 }
443 #endif
444
445 static unsigned short stab[65536];
446 static unsigned int itab[65536];
447 static int table_inited;
448
449 unsigned short *pixelbuf;
450 static void ConvertAndDraw()
451 {
452     int i;
453     
454     unsigned short *pDests;
455     unsigned int *pDesti;
456     unsigned short *pSrcs;
457     unsigned char *pixels = (unsigned char *)g_vBackBuf1;
458     int x, y;
459
460 if (g_truecolor) {
461         pSrcs = (unsigned short *)pixels;
462         
463         /*
464         if (table_inited == 0) {
465                 int r, g, b;
466                 
467                 table_inited = 1;
468                 
469                 for (i = 0; i < 65536; i++) {
470                         r = (i & 0x7c00) >> 10;
471                         g = (i & 0x03e0) >> 5;
472                         b = (i & 0x001f) >> 0;
473                         
474                         stab[i]  = 1 << 15;
475                         stab[i] |= (r << 10)&0x7c00;
476                         stab[i] |= (g <<  5)&0x03e0;
477                         stab[i] |= (b <<  0)&0x001f;
478                 }
479         }
480         */
481         
482         pDests = pixelbuf;
483
484         if (g_screenWidth > g_width) {
485                 pDests += ((g_screenWidth - g_width) / 2) / 2;
486         }
487         if (g_screenHeight > g_height) {
488                 pDests += ((g_screenHeight - g_height) / 2) * g_screenWidth;
489         }
490
491         for (y=0; y<g_height; y++) {
492                 for (x = 0; x < g_width; x++) {
493                         //pDests[x] = stab[*pSrcs];
494                         pDests[x] = (1<<15)|*pSrcs;
495                 
496                         pSrcs++;
497                 }
498                 pDests += g_screenWidth;
499         }
500 } else {
501 #if 0
502 /* original slow 8 bit code */
503     int i;
504     unsigned char *pal = g_palette;
505     unsigned char *pDest;
506     unsigned char *pixels = g_vBackBuf1;
507     SDL_Surface *screenSprite, *initSprite;
508     SDL_Rect renderArea;
509     int x, y;
510
511        initSprite = SDL_CreateRGBSurface(SDL_SWSURFACE, g_width, g_height, 8, 0, 0, 0, 0);
512
513     if (!g_truecolor) {
514         for(i = 0; i < 256; i++)
515             {
516                 initSprite->format->palette->colors[i].r = (*pal++) << 2;
517                 initSprite->format->palette->colors[i].g = (*pal++) << 2;
518                 initSprite->format->palette->colors[i].b = (*pal++) << 2;
519                 initSprite->format->palette->colors[i].unused = 0;
520             }    
521     }
522     
523     pDest = initSprite->pixels;
524     for (i=0; i<g_height; i++)
525     {
526         memcpy(pDest, pixels, g_width * (g_truecolor?2:1));
527         pixels += g_width* (g_truecolor?2:1);
528         pDest += initSprite->pitch;
529     }
530
531     screenSprite = SDL_DisplayFormat(initSprite);
532     SDL_FreeSurface(initSprite);
533
534     if (g_screenWidth > screenSprite->w) x = (g_screenWidth - screenSprite->w) >> 1;
535     else x=0;
536     if (g_screenHeight > screenSprite->h) y = (g_screenHeight - screenSprite->h) >> 1;
537     else y=0;
538     renderArea.x = x;
539     renderArea.y = y;
540     renderArea.w = MIN(g_screenWidth  - x, screenSprite->w);
541     renderArea.h = MIN(g_screenHeight - y, screenSprite->h);
542     SDL_BlitSurface(screenSprite, NULL, g_screen, &renderArea);
543
544         SDL_FreeSurface(screenSprite);
545 #endif
546 }
547
548 }
549
550 static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
551 {
552         ConvertAndDraw();
553 #if 0
554                 
555         SDL_Flip(g_screen);
556         
557         do_sdl_events();
558 #endif
559         /* DDOI - This is probably really fricking slow */
560         int bitmap = bm_create (16, g_screenWidth, g_screenHeight, pixelbuf, 0);
561         gr_set_bitmap (bitmap);
562         gr_bitmap (0, 0);
563         bm_release (bitmap);
564         gr_flip ();
565         
566         return 1;
567 }
568
569 static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
570 {
571     short width, height;
572     width = get_short(data);
573     height = get_short(data+2);
574 #if 0
575     g_screen = SDL_SetVideoMode(width, height, 16, SDL_ANYFORMAT|SDL_DOUBLEBUF);
576 #endif
577     // DDOI - Allocate RGB565 pixel buffer
578     pixelbuf = (unsigned short *)malloc (width * height * 2);
579     g_screenWidth = width;
580     g_screenHeight = height;
581     memset(g_palette, 0, 768);
582     return 1;
583 }
584
585 static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
586 {
587     short start, count;
588     start = get_short(data);
589     count = get_short(data+2);
590     memcpy(g_palette + 3*start, data+4, 3*count);
591     return 1;
592 }
593
594 static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
595 {
596     g_pCurMap = data;
597     g_nMapLength = len;
598     return 1;
599 }
600
601 void decodeFrame16(unsigned char *pFrame, unsigned char *pMap, int mapRemain, unsigned char *pData, int dataRemain);
602
603 static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
604 {
605     short nFrameHot, nFrameCold;
606     short nXoffset, nYoffset;
607     short nXsize, nYsize;
608     unsigned short nFlags;
609     unsigned char *temp;
610
611     nFrameHot  = get_short(data);
612     nFrameCold = get_short(data+2);
613     nXoffset   = get_short(data+4);
614     nYoffset   = get_short(data+6);
615     nXsize     = get_short(data+8);
616     nYsize     = get_short(data+10);
617     nFlags     = get_ushort(data+12);
618
619     if (nFlags & 1)
620     {
621         temp = (unsigned char *)g_vBackBuf1;
622         g_vBackBuf1 = g_vBackBuf2;
623         g_vBackBuf2 = temp;
624     }
625
626     /* convert the frame */
627     if (g_truecolor) {
628         decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
629 #if 0
630     } else {
631         decodeFrame8(g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
632 #endif
633     }
634
635     return 1;
636 }
637
638 static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context)
639 {
640     g_pCurMap=NULL;
641     return 1;
642 }
643
644 void initializeMovie(MVESTREAM *mve)
645 {
646     int i;
647     
648     for (i = 0; i < 32; i++) {
649         mve_set_handler(mve, i, default_seg_handler);
650     }
651     
652     mve_set_handler(mve, 0x00, end_movie_handler);
653     mve_set_handler(mve, 0x01, end_chunk_handler);
654     mve_set_handler(mve, 0x02, create_timer_handler);
655     mve_set_handler(mve, 0x03, create_audiobuf_handler);
656     mve_set_handler(mve, 0x04, play_audio_handler);
657     mve_set_handler(mve, 0x05, create_videobuf_handler);
658     mve_set_handler(mve, 0x07, display_video_handler);
659     mve_set_handler(mve, 0x08, audio_data_handler);
660     mve_set_handler(mve, 0x09, audio_data_handler);
661     mve_set_handler(mve, 0x0a, init_video_handler);
662     mve_set_handler(mve, 0x0c, video_palette_handler);
663     mve_set_handler(mve, 0x0f, video_codemap_handler);
664     mve_set_handler(mve, 0x11, video_data_handler);
665 }
666
667 void playMovie(MVESTREAM *mve)
668 {
669     int init_timer=0;
670     int cont=1;
671     while (cont)
672     {
673         cont = mve_play_next_chunk(mve);
674         if (micro_frame_delay  &&  !init_timer)
675         {
676             timer_start();
677             init_timer = 1;
678         }
679
680         do_timer_wait();
681     }
682 }
683
684 void shutdownMovie(MVESTREAM *mve)
685 {
686         free (pixelbuf);
687 }