mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-12 06:00:48 +00:00
226 lines
5.1 KiB
C++
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
|