]> icculus.org git repositories - taylor/freespace2.git/blob - src/movie/mveplayer.cpp
Merge branch 'sdl2'
[taylor/freespace2.git] / src / movie / mveplayer.cpp
1 /*
2  * $Logfile: /Freespace2/code/movie/mveplayer.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * MVE movie playing routines
8  *
9  * $Log$
10  * Revision 1.7  2005/10/01 21:48:01  taylor
11  * various cleanups
12  * fix decoder to swap opcode 0xb since it screws up on PPC
13  * the previous opcode 0xc change was wrong since we had already determined that it messes up FS1 movies
14  *
15  * Revision 1.6  2005/08/12 08:47:24  taylor
16  * use new audiostr code rather than old windows/unix version
17  * update all OpenAL commands with new error checking macros
18  * fix play_position to properly account for real position, fixes the talking heads and message text cutting out early
19  * movies will now use better filtering when scaled
20  *
21  * Revision 1.5  2005/03/31 21:26:02  taylor
22  * s/alGetSourceiv/alGetSourcei/
23  *
24  * Revision 1.4  2005/03/31 00:06:20  taylor
25  * go back to more accurate timer and allow video scaling for movies
26  *
27  * Revision 1.3  2005/03/29 07:50:34  taylor
28  * Update to newest movie code with much better video support and audio support from
29  *   Pierre Willenbrock.  Movies are enabled always now (no longer a build option)
30  *   and but can be skipped with the "--nomovies" or "-n" cmdline options.
31  *
32  *
33  * $NoKeywords: $
34  */
35  
36 #include "pstypes.h"
37 #include "mvelib.h"
38 #include "movie.h"
39 #include "2d.h"
40 #include "key.h"
41 #include "osapi.h"
42 #include "timer.h"
43 #include "sound.h"
44 #include "bmpman.h"
45 #include "osregistry.h"
46 #include "oal.h"
47 #include "gropengl.h"
48 #include <vector>
49
50 static int mve_playing;
51
52
53 // timer variables
54 static int micro_frame_delay = 0;
55 static int timer_started = 0;
56 static int timer_created = 0;
57 static int timer_expire;
58 static Uint64 micro_timer_start = 0;
59 static Uint64 micro_timer_freq = 0;
60
61 // audio variables
62 #define MVE_AUDIO_BUFFERS 8  // total buffers to interact with stream
63
64 static std::vector<ALuint> mve_audio_bufl_free;
65 static ubyte *mve_audio_buf = NULL;
66 static size_t mve_audio_buf_size = 0;
67 static size_t mve_audio_buf_offset = 0;
68
69 static int mve_audio_playing = 0;
70 static int mve_audio_canplay = 0;
71 static int mve_audio_compressed = 0;
72 static int audiobuf_created = 0;
73
74 // struct for the audio stream information
75 struct mve_audio_t {
76         sound_channel *chan;
77         ALenum format;
78         int sample_rate;
79         int bytes_per_sec;
80         int channels;
81         int bitsize;
82         ALuint buffers[MVE_AUDIO_BUFFERS];
83 };
84
85 mve_audio_t *mas = NULL;  // mve_audio_stream
86
87
88
89 // video variables
90 int g_width, g_height;
91 void *g_vBuffers = NULL;
92 void *g_vBackBuf1, *g_vBackBuf2;
93 ushort *pixelbuf = NULL;
94 static ubyte *g_pCurMap=NULL;
95 static int g_nMapLength=0;
96 static int videobuf_created;
97 static int mve_scale_video = 0;
98 static GLuint tex = 0;
99
100 struct g_coords_t {
101         int x, y;
102         float u, v;
103 };
104
105 static g_coords_t g_coords[4];
106
107
108 // the decoder
109 void decodeFrame16(ubyte *pFrame, ubyte *pMap, int mapRemain, ubyte *pData, int dataRemain);
110
111 /*************************
112  * general handlers
113  *************************/
114 void mve_end_movie()
115 {
116         mve_playing = 0;
117 }
118
119 /*************************
120  * timer handlers
121  *************************/
122
123 int mve_timer_create(ubyte *data)
124 {
125         micro_frame_delay = mve_get_int(data) * (int)mve_get_short(data+4);
126
127         micro_timer_start = SDL_GetPerformanceCounter();
128         micro_timer_freq = SDL_GetPerformanceFrequency();
129
130         if (micro_timer_freq < 1000) {
131                 micro_timer_freq = 1000;
132         }
133
134         timer_created = 1;
135
136         return 1;
137 }
138
139 static int mve_timer_get_microseconds()
140 {
141
142         Uint64 us = SDL_GetPerformanceCounter() - micro_timer_start;
143
144         if (micro_timer_freq >= 1000000) {
145                 us /= (micro_timer_freq / 1000000);
146         } else {
147                 us *= (1000000 / micro_timer_freq);
148         }
149
150         return (int)us;
151 }
152
153 static void mve_timer_start(void)
154 {
155         if (!timer_created)
156                 return;
157
158         timer_expire = mve_timer_get_microseconds();
159         timer_expire += micro_frame_delay;
160
161         timer_started = 1;
162 }
163
164 static int mve_do_timer_wait(void)
165 {
166         if (!timer_started)
167                 return 0;
168
169         int tv, ts;
170
171         tv = mve_timer_get_microseconds();
172
173         if (tv > timer_expire)
174                 goto end;
175
176         ts = timer_expire - tv;
177
178         SDL_Delay(ts / 1000);
179
180         // try and burn off excess in attempt to keep sync
181         if (ts % 1000) {
182                 for (int i = 0; i < 10; i++) {
183                         SDL_Delay(0);
184                 }
185         }
186 end:
187         timer_expire += micro_frame_delay;
188
189         return 0;
190 }
191
192 static void mve_timer_stop()
193 {
194         timer_expire = 0;
195         timer_started = 0;
196         timer_created = 0;
197
198         micro_frame_delay = 0;
199
200         micro_timer_start = 0;
201         micro_timer_freq = 0;
202 }
203
204 /*************************
205  * audio handlers
206  *************************/
207
208 // setup the audio information from the data stream
209 void mve_audio_createbuf(ubyte minor, ubyte *data)
210 {
211         if (audiobuf_created)
212                 return;
213
214         // if game sound disabled don't try and play movie audio
215         if ( !Sound_enabled ) {
216                 mve_audio_canplay = 0;
217                 audiobuf_created = 1;
218                 return;
219         }
220
221         int flags, desired_buffer, sample_rate;
222
223         mas = (mve_audio_t *) malloc ( sizeof(mve_audio_t) );
224
225         if (mas == NULL) {
226                 mve_audio_canplay = 0;
227                 audiobuf_created = 1;
228                 return;
229         }
230
231         memset(mas, 0, sizeof(mve_audio_t));
232
233         mas->format = AL_INVALID;
234
235         flags = mve_get_ushort(data + 2);
236         sample_rate = mve_get_ushort(data + 4);
237         desired_buffer = mve_get_int(data + 6);
238
239         if (desired_buffer > 0) {
240                 mve_audio_buf = (ubyte*) malloc (desired_buffer);
241
242                 if (mve_audio_buf == NULL) {
243                         mve_audio_canplay = 0;
244                         audiobuf_created = 1;
245                         return;
246                 }
247
248                 mve_audio_buf_size = desired_buffer;
249                 mve_audio_buf_offset = 0;
250         } else {
251                 mve_audio_canplay = 0;
252                 audiobuf_created = 1;
253                 return;
254         }
255
256         mas->channels = (flags & 0x0001) ? 2 : 1;
257         mas->bitsize = (flags & 0x0002) ? 16 : 8;
258
259         mas->sample_rate = sample_rate;
260
261         if (minor > 0) {
262                 mve_audio_compressed = flags & 0x0004 ? 1 : 0;
263         } else {
264                 mve_audio_compressed = 0;
265         }
266
267         if (mas->bitsize == 16) {
268                 if (mas->channels == 2) {
269                         mas->format = AL_FORMAT_STEREO16;
270                 } else if (mas->channels == 1) {
271                         mas->format = AL_FORMAT_MONO16;
272                 }
273         } else if (mas->bitsize == 8) {
274                 if (mas->channels == 2) {
275                         mas->format = AL_FORMAT_STEREO8;
276                 } else if (mas->channels == 1) {
277                         mas->format = AL_FORMAT_MONO8;
278                 }
279         }
280
281         // somethings wrong, bail now
282         if (mas->format == AL_INVALID) {
283                 mve_audio_canplay = 0;
284                 audiobuf_created = 1;
285                 return;
286         }
287
288         oal_check_for_errors("mve_audio_createbuf() begin");
289
290         for (int i = 0; i < MVE_AUDIO_BUFFERS; i++) {
291                 alGenBuffers(1, &mas->buffers[i]);
292
293                 if ( !mas->buffers[i] ) {
294                         mve_audio_canplay = 0;
295                         audiobuf_created = 1;
296                         return;
297                 }
298         }
299
300         mve_audio_bufl_free.assign(mas->buffers, mas->buffers+MVE_AUDIO_BUFFERS);
301
302         mas->chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
303
304         if (mas->chan == NULL) {
305                 mve_audio_canplay = 0;
306                 audiobuf_created = 1;
307                 return;
308         }
309
310         alSourcef(mas->chan->source_id, AL_GAIN, 1.0f);
311         alSource3f(mas->chan->source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
312         alSource3f(mas->chan->source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
313         alSource3f(mas->chan->source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
314         alSourcef(mas->chan->source_id, AL_ROLLOFF_FACTOR, 0.0f);
315         alSourcei(mas->chan->source_id, AL_SOURCE_RELATIVE, AL_TRUE);
316         alSourcei(mas->chan->source_id, AL_LOOPING, AL_FALSE);
317
318         oal_check_for_errors("mve_audio_createbuf() end");
319
320         audiobuf_created = 1;
321         mve_audio_canplay = 1;
322 }
323
324 // play and stream the audio
325 void mve_audio_play()
326 {
327         if (mve_audio_canplay) {
328                 ALint queued = 0;
329                 ALint status = AL_INVALID;
330
331                 oal_check_for_errors("mve_audio_play() begin");
332
333                 alGetSourcei(mas->chan->source_id, AL_BUFFERS_QUEUED, &queued);
334                 alGetSourcei(mas->chan->source_id, AL_SOURCE_STATE, &status);
335
336                 if ( (status != AL_PLAYING) && (queued > 0) ) {
337                         alSourcePlay(mas->chan->source_id);
338                         mve_audio_playing = 1;
339                 }
340
341                 oal_check_for_errors("mve_audio_play() end");
342         }
343 }
344
345 // call this in shutdown to stop and close audio
346 static void mve_audio_stop()
347 {
348         if (!audiobuf_created)
349                 return;
350
351         oal_check_for_errors("mve_audio_stop() begin");
352
353         mve_audio_playing = 0;
354         mve_audio_canplay = 0;
355         mve_audio_compressed = 0;
356
357         audiobuf_created = 0;
358
359         mve_audio_bufl_free.clear();
360
361         if (mas) {
362                 if (mas->chan) {
363                         alSourceStop(mas->chan->source_id);
364
365                         // detach buffers from source so that we can delete them
366                         alSourcei(mas->chan->source_id, AL_BUFFER, 0);
367                 }
368
369                 for (int i = 0; i < MVE_AUDIO_BUFFERS; i++) {
370                         if ( alIsBuffer(mas->buffers[i]) ) {
371                                 alDeleteBuffers(1, &mas->buffers[i]);
372                         }
373                 }
374         }
375
376         if (mas != NULL) {
377                 free(mas);
378                 mas = NULL;
379         }
380
381         if (mve_audio_buf != NULL) {
382                 free(mve_audio_buf);
383                 mve_audio_buf = NULL;
384         }
385
386         mve_audio_buf_size = 0;
387         mve_audio_buf_offset = 0;
388
389         oal_check_for_errors("mve_audio_stop() end");
390 }
391
392 int mve_audio_data(ubyte major, ubyte *data)
393 {
394         static const int selected_chan = 1;
395         int chan;
396         int nsamp;
397         ALint processed = 0;
398         ALuint bid;
399
400         if (mve_audio_canplay) {
401                 chan = mve_get_ushort(data + 2);
402                 nsamp = mve_get_ushort(data + 4);
403
404                 if (chan & selected_chan) {
405                         oal_check_for_errors("mve_audio_data() begin");
406
407                         if ( (mve_audio_buf_offset+nsamp+4) <= mve_audio_buf_size ) {
408                                 if (major == 8) {
409                                         if (mve_audio_compressed) {
410                                                 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
411                                                 nsamp += 4;
412
413                                                 mveaudio_uncompress(mve_audio_buf+mve_audio_buf_offset, data, -1);
414                                         } else {
415                                                 nsamp -= 8;
416                                                 data += 8;
417
418                                                 memcpy(mve_audio_buf+mve_audio_buf_offset, data, nsamp);
419                                         }
420                                 } else {
421                                         // silence
422                                         memset(mve_audio_buf+mve_audio_buf_offset, 0, nsamp);
423                                 }
424
425                                 mve_audio_buf_offset += nsamp;
426                         } else {
427                                 mprintf(("MVE audio_buf overrun!!\n"));
428                         }
429
430                         alGetSourcei(mas->chan->source_id, AL_BUFFERS_PROCESSED, &processed);
431
432                         while (processed) {
433                                 alSourceUnqueueBuffers(mas->chan->source_id, 1, &bid);
434
435                                 mve_audio_bufl_free.push_back(bid);
436                                 --processed;
437                         }
438
439                         if ( !mve_audio_bufl_free.empty() ) {
440                                 bid = mve_audio_bufl_free.back();
441
442                                 alBufferData(bid, mas->format, mve_audio_buf, mve_audio_buf_offset, mas->sample_rate);
443                                 alSourceQueueBuffers(mas->chan->source_id, 1, &bid);
444
445                                 mve_audio_buf_offset = 0;
446                                 mve_audio_bufl_free.pop_back();
447                         }
448
449                         if ( !mve_audio_playing ) {
450                                 mve_audio_play();
451                         }
452
453                         oal_check_for_errors("mve_audio_data() end");
454                 }
455         }
456
457         return 1;
458 }
459
460 /*************************
461  * video handlers
462  *************************/
463
464 int mve_video_createbuf(ubyte minor, ubyte *data)
465 {
466         if (videobuf_created)
467                 return 1;
468
469         if (gr_screen.mode != GR_OPENGL) {
470                 mprintf(("MVE-ERROR: Movie playback requires OpenGL renderer\n"));
471                 videobuf_created = 1;
472                 return 0;
473         }
474
475         if (gr_screen.use_sections) {
476                 mprintf(("MVE-ERROR: Bitmap sections not supported\n"));
477                 videobuf_created = 1;
478                 return 0;
479         }
480
481         int tex_w, tex_h;
482         short w, h;
483
484         w = mve_get_short(data);
485         h = mve_get_short(data+2);
486
487         g_width = w << 3;
488         g_height = h << 3;
489
490         // with Pierre's decoder16 fix in opcode 0xc, 8 should no longer be needed
491         g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 4);
492
493         if (g_vBackBuf1 == NULL) {
494                 mprintf(("MVE-ERROR: Can't allocate video buffer\n"));
495                 videobuf_created = 1;
496                 return 0;
497         }
498
499         g_vBackBuf2 = (ushort *)g_vBackBuf1 + (g_width * g_height);
500
501         memset(g_vBackBuf1, 0, g_width * g_height * 4);
502
503         // DDOI - Allocate RGB565 pixel buffer
504         pixelbuf = (ushort *)malloc (g_width * g_height * 2);
505
506         if (pixelbuf == NULL) {
507                 mprintf(("MVE-ERROR: Can't allocate memory for pixelbuf\n"));
508                 videobuf_created = 1;
509                 return 0;
510         }
511
512         memset(pixelbuf, 0, g_width * g_height * 2);
513
514         // set height and width to a power of 2
515         tex_w = next_pow2(g_width);
516         tex_h = next_pow2(g_height);
517
518         SDL_assert(tex_w > 0);
519         SDL_assert(tex_h > 0);
520
521         glGenTextures(1, &tex);
522
523         if (tex == 0) {
524                 mprintf(("MVE-ERROR: Can't create a GL texture\n"));
525                 videobuf_created = 1;
526                 return 0;
527         }
528
529         glBindTexture(GL_TEXTURE_2D, tex);
530
531         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
532         glDepthFunc(GL_ALWAYS);
533         glDepthMask(GL_FALSE);
534         glDisable(GL_DEPTH_TEST);
535         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
536         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
537
538         int x, y;
539
540         // centers
541         x = ((gr_screen.max_w - g_width) / 2);
542         y = ((gr_screen.max_h - g_height) / 2);
543
544         if ( os_config_read_uint("Video", "ScaleMovies", 1) ) {
545                 extern int GL_viewport_w;
546
547                 float scale_by = GL_viewport_w / (float)g_width;
548
549                 // don't bother setting anything if we aren't going to need it
550                 if (scale_by != 1.0f) {
551                         glMatrixMode(GL_MODELVIEW);
552                         glPushMatrix();
553                         glLoadIdentity();
554
555                         glScalef( scale_by, scale_by, 1.0f );
556                         mve_scale_video = 1;
557
558                         x = 0;
559                         y = ((480 - g_height) / 2);
560                 }
561         }
562
563         g_coords[0].x = x;
564         g_coords[0].y = y;
565         g_coords[0].u = 0.0f;
566         g_coords[0].v = 0.0f;
567
568         g_coords[1].x = x;
569         g_coords[1].y = y + g_height;
570         g_coords[1].u = 0.0f;
571         g_coords[1].v = i2fl(g_height) / i2fl(tex_h);
572
573         g_coords[2].x = x + g_width;
574         g_coords[2].y = y;
575         g_coords[2].u = i2fl(g_width) / i2fl(tex_w);
576         g_coords[2].v = 0.0f;
577
578         g_coords[3].x = x + g_width;
579         g_coords[3].y = y + g_height;
580         g_coords[3].u = i2fl(g_width) / i2fl(tex_w);
581         g_coords[3].v = i2fl(g_height) / i2fl(tex_h);
582
583         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
584         glEnableClientState(GL_VERTEX_ARRAY);
585
586         glTexCoordPointer(2, GL_FLOAT, sizeof(g_coords_t), &g_coords[0].u);
587         glVertexPointer(2, GL_INT, sizeof(g_coords_t), &g_coords[0].x);
588
589         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, tex_w, tex_h, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
590
591         videobuf_created = 1;
592
593         return 1;
594 }
595
596 static void mve_convert_and_draw()
597 {
598         ushort *pDests;
599         ushort *pSrcs;
600         ushort *pixels = (ushort *)g_vBackBuf1;
601         int x, y;
602
603         pSrcs = pixels;
604
605         pDests = pixelbuf;
606
607         for (y=0; y<g_height; y++) {
608                 for (x = 0; x < g_width; x++) {
609                         pDests[x] = (1<<15)|*pSrcs;
610
611                         pSrcs++;
612                 }
613                 pDests += g_width;
614         }
615 }
616
617 void mve_video_display()
618 {
619         static uint mve_video_skiptimer = 0;
620
621         fix t1 = timer_get_fixed_seconds();
622
623         // micro_frame_delay is divided by 10 to match mve_video_skiptimer overflow catch
624         if ( mve_video_skiptimer > (uint)(micro_frame_delay/10) ) {
625                 // we are running slow so subtract desired time from actual and skip this frame
626                 mve_video_skiptimer -= (micro_frame_delay/10);
627                 return;
628         } else {
629                 // zero out so we can get a new count
630                 mve_video_skiptimer = 0;
631         }
632
633         mve_convert_and_draw();
634
635         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, g_width, g_height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixelbuf);
636
637         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
638
639         gr_flip();
640
641         fix t2 = timer_get_fixed_seconds();
642
643         // only get a new count if we are definitely through with old count
644         if ( mve_video_skiptimer == 0 ) {
645                 // for a more accurate count convert the frame rate to a float and multiply
646                 // by one-hundred-thousand before converting to an uint.
647                 mve_video_skiptimer = (uint)(f2fl(t2-t1) * 100000);
648         }
649 }
650
651 void mve_video_codemap(ubyte *data, int len)
652 {
653         g_pCurMap = data;
654         g_nMapLength = len;
655 }
656
657 void mve_video_data(ubyte *data, int len)
658 {
659         ushort nFlags;
660         ubyte *temp;
661
662         nFlags = mve_get_ushort(data+12);
663
664         if (nFlags & 1) {
665                 temp = (ubyte *)g_vBackBuf1;
666                 g_vBackBuf1 = g_vBackBuf2;
667                 g_vBackBuf2 = temp;
668         }
669
670         decodeFrame16((ubyte *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
671 }
672
673 void mve_end_chunk()
674 {
675         g_pCurMap = NULL;
676 }
677
678 void mve_init(MVESTREAM *mve)
679 {
680         // reset to default values
681         mve_audio_playing = 0;
682         mve_audio_canplay = 0;
683         mve_audio_compressed = 0;
684         mve_audio_buf_offset = 0;
685         audiobuf_created = 0;
686
687         videobuf_created = 0;
688         mve_scale_video = 0;
689
690         mve_playing = 1;
691 }
692
693 void mve_play(MVESTREAM *mve)
694 {
695         int init_timer = 0, timer_error = 0;
696         int cont = 1;
697
698         if (!timer_started)
699                 mve_timer_start();
700
701         while (cont && mve_playing && !timer_error) {
702                 cont = mve_play_next_chunk(mve);
703
704                 if (micro_frame_delay && !init_timer) {
705                         mve_timer_start();
706                         init_timer = 1;
707                 }
708
709                 timer_error = mve_do_timer_wait();
710
711                 os_poll();
712
713                 if (key_inkey() == SDLK_ESCAPE) {
714                         mve_playing = 0;
715                 }
716         }
717 }
718
719 void mve_shutdown()
720 {
721         mve_audio_stop();
722
723         mve_timer_stop();
724
725         if (pixelbuf != NULL) {
726                 free(pixelbuf);
727                 pixelbuf = NULL;
728         }
729
730         if (g_vBuffers != NULL) {
731                 free(g_vBuffers);
732                 g_vBuffers = NULL;
733         }
734
735         if (gr_screen.mode == GR_OPENGL) {
736                 if (tex > 0) {
737                         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
738                         glDisableClientState(GL_VERTEX_ARRAY);
739
740                         glBindTexture(GL_TEXTURE_2D, 0);
741                         glDeleteTextures(1, &tex);
742                         tex = 0;
743                 }
744
745                 if (mve_scale_video) {
746                         glMatrixMode(GL_MODELVIEW);
747                         glPopMatrix();
748                 }
749
750                 glEnable(GL_DEPTH_TEST);
751         }
752 }