2011-10-01 02:56:54 +02:00

226 lines
5.1 KiB
C++

/* Residual - A 3D game interpreter
*
* Residual 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 library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library 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
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include "graphics/surface.h"
#include "common/system.h"
#include "common/timer.h"
#include "engines/grim/movie/movie.h"
#include "engines/grim/grim.h"
#include "engines/grim/debug.h"
#include "engines/grim/savegame.h"
namespace Grim {
MoviePlayer *g_movie;
MoviePlayer::MoviePlayer() {
_speed = 0;
_channels = -1;
_freq = 22050;
_videoFinished = false;
_videoLooping = false;
_videoPause = true;
_updateNeeded = false;
_movieTime = 0;
_frame = 0;
_x = 0;
_y = 0;
_surface = new Graphics::Surface();
_externalSurface = new Graphics::Surface();
}
void MoviePlayer::pause(bool p) {
_videoPause = p;
_videoDecoder->pauseVideo(p);
}
void MoviePlayer::stop() {
deinit();
g_grim->setMode(ENGINE_MODE_NORMAL);
}
void MoviePlayer::timerCallback(void *) {
g_movie->_frameMutex.lock();
g_movie->handleFrame();
g_movie->_frameMutex.unlock();
}
bool MoviePlayer::basicHandleFrame() {
if (_videoDecoder->endOfVideo())
_videoFinished = true;
if (_videoPause)
return false;
if (_videoFinished) {
g_grim->setMode(ENGINE_MODE_NORMAL);
_videoPause = true;
return false;
}
if (_videoDecoder->getTimeToNextFrame() > 0)
return false;
_surface->copyFrom(*_videoDecoder->decodeNextFrame());
// Avoid updating the _externalBuffer if it's flagged as updateNeeded
// since the draw-loop might access it then. This way, any late frames
// will be dropped, and the sound will continue, in synch.
if (!_updateNeeded) {
_externalSurface->copyFrom(*_surface);
_updateNeeded = true;
}
_movieTime = _videoDecoder->getElapsedTime();
_frame = _videoDecoder->getCurFrame();
return true;
}
Graphics::Surface *MoviePlayer::getDstSurface() {
return _externalSurface;
}
void MoviePlayer::init() {
_frame = 0;
_movieTime = 0;
_updateNeeded = false;
_videoFinished = false;
g_system->getTimerManager()->installTimerProc(&timerCallback, _speed, NULL);
}
void MoviePlayer::deinit() {
_frameMutex.unlock();
g_system->getTimerManager()->removeTimerProc(&timerCallback);
_videoDecoder->close();
_surface->free();
_externalSurface->free();
_videoPause = false;
_videoFinished = true;
}
bool MoviePlayer::play(const char *filename, bool looping, int x, int y) {
deinit();
_x = x;
_y = y;
_fname = filename;
_videoLooping = looping;
if (!_videoDecoder->loadFile(_fname))
return false;
if (gDebugLevel == DEBUG_MOVIE)
warning("Playing video '%s'.\n", filename);
init();
return true;
}
void MoviePlayer::saveState(SaveGame *state) {
state->beginSection('SMUS');
state->writeString(_fname);
state->writeLESint32(_frame);
state->writeFloat(_movieTime);
state->writeLESint32(_videoFinished);
state->writeLESint32(_videoLooping);
state->writeLESint32(_x);
state->writeLESint32(_y);
state->endSection();
}
void MoviePlayer::restoreState(SaveGame *state) {
state->beginSection('SMUS');
_fname = state->readString();
int32 frame = state->readLESint32();
float movieTime = state->readFloat();
bool videoFinished = state->readLESint32();
bool videoLooping = state->readLESint32();
int x = state->readLESint32();
int y = state->readLESint32();
if (!videoFinished) {
play(_fname.c_str(), videoLooping, x, y);
}
_frame = frame;
_movieTime = movieTime;
state->endSection();
}
#if !defined(USE_MPEG2) || !defined(USE_SMUSH) || !defined(USE_BINK)
#define NEED_NULLPLAYER
#endif
// Fallback for when USE_MPEG2 / USE_BINK / USE_SMUSH isnt defined
#ifdef NEED_NULLPLAYER
class NullPlayer : public MoviePlayer {
public:
NullPlayer(const char* codecID) {
warning("%s-playback not compiled in, but needed", codecID);
_videoFinished = true; // Rigs all movies to be completed.
}
~NullPlayer() {}
bool play(const char* filename, bool looping, int x, int y) {return true;}
void stop() {}
void saveState(SaveGame *state) {}
void restoreState(SaveGame *state) {}
private:
static void timerCallback(void *ptr) {}
void handleFrame() {}
void init() {}
void deinit() {}
};
#endif
#ifndef USE_MPEG2
MoviePlayer *CreateMpegPlayer() {
return new NullPlayer("MPEG2");
}
#endif
#ifndef USE_SMUSH
MoviePlayer *CreateSmushPlayer() {
return new NullPlayer("SMUSH");
}
#endif
#ifndef USE_BINK
MoviePlayer *CreateBinkPlayer() {
return new NullPlayer("BINK");
}
#endif
} // end of namespace Grim