From 3d3f1db15c50c9b675e29e0a10ee896fd8928445 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Wed, 1 Sep 2010 07:35:38 +0000 Subject: SWORD25: Merge of my pending changes to movie playback svn-id: r53300 --- engines/sword25/fmv/movieplayer.cpp | 98 +++++++++++++++++++++------------- engines/sword25/fmv/movieplayer.h | 17 +++--- engines/sword25/fmv/theora_decoder.cpp | 19 ++++--- engines/sword25/fmv/theora_decoder.h | 1 + 4 files changed, 86 insertions(+), 49 deletions(-) (limited to 'engines/sword25/fmv') diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp index f3504fcb8f..0475c9003e 100644 --- a/engines/sword25/fmv/movieplayer.cpp +++ b/engines/sword25/fmv/movieplayer.cpp @@ -32,100 +32,126 @@ * */ -#include "graphics/surface.h" - #include "sword25/fmv/movieplayer.h" -#include "sword25/fmv/theora_decoder.h" -#include "sword25/kernel/kernel.h" #include "sword25/gfx/graphicengine.h" +#include "sword25/gfx/panel.h" +#include "sword25/kernel/kernel.h" #include "sword25/package/packagemanager.h" +#include "sword25/sfx/soundengine.h" namespace Sword25 { #define BS_LOG_PREFIX "MOVIEPLAYER" +#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */ + Service *OggTheora_CreateObject(Kernel *pKernel) { return new MoviePlayer(pKernel); } -MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel) { +MoviePlayer::MoviePlayer(Kernel *pKernel) : Service(pKernel), + _decoder(g_system->getMixer()) { if (!_RegisterScriptBindings()) BS_LOG_ERRORLN("Script bindings could not be registered."); else BS_LOGLN("Script bindings registered."); - - _decoder = new TheoraDecoder(); - _backSurface = (static_cast(Kernel::GetInstance()->GetService("gfx")))->getSurface(); } -bool MoviePlayer::LoadMovie(const Common::String &filename, unsigned int z) { - Common::SeekableReadStream *in = Kernel::GetInstance()->GetPackage()->GetStream(filename); +MoviePlayer::~MoviePlayer() { + _decoder.close(); +} - if (!in) { - BS_LOG_ERRORLN("Could not open movie file \"%s\".", filename.c_str()); +bool MoviePlayer::LoadMovie(const Common::String &Filename, unsigned int Z) { + // Get the file and load it into the decoder + uint dataSize; + const byte *data = reinterpret_cast(Kernel::GetInstance()->GetPackage()->GetFile(Filename, &dataSize)); + Common::MemoryReadStream *stream = new Common::MemoryReadStream( + data, dataSize, DisposeAfterUse::YES); + _decoder.load(stream); + + // Ausgabebitmap erstellen + GraphicEngine *pGfx = Kernel::GetInstance()->GetGfx(); + _outputBitmap = pGfx->GetMainPanel()->AddDynamicBitmap( + _decoder.getWidth(), _decoder.getHeight()); + if (!_outputBitmap.IsValid()) { + BS_LOG_ERRORLN("Output bitmap for movie playback could not be created."); return false; } - debug(2, "LoadMovie(%s, %d)", filename.c_str(), z); + // Skalierung des Ausgabebitmaps berechnen, so dass es möglichst viel Bildschirmfläche einnimmt. + float ScreenToVideoWidth = (float) pGfx->GetDisplayWidth() / (float) _outputBitmap->GetWidth(); + float ScreenToVideoHeight = (float) pGfx->GetDisplayHeight() / (float) _outputBitmap->GetHeight(); + float ScaleFactor = MIN(ScreenToVideoWidth, ScreenToVideoHeight); + if (abs(ScaleFactor - 1.0f) < FLT_EPSILON) ScaleFactor = 1.0f; + _outputBitmap->SetScaleFactor(ScaleFactor); - if (!_decoder->load(in)) { - BS_LOG_ERRORLN("Could not load movie file \"%s\".", filename.c_str()); - return false; - } + // Z-Wert setzen + _outputBitmap->SetZ(Z); - warning("STUB: MoviePlayer::LoadMovie(). Z is not handled"); + // Ausgabebitmap auf dem Bildschirm zentrieren + _outputBitmap->SetX((pGfx->GetDisplayWidth() - _outputBitmap->GetWidth()) / 2); + _outputBitmap->SetY((pGfx->GetDisplayHeight() - _outputBitmap->GetHeight()) / 2); return true; } bool MoviePlayer::UnloadMovie() { - _decoder->close(); + _decoder.close(); + _outputBitmap.Erase(); return true; } bool MoviePlayer::Play() { - _decoder->pauseVideo(false); - + _decoder.pauseVideo(false); return true; } bool MoviePlayer::Pause() { - _decoder->pauseVideo(true); - + _decoder.pauseVideo(true); return true; } void MoviePlayer::Update() { - if (!_decoder->isVideoLoaded()) - return; + if (_decoder.isVideoLoaded()) { + Graphics::Surface *s = _decoder.decodeNextFrame(); - Graphics::Surface *surface = _decoder->decodeNextFrame(); - - // Probably it's better to copy to _backSurface - if (surface->w > 0 && surface->h > 0) - g_system->copyRectToScreen((byte *)surface->getBasePtr(0, 0), surface->pitch, 0, 0, - MIN(surface->w, _backSurface->w), MIN(surface->h, _backSurface->h)); + // Transfer the next frame + assert(s->bytesPerPixel == 4); + byte *frameData = (byte *)s->getBasePtr(0, 0); + _outputBitmap->SetContent(frameData, s->pitch * s->h, 0, s->pitch); + } } bool MoviePlayer::IsMovieLoaded() { - return _decoder->isVideoLoaded(); + return _decoder.isVideoLoaded(); } bool MoviePlayer::IsPaused() { - return _decoder->isPaused(); + return _decoder.isPaused(); } float MoviePlayer::GetScaleFactor() { - return 1.0f; + if (_decoder.isVideoLoaded()) + return _outputBitmap->GetScaleFactorX(); + else + return 0; } void MoviePlayer::SetScaleFactor(float ScaleFactor) { + if (_decoder.isVideoLoaded()) { + _outputBitmap->SetScaleFactor(ScaleFactor); + + // Ausgabebitmap auf dem Bildschirm zentrieren + GraphicEngine *gfxPtr = Kernel::GetInstance()->GetGfx(); + _outputBitmap->SetX((gfxPtr->GetDisplayWidth() - _outputBitmap->GetWidth()) / 2); + _outputBitmap->SetY((gfxPtr->GetDisplayHeight() - _outputBitmap->GetHeight()) / 2); + } } double MoviePlayer::GetTime() { - return (double)_decoder->getElapsedTime() / 1000.0; + // FIXME: This may need conversion + return _decoder.getElapsedTime(); } - } // End of namespace Sword25 diff --git a/engines/sword25/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h index afca1eb808..cdbcf13f53 100644 --- a/engines/sword25/fmv/movieplayer.h +++ b/engines/sword25/fmv/movieplayer.h @@ -41,11 +41,14 @@ #include "sword25/kernel/common.h" #include "sword25/kernel/service.h" -#include "graphics/surface.h" +#include "sword25/fmv/theora_decoder.h" +#include "sword25/gfx/bitmap.h" namespace Sword25 { -class TheoraDecoder; +// ----------------------------------------------------------------------------- +// Class definitions +// ----------------------------------------------------------------------------- class MoviePlayer : public Service { public: @@ -54,10 +57,10 @@ public: // ----------------------------------------------------------------------------- MoviePlayer(Kernel *pKernel); - ~MoviePlayer() {}; + ~MoviePlayer(); // ----------------------------------------------------------------------------- - // Abstract interface must be implemented by each Movie Player + // Player interface must be implemented by a Movie Player // ----------------------------------------------------------------------------- /** @@ -136,12 +139,12 @@ public: * @remark This method can only be called when IsMovieLoaded() returns true. */ double GetTime(); - private: bool _RegisterScriptBindings(); - TheoraDecoder *_decoder; - Graphics::Surface *_backSurface; + TheoraDecoder _decoder; + + RenderObjectPtr _outputBitmap; }; } // End of namespace Sword25 diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp index bc95e10678..cbd60d9fdd 100644 --- a/engines/sword25/fmv/theora_decoder.cpp +++ b/engines/sword25/fmv/theora_decoder.cpp @@ -53,15 +53,18 @@ TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT _fileStream = 0; _surface = 0; + _theoraPacket = 0; + _vorbisPacket = 0; + _theoraSetup = 0; + _stateFlag = false; + _soundType = soundType; _audStream = 0; _audHandle = new Audio::SoundHandle(); - _theoraDecode = 0; - _theoraSetup = 0; + ogg_sync_init(&_oggSync); _curFrame = 0; - _audiobuf = (ogg_int16_t *)calloc(AUDIOFD_FRAGSIZE, sizeof(ogg_int16_t)); reset(); @@ -69,6 +72,7 @@ TheoraDecoder::TheoraDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT TheoraDecoder::~TheoraDecoder() { close(); + delete _fileStream; delete _audHandle; free(_audiobuf); } @@ -249,14 +253,12 @@ bool TheoraDecoder::load(Common::SeekableReadStream *stream) { _ppLevel = _ppLevelMax; th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); _ppInc = 0; - } else { // tear down the partial theora setup th_info_clear(&_theoraInfo); th_comment_clear(&_theoraComment); } - th_setup_free(_theoraSetup); _theoraSetup = 0; @@ -279,6 +281,7 @@ bool TheoraDecoder::load(Common::SeekableReadStream *stream) { } _surface = new Graphics::Surface(); + _surface->create(_theoraInfo.frame_width, _theoraInfo.frame_height, 4); return true; @@ -295,6 +298,7 @@ void TheoraDecoder::close() { if (_mixer) _mixer->stopHandle(*_audHandle); _audStream = 0; + _vorbisPacket = false; } if (_theoraPacket) { ogg_stream_clear(&_theoraOut); @@ -302,6 +306,7 @@ void TheoraDecoder::close() { th_comment_clear(&_theoraComment); th_info_clear(&_theoraInfo); _theoraDecode = 0; + _theoraPacket = false; } if (!_fileStream) @@ -322,7 +327,7 @@ void TheoraDecoder::close() { Graphics::Surface *TheoraDecoder::decodeNextFrame() { int i, j; - _stateFlag = false; // playback has not begun +// _stateFlag = false; // playback has not begun // we want a video and audio frame ready to go at all times. If // we have to buffer incoming, buffer the compressed data (ie, let @@ -404,9 +409,11 @@ Graphics::Surface *TheoraDecoder::decodeNextFrame() { } // If playback has begun, top audio buffer off immediately. +/* FIXME: This is currently crashing if (_stateFlag) { _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO); } +*/ // are we at or past time for this video frame? if (_stateFlag && _videobufReady) { diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h index 3ce53e0900..12d8035c0a 100644 --- a/engines/sword25/fmv/theora_decoder.h +++ b/engines/sword25/fmv/theora_decoder.h @@ -82,6 +82,7 @@ public: // 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); -- cgit v1.2.3