aboutsummaryrefslogtreecommitdiff
path: root/engines/sludge/movie.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sludge/movie.cpp')
-rw-r--r--engines/sludge/movie.cpp1043
1 files changed, 1043 insertions, 0 deletions
diff --git a/engines/sludge/movie.cpp b/engines/sludge/movie.cpp
new file mode 100644
index 0000000000..debec5e9dc
--- /dev/null
+++ b/engines/sludge/movie.cpp
@@ -0,0 +1,1043 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#if 0
+#include <SDL/SDL.h>
+#endif
+
+#include <math.h>
+
+#include "CommonCode/specialsettings.h"
+
+#include "libwebm/mkvreader.hpp"
+#include "libwebm/mkvparser.hpp"
+
+#if 0
+#define VPX_CODEC_DISABLE_COMPAT 1
+#include "vpx/vpx_decoder.h"
+#include "vpx/vp8dx.h"
+#define interface (&vpx_codec_vp8_dx_algo)
+#endif
+
+#include "newfatal.h"
+#include "timing.h"
+#include "graphics.h"
+#include "movie.h"
+#include "shaders.h"
+
+#include "sound.h"
+#include "vorbis/codec.h"
+#define OV_EXCLUDE_STATIC_CALLBACKS
+#include "vorbis/vorbisfile.h"
+
+#if 0
+#include "ogg/ogg.h"
+#include "libvorbis/vorbis_os.h"
+
+#include "AL/alure.h"
+#endif
+
+extern int specialSettings;
+
+// in main.c
+int checkInput();
+extern int weAreDoneSoQuit;
+
+// Sludger.cpp
+bool handleInput();
+
+// sound_openal.cpp
+void playMovieStream(int a);
+#if 0
+int initMovieSound(int f, ALenum format, int audioChannels, ALuint samplerate,
+ ALuint(*callback)(void *userdata, ALubyte *data, ALuint bytes));
+#endif
+
+movieStates movieIsPlaying = nothing;
+
+int movieIsEnding = 0;
+
+float movieAspect = 1.6;
+#if 0
+typedef struct audioBuffers {
+ char *buffer;
+ unsigned int size;
+ audioBuffers *next;
+ Uint32 time_ms;
+} audioBuffers;
+
+typedef struct audioQueue {
+ audioBuffers *first, *last;
+ int size;
+ SDL_mutex *mutex;
+ SDL_cond *cond;
+} audioQueue;
+
+audioQueue audioQ;
+
+Uint32 movieStartTick, movieCurrentTime;
+
+long long audioNsPerByte;
+long long audioNsPlayed;
+long long audioNsBuffered;
+long long audioBufferLen;
+bool movieSoundPlaying = false;
+int movieAudioIndex;
+GLuint yTextureName = 0;
+GLuint uTextureName = 0;
+GLuint vTextureName = 0;
+
+typedef struct videoBuffers {
+ GLubyte *ytex;
+ GLubyte *utex;
+ GLubyte *vtex;
+ videoBuffers *next;
+ GLsizei w, h;
+ Uint32 time_ms;
+} videoBuffers;
+
+typedef struct videoQueue {
+ videoBuffers *first, *last;
+ int size;
+ SDL_mutex *mutex;
+ SDL_cond *cond;
+} videoQueue;
+
+videoQueue videoQ;
+
+
+void audio_queue_init(audioQueue *q) {
+ memset(q, 0, sizeof(audioQueue));
+
+ q->mutex = SDL_CreateMutex();
+ q->cond = SDL_CreateCond();
+
+}
+int audio_queue_put(audioQueue *q, char *buffer, unsigned int size, long long time_ms) {
+
+ audioBuffers *audioBuf = new audioBuffers;
+ if (!audioBuf)
+ return -1;
+ audioBuf->buffer = buffer;
+ audioBuf->next = NULL;
+ audioBuf->size = size;
+ audioBuf->time_ms = time_ms;
+
+ SDL_LockMutex(q->mutex);
+
+ if (!q->last)
+ q->first = audioBuf;
+ else
+ q->last->next = audioBuf;
+ q->last = audioBuf;
+ q->size ++;
+ SDL_CondSignal(q->cond);
+
+ SDL_UnlockMutex(q->mutex);
+
+ return 0;
+}
+inline static int audio_queue_get(audioQueue *q, char **buffer) {
+ int ret = 0;
+
+
+ audioBuffers *audioBuf;
+
+ SDL_LockMutex(q->mutex);
+
+ audioBuf = q->first;
+ if (audioBuf) {
+ // Synch video timer to audio
+ Uint32 tick = SDL_GetTicks() + 100;
+ if (abs((long int)((tick - movieStartTick) - (audioBuf->time_ms))) > 300) {
+ movieStartTick = tick - audioBuf->time_ms;
+ }
+
+ q->first = audioBuf->next;
+ if (!q->first)
+ q->last = NULL;
+ q->size--;
+ *buffer = audioBuf->buffer;
+ ret = audioBuf->size;
+ delete audioBuf;
+ }
+
+ SDL_UnlockMutex(q->mutex);
+
+ return ret;
+}
+
+void video_queue_init(videoQueue *q) {
+ memset(q, 0, sizeof(videoQueue));
+ q->mutex = SDL_CreateMutex();
+ q->cond = SDL_CreateCond();
+}
+int video_queue_put(videoQueue *q, GLubyte *ytex,
+ GLubyte *utex,
+ GLubyte *vtex,
+ GLsizei w, GLsizei h,
+ long long time_ms) {
+
+ videoBuffers *videoBuf = new videoBuffers;
+ if (!videoBuf)
+ return -1;
+ videoBuf->ytex = ytex;
+ videoBuf->utex = utex;
+ videoBuf->vtex = vtex;
+ videoBuf->next = NULL;
+ videoBuf->w = w;
+ videoBuf->h = h;
+ videoBuf->time_ms = time_ms;
+
+ SDL_LockMutex(q->mutex);
+
+ if (!q->last)
+ q->first = videoBuf;
+ else
+ q->last->next = videoBuf;
+ q->last = videoBuf;
+ q->size ++;
+ SDL_CondSignal(q->cond);
+
+ SDL_UnlockMutex(q->mutex);
+ return 0;
+}
+inline static int video_queue_get(videoQueue *q,
+ GLubyte **ytex,
+ GLubyte **utex,
+ GLubyte **vtex,
+ GLsizei *w, GLsizei *h) {
+ videoBuffers *videoBuf;
+ int ret = 0;
+
+ SDL_LockMutex(q->mutex);
+
+ videoBuf = q->first;
+ if (videoBuf) {
+ q->first = videoBuf->next;
+ if (!q->first)
+ q->last = NULL;
+ q->size--;
+ *ytex = videoBuf->ytex;
+ *utex = videoBuf->utex;
+ *vtex = videoBuf->vtex;
+ *w = videoBuf->w;
+ *h = videoBuf->h;
+ ret = 1;
+ delete videoBuf;
+ }
+
+ SDL_UnlockMutex(q->mutex);
+
+ return ret;
+}
+
+#if 0
+static void die_codec(vpx_codec_ctx_t *ctx, const char *s) {
+ //const char *detail = vpx_codec_error_detail(ctx);
+ fatal(s, vpx_codec_error(ctx));
+}
+#endif
+
+void setMovieViewport() {
+ float realAspect = (float) realWinWidth / realWinHeight;
+
+ int vpHeight, vpWidth, vpOffsetX, vpOffsetY;
+ if (realAspect > movieAspect) {
+ vpHeight = realWinHeight;
+ vpWidth = (int)(realWinHeight * movieAspect);
+ vpOffsetY = 0;
+ vpOffsetX = (realWinWidth - vpWidth) / 2;
+ } else {
+ vpWidth = realWinWidth;
+ vpHeight = (int)((float) realWinWidth / movieAspect);
+ vpOffsetY = (realWinHeight - vpHeight) / 2;
+ vpOffsetX = 0;
+ }
+#if 0
+ glViewport(vpOffsetX, vpOffsetY, vpWidth, vpHeight);
+#endif
+ const GLfloat bPMVMatrix[] = {
+ 2.0f / 640.f, .0, .0, .0,
+ .0, -2.0f / 400.f, .0, .0,
+ .0, .0, 1.0f, .0,
+ -1.0, 1.0f, .0, 1.0f
+
+ };
+ for (int i = 0; i < 16; i++) {
+ aPMVMatrix[i] = bPMVMatrix[i];
+ }
+}
+
+static uint64_t xiph_lace_value(unsigned char **np) {
+ uint64_t lace;
+ uint64_t value;
+ unsigned char *p = *np;
+
+ lace = *p++;
+ value = lace;
+ while (lace == 255) {
+ lace = *p++;
+ value += lace;
+ }
+
+ *np = p;
+
+ return value;
+}
+
+vorbis_dsp_state vorbisDspState;
+long long audioChannels;
+
+bool fakeAudio = false;
+
+// send audio to audio device...
+ALuint feedAudio(void *userdata, ALubyte *data, ALuint length) {
+ static char *buffer = NULL;
+ static unsigned int bufOffset = 0;
+ static unsigned int bufSize = 0;
+
+ ALuint got = 0;
+ int bufLen;
+
+ if (! buffer) {
+ bufSize = audio_queue_get(&audioQ, &buffer);
+ bufOffset = 0;
+ if (bufSize <= 0) {
+ bufSize = 0;
+ buffer = NULL;
+ if (! got) {
+ got = audioChannels * 2;
+ memset(data, 0, got);
+ fprintf(stderr, "Faking audio...\n");
+ fakeAudio = true;
+ }
+// SDL_CondSignal(audioQ.cond);
+ return got;
+ }
+ }
+
+ fakeAudio = false;
+
+ if (length > bufSize - bufOffset)
+ bufLen = bufSize - bufOffset;
+ else
+ bufLen = length;
+
+ memcpy(data, buffer + bufOffset, bufLen);
+
+ bufOffset += bufLen;
+ length -= bufLen;
+ got += bufLen;
+
+ if (bufSize <= bufOffset) {
+ buffer = NULL;
+ delete [] buffer;
+ }
+// fprintf (stderr, "Sending %d bytes of audio.\n", got);
+
+ return got;
+}
+#endif
+
+int playMovie(int fileNumber) {
+#if 0
+ if (specialSettings & SPECIAL_SILENT)
+ return 0;
+
+ if (movieIsPlaying) return 0;
+
+ movieSoundPlaying = false;
+
+ vpx_codec_ctx_t codec;
+
+ float pausefade = 1.0;
+
+ using namespace mkvparser;
+
+ MkvReader reader;
+
+ if (reader.Open(fileNumber)) {
+ warning(ERROR_MOVIE_ODDNESS);
+ return 0;
+ }
+
+ long long pos = 0;
+
+ EBMLHeader ebmlHeader;
+
+ ebmlHeader.Parse(&reader, pos);
+
+ mkvparser::Segment *pSegment;
+
+ long long ret = mkvparser::Segment::CreateInstance(&reader, pos, pSegment);
+ if (ret) {
+ fatal("Movie error: Segment::CreateInstance() failed.\n");
+ }
+
+ ret = pSegment->Load();
+ if (ret < 0) {
+ fatal("Movie error: Segment::Load() failed.\n");
+ }
+
+ //const SegmentInfo* const pSegmentInfo = pSegment->GetInfo();
+ //const long long timeCodeScale = pSegmentInfo->GetTimeCodeScale();
+ //const long long duration_ns = pSegmentInfo->GetDuration();
+ //const char* const pTitle = pSegmentInfo->GetTitleAsUTF8();
+ //const char* const pMuxingApp = pSegmentInfo->GetMuxingAppAsUTF8();
+ //const char* const pWritingApp = pSegmentInfo->GetWritingAppAsUTF8();
+
+ const mkvparser::Tracks *pTracks = pSegment->GetTracks();
+
+ unsigned long i = 0;
+ const unsigned long j = pTracks->GetTracksCount();
+
+ enum { VIDEO_TRACK = 1, AUDIO_TRACK = 2 };
+ int videoTrack = -1;
+ int audioTrack = -1;
+ long long audioBitDepth;
+ double audioSampleRate;
+ ogg_packet oggPacket;
+ vorbis_info vorbisInfo;
+ vorbis_comment vorbisComment;
+ vorbis_block vorbisBlock;
+
+ while (i != j) {
+ const Track *const pTrack = pTracks->GetTrackByIndex(i++);
+
+ if (pTrack == NULL)
+ continue;
+
+ const long long trackType = pTrack->GetType();
+ //const unsigned long long trackUid = pTrack->GetUid();
+ //const char* pTrackName = pTrack->GetNameAsUTF8();
+
+ if (trackType == VIDEO_TRACK && videoTrack < 0) {
+ videoTrack = pTrack->GetNumber();
+ const VideoTrack *const pVideoTrack =
+ static_cast<const VideoTrack *>(pTrack);
+
+ const long long width = pVideoTrack->GetWidth();
+ const long long height = pVideoTrack->GetHeight();
+
+ const double rate = pVideoTrack->GetFrameRate();
+
+ if (rate > 0)
+ Init_Special_Timer(rate);
+
+ movieAspect = (float)width / height;
+ }
+
+ if (trackType == AUDIO_TRACK && audioTrack < 0) {
+ audioTrack = pTrack->GetNumber();
+ const AudioTrack *const pAudioTrack =
+ static_cast<const AudioTrack *>(pTrack);
+
+ audioChannels = pAudioTrack->GetChannels();
+ audioBitDepth = pAudioTrack->GetBitDepth();
+ audioSampleRate = pAudioTrack->GetSamplingRate();
+
+ size_t audioHeaderSize;
+ const unsigned char *audioHeader = pAudioTrack->GetCodecPrivate(audioHeaderSize);
+
+ if (audioHeaderSize < 1) {
+ warning("Strange audio track in movie.");
+ audioTrack = -1;
+ continue;
+ }
+
+ unsigned char *p = (unsigned char *)audioHeader;
+
+ unsigned int count = *p++ + 1;
+ if (count != 3) {
+ warning("Strange audio track in movie.");
+ audioTrack = -1;
+ continue;
+ }
+
+ uint64_t sizes[3], total;
+
+ int i = 0;
+ total = 0;
+ while (--count) {
+ sizes[i] = xiph_lace_value(&p);
+ total += sizes[i];
+ i += 1;
+ }
+ sizes[i] = audioHeaderSize - total - (p - audioHeader);
+
+ // initialize vorbis
+ vorbis_info_init(&vorbisInfo);
+ vorbis_comment_init(&vorbisComment);
+ memset(&vorbisDspState, 0, sizeof(vorbisDspState));
+ memset(&vorbisBlock, 0, sizeof(vorbisBlock));
+
+ oggPacket.e_o_s = false;
+ oggPacket.granulepos = 0;
+ oggPacket.packetno = 0;
+ int r;
+ for (int i = 0; i < 3; i++) {
+ oggPacket.packet = p;
+ oggPacket.bytes = sizes[i];
+ oggPacket.b_o_s = oggPacket.packetno == 0;
+ r = vorbis_synthesis_headerin(&vorbisInfo, &vorbisComment, &oggPacket);
+ if (r)
+ fprintf(stderr, "vorbis_synthesis_headerin failed, error: %d", r);
+ oggPacket.packetno++;
+ p += sizes[i];
+ }
+
+ r = vorbis_synthesis_init(&vorbisDspState, &vorbisInfo);
+ if (r)
+ fprintf(stderr, "vorbis_synthesis_init failed, error: %d", r);
+ r = vorbis_block_init(&vorbisDspState, &vorbisBlock);
+ if (r)
+ fprintf(stderr, "vorbis_block_init failed, error: %d", r);
+
+ ALenum audioFormat = alureGetSampleFormat(audioChannels, 16, 0);
+ movieAudioIndex = initMovieSound(fileNumber, audioFormat, audioChannels, (ALuint) audioSampleRate, feedAudio);
+
+ fprintf(stderr, "Movie sound inited.\n");
+ audio_queue_init(&audioQ);
+ audioNsPerByte = (1000000000 / audioSampleRate) / (audioChannels * 2);
+ audioNsBuffered = 0;
+ audioBufferLen = audioChannels * audioSampleRate;
+ }
+ }
+
+ if (videoTrack < 0)
+ fatal("Movie error: No video in movie file.");
+
+ if (audioTrack < 0)
+ fatal("Movie error: No sound found.");
+
+ video_queue_init(&videoQ);
+
+ const unsigned long clusterCount = pSegment->GetCount();
+
+ if (clusterCount == 0) {
+ fatal("Movie error: Segment has no clusters.\n");
+ }
+
+
+ /* Initialize video codec */
+ if (vpx_codec_dec_init(&codec, interface, NULL, 0))
+ die_codec(&codec, "Failed to initialize decoder for movie.");
+
+
+ unsigned char *frame = new unsigned char[256 * 1024];
+ if (! checkNew(frame)) return false;
+
+ const mkvparser::Cluster *pCluster = pSegment->GetFirst();
+
+ setMovieViewport();
+
+ movieIsPlaying = playing;
+ movieIsEnding = 0;
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+
+ //const long long timeCode = pCluster->GetTimeCode();
+ long long time_ns = pCluster->GetTime();
+
+ const BlockEntry *pBlockEntry = pCluster->GetFirst();
+
+ if ((pBlockEntry == NULL) || pBlockEntry->EOS()) {
+ pCluster = pSegment->GetNext(pCluster);
+ if ((pCluster == NULL) || pCluster->EOS()) {
+ fatal("Error: No movie found in the movie file.");
+ }
+ pBlockEntry = pCluster->GetFirst();
+ }
+ const Block *pBlock = pBlockEntry->GetBlock();
+ long long trackNum = pBlock->GetTrackNumber();
+ unsigned long tn = static_cast<unsigned long>(trackNum);
+ const Track *pTrack = pTracks->GetTrackByNumber(tn);
+ long long trackType = pTrack->GetType();
+ int frameCount = pBlock->GetFrameCount();
+ time_ns = pBlock->GetTime(pCluster);
+
+ const GLfloat texCoords[] = {
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0
+ };
+
+ const GLfloat vertices[] = {
+ 0.0, 0.0, 0.1,
+ 640.0, 0.0, 0.1,
+ 0.0, 400.0, 0.1,
+ 640.0, 400.0, 0.1
+ };
+
+ const GLfloat vertices1[] = {
+ 7.0, 7.0, 0.1,
+ 17.0, 7.0, 0.1,
+ 7.0, 29.0, 0.1,
+ 17.0, 29.0, 0.1
+ };
+
+ const GLfloat vertices2[] = {
+ 27.0, 7.0, 0.1,
+ 37.0, 7.0, 0.1,
+ 27.0, 29.0, 0.1,
+ 37.0, 29.0, 0.1
+ };
+
+ const GLfloat vertices3[] = {
+ 5.0, 5.0, 0.1,
+ 15.0, 5.0, 0.1,
+ 5.0, 27.0, 0.1,
+ 15.0, 27.0, 0.1
+ };
+
+ const GLfloat vertices4[] = {
+ 25.0, 5.0, 0.1,
+ 35.0, 5.0, 0.1,
+ 25.0, 27.0, 0.1,
+ 35.0, 27.0, 0.1
+ };
+
+ int frameCounter = 0;
+
+ movieStartTick = SDL_GetTicks();
+#ifdef HAVE_GLES2
+ GLuint old_fbo;
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&old_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+
+ while (movieIsPlaying) {
+
+ checkInput();
+ if (weAreDoneSoQuit)
+ break;
+ handleInput();
+
+ if (movieIsPlaying && (! movieIsEnding) && (videoQ.size < 100 || audioQ.size < 100)) {
+ // Decode a frame!
+
+ if ((pCluster != NULL) && !pCluster->EOS()) {
+
+ if (frameCounter >= frameCount) {
+
+ pBlockEntry = pCluster->GetNext(pBlockEntry);
+ if ((pBlockEntry == NULL) || pBlockEntry->EOS()) {
+ pCluster = pSegment->GetNext(pCluster);
+ if ((pCluster == NULL) || pCluster->EOS()) {
+ goto movieHasEnded;
+ }
+ pBlockEntry = pCluster->GetFirst();
+ }
+ pBlock = pBlockEntry->GetBlock();
+ trackNum = pBlock->GetTrackNumber();
+ tn = static_cast<unsigned long>(trackNum);
+ pTrack = pTracks->GetTrackByNumber(tn);
+ trackType = pTrack->GetType();
+ frameCount = pBlock->GetFrameCount();
+ time_ns = pBlock->GetTime(pCluster);
+
+ frameCounter = 0;
+ }
+
+ const Block::Frame &theFrame = pBlock->GetFrame(frameCounter);
+ const long size = theFrame.len;
+ // const long long offset = theFrame.pos;
+
+ if (size > sizeof(frame)) {
+ if (frame) delete [] frame;
+ frame = new unsigned char[size];
+ if (! checkNew(frame)) return 0;
+ }
+ /*
+ fprintf (stderr, "Block :%s,%s,%15lld\n",
+ (trackType == VIDEO_TRACK) ? "V" : "A",
+ pBlock->IsKey() ? "I" : "P",
+ time_ns);
+ */
+
+ if (trackNum == videoTrack) {
+
+ theFrame.Read(&reader, frame);
+
+
+ /* Decode the frame */
+ if (vpx_codec_decode(&codec, frame, size, NULL, 0))
+ die_codec(&codec, "Failed to decode frame");
+
+ // Let's decode an image frame!
+ vpx_codec_iter_t iter = NULL;
+ vpx_image_t *img;
+ /* Get frame data */
+ while ((img = vpx_codec_get_frame(&codec, &iter))) {
+ if (img->fmt != VPX_IMG_FMT_I420)
+ fatal("Movie error. The movie is not in I420 colour format, which is the only one I can hanlde at the moment.");
+
+ unsigned int y;
+
+ GLubyte *ytex = NULL;
+ GLubyte *utex = NULL;
+ GLubyte *vtex = NULL;
+
+ if (! ytex) {
+ ytex = new GLubyte [img->d_w * img->d_h];
+ utex = new GLubyte [(img->d_w >> 1) * (img->d_h >> 1)];
+ vtex = new GLubyte [(img->d_w >> 1) * (img->d_h >> 1)];
+ if (!ytex || !utex || !vtex)
+ fatal(ERROR_OUT_OF_MEMORY);
+
+ }
+
+ unsigned char *buf = img->planes[0];
+ for (y = 0; y < img->d_h; y++) {
+ memcpy(ytex + y * img->d_w, buf, img->d_w);
+ buf += img->stride[0];
+ }
+ buf = img->planes[1];
+ for (y = 0; y < img->d_h >> 1; y++) {
+ memcpy(utex + y * (img->d_w >> 1), buf, img->d_w >> 1);
+ buf += img->stride[1];
+ }
+ buf = img->planes[2];
+ for (y = 0; y < img->d_h >> 1; y++) {
+ memcpy(vtex + y * (img->d_w >> 1), buf, img->d_w >> 1);
+ buf += img->stride[2];
+ }
+
+ video_queue_put(&videoQ, ytex, utex, vtex,
+ img->d_w, img->d_h, time_ns / 1000000);
+
+
+ }
+
+ } else if (trackNum == audioTrack) {
+ // Use this Audio Track
+ if (size > 0) {
+ theFrame.Read(&reader, frame);
+ oggPacket.packet = frame;
+ oggPacket.bytes = size;
+ oggPacket.b_o_s = false;
+ oggPacket.packetno++;
+ oggPacket.granulepos = -1;
+ if (! vorbis_synthesis(&vorbisBlock, &oggPacket)) {
+ if (vorbis_synthesis_blockin(&vorbisDspState, &vorbisBlock))
+ fprintf(stderr, "Vorbis Synthesis block in error.\n");
+
+ } else {
+ fprintf(stderr, "Vorbis Synthesis error.\n");
+ }
+
+ float **pcm;
+
+ int numSamples = vorbis_synthesis_pcmout(&vorbisDspState, &pcm);
+
+ if (numSamples > 0) {
+ int word = 2;
+ int sgned = 1;
+ int i, j;
+ long bytespersample = audioChannels * word;
+ vorbis_fpu_control fpu;
+
+ char *buffer = new char[bytespersample * numSamples];
+ if (! checkNew(buffer)) return false;
+
+ /* a tight loop to pack each size */
+ {
+ int val;
+ if (word == 1) {
+ int off = (sgned ? 0 : 128);
+ vorbis_fpu_setround(&fpu);
+ for (j = 0; j < numSamples; j++)
+ for (i = 0; i < audioChannels; i++) {
+ val = vorbis_ftoi(pcm[i][j] * 128.f);
+ if (val > 127)val = 127;
+ else if (val < -128)val = -128;
+ *buffer++ = val + off;
+ }
+ vorbis_fpu_restore(fpu);
+ } else {
+ int off = (sgned ? 0 : 32768);
+
+ if (sgned) {
+
+ vorbis_fpu_setround(&fpu);
+ for (i = 0; i < audioChannels; i++) { /* It's faster in this order */
+ float *src = pcm[i];
+ short *dest = ((short *)buffer) + i;
+ for (j = 0; j < numSamples; j++) {
+ val = vorbis_ftoi(src[j] * 32768.f);
+ if (val > 32767)val = 32767;
+ else if (val < -32768)val = -32768;
+ *dest = val;
+ dest += audioChannels;
+ }
+ }
+ vorbis_fpu_restore(fpu);
+
+ } else {
+
+ vorbis_fpu_setround(&fpu);
+ for (i = 0; i < audioChannels; i++) {
+ float *src = pcm[i];
+ short *dest = ((short *)buffer) + i;
+ for (j = 0; j < numSamples; j++) {
+ val = vorbis_ftoi(src[j] * 32768.f);
+ if (val > 32767)val = 32767;
+ else if (val < -32768)val = -32768;
+ *dest = val + off;
+ dest += audioChannels;
+ }
+ }
+ vorbis_fpu_restore(fpu);
+
+ }
+
+ }
+ }
+
+ vorbis_synthesis_read(&vorbisDspState, numSamples);
+ audioBufferLen = bytespersample * numSamples;
+ audio_queue_put(&audioQ, buffer, audioBufferLen, time_ns / 1000000);
+
+ //fprintf (stderr, "Audio buffered: %lld byte %lld ns\n",audioBufferLen, audioNsPerByte*audioBufferLen);
+
+ if (! movieSoundPlaying && size > 1) {
+ fprintf(stderr, "** starting sound ** \n");
+ playMovieStream(movieAudioIndex);
+ movieSoundPlaying = true;
+ }
+ }
+ }
+ }
+ ++frameCounter;
+
+ } else {
+movieHasEnded:
+ movieIsEnding = 1;
+ }
+ }
+
+ bool videoUpdated = false;
+ // Get a video frame.
+ if (movieIsPlaying == playing) {
+
+ videoBuffers *vB;
+ // Do we have decoded video waiting?
+ if (vB = videoQ.first) {
+ Uint32 tick = SDL_GetTicks() - movieStartTick;
+
+ // Is it time to display the frame yet?
+ if ((tick + 1) < vB->time_ms) {
+ SDL_Delay(1);
+ } else {
+ GLubyte *ytex = NULL;
+ GLubyte *utex = NULL;
+ GLubyte *vtex = NULL;
+ GLsizei w, h;
+
+ if (video_queue_get(&videoQ, &ytex, &utex, &vtex, &w, &h)) {
+
+ if (! yTextureName) glGenTextures(1, &yTextureName);
+ if (! uTextureName) glGenTextures(1, &uTextureName);
+ if (! vTextureName) glGenTextures(1, &vTextureName);
+ glBindTexture(GL_TEXTURE_2D, yTextureName);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, ytex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glBindTexture(GL_TEXTURE_2D, uTextureName);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w >> 1, h >> 1, 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, utex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glBindTexture(GL_TEXTURE_2D, vTextureName);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w >> 1, h >> 1, 0,
+ GL_ALPHA, GL_UNSIGNED_BYTE, vtex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+
+ glBindTexture(GL_TEXTURE_2D, yTextureName);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
+ GL_ALPHA, GL_UNSIGNED_BYTE, ytex);
+ glBindTexture(GL_TEXTURE_2D, uTextureName);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w >> 1, h >> 1,
+ GL_ALPHA, GL_UNSIGNED_BYTE, utex);
+ glBindTexture(GL_TEXTURE_2D, vTextureName);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w >> 1, h >> 1,
+ GL_ALPHA, GL_UNSIGNED_BYTE, vtex);
+
+ delete [] ytex;
+ delete [] utex;
+ delete [] vtex;
+ ytex = utex = vtex = NULL;
+ videoUpdated = true;
+
+ }
+ }
+ } else if (movieIsEnding) {
+ // We have reached the end of the movie.
+ movieIsPlaying = nothing;
+ }
+ }
+
+ // Update the screen if there's new video, or if we're paused
+ if (videoUpdated || movieIsPlaying == paused) {
+ // Clear The Screen
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Display the current frame here
+ if (shader.yuv) {
+ glUseProgram(shader.yuv);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, uTextureName);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, vTextureName);
+ glActiveTexture(GL_TEXTURE0);
+ }
+ glBindTexture(GL_TEXTURE_2D, yTextureName);
+ glEnable(GL_BLEND);
+ //glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ setPMVMatrix(shader.yuv);
+ drawQuad(shader.yuv, vertices, 1, texCoords);
+
+ glUseProgram(0);
+
+ if (movieIsPlaying == paused) {
+ pausefade -= 1.0 / 24;
+ if (pausefade < -1.0) pausefade = 1.0;
+
+ // Paused.
+ glEnable(GL_BLEND);
+
+ glUseProgram(shader.color);
+
+ setPMVMatrix(shader.color);
+ setPrimaryColor(0.0f, 0.0f, 0.0f, fabs(pausefade));
+ drawQuad(shader.color, vertices1, 0);
+ drawQuad(shader.color, vertices2, 0);
+ setPrimaryColor(1.0f, 1.0f, 1.0f, fabs(pausefade));
+ drawQuad(shader.color, vertices3, 0);
+ drawQuad(shader.color, vertices4, 0);
+
+ glUseProgram(0);
+
+
+ glDisable(GL_BLEND);
+
+ Wait_Frame();
+ }
+
+ glFlush();
+#if !defined(HAVE_GLES2)
+ SDL_GL_SwapBuffers();
+#else
+ EGL_SwapBuffers();
+#endif
+
+ }
+ videoUpdated = false;
+ }
+
+ // Cleanup
+#ifdef HAVE_GLES2
+ glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
+
+ movieIsPlaying = nothing;
+ for (int i = 0; i < 10; i++) Wait_Frame();
+ huntKillFreeSound(fileNumber);
+
+
+ if (vpx_codec_destroy(&codec))
+ die_codec(&codec, "Failed to destroy codec");
+
+
+ vorbis_dsp_clear(&vorbisDspState);
+ vorbis_block_clear(&vorbisBlock);
+ vorbis_comment_clear(&vorbisComment);
+ vorbis_info_clear(&vorbisInfo);
+ delete pSegment;
+ deleteTextures(1, &yTextureName);
+ deleteTextures(1, &uTextureName);
+ deleteTextures(1, &vTextureName);
+ yTextureName = uTextureName = vTextureName = 0;
+
+ // Delete any remaining buffers
+ videoBuffers *vB = videoQ.first;
+ while (vB = videoQ.first) {
+ videoQ.first = vB->next;
+ delete [] vB->ytex;
+ delete [] vB->utex;
+ delete [] vB->vtex;
+ delete vB;
+ }
+ videoQ.size = 0;
+
+ audioBuffers *aB = audioQ.first;
+ while (aB = audioQ.first) {
+ audioQ.first = aB->next;
+ delete [] aB->buffer;
+ delete aB;
+ }
+ audioQ.size = 0;
+
+ Init_Timer();
+
+ glViewport(viewportOffsetX, viewportOffsetY, viewportWidth, viewportHeight);
+#endif
+ setPixelCoords(false);
+#endif
+ return 1;
+}
+
+int stopMovie() {
+ int r = movieIsPlaying;
+ movieIsPlaying = nothing;
+ return r;
+}
+
+int pauseMovie() {
+#if 0
+ if (movieIsPlaying == playing) {
+ ALuint source = getSoundSource(movieAudioIndex);
+ if (source) {
+
+ alurePauseSource(source);
+
+ }
+ movieIsPlaying = paused;
+ fprintf(stderr, "** Pausing **\n");
+ } else if (movieIsPlaying == paused) {
+ ALuint source = getSoundSource(movieAudioIndex);
+ if (source) {
+
+ alureResumeSource(source);
+
+ }
+ fprintf(stderr, "** Restarted movie ** sound: %d source: %d\n", movieSoundPlaying, source);
+ movieIsPlaying = playing;
+ }
+#endif
+ return movieIsPlaying;
+}