From e6452518ddb13294c2b3264e9dc754c8ad6ff3ef Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 14 May 2011 22:48:44 -0400 Subject: SWORD25: Begin fixing the TheoraDecoder implementation getFrameRate() and endOfVideo() have been fixed so it can be used as a standalone decoder. a/v sync still needs to be fixed --- engines/sword25/fmv/movieplayer.cpp | 2 +- engines/sword25/fmv/theora_decoder.cpp | 117 +++++++++++++-------------------- engines/sword25/fmv/theora_decoder.h | 34 +++------- 3 files changed, 56 insertions(+), 97 deletions(-) (limited to 'engines/sword25') diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp index 2a55f6dd91..c60f5d4cbf 100644 --- a/engines/sword25/fmv/movieplayer.cpp +++ b/engines/sword25/fmv/movieplayer.cpp @@ -46,7 +46,7 @@ namespace Sword25 { #define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */ #ifdef USE_THEORADEC -MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel), _decoder(g_system->getMixer()) { +MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel), _decoder() { if (!registerScriptBindings()) error("Script bindings could not be registered."); else diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp index 15e81af79c..f7e5e7ae25 100644 --- a/engines/sword25/fmv/theora_decoder.cpp +++ b/engines/sword25/fmv/theora_decoder.cpp @@ -51,7 +51,7 @@ static double rint(double v) { return floor(v + 0.5); } -TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) { +TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) { _fileStream = 0; _surface = 0; @@ -59,7 +59,6 @@ TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT _vorbisPacket = 0; _theoraDecode = 0; _theoraSetup = 0; - _stateFlag = false; _soundType = soundType; _audStream = 0; @@ -67,7 +66,7 @@ TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT ogg_sync_init(&_oggSync); - _curFrame = 0; + _curFrame = -1; _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); reset(); @@ -115,7 +114,8 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { // Ogg file open; parse the headers // Only interested in Vorbis/Theora streams - while (!_stateFlag) { + bool foundHeader = false; + while (!foundHeader) { int ret = bufferData(); if (ret == 0) @@ -128,7 +128,7 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { if (!ogg_page_bos(&_oggPage)) { // don't leak the page; get it into the appropriate stream queuePage(&_oggPage); - _stateFlag = true; + foundHeader = true; break; } @@ -280,15 +280,17 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { // open audio if (_vorbisPacket) { - _audStream = createAudioStream(); - if (_audStream && _mixer) - _mixer->playStream(_soundType, _audHandle, _audStream); + _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); + if (_audStream) + g_system->getMixer()->playStream(_soundType, _audHandle, _audStream); } _surface = new Graphics::Surface(); - _surface->create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat()); + // Set the frame rate + _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator); + return true; } @@ -300,8 +302,8 @@ void TheoraDecoder::close() { vorbis_comment_clear(&_vorbisComment); vorbis_info_clear(&_vorbisInfo); - if (_mixer) - _mixer->stopHandle(*_audHandle); + g_system->getMixer()->stopHandle(*_audHandle); + _audStream = 0; _vorbisPacket = false; } @@ -372,7 +374,7 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() { } } - while (_theoraPacket && !_videobufReady) { + while (_theoraPacket && !_theoraOut.e_o_s) { // theora is one in, one out... if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { @@ -399,26 +401,28 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() { if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) { #endif _curFrame++; - _videobufReady = true; - } - } else - break; - } - if (!_videobufReady && !_audiobufReady && _fileStream->eos()) { - return NULL; - } + // Convert YUV data to RGB data + th_ycbcr_buffer yuv; + th_decode_ycbcr_out(_theoraDecode, yuv); + translateYUVtoRGBA(yuv); - if (!_videobufReady || !_audiobufReady) { - // no data yet for somebody. Grab another page - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { - queuePage(&_oggPage); + if (_curFrame == 0) + _startTime = g_system->getMillis(); + + // break out + break; + } + } else { + // Queue more data + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); } } // If playback has begun, top audio buffer off immediately. - if (_stateFlag && _audiobufReady) { + if (_audiobufReady) { _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO); // The audio mixer is now responsible for the old audio buffer. @@ -428,39 +432,17 @@ const Graphics::Surface *TheoraDecoder::decodeNextFrame() { _audiobufReady = false; } - // are we at or past time for this video frame? - if (_stateFlag && _videobufReady) { - th_ycbcr_buffer yuv; - - th_decode_ycbcr_out(_theoraDecode, yuv); - - // Convert YUV data to RGB data - translateYUVtoRGBA(yuv, (byte *)_surface->getBasePtr(0, 0)); - - _videobufReady = false; - } - - // if our buffers either don't exist or are ready to go, - // we can begin playback - if ((!_theoraPacket || _videobufReady) && - (!_vorbisPacket || _audiobufReady)) - _stateFlag = true; - - // same if we've run out of input - if (_fileStream->eos()) - _stateFlag = true; - return _surface; } void TheoraDecoder::reset() { FixedRateVideoDecoder::reset(); + // FIXME: This does a rewind() instead of a reset()! + if (_fileStream) _fileStream->seek(0); - _videobufReady = false; - #if ENABLE_THEORA_SEEKING _videobufGranulePos = -1; _audiobufGranulePos = 0; @@ -470,36 +452,31 @@ void TheoraDecoder::reset() { _audiobufFill = 0; _audiobufReady = false; - _curFrame = 0; + _curFrame = -1; _theoraPacket = 0; _vorbisPacket = 0; - _stateFlag = false; } bool TheoraDecoder::endOfVideo() const { - return !isVideoLoaded(); + return !isVideoLoaded() || _theoraOut.e_o_s; } - uint32 TheoraDecoder::getElapsedTime() const { - if (_audStream && _mixer) - return _mixer->getSoundElapsedTime(*_audHandle); + if (_audStream) + return g_system->getMixer()->getSoundElapsedTime(*_audHandle); return FixedRateVideoDecoder::getElapsedTime(); } -Audio::QueuingAudioStream *TheoraDecoder::createAudioStream() { - return Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); -} - -static void convertYUVtoBGRA(int y, int u, int v, byte *dst) { +static void convertYUVtoBGRA(int y, int u, int v, byte *dst, Graphics::PixelFormat format) { byte r, g, b; Graphics::YUV2RGB(y, u, v, r, g, b); - *(dst + 0) = b; - *(dst + 1) = g; - *(dst + 2) = r; - *(dst + 3) = 0xFF; + + if (format.bytesPerPixel == 2) + *((uint16 *)dst) = format.RGBToColor(r, g, b); + else + *((uint32 *)dst) = format.RGBToColor(r, g, b); } enum TheoraYUVBuffers { @@ -508,7 +485,7 @@ enum TheoraYUVBuffers { kBufferV = 2 }; -void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelData) { +void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { // Width and height of all buffers have to be divisible by 2. assert((YUVBuffer[kBufferY].width & 1) == 0); assert((YUVBuffer[kBufferY].height & 1) == 0); @@ -524,10 +501,10 @@ void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelDa const byte *ySrc = YUVBuffer[kBufferY].data; const byte *uSrc = YUVBuffer[kBufferU].data; const byte *vSrc = YUVBuffer[kBufferV].data; - byte *dst = pixelData; + byte *dst = (byte *)_surface->pixels; int u = 0, v = 0; - const int blockSize = YUVBuffer[kBufferY].width << 2; + const int blockSize = YUVBuffer[kBufferY].width * getPixelFormat().bytesPerPixel; const int halfHeight = YUVBuffer[kBufferY].height >> 1; const int halfWidth = YUVBuffer[kBufferY].width >> 1; const int yStep = (YUVBuffer[kBufferY].stride << 1) - YUVBuffer[kBufferY].width; @@ -543,8 +520,8 @@ void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelDa v = *vSrc++; for (int i = 0; i <= 1; i++) { - convertYUVtoBGRA(*ySrc, u, v, dst); - convertYUVtoBGRA(*(ySrc + stride), u, v, dst + blockSize); + convertYUVtoBGRA(*ySrc, u, v, dst, getPixelFormat()); + convertYUVtoBGRA(*(ySrc + stride), u, v, dst + blockSize, getPixelFormat()); ySrc++; dst += 4; // BGRA } diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h index d8da024ab9..a1ce3ae473 100644 --- a/engines/sword25/fmv/theora_decoder.h +++ b/engines/sword25/fmv/theora_decoder.h @@ -53,7 +53,7 @@ namespace Sword25 { */ class TheoraDecoder : public Video::FixedRateVideoDecoder { public: - TheoraDecoder(Audio::Mixer *mixer = 0, Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); + TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); virtual ~TheoraDecoder(); /** @@ -71,43 +71,30 @@ public: */ const Graphics::Surface *decodeNextFrame(); - bool isVideoLoaded() const { - return _fileStream != 0; - } - bool isPaused() const { - return (FixedRateVideoDecoder::isPaused() || !isVideoLoaded()); - } + bool isVideoLoaded() const { return _fileStream != 0; } + uint16 getWidth() const { return _surface->w; } + uint16 getHeight() const { return _surface->h; } - uint16 getWidth() const { - return _surface->w; - } - uint16 getHeight() const { - return _surface->h; - } uint32 getFrameCount() const { // It is not possible to get frame count easily // I.e. seeking is required assert(0); return 0; } - Graphics::PixelFormat getPixelFormat() const { - return Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24); - } + + Graphics::PixelFormat getPixelFormat() const { return _surface->format; } uint32 getElapsedTime() const; bool endOfVideo() const; protected: - Common::Rational getFrameRate() const { - return _frameRate; - } + Common::Rational getFrameRate() const { return _frameRate; } private: void queuePage(ogg_page *page); int bufferData(); - Audio::QueuingAudioStream *createAudioStream(); - void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer, byte *pixelData); + void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); private: Common::SeekableReadStream *_fileStream; @@ -115,7 +102,6 @@ private: Common::Rational _frameRate; uint32 _frameCount; - Audio::Mixer *_mixer; Audio::Mixer::SoundType _soundType; Audio::SoundHandle *_audHandle; Audio::QueuingAudioStream *_audStream; @@ -136,15 +122,11 @@ private: int _theoraPacket; int _vorbisPacket; - bool _stateFlag; int _ppLevelMax; int _ppLevel; int _ppInc; - // single frame video buffering - bool _videobufReady; - // single audio fragment audio buffering int _audiobufFill; bool _audiobufReady; -- cgit v1.2.3