1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "sludge/movie.h"
24 #include "sludge/sound.h"
25 
26 namespace Sludge {
27 
28 // sound_openal.cpp
29 void playMovieStream(int a);
30 #if 0
31 int initMovieSound(int f, ALenum format, int audioChannels, ALuint samplerate,
32 		ALuint(*callback)(void *userdata, ALubyte *data, ALuint bytes));
33 #endif
34 
35 MovieStates movieIsPlaying = nothing;
36 
37 int movieIsEnding = 0;
38 
39 float movieAspect = 1.6F;
40 #if 0
41 typedef struct audioBuffers {
42 	char *buffer;
43 	uint size;
44 	audioBuffers *next;
45 	Uint32 time_ms;
46 }audioBuffers;
47 
48 typedef struct audioQueue {
49 	audioBuffers *first, *last;
50 	int size;
51 	SDL_mutex *mutex;
52 	SDL_cond *cond;
53 }audioQueue;
54 
55 audioQueue audioQ;
56 
57 uint32 movieStartTick, movieCurrentTime;
58 
59 int64 audioNsPerByte;
60 int64 audioNsPlayed;
61 int64 audioNsBuffered;
62 int64 audioBufferLen;
63 bool movieSoundPlaying = false;
64 int movieAudioIndex;
65 GLuint yTextureName = 0;
66 GLuint uTextureName = 0;
67 GLuint vTextureName = 0;
68 
69 typedef struct videoBuffers {
70 	GLubyte *ytex;
71 	GLubyte *utex;
72 	GLubyte *vtex;
73 	videoBuffers *next;
74 	GLsizei w, h;
75 	Uint32 time_ms;
76 }videoBuffers;
77 
78 typedef struct videoQueue {
79 	videoBuffers *first, *last;
80 	int size;
81 	SDL_mutex *mutex;
82 	SDL_cond *cond;
83 }videoQueue;
84 
85 videoQueue videoQ;
86 
87 void audio_queue_init(audioQueue *q) {
88 	memset(q, 0, sizeof(audioQueue));
89 
90 	q->mutex = SDL_CreateMutex();
91 	q->cond = SDL_CreateCond();
92 
93 }
94 int audio_queue_put(audioQueue *q, char *buffer, uint size, int64 time_ms) {
95 
96 	audioBuffers *audioBuf = new audioBuffers;
97 	if (!audioBuf)
98 	return -1;
99 	audioBuf->buffer = buffer;
100 	audioBuf->next = NULL;
101 	audioBuf->size = size;
102 	audioBuf->time_ms = time_ms;
103 
104 	SDL_LockMutex(q->mutex);
105 
106 	if (!q->last)
107 	q->first = audioBuf;
108 	else
109 	q->last->next = audioBuf;
110 	q->last = audioBuf;
111 	q->size ++;
112 	SDL_CondSignal(q->cond);
113 
114 	SDL_UnlockMutex(q->mutex);
115 
116 	return 0;
117 }
118 inline static int audio_queue_get(audioQueue *q, char **buffer) {
119 	int ret = 0;
120 
121 	audioBuffers *audioBuf;
122 
123 	SDL_LockMutex(q->mutex);
124 
125 	audioBuf = q->first;
126 	if (audioBuf) {
127 		// Synch video timer to audio
128 		Uint32 tick = SDL_GetTicks() + 100;
129 		if (ABS((long int)((tick - movieStartTick) - (audioBuf->time_ms))) > 300) {
130 			movieStartTick = tick - audioBuf->time_ms;
131 		}
132 
133 		q->first = audioBuf->next;
134 		if (!q->first)
135 		q->last = NULL;
136 		q->size--;
137 		*buffer = audioBuf->buffer;
138 		ret = audioBuf->size;
139 		delete audioBuf;
140 	}
141 
142 	SDL_UnlockMutex(q->mutex);
143 
144 	return ret;
145 }
146 
147 void video_queue_init(videoQueue *q) {
148 	memset(q, 0, sizeof(videoQueue));
149 	q->mutex = SDL_CreateMutex();
150 	q->cond = SDL_CreateCond();
151 }
152 int video_queue_put(videoQueue *q, GLubyte *ytex,
153 		GLubyte *utex,
154 		GLubyte *vtex,
155 		GLsizei w, GLsizei h,
156 		int64 time_ms) {
157 
158 	videoBuffers *videoBuf = new videoBuffers;
159 	if (!videoBuf)
160 	return -1;
161 	videoBuf->ytex = ytex;
162 	videoBuf->utex = utex;
163 	videoBuf->vtex = vtex;
164 	videoBuf->next = NULL;
165 	videoBuf->w = w;
166 	videoBuf->h = h;
167 	videoBuf->time_ms = time_ms;
168 
169 	SDL_LockMutex(q->mutex);
170 
171 	if (!q->last)
172 	q->first = videoBuf;
173 	else
174 	q->last->next = videoBuf;
175 	q->last = videoBuf;
176 	q->size ++;
177 	SDL_CondSignal(q->cond);
178 
179 	SDL_UnlockMutex(q->mutex);
180 	return 0;
181 }
182 inline static int video_queue_get(videoQueue *q,
183 		GLubyte **ytex,
184 		GLubyte **utex,
185 		GLubyte **vtex,
186 		GLsizei *w, GLsizei *h) {
187 	videoBuffers *videoBuf;
188 	int ret = 0;
189 
190 	SDL_LockMutex(q->mutex);
191 
192 	videoBuf = q->first;
193 	if (videoBuf) {
194 		q->first = videoBuf->next;
195 		if (!q->first)
196 		q->last = NULL;
197 		q->size--;
198 		*ytex = videoBuf->ytex;
199 		*utex = videoBuf->utex;
200 		*vtex = videoBuf->vtex;
201 		*w = videoBuf->w;
202 		*h = videoBuf->h;
203 		ret = 1;
204 		delete videoBuf;
205 	}
206 
207 	SDL_UnlockMutex(q->mutex);
208 
209 	return ret;
210 }
211 
212 #if 0
213 static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
214 	//const char *detail = vpx_codec_error_detail(ctx);
215 	fatal(s, vpx_codec_error(ctx));
216 }
217 #endif
218 
219 void setMovieViewport() {
220 	float realAspect = (float) realWinWidth / realWinHeight;
221 
222 	int vpHeight, vpWidth, vpOffsetX, vpOffsetY;
223 	if (realAspect > movieAspect) {
224 		vpHeight = realWinHeight;
225 		vpWidth = (int)(realWinHeight * movieAspect);
226 		vpOffsetY = 0;
227 		vpOffsetX = (realWinWidth - vpWidth) / 2;
228 	} else {
229 		vpWidth = realWinWidth;
230 		vpHeight = (int)((float) realWinWidth / movieAspect);
231 		vpOffsetY = (realWinHeight - vpHeight) / 2;
232 		vpOffsetX = 0;
233 	}
234 #if 0
235 	glViewport(vpOffsetX, vpOffsetY, vpWidth, vpHeight);
236 #endif
237 	const GLfloat bPMVMatrix[] = {
238 		2.0f / 640.f, .0, .0, .0,
239 		.0, -2.0f / 400.f, .0, .0,
240 		.0, .0, 1.0f, .0,
241 		-1.0, 1.0f, .0, 1.0f
242 
243 	};
244 	for (int i = 0; i < 16; i++) {
245 		aPMVMatrix[i] = bPMVMatrix[i];
246 	}
247 }
248 
249 static uint64_t xiph_lace_value(byte **np) {
250 	uint64_t lace;
251 	uint64_t value;
252 	byte *p = *np;
253 
254 	lace = *p++;
255 	value = lace;
256 	while (lace == 255) {
257 		lace = *p++;
258 		value += lace;
259 	}
260 
261 	*np = p;
262 
263 	return value;
264 }
265 
266 vorbis_dsp_state vorbisDspState;
267 int64 audioChannels;
268 
269 bool fakeAudio = false;
270 
271 // send audio to audio device...
272 ALuint feedAudio(void *userdata, ALubyte *data, ALuint length) {
273 	static char *buffer = NULL;
274 	static uint bufOffset = 0;
275 	static uint bufSize = 0;
276 
277 	ALuint got = 0;
278 	int bufLen;
279 
280 	if (! buffer) {
281 		bufSize = audio_queue_get(&audioQ, &buffer);
282 		bufOffset = 0;
283 		if (bufSize <= 0) {
284 			bufSize = 0;
285 			buffer = NULL;
286 			if (! got) {
287 				got = audioChannels * 2;
288 				memset(data, 0, got);
289 				fprintf(stderr, "Faking audio...\n");
290 				fakeAudio = true;
291 			}
292 //				SDL_CondSignal(audioQ.cond);
293 			return got;
294 		}
295 	}
296 
297 	fakeAudio = false;
298 
299 	if (length > bufSize - bufOffset)
300 	bufLen = bufSize - bufOffset;
301 	else
302 	bufLen = length;
303 
304 	memcpy(data, buffer + bufOffset, bufLen);
305 
306 	bufOffset += bufLen;
307 	length -= bufLen;
308 	got += bufLen;
309 
310 	if (bufSize <= bufOffset) {
311 		buffer = NULL;
312 		delete [] buffer;
313 	}
314 //	fprintf (stderr, "Sending %d bytes of audio.\n", got);
315 
316 	return got;
317 }
318 #endif
319 
playMovie(int fileNumber)320 int playMovie(int fileNumber) {
321 #if 0
322 	if (specialSettings & SPECIAL_SILENT)
323 	return 0;
324 
325 	if (movieIsPlaying) return 0;
326 
327 	movieSoundPlaying = false;
328 
329 	vpx_codec_ctx_t codec;
330 
331 	float pausefade = 1.0;
332 
333 	using namespace mkvparser;
334 
335 	MkvReader reader;
336 
337 	if (reader.Open(fileNumber)) {
338 		warning(ERROR_MOVIE_ODDNESS);
339 		return 0;
340 	}
341 
342 	int64 pos = 0;
343 
344 	EBMLHeader ebmlHeader;
345 
346 	ebmlHeader.Parse(&reader, pos);
347 
348 	mkvparser::Segment *pSegment;
349 
350 	int64 ret = mkvparser::Segment::CreateInstance(&reader, pos, pSegment);
351 	if (ret) {
352 		fatal("Movie error: Segment::CreateInstance() failed.\n");
353 	}
354 
355 	ret = pSegment->Load();
356 	if (ret < 0) {
357 		fatal("Movie error: Segment::Load() failed.\n");
358 	}
359 
360 	//const SegmentInfo* const pSegmentInfo = pSegment->GetInfo();
361 	//const int64 timeCodeScale = pSegmentInfo->GetTimeCodeScale();
362 	//const int64 duration_ns = pSegmentInfo->GetDuration();
363 	//const char* const pTitle = pSegmentInfo->GetTitleAsUTF8();
364 	//const char* const pMuxingApp = pSegmentInfo->GetMuxingAppAsUTF8();
365 	//const char* const pWritingApp = pSegmentInfo->GetWritingAppAsUTF8();
366 
367 	const mkvparser::Tracks *pTracks = pSegment->GetTracks();
368 
369 	uint32 i = 0;
370 	const uint32 j = pTracks->GetTracksCount();
371 
372 	enum {VIDEO_TRACK = 1, AUDIO_TRACK = 2};
373 	int videoTrack = -1;
374 	int audioTrack = -1;
375 	int64 audioBitDepth;
376 	double audioSampleRate;
377 	ogg_packet oggPacket;
378 	vorbis_info vorbisInfo;
379 	vorbis_comment vorbisComment;
380 	vorbis_block vorbisBlock;
381 
382 	while (i != j) {
383 		const Track *const pTrack = pTracks->GetTrackByIndex(i++);
384 
385 		if (pTrack == NULL)
386 		continue;
387 
388 		const int64 trackType = pTrack->GetType();
389 		//const unsigned int64 trackUid = pTrack->GetUid();
390 		//const char* pTrackName = pTrack->GetNameAsUTF8();
391 
392 		if (trackType == VIDEO_TRACK && videoTrack < 0) {
393 			videoTrack = pTrack->GetNumber();
394 			const VideoTrack *const pVideoTrack =
395 			static_cast<const VideoTrack *>(pTrack);
396 
397 			const int64 width = pVideoTrack->GetWidth();
398 			const int64 height = pVideoTrack->GetHeight();
399 
400 			const double rate = pVideoTrack->GetFrameRate();
401 
402 			if (rate > 0)
403 			Init_Special_Timer(rate);
404 
405 			movieAspect = (float)width / height;
406 		}
407 
408 		if (trackType == AUDIO_TRACK && audioTrack < 0) {
409 			audioTrack = pTrack->GetNumber();
410 			const AudioTrack *const pAudioTrack =
411 			static_cast<const AudioTrack *>(pTrack);
412 
413 			audioChannels = pAudioTrack->GetChannels();
414 			audioBitDepth = pAudioTrack->GetBitDepth();
415 			audioSampleRate = pAudioTrack->GetSamplingRate();
416 
417 			uint audioHeaderSize;
418 			const byte *audioHeader = pAudioTrack->GetCodecPrivate(audioHeaderSize);
419 
420 			if (audioHeaderSize < 1) {
421 				warning("Strange audio track in movie.");
422 				audioTrack = -1;
423 				continue;
424 			}
425 
426 			byte *p = (byte *)audioHeader;
427 
428 			uint count = *p++ + 1;
429 			if (count != 3) {
430 				warning("Strange audio track in movie.");
431 				audioTrack = -1;
432 				continue;
433 			}
434 
435 			uint64_t sizes[3], total;
436 
437 			int i = 0;
438 			total = 0;
439 			while (--count) {
440 				sizes[i] = xiph_lace_value(&p);
441 				total += sizes[i];
442 				i += 1;
443 			}
444 			sizes[i] = audioHeaderSize - total - (p - audioHeader);
445 
446 			// initialize vorbis
447 			vorbis_info_init(&vorbisInfo);
448 			vorbis_comment_init(&vorbisComment);
449 			memset(&vorbisDspState, 0, sizeof(vorbisDspState));
450 			memset(&vorbisBlock, 0, sizeof(vorbisBlock));
451 
452 			oggPacket.e_o_s = false;
453 			oggPacket.granulepos = 0;
454 			oggPacket.packetno = 0;
455 			int r;
456 			for (int i = 0; i < 3; i++) {
457 				oggPacket.packet = p;
458 				oggPacket.bytes = sizes[i];
459 				oggPacket.b_o_s = oggPacket.packetno == 0;
460 				r = vorbis_synthesis_headerin(&vorbisInfo, &vorbisComment, &oggPacket);
461 				if (r)
462 				fprintf(stderr, "vorbis_synthesis_headerin failed, error: %d", r);
463 				oggPacket.packetno++;
464 				p += sizes[i];
465 			}
466 
467 			r = vorbis_synthesis_init(&vorbisDspState, &vorbisInfo);
468 			if (r)
469 			fprintf(stderr, "vorbis_synthesis_init failed, error: %d", r);
470 			r = vorbis_block_init(&vorbisDspState, &vorbisBlock);
471 			if (r)
472 			fprintf(stderr, "vorbis_block_init failed, error: %d", r);
473 
474 			ALenum audioFormat = alureGetSampleFormat(audioChannels, 16, 0);
475 			movieAudioIndex = initMovieSound(fileNumber, audioFormat, audioChannels, (ALuint) audioSampleRate, feedAudio);
476 
477 			fprintf(stderr, "Movie sound inited.\n");
478 			audio_queue_init(&audioQ);
479 			audioNsPerByte = (1000000000 / audioSampleRate) / (audioChannels * 2);
480 			audioNsBuffered = 0;
481 			audioBufferLen = audioChannels * audioSampleRate;
482 		}
483 	}
484 
485 	if (videoTrack < 0)
486 	fatal("Movie error: No video in movie file.");
487 
488 	if (audioTrack < 0)
489 	fatal("Movie error: No sound found.");
490 
491 	video_queue_init(&videoQ);
492 
493 	const unsigned long clusterCount = pSegment->GetCount();
494 
495 	if (clusterCount == 0) {
496 		fatal("Movie error: Segment has no clusters.\n");
497 	}
498 
499 	/* Initialize video codec */
500 	if (vpx_codec_dec_init(&codec, interface, NULL, 0))
501 	die_codec(&codec, "Failed to initialize decoder for movie.");
502 
503 	byte *frame = new byte[256 * 1024];
504 	if (! checkNew(frame)) return false;
505 
506 	const mkvparser::Cluster *pCluster = pSegment->GetFirst();
507 
508 	setMovieViewport();
509 
510 	movieIsPlaying = playing;
511 	movieIsEnding = 0;
512 
513 	glDepthMask(GL_FALSE);
514 	glDisable(GL_DEPTH_TEST);
515 
516 	//const int64 timeCode = pCluster->GetTimeCode();
517 	int64 time_ns = pCluster->GetTime();
518 
519 	const BlockEntry *pBlockEntry = pCluster->GetFirst();
520 
521 	if ((pBlockEntry == NULL) || pBlockEntry->EOS()) {
522 		pCluster = pSegment->GetNext(pCluster);
523 		if ((pCluster == NULL) || pCluster->EOS()) {
524 			fatal("Error: No movie found in the movie file.");
525 		}
526 		pBlockEntry = pCluster->GetFirst();
527 	}
528 	const Block *pBlock = pBlockEntry->GetBlock();
529 	int64 trackNum = pBlock->GetTrackNumber();
530 	unsigned long tn = static_cast<unsigned long>(trackNum);
531 	const Track *pTrack = pTracks->GetTrackByNumber(tn);
532 	int64 trackType = pTrack->GetType();
533 	int frameCount = pBlock->GetFrameCount();
534 	time_ns = pBlock->GetTime(pCluster);
535 
536 	const GLfloat texCoords[] = {
537 		0.0, 0.0,
538 		1.0, 0.0,
539 		0.0, 1.0,
540 		1.0, 1.0
541 	};
542 
543 	const GLfloat vertices[] = {
544 		0.0, 0.0, 0.1,
545 		640.0, 0.0, 0.1,
546 		0.0, 400.0, 0.1,
547 		640.0, 400.0, 0.1
548 	};
549 
550 	const GLfloat vertices1[] = {
551 		7.0, 7.0, 0.1,
552 		17.0, 7.0, 0.1,
553 		7.0, 29.0, 0.1,
554 		17.0, 29.0, 0.1
555 	};
556 
557 	const GLfloat vertices2[] = {
558 		27.0, 7.0, 0.1,
559 		37.0, 7.0, 0.1,
560 		27.0, 29.0, 0.1,
561 		37.0, 29.0, 0.1
562 	};
563 
564 	const GLfloat vertices3[] = {
565 		5.0, 5.0, 0.1,
566 		15.0, 5.0, 0.1,
567 		5.0, 27.0, 0.1,
568 		15.0, 27.0, 0.1
569 	};
570 
571 	const GLfloat vertices4[] = {
572 		25.0, 5.0, 0.1,
573 		35.0, 5.0, 0.1,
574 		25.0, 27.0, 0.1,
575 		35.0, 27.0, 0.1
576 	};
577 
578 	int frameCounter = 0;
579 
580 	movieStartTick = SDL_GetTicks();
581 
582 	while (movieIsPlaying) {
583 
584 		checkInput();
585 		if (weAreDoneSoQuit)
586 		break;
587 		handleInput();
588 
589 		if (movieIsPlaying && (! movieIsEnding) && (videoQ.size < 100 || audioQ.size < 100)) {
590 			// Decode a frame!
591 
592 			if ((pCluster != NULL) && !pCluster->EOS()) {
593 
594 				if (frameCounter >= frameCount) {
595 
596 					pBlockEntry = pCluster->GetNext(pBlockEntry);
597 					if ((pBlockEntry == NULL) || pBlockEntry->EOS()) {
598 						pCluster = pSegment->GetNext(pCluster);
599 						if ((pCluster == NULL) || pCluster->EOS()) {
600 							goto movieHasEnded;
601 						}
602 						pBlockEntry = pCluster->GetFirst();
603 					}
604 					pBlock = pBlockEntry->GetBlock();
605 					trackNum = pBlock->GetTrackNumber();
606 					tn = static_cast<unsigned long>(trackNum);
607 					pTrack = pTracks->GetTrackByNumber(tn);
608 					trackType = pTrack->GetType();
609 					frameCount = pBlock->GetFrameCount();
610 					time_ns = pBlock->GetTime(pCluster);
611 
612 					frameCounter = 0;
613 				}
614 
615 				const Block::Frame &theFrame = pBlock->GetFrame(frameCounter);
616 				const long size = theFrame.len;
617 				//                const int64 offset = theFrame.pos;
618 
619 				if (size > sizeof(frame)) {
620 					if (frame) delete [] frame;
621 					frame = new byte[size];
622 					if (! checkNew(frame)) return 0;
623 				}
624 				/*
625 				 fprintf (stderr, "Block :%s,%s,%15lld\n",
626 				 (trackType == VIDEO_TRACK) ? "V" : "A",
627 				 pBlock->IsKey() ? "I" : "P",
628 				 time_ns);
629 				 */
630 
631 				if (trackNum == videoTrack) {
632 
633 					theFrame.Read(&reader, frame);
634 
635 					/* Decode the frame */
636 					if (vpx_codec_decode(&codec, frame, size, NULL, 0))
637 					die_codec(&codec, "Failed to decode frame");
638 
639 					// Let's decode an image frame!
640 					vpx_codec_iter_t iter = NULL;
641 					vpx_image_t *img;
642 					/* Get frame data */
643 					while ((img = vpx_codec_get_frame(&codec, &iter))) {
644 						if (img->fmt != VPX_IMG_FMT_I420)
645 						fatal("Movie error. The movie is not in I420 colour format, which is the only one I can hanlde at the moment.");
646 
647 						uint y;
648 
649 						GLubyte *ytex = NULL;
650 						GLubyte *utex = NULL;
651 						GLubyte *vtex = NULL;
652 
653 						if (! ytex) {
654 							ytex = new GLubyte [img->d_w * img->d_h];
655 							utex = new GLubyte [(img->d_w >> 1) * (img->d_h >> 1)];
656 							vtex = new GLubyte [(img->d_w >> 1) * (img->d_h >> 1)];
657 							if (!ytex || !utex || !vtex)
658 							fatal(ERROR_OUT_OF_MEMORY);
659 
660 						}
661 
662 						byte *buf = img->planes[0];
663 						for (y = 0; y < img->d_h; y++) {
664 							memcpy(ytex + y * img->d_w, buf, img->d_w);
665 							buf += img->stride[0];
666 						}
667 						buf = img->planes[1];
668 						for (y = 0; y < img->d_h >> 1; y++) {
669 							memcpy(utex + y * (img->d_w >> 1), buf, img->d_w >> 1);
670 							buf += img->stride[1];
671 						}
672 						buf = img->planes[2];
673 						for (y = 0; y < img->d_h >> 1; y++) {
674 							memcpy(vtex + y * (img->d_w >> 1), buf, img->d_w >> 1);
675 							buf += img->stride[2];
676 						}
677 
678 						video_queue_put(&videoQ, ytex, utex, vtex,
679 								img->d_w, img->d_h, time_ns / 1000000);
680 
681 					}
682 
683 				} else if (trackNum == audioTrack) {
684 					// Use this Audio Track
685 					if (size > 0) {
686 						theFrame.Read(&reader, frame);
687 						oggPacket.packet = frame;
688 						oggPacket.bytes = size;
689 						oggPacket.b_o_s = false;
690 						oggPacket.packetno++;
691 						oggPacket.granulepos = -1;
692 						if (! vorbis_synthesis(&vorbisBlock, &oggPacket)) {
693 							if (vorbis_synthesis_blockin(&vorbisDspState, &vorbisBlock))
694 							fprintf(stderr, "Vorbis Synthesis block in error.\n");
695 
696 						} else {
697 							fprintf(stderr, "Vorbis Synthesis error.\n");
698 						}
699 
700 						float **pcm;
701 
702 						int numSamples = vorbis_synthesis_pcmout(&vorbisDspState, &pcm);
703 
704 						if (numSamples > 0) {
705 							int word = 2;
706 							int sgned = 1;
707 							int i, j;
708 							long bytespersample = audioChannels * word;
709 							vorbis_fpu_control fpu;
710 
711 							char *buffer = new char[bytespersample * numSamples];
712 							if (! checkNew(buffer)) return false;
713 
714 							/* a tight loop to pack each size */
715 							{
716 								int val;
717 								if (word == 1) {
718 									int off = (sgned ? 0 : 128);
719 									vorbis_fpu_setround(&fpu);
720 									for (j = 0; j < numSamples; j++)
721 									for (i = 0; i < audioChannels; i++) {
722 										val = vorbis_ftoi(pcm[i][j] * 128.f);
723 										if (val > 127)val = 127;
724 										else if (val < -128)val = -128;
725 										*buffer++ = val + off;
726 									}
727 									vorbis_fpu_restore(fpu);
728 								} else {
729 									int off = (sgned ? 0 : 32768);
730 
731 									if (sgned) {
732 
733 										vorbis_fpu_setround(&fpu);
734 										for (i = 0; i < audioChannels; i++) { /* It's faster in this order */
735 											float *src = pcm[i];
736 											int16 *dest = ((int16 *)buffer) + i;
737 											for (j = 0; j < numSamples; j++) {
738 												val = vorbis_ftoi(src[j] * 32768.f);
739 												if (val > 32767)val = 32767;
740 												else if (val < -32768)val = -32768;
741 												*dest = val;
742 												dest += audioChannels;
743 											}
744 										}
745 										vorbis_fpu_restore(fpu);
746 
747 									} else {
748 
749 										vorbis_fpu_setround(&fpu);
750 										for (i = 0; i < audioChannels; i++) {
751 											float *src = pcm[i];
752 											int16 *dest = ((int16 *)buffer) + i;
753 											for (j = 0; j < numSamples; j++) {
754 												val = vorbis_ftoi(src[j] * 32768.f);
755 												if (val > 32767)val = 32767;
756 												else if (val < -32768)val = -32768;
757 												*dest = val + off;
758 												dest += audioChannels;
759 											}
760 										}
761 										vorbis_fpu_restore(fpu);
762 
763 									}
764 
765 								}
766 							}
767 
768 							vorbis_synthesis_read(&vorbisDspState, numSamples);
769 							audioBufferLen = bytespersample * numSamples;
770 							audio_queue_put(&audioQ, buffer, audioBufferLen, time_ns / 1000000);
771 
772 							//fprintf (stderr, "Audio buffered: %lld byte %lld ns\n",audioBufferLen, audioNsPerByte*audioBufferLen);
773 
774 							if (! movieSoundPlaying && size > 1) {
775 								fprintf(stderr, "** starting sound ** \n");
776 								playMovieStream(movieAudioIndex);
777 								movieSoundPlaying = true;
778 							}
779 						}
780 					}
781 				}
782 				frameCounter++;
783 
784 			} else {
785 				movieHasEnded:
786 				movieIsEnding = 1;
787 			}
788 		}
789 
790 		bool videoUpdated = false;
791 		// Get a video frame.
792 		if (movieIsPlaying == playing) {
793 
794 			videoBuffers *vB;
795 			// Do we have decoded video waiting?
796 			if (vB = videoQ.first) {
797 				Uint32 tick = SDL_GetTicks() - movieStartTick;
798 
799 				// Is it time to display the frame yet?
800 				if ((tick + 1) < vB->time_ms) {
801 					SDL_Delay(1);
802 				} else {
803 					GLubyte *ytex = NULL;
804 					GLubyte *utex = NULL;
805 					GLubyte *vtex = NULL;
806 					GLsizei w, h;
807 
808 					if (video_queue_get(&videoQ, &ytex, &utex, &vtex, &w, &h)) {
809 
810 						if (! yTextureName) glGenTextures(1, &yTextureName);
811 						if (! uTextureName) glGenTextures(1, &uTextureName);
812 						if (! vTextureName) glGenTextures(1, &vTextureName);
813 						glBindTexture(GL_TEXTURE_2D, yTextureName);
814 						glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0,
815 								GL_ALPHA, GL_UNSIGNED_BYTE, ytex);
816 						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
817 						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
818 						glBindTexture(GL_TEXTURE_2D, uTextureName);
819 						glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w >> 1, h >> 1, 0,
820 								GL_ALPHA, GL_UNSIGNED_BYTE, utex);
821 						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
822 						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
823 						glBindTexture(GL_TEXTURE_2D, vTextureName);
824 						glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w >> 1, h >> 1, 0,
825 								GL_ALPHA, GL_UNSIGNED_BYTE, vtex);
826 						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
827 						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
828 
829 						glBindTexture(GL_TEXTURE_2D, yTextureName);
830 						glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
831 								GL_ALPHA, GL_UNSIGNED_BYTE, ytex);
832 						glBindTexture(GL_TEXTURE_2D, uTextureName);
833 						glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w >> 1, h >> 1,
834 								GL_ALPHA, GL_UNSIGNED_BYTE, utex);
835 						glBindTexture(GL_TEXTURE_2D, vTextureName);
836 						glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w >> 1, h >> 1,
837 								GL_ALPHA, GL_UNSIGNED_BYTE, vtex);
838 
839 						delete [] ytex;
840 						delete [] utex;
841 						delete [] vtex;
842 						ytex = utex = vtex = NULL;
843 						videoUpdated = true;
844 
845 					}
846 				}
847 			} else if (movieIsEnding) {
848 				// We have reached the end of the movie.
849 				movieIsPlaying = nothing;
850 			}
851 		}
852 
853 		// Update the screen if there's new video, or if we're paused
854 		if (videoUpdated || movieIsPlaying == paused) {
855 			// Clear The Screen
856 			glClear(GL_COLOR_BUFFER_BIT);
857 
858 			// Display the current frame here
859 			if (shader.yuv) {
860 				glUseProgram(shader.yuv);
861 				glActiveTexture(GL_TEXTURE1);
862 				glBindTexture(GL_TEXTURE_2D, uTextureName);
863 				glActiveTexture(GL_TEXTURE2);
864 				glBindTexture(GL_TEXTURE_2D, vTextureName);
865 				glActiveTexture(GL_TEXTURE0);
866 			}
867 			glBindTexture(GL_TEXTURE_2D, yTextureName);
868 			glEnable(GL_BLEND);
869 			//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
870 
871 			setPMVMatrix(shader.yuv);
872 			drawQuad(shader.yuv, vertices, 1, texCoords);
873 
874 			glUseProgram(0);
875 
876 			if (movieIsPlaying == paused) {
877 				pausefade -= 1.0 / 24;
878 				if (pausefade < -1.0) pausefade = 1.0;
879 
880 				// Paused.
881 				glEnable(GL_BLEND);
882 
883 				glUseProgram(shader.color);
884 
885 				setPMVMatrix(shader.color);
886 				setPrimaryColor(0.0f, 0.0f, 0.0f, fabs(pausefade));
887 				drawQuad(shader.color, vertices1, 0);
888 				drawQuad(shader.color, vertices2, 0);
889 				setPrimaryColor(1.0f, 1.0f, 1.0f, fabs(pausefade));
890 				drawQuad(shader.color, vertices3, 0);
891 				drawQuad(shader.color, vertices4, 0);
892 
893 				glUseProgram(0);
894 
895 				glDisable(GL_BLEND);
896 
897 				Wait_Frame();
898 			}
899 
900 			glFlush();
901 
902 			EGL_SwapBuffers();
903 
904 		}
905 		videoUpdated = false;
906 	}
907 
908 	// Cleanup
909 	glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
910 
911 	movieIsPlaying = nothing;
912 	for (int i = 0; i < 10; i++)
913 		Wait_Frame();
914 	huntKillFreeSound(fileNumber);
915 
916 	if (vpx_codec_destroy(&codec))
917 	die_codec(&codec, "Failed to destroy codec");
918 
919 	vorbis_dsp_clear(&vorbisDspState);
920 	vorbis_block_clear(&vorbisBlock);
921 	vorbis_comment_clear(&vorbisComment);
922 	vorbis_info_clear(&vorbisInfo);
923 	delete pSegment;
924 	deleteTextures(1, &yTextureName);
925 	deleteTextures(1, &uTextureName);
926 	deleteTextures(1, &vTextureName);
927 	yTextureName = uTextureName = vTextureName = 0;
928 
929 	// Delete any remaining buffers
930 	videoBuffers *vB = videoQ.first;
931 	while (vB = videoQ.first) {
932 		videoQ.first = vB->next;
933 		delete [] vB->ytex;
934 		delete [] vB->utex;
935 		delete [] vB->vtex;
936 		delete vB;
937 	}
938 	videoQ.size = 0;
939 
940 	audioBuffers *aB = audioQ.first;
941 	while (aB = audioQ.first) {
942 		audioQ.first = aB->next;
943 		delete [] aB->buffer;
944 		delete aB;
945 	}
946 	audioQ.size = 0;
947 
948 	Init_Timer();
949 
950 	glViewport(viewportOffsetX, viewportOffsetY, viewportWidth, viewportHeight);
951 
952 	setPixelCoords(false);
953 #endif
954 	return 0;
955 }
956 
stopMovie()957 int stopMovie() {
958 	int r = movieIsPlaying;
959 	movieIsPlaying = nothing;
960 	return r;
961 }
962 
pauseMovie()963 int pauseMovie() {
964 #if 0
965 	if (movieIsPlaying == playing) {
966 		ALuint source = getSoundSource(movieAudioIndex);
967 		if (source) {
968 
969 			alurePauseSource(source);
970 
971 		}
972 		movieIsPlaying = paused;
973 		fprintf(stderr, "** Pausing **\n");
974 	} else if (movieIsPlaying == paused) {
975 		ALuint source = getSoundSource(movieAudioIndex);
976 		if (source) {
977 
978 			alureResumeSource(source);
979 
980 		}
981 		fprintf(stderr, "** Restarted movie ** sound: %d source: %d\n", movieSoundPlaying, source);
982 		movieIsPlaying = playing;
983 	}
984 #endif
985 	return movieIsPlaying;
986 }
987 
988 } // End of namespace Sludge
989