2 * $Logfile: /Freespace2/code/movie/mveplayer.cpp $
7 * MVE movie playing routines
10 * Revision 1.7 2005/10/01 21:48:01 taylor
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
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
21 * Revision 1.5 2005/03/31 21:26:02 taylor
22 * s/alGetSourceiv/alGetSourcei/
24 * Revision 1.4 2005/03/31 00:06:20 taylor
25 * go back to more accurate timer and allow video scaling for movies
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.
45 #include "osregistry.h"
49 static int mve_playing;
53 static int micro_frame_delay = 0;
54 static int timer_started = 0;
55 static int timer_created = 0;
56 static int timer_expire;
57 static Uint64 micro_timer_start = 0;
58 static Uint64 micro_timer_freq = 0;
61 #define MVE_AUDIO_BUFFERS 8 // total buffers to interact with stream
63 static std::vector<ALuint> mve_audio_bufl_free;
64 static ubyte *mve_audio_buf = NULL;
65 static size_t mve_audio_buf_size = 0;
66 static size_t mve_audio_buf_offset = 0;
68 static int mve_audio_playing = 0;
69 static int mve_audio_canplay = 0;
70 static int mve_audio_compressed = 0;
71 static int audiobuf_created = 0;
73 // struct for the audio stream information
81 ALuint buffers[MVE_AUDIO_BUFFERS];
84 mve_audio_t *mas = NULL; // mve_audio_stream
89 int g_width, g_height;
90 void *g_vBuffers = NULL;
91 void *g_vBackBuf1, *g_vBackBuf2;
92 ushort *pixelbuf = NULL;
93 static ubyte *g_pCurMap=NULL;
94 static int g_nMapLength=0;
95 static int videobuf_created;
99 void decodeFrame16(ubyte *pFrame, ubyte *pMap, int mapRemain, ubyte *pData, int dataRemain);
101 /*************************
103 *************************/
109 /*************************
111 *************************/
113 int mve_timer_create(ubyte *data)
115 micro_frame_delay = mve_get_int(data) * (int)mve_get_short(data+4);
117 micro_timer_start = SDL_GetPerformanceCounter();
118 micro_timer_freq = SDL_GetPerformanceFrequency();
120 if (micro_timer_freq < 1000) {
121 micro_timer_freq = 1000;
129 static int mve_timer_get_microseconds()
132 Uint64 us = SDL_GetPerformanceCounter() - micro_timer_start;
134 if (micro_timer_freq >= 1000000) {
135 us /= (micro_timer_freq / 1000000);
137 us *= (1000000 / micro_timer_freq);
143 static void mve_timer_start(void)
148 timer_expire = mve_timer_get_microseconds();
149 timer_expire += micro_frame_delay;
154 static int mve_do_timer_wait(void)
161 tv = mve_timer_get_microseconds();
163 if (tv > timer_expire)
166 ts = timer_expire - tv;
168 SDL_Delay(ts / 1000);
170 // try and burn off excess in attempt to keep sync
172 for (int i = 0; i < 10; i++) {
177 timer_expire += micro_frame_delay;
182 static void mve_timer_stop()
188 micro_frame_delay = 0;
190 micro_timer_start = 0;
191 micro_timer_freq = 0;
194 /*************************
196 *************************/
198 // setup the audio information from the data stream
199 void mve_audio_createbuf(ubyte minor, ubyte *data)
201 if (audiobuf_created)
204 // if game sound disabled don't try and play movie audio
205 if ( !Sound_enabled ) {
206 mve_audio_canplay = 0;
207 audiobuf_created = 1;
211 int flags, desired_buffer, sample_rate;
213 mas = (mve_audio_t *) malloc ( sizeof(mve_audio_t) );
216 mve_audio_canplay = 0;
217 audiobuf_created = 1;
221 memset(mas, 0, sizeof(mve_audio_t));
223 mas->format = AL_INVALID;
225 flags = mve_get_ushort(data + 2);
226 sample_rate = mve_get_ushort(data + 4);
227 desired_buffer = mve_get_int(data + 6);
229 if (desired_buffer > 0) {
230 mve_audio_buf = (ubyte*) malloc (desired_buffer);
232 if (mve_audio_buf == NULL) {
233 mve_audio_canplay = 0;
234 audiobuf_created = 1;
238 mve_audio_buf_size = desired_buffer;
239 mve_audio_buf_offset = 0;
241 mve_audio_canplay = 0;
242 audiobuf_created = 1;
246 mas->channels = (flags & 0x0001) ? 2 : 1;
247 mas->bitsize = (flags & 0x0002) ? 16 : 8;
249 mas->sample_rate = sample_rate;
252 mve_audio_compressed = flags & 0x0004 ? 1 : 0;
254 mve_audio_compressed = 0;
257 if (mas->bitsize == 16) {
258 if (mas->channels == 2) {
259 mas->format = AL_FORMAT_STEREO16;
260 } else if (mas->channels == 1) {
261 mas->format = AL_FORMAT_MONO16;
263 } else if (mas->bitsize == 8) {
264 if (mas->channels == 2) {
265 mas->format = AL_FORMAT_STEREO8;
266 } else if (mas->channels == 1) {
267 mas->format = AL_FORMAT_MONO8;
271 // somethings wrong, bail now
272 if (mas->format == AL_INVALID) {
273 mve_audio_canplay = 0;
274 audiobuf_created = 1;
278 oal_check_for_errors("mve_audio_createbuf() begin");
280 for (int i = 0; i < MVE_AUDIO_BUFFERS; i++) {
281 alGenBuffers(1, &mas->buffers[i]);
283 if ( !mas->buffers[i] ) {
284 mve_audio_canplay = 0;
285 audiobuf_created = 1;
290 mve_audio_bufl_free.assign(mas->buffers, mas->buffers+MVE_AUDIO_BUFFERS);
292 mas->chan = oal_get_free_channel(1.0f, -1, SND_PRIORITY_MUST_PLAY);
294 if (mas->chan == NULL) {
295 mve_audio_canplay = 0;
296 audiobuf_created = 1;
300 alSourcef(mas->chan->source_id, AL_GAIN, 1.0f);
301 alSource3f(mas->chan->source_id, AL_POSITION, 0.0f, 0.0f, 0.0f);
302 alSource3f(mas->chan->source_id, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
303 alSource3f(mas->chan->source_id, AL_DIRECTION, 0.0f, 0.0f, 0.0f);
304 alSourcef(mas->chan->source_id, AL_ROLLOFF_FACTOR, 0.0f);
305 alSourcei(mas->chan->source_id, AL_SOURCE_RELATIVE, AL_TRUE);
306 alSourcei(mas->chan->source_id, AL_LOOPING, AL_FALSE);
308 oal_check_for_errors("mve_audio_createbuf() end");
310 audiobuf_created = 1;
311 mve_audio_canplay = 1;
314 // play and stream the audio
315 void mve_audio_play()
317 if (mve_audio_canplay) {
319 ALint status = AL_INVALID;
321 oal_check_for_errors("mve_audio_play() begin");
323 alGetSourcei(mas->chan->source_id, AL_BUFFERS_QUEUED, &queued);
324 alGetSourcei(mas->chan->source_id, AL_SOURCE_STATE, &status);
326 if ( (status != AL_PLAYING) && (queued > 0) ) {
327 alSourcePlay(mas->chan->source_id);
328 mve_audio_playing = 1;
331 oal_check_for_errors("mve_audio_play() end");
335 // call this in shutdown to stop and close audio
336 static void mve_audio_stop()
338 if (!audiobuf_created)
341 oal_check_for_errors("mve_audio_stop() begin");
343 mve_audio_playing = 0;
344 mve_audio_canplay = 0;
345 mve_audio_compressed = 0;
347 audiobuf_created = 0;
349 mve_audio_bufl_free.clear();
353 alSourceStop(mas->chan->source_id);
355 // detach buffers from source so that we can delete them
356 alSourcei(mas->chan->source_id, AL_BUFFER, 0);
359 for (int i = 0; i < MVE_AUDIO_BUFFERS; i++) {
360 if ( alIsBuffer(mas->buffers[i]) ) {
361 alDeleteBuffers(1, &mas->buffers[i]);
371 if (mve_audio_buf != NULL) {
373 mve_audio_buf = NULL;
376 mve_audio_buf_size = 0;
377 mve_audio_buf_offset = 0;
379 oal_check_for_errors("mve_audio_stop() end");
382 int mve_audio_data(ubyte major, ubyte *data)
384 static const int selected_chan = 1;
390 if (mve_audio_canplay) {
391 chan = mve_get_ushort(data + 2);
392 nsamp = mve_get_ushort(data + 4);
394 if (chan & selected_chan) {
395 oal_check_for_errors("mve_audio_data() begin");
397 if ( (mve_audio_buf_offset+nsamp+4) <= mve_audio_buf_size ) {
399 if (mve_audio_compressed) {
400 /* HACK: +4 mveaudio_uncompress adds 4 more bytes */
403 mveaudio_uncompress(mve_audio_buf+mve_audio_buf_offset, data, -1);
408 memcpy(mve_audio_buf+mve_audio_buf_offset, data, nsamp);
412 memset(mve_audio_buf+mve_audio_buf_offset, 0, nsamp);
415 mve_audio_buf_offset += nsamp;
417 mprintf(("MVE audio_buf overrun!!\n"));
420 alGetSourcei(mas->chan->source_id, AL_BUFFERS_PROCESSED, &processed);
423 alSourceUnqueueBuffers(mas->chan->source_id, 1, &bid);
425 mve_audio_bufl_free.push_back(bid);
429 if ( !mve_audio_bufl_free.empty() ) {
430 bid = mve_audio_bufl_free.back();
432 alBufferData(bid, mas->format, mve_audio_buf, mve_audio_buf_offset, mas->sample_rate);
433 alSourceQueueBuffers(mas->chan->source_id, 1, &bid);
435 mve_audio_buf_offset = 0;
436 mve_audio_bufl_free.pop_back();
439 if ( !mve_audio_playing ) {
443 oal_check_for_errors("mve_audio_data() end");
450 /*************************
452 *************************/
454 int mve_video_createbuf(ubyte minor, ubyte *data)
456 if (videobuf_created)
461 w = mve_get_short(data);
462 h = mve_get_short(data+2);
467 // with Pierre's decoder16 fix in opcode 0xc, 8 should no longer be needed
468 g_vBackBuf1 = g_vBuffers = malloc(g_width * g_height * 4);
470 if (g_vBackBuf1 == NULL) {
471 mprintf(("MVE-ERROR: Can't allocate video buffer\n"));
472 videobuf_created = 1;
476 g_vBackBuf2 = (ushort *)g_vBackBuf1 + (g_width * g_height);
478 memset(g_vBackBuf1, 0, g_width * g_height * 4);
480 // DDOI - Allocate RGB565 pixel buffer
481 pixelbuf = (ushort *)malloc (g_width * g_height * 2);
483 if (pixelbuf == NULL) {
484 mprintf(("MVE-ERROR: Can't allocate memory for pixelbuf\n"));
485 videobuf_created = 1;
489 memset(pixelbuf, 0, g_width * g_height * 2);
491 gr_stream_start(-1, -1, g_width, g_height);
493 videobuf_created = 1;
498 static void mve_convert_and_draw()
502 ushort *pixels = (ushort *)g_vBackBuf1;
511 for (y=0; y<g_height; y++) {
512 for (x = 0; x < g_width; x++) {
513 // convert from abgr to rgba
516 r = ubyte((px & 0x7C00) >> 10);
517 g = ubyte((px & 0x3E0) >> 5);
518 b = ubyte((px & 0x1F) >> 0);
519 a = ubyte((px & 0x8000) >> 15);
521 pDests[x] = (r << 11) | (g << 6) | (b << 1) | (a << 0);
529 void mve_video_display()
531 static uint mve_video_skiptimer = 0;
533 fix t1 = timer_get_fixed_seconds();
535 // micro_frame_delay is divided by 10 to match mve_video_skiptimer overflow catch
536 if ( mve_video_skiptimer > (uint)(micro_frame_delay/10) ) {
537 // we are running slow so subtract desired time from actual and skip this frame
538 mve_video_skiptimer -= (micro_frame_delay/10);
541 // zero out so we can get a new count
542 mve_video_skiptimer = 0;
545 mve_convert_and_draw();
547 gr_stream_frame( (ubyte*)pixelbuf );
551 fix t2 = timer_get_fixed_seconds();
553 // only get a new count if we are definitely through with old count
554 if ( mve_video_skiptimer == 0 ) {
555 // for a more accurate count convert the frame rate to a float and multiply
556 // by one-hundred-thousand before converting to an uint.
557 mve_video_skiptimer = (uint)(f2fl(t2-t1) * 100000);
561 void mve_video_codemap(ubyte *data, int len)
567 void mve_video_data(ubyte *data, int len)
572 nFlags = mve_get_ushort(data+12);
575 temp = (ubyte *)g_vBackBuf1;
576 g_vBackBuf1 = g_vBackBuf2;
580 decodeFrame16((ubyte *)g_vBackBuf1, g_pCurMap, g_nMapLength, data+14, len-14);
588 void mve_init(MVESTREAM *mve)
590 // reset to default values
591 mve_audio_playing = 0;
592 mve_audio_canplay = 0;
593 mve_audio_compressed = 0;
594 mve_audio_buf_offset = 0;
595 audiobuf_created = 0;
597 videobuf_created = 0;
602 void mve_play(MVESTREAM *mve)
604 int init_timer = 0, timer_error = 0;
610 while (cont && mve_playing && !timer_error) {
611 cont = mve_play_next_chunk(mve);
613 if (micro_frame_delay && !init_timer) {
618 timer_error = mve_do_timer_wait();
622 if (key_inkey() == SDLK_ESCAPE) {
634 if (pixelbuf != NULL) {
639 if (g_vBuffers != NULL) {