aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/agos/animation.cpp117
-rw-r--r--engines/agos/animation.h10
-rw-r--r--engines/mohawk/jpeg.h1
-rw-r--r--engines/mohawk/video/cinepak.h1
-rw-r--r--engines/mohawk/video/qtrle.h1
-rw-r--r--engines/mohawk/video/rpza.h1
-rw-r--r--engines/mohawk/video/smc.h1
-rw-r--r--engines/saga/introproc_saga2.cpp59
-rw-r--r--engines/saga/scene.h1
-rw-r--r--engines/sci/console.cpp66
-rw-r--r--engines/sci/engine/kgraphics.cpp66
-rw-r--r--engines/sci/video/seq_decoder.cpp80
-rw-r--r--engines/sci/video/seq_decoder.h50
-rw-r--r--engines/sci/video/vmd_decoder.cpp74
-rw-r--r--engines/sci/video/vmd_decoder.h31
-rw-r--r--engines/scumm/he/animation_he.cpp27
-rw-r--r--engines/scumm/he/animation_he.h3
-rw-r--r--engines/scumm/he/script_v100he.cpp2
-rw-r--r--engines/scumm/he/script_v90he.cpp2
-rw-r--r--engines/sword1/animation.cpp78
-rw-r--r--engines/sword1/animation.h13
-rw-r--r--engines/sword2/animation.cpp78
-rw-r--r--engines/sword2/animation.h11
-rw-r--r--engines/tucker/sequences.cpp73
-rw-r--r--graphics/module.mk2
-rw-r--r--graphics/video/avi_decoder.cpp110
-rw-r--r--graphics/video/avi_decoder.h33
-rw-r--r--graphics/video/codecs/codec.h3
-rw-r--r--graphics/video/codecs/msrle.h1
-rw-r--r--graphics/video/codecs/msvideo1.cpp2
-rw-r--r--graphics/video/codecs/msvideo1.h1
-rw-r--r--graphics/video/dxa_decoder.cpp182
-rw-r--r--graphics/video/dxa_decoder.h39
-rw-r--r--graphics/video/flic_decoder.cpp122
-rw-r--r--graphics/video/flic_decoder.h43
-rw-r--r--graphics/video/smk_decoder.cpp152
-rw-r--r--graphics/video/smk_decoder.h36
-rw-r--r--graphics/video/video_decoder.cpp101
-rw-r--r--graphics/video/video_decoder.h184
-rw-r--r--graphics/video/video_player.cpp245
-rw-r--r--graphics/video/video_player.h221
41 files changed, 1108 insertions, 1215 deletions
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
index eccb51c732..1b3ac9fd65 100644
--- a/engines/agos/animation.cpp
+++ b/engines/agos/animation.cpp
@@ -241,29 +241,46 @@ MoviePlayerDXA::MoviePlayerDXA(AGOSEngine_Feeble *vm, const char *name)
}
bool MoviePlayerDXA::load() {
- char videoName[20];
- uint i;
-
if ((_vm->getPlatform() == Common::kPlatformAmiga || _vm->getPlatform() == Common::kPlatformMacintosh) &&
_vm->_language != Common::EN_ANY) {
_sequenceNum = 0;
- for (i = 0; i < 90; i++) {
+ for (uint i = 0; i < 90; i++) {
if (!scumm_stricmp(baseName, _sequenceList[i]))
_sequenceNum = i;
}
}
- sprintf(videoName, "%s.dxa", baseName);
+ Common::String videoName = Common::String::printf("%s.dxa", baseName);
if (!loadFile(videoName))
- error("Failed to load video file %s", videoName);
+ error("Failed to load video file %s", videoName.c_str());
- debug(0, "Playing video %s", videoName);
+ debug(0, "Playing video %s", videoName.c_str());
CursorMan.showMouse(false);
+ _firstFrameOffset = _fileStream->pos();
+
return true;
}
+void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
+ uint h = getHeight();
+ uint w = getWidth();
+
+ Graphics::Surface *surface = decodeNextFrame();
+ byte *src = (byte *)surface->pixels;
+ dst += y * pitch + x;
+
+ do {
+ memcpy(dst, src, w);
+ dst += pitch;
+ src += w;
+ } while (--h);
+
+ if (hasDirtyPalette())
+ setSystemPalette();
+}
+
void MoviePlayerDXA::playVideo() {
// Most of the videos included in the Amiga version, reduced the
// resoluton to 384 x 280, so require the screen to be cleared,
@@ -277,7 +294,7 @@ void MoviePlayerDXA::playVideo() {
}
void MoviePlayerDXA::stopVideo() {
- closeFile();
+ close();
_mixer->stopHandle(_bgSound);
}
@@ -318,70 +335,56 @@ void MoviePlayerDXA::startSound() {
}
void MoviePlayerDXA::nextFrame() {
- if (_bgSoundStream && _vm->_mixer->isSoundHandleActive(_bgSound) && (_vm->_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 <= (uint32)getCurFrame()) {
+ if (_bgSoundStream && _vm->_mixer->isSoundHandleActive(_bgSound) && needsUpdate()) {
copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
return;
}
if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) {
- _fileStream->seek(_videoInfo.firstframeOffset);
- _videoInfo.currentFrame = -1;
+ _fileStream->seek(_firstFrameOffset);
+ _curFrame = -1;
startSound();
}
if (!endOfVideo()) {
- decodeNextFrame();
if (_vm->_interactiveVideo == TYPE_OMNITV) {
copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
} else if (_vm->_interactiveVideo == TYPE_LOOPING) {
copyFrameToBuffer(_vm->getBackBuf(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
}
} else if (_vm->_interactiveVideo == TYPE_OMNITV) {
- closeFile();
+ close();
_vm->_interactiveVideo = 0;
_vm->_variableArray[254] = 6747;
}
}
void MoviePlayerDXA::handleNextFrame() {
- decodeNextFrame();
if (processFrame())
_vm->_system->updateScreen();
MoviePlayer::handleNextFrame();
}
-void MoviePlayerDXA::setPalette(byte *pal) {
- byte palette[1024];
- byte *p = palette;
-
- for (int i = 0; i < 256; i++) {
- *p++ = *pal++;
- *p++ = *pal++;
- *p++ = *pal++;
- *p++ = 0;
- }
-
- _vm->_system->setPalette(palette, 0, 256);
-}
-
bool MoviePlayerDXA::processFrame() {
Graphics::Surface *screen = _vm->_system->lockScreen();
copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
_vm->_system->unlockScreen();
- if ((_bgSoundStream == NULL) || ((int)(_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 <= getCurFrame())) {
+ Common::Rational soundTime(_mixer->getSoundElapsedTime(_bgSound), 1000);
+ if ((_bgSoundStream == NULL) || ((int)(soundTime * getFrameRate()) / 1000 < getCurFrame() + 1)) {
if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) {
- while (_mixer->isSoundHandleActive(_bgSound) && (_mixer->getSoundElapsedTime(_bgSound) * getFrameRate()) / 1000 <= (uint32)getCurFrame()) {
+ while (_mixer->isSoundHandleActive(_bgSound) && ((int) (soundTime * getFrameRate())) < getCurFrame()) {
_vm->_system->delayMillis(10);
+ soundTime = Common::Rational(_mixer->getSoundElapsedTime(_bgSound), 1000);
}
// In case the background sound ends prematurely, update
// _ticks so that we can still fall back on the no-sound
// sync case for the subsequent frames.
_ticks = _vm->_system->getMillis();
} else {
- _ticks += getFrameWaitTime();
+ _ticks += getTimeToNextFrame();
while (_vm->_system->getMillis() < _ticks)
_vm->_system->delayMillis(10);
}
@@ -407,33 +410,51 @@ MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name)
}
bool MoviePlayerSMK::load() {
- char videoName[20];
+ Common::String videoName = Common::String::printf("%s.smk", baseName);
- sprintf(videoName, "%s.smk", baseName);
if (!loadFile(videoName))
- error("Failed to load video file %s", videoName);
+ error("Failed to load video file %s", videoName.c_str());
- debug(0, "Playing video %s", videoName);
+ debug(0, "Playing video %s", videoName.c_str());
CursorMan.showMouse(false);
+ _firstFrameOffset = _fileStream->pos();
+
return true;
}
+void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
+ uint h = getHeight();
+ uint w = getWidth();
+
+ Graphics::Surface *surface = decodeNextFrame();
+ byte *src = (byte *)surface->pixels;
+ dst += y * pitch + x;
+
+ do {
+ memcpy(dst, src, w);
+ dst += pitch;
+ src += w;
+ } while (--h);
+
+ if (hasDirtyPalette())
+ setSystemPalette();
+}
+
void MoviePlayerSMK::playVideo() {
while (!endOfVideo() && !_skipMovie && !_vm->shouldQuit())
handleNextFrame();
}
void MoviePlayerSMK::stopVideo() {
- closeFile();
+ close();
}
void MoviePlayerSMK::startSound() {
}
void MoviePlayerSMK::handleNextFrame() {
- decodeNextFrame();
processFrame();
MoviePlayer::handleNextFrame();
@@ -441,8 +462,8 @@ void MoviePlayerSMK::handleNextFrame() {
void MoviePlayerSMK::nextFrame() {
if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) {
- _fileStream->seek(_videoInfo.firstframeOffset);
- _videoInfo.currentFrame = -1;
+ _fileStream->seek(_firstFrameOffset);
+ _curFrame = -1;
}
if (!endOfVideo()) {
@@ -453,32 +474,18 @@ void MoviePlayerSMK::nextFrame() {
copyFrameToBuffer(_vm->getBackBuf(), (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
}
} else if (_vm->_interactiveVideo == TYPE_OMNITV) {
- closeFile();
+ close();
_vm->_interactiveVideo = 0;
_vm->_variableArray[254] = 6747;
}
}
-void MoviePlayerSMK::setPalette(byte *pal) {
- byte palette[1024];
- byte *p = palette;
-
- for (int i = 0; i < 256; i++) {
- *p++ = *pal++;
- *p++ = *pal++;
- *p++ = *pal++;
- *p++ = 0;
- }
-
- _vm->_system->setPalette(palette, 0, 256);
-}
-
bool MoviePlayerSMK::processFrame() {
Graphics::Surface *screen = _vm->_system->lockScreen();
copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, _vm->_screenWidth);
_vm->_system->unlockScreen();
- uint32 waitTime = getFrameWaitTime();
+ uint32 waitTime = getTimeToNextFrame();
if (!waitTime) {
warning("dropped frame %i", getCurFrame());
diff --git a/engines/agos/animation.h b/engines/agos/animation.h
index 6a1bdccadf..68a76e1f88 100644
--- a/engines/agos/animation.h
+++ b/engines/agos/animation.h
@@ -72,6 +72,9 @@ private:
virtual void handleNextFrame();
virtual bool processFrame() = 0;
virtual void startSound() {}
+
+protected:
+ uint32 _firstFrameOffset;
};
class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXADecoder {
@@ -84,13 +87,12 @@ public:
void playVideo();
void nextFrame();
virtual void stopVideo();
-protected:
- void setPalette(byte *pal);
private:
void handleNextFrame();
bool processFrame();
void startSound();
+ void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch);
};
class MoviePlayerSMK : public MoviePlayer, ::Graphics::SmackerDecoder {
@@ -101,12 +103,12 @@ public:
void playVideo();
void nextFrame();
virtual void stopVideo();
-protected:
- void setPalette(byte *pal);
+
private:
void handleNextFrame();
bool processFrame();
void startSound();
+ void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch);
};
MoviePlayer *makeMoviePlayer(AGOSEngine_Feeble *vm, const char *name);
diff --git a/engines/mohawk/jpeg.h b/engines/mohawk/jpeg.h
index 086e78332f..ec87b1e7af 100644
--- a/engines/mohawk/jpeg.h
+++ b/engines/mohawk/jpeg.h
@@ -45,6 +45,7 @@ public:
~JPEGDecoder();
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
Graphics::PixelFormat _pixelFormat;
diff --git a/engines/mohawk/video/cinepak.h b/engines/mohawk/video/cinepak.h
index 43cc22bfc9..3f4cbba17c 100644
--- a/engines/mohawk/video/cinepak.h
+++ b/engines/mohawk/video/cinepak.h
@@ -65,6 +65,7 @@ public:
~CinepakDecoder();
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
CinepakFrame _curFrame;
diff --git a/engines/mohawk/video/qtrle.h b/engines/mohawk/video/qtrle.h
index fdccf626a6..2832bd6b24 100644
--- a/engines/mohawk/video/qtrle.h
+++ b/engines/mohawk/video/qtrle.h
@@ -37,6 +37,7 @@ public:
~QTRLEDecoder();
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
byte _bitsPerPixel;
diff --git a/engines/mohawk/video/rpza.h b/engines/mohawk/video/rpza.h
index b9522ec2e3..c6d0ada6f5 100644
--- a/engines/mohawk/video/rpza.h
+++ b/engines/mohawk/video/rpza.h
@@ -37,6 +37,7 @@ public:
~RPZADecoder() { delete _surface; }
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
private:
Graphics::Surface *_surface;
diff --git a/engines/mohawk/video/smc.h b/engines/mohawk/video/smc.h
index 331fddb9a5..c52226100e 100644
--- a/engines/mohawk/video/smc.h
+++ b/engines/mohawk/video/smc.h
@@ -43,6 +43,7 @@ public:
~SMCDecoder() { delete _surface; }
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
private:
Graphics::Surface *_surface;
diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp
index 0af31dae61..7491815303 100644
--- a/engines/saga/introproc_saga2.cpp
+++ b/engines/saga/introproc_saga2.cpp
@@ -40,13 +40,7 @@ namespace Saga {
int Scene::DinoStartProc() {
_vm->_gfx->showCursor(false);
- Graphics::SmackerDecoder *smkDecoder = new Graphics::SmackerDecoder(_vm->_mixer);
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(smkDecoder);
- if (smkDecoder->loadFile("testvid.smk"))
- player->playVideo(); // Play introduction
- smkDecoder->closeFile();
- delete player;
- delete smkDecoder;
+ playMovie("testvid.smk");
// HACK: Forcibly quit here
_vm->quitGame();
@@ -57,16 +51,8 @@ int Scene::DinoStartProc() {
int Scene::FTA2StartProc() {
_vm->_gfx->showCursor(false);
- Graphics::SmackerDecoder *smkDecoder = new Graphics::SmackerDecoder(_vm->_mixer);
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(smkDecoder);
- if (smkDecoder->loadFile("trimark.smk"))
- player->playVideo(); // Show Ignite logo
- smkDecoder->closeFile();
- if (smkDecoder->loadFile("intro.smk"))
- player->playVideo(); // Play introduction
- smkDecoder->closeFile();
- delete player;
- delete smkDecoder;
+ playMovie("trimark.smk");
+ playMovie("intro.smk");
// HACK: Forcibly quit here
_vm->quitGame();
@@ -100,18 +86,41 @@ int Scene::FTA2EndProc(FTA2Endings whichEnding) {
_vm->_gfx->showCursor(false);
// Play ending
- Graphics::SmackerDecoder *smkDecoder = new Graphics::SmackerDecoder(_vm->_mixer);
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(smkDecoder);
- if (smkDecoder->loadFile(videoName)) {
- player->playVideo();
- smkDecoder->closeFile();
- }
- delete player;
- delete smkDecoder;
+ playMovie(videoName);
return SUCCESS;
}
+void Scene::playMovie(const char *filename) {
+ Graphics::SmackerDecoder *smkDecoder = new Graphics::SmackerDecoder(_vm->_mixer);
+
+ if (!smkDecoder->loadFile(filename))
+ return;
+
+ uint16 x = (g_system->getWidth() - smkDecoder->getWidth()) / 2;
+ uint16 y = (g_system->getHeight() - smkDecoder->getHeight()) / 2;
+
+ while (!_vm->shouldQuit() && !smkDecoder->endOfVideo()) {
+ if (smkDecoder->needsUpdate()) {
+ Graphics::Surface *frame = smkDecoder->decodeNextFrame();
+ if (frame) {
+ _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+
+ if (smkDecoder->hasDirtyPalette())
+ smkDecoder->setSystemPalette();
+
+ _vm->_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (_vm->_system->getEventManager()->pollEvent(event))
+ ;
+
+ _vm->_system->delayMillis(10);
+ }
+}
+
} // End of namespace Saga
#endif
diff --git a/engines/saga/scene.h b/engines/saga/scene.h
index 4fbde560b5..0131e01abb 100644
--- a/engines/saga/scene.h
+++ b/engines/saga/scene.h
@@ -424,6 +424,7 @@ class Scene {
int DinoStartProc();
int FTA2StartProc();
int FTA2EndProc(FTA2Endings whichEnding);
+ void playMovie(const char *filename);
void IHNMLoadCutaways();
bool checkKey();
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 73b9788ca0..f2e5601c9e 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -222,42 +222,48 @@ void Console::postEnter() {
if (!_videoFile.empty()) {
_engine->_gfxCursor->kernelHide();
+ Graphics::VideoDecoder *videoDecoder = 0;
+
if (_videoFile.hasSuffix(".seq")) {
- SeqDecoder *seqDecoder = new SeqDecoder();
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(seqDecoder);
- if (seqDecoder->loadFile(_videoFile.c_str(), _videoFrameDelay))
- player->playVideo();
- else
- DebugPrintf("Failed to open movie file %s\n", _videoFile.c_str());
- seqDecoder->closeFile();
- delete player;
- delete seqDecoder;
- } else if (_videoFile.hasSuffix(".avi")) {
- Graphics::AviDecoder *aviDecoder = new Graphics::AviDecoder(g_system->getMixer());
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(aviDecoder);
- if (aviDecoder->loadFile(_videoFile.c_str()))
- player->playVideo();
- else
- DebugPrintf("Failed to open movie file %s\n", _videoFile.c_str());
- aviDecoder->closeFile();
- delete player;
- delete aviDecoder;
- } else if (_videoFile.hasSuffix(".vmd")) {
+ videoDecoder = new SeqDecoder();
+ ((SeqDecoder *)videoDecoder)->setFrameDelay(_videoFrameDelay);
#ifdef ENABLE_SCI32
- VMDDecoder *vmdDecoder = new VMDDecoder(g_system->getMixer());
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(vmdDecoder);
- if (vmdDecoder->loadFile(_videoFile.c_str()))
- player->playVideo();
- else
- DebugPrintf("Failed to open movie file %s\n", _videoFile.c_str());
- vmdDecoder->closeFile();
- delete player;
- delete vmdDecoder;
+ } else if (_videoFile.hasSuffix(".vmd")) {
+ videoDecoder = new VMDDecoder(g_system->getMixer());
#endif
+ } else if (_videoFile.hasSuffix(".avi")) {
+ videoDecoder = new Graphics::AviDecoder(g_system->getMixer());
}
- _engine->_gfxCursor->kernelShow();
+ if (videoDecoder && videoDecoder->loadFile(_videoFile)) {
+ uint16 x = (g_system->getWidth() - videoDecoder->getWidth()) / 2;
+ uint16 y = (g_system->getHeight() - videoDecoder->getHeight()) / 2;
+
+ while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
+ if (videoDecoder->needsUpdate()) {
+ Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+ if (frame) {
+ g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ if (videoDecoder->hasDirtyPalette())
+ videoDecoder->setSystemPalette();
+
+ g_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event))
+ ;
+
+ g_system->delayMillis(10);
+ }
+
+ delete videoDecoder;
+ } else
+ warning("Could not play video %s\n", _videoFile.c_str());
+
+ _engine->_gfxCursor->kernelShow();
_videoFile.clear();
_videoFrameDelay = 0;
}
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index da18bc7e03..d587790b6c 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -1078,8 +1078,6 @@ reg_t kDisplay(EngineState *s, int argc, reg_t *argv) {
}
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
- bool playedVideo = false;
-
// Hide the cursor if it's showing and then show it again if it was
// previously visible.
bool reshowCursor;
@@ -1087,30 +1085,29 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
reshowCursor = g_sci->_gfxCursor->isVisible();
if (reshowCursor)
g_sci->_gfxCursor->kernelHide();
+
+ Graphics::VideoDecoder *videoDecoder = 0;
if (argv[0].segment != 0) {
+ Common::String filename = s->_segMan->getString(argv[0]);
+
if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
// Mac QuickTime
// The only argument is the string for the video
- warning("TODO: Play QuickTime movie '%s'", s->_segMan->getString(argv[0]).c_str());
+ warning("TODO: Play QuickTime movie '%s'", filename.c_str());
return s->r_acc;
} else {
// DOS SEQ
// SEQ's are called with no subops, just the string and delay
- Common::String filename = s->_segMan->getString(argv[0]);
- int delay = argv[1].toUint16(); // Time between frames in ticks
-
SeqDecoder *seqDecoder = new SeqDecoder();
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(seqDecoder);
- if (seqDecoder->loadFile(filename.c_str(), delay)) {
- player->playVideo();
- playedVideo = true;
- } else {
+ seqDecoder->setFrameDelay(argv[1].toUint16()); // Time between frames in ticks
+ videoDecoder = seqDecoder;
+
+ if (!videoDecoder->loadFile(filename)) {
warning("Failed to open movie file %s", filename.c_str());
+ delete videoDecoder;
+ videoDecoder = 0;
}
- seqDecoder->closeFile();
- delete player;
- delete seqDecoder;
}
} else {
// Windows AVI (Macintosh QuickTime? Need to check KQ6 Macintosh)
@@ -1130,17 +1127,13 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
switch (argv[0].toUint16()) {
case 0: {
Common::String filename = s->_segMan->getString(argv[1]);
- Graphics::AviDecoder *aviDecoder = new Graphics::AviDecoder(g_system->getMixer());
- Graphics::VideoPlayer *player = new Graphics::VideoPlayer(aviDecoder);
- if (aviDecoder->loadFile(filename.c_str())) {
- player->playVideo();
- playedVideo = true;
- } else {
+ videoDecoder = new Graphics::AviDecoder(g_system->getMixer());
+
+ if (!videoDecoder->loadFile(filename.c_str())) {
warning("Failed to open movie file %s", filename.c_str());
+ delete videoDecoder;
+ videoDecoder = 0;
}
- aviDecoder->closeFile();
- delete player;
- delete aviDecoder;
break;
}
default:
@@ -1148,8 +1141,33 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
}
}
- if (playedVideo)
+ if (videoDecoder) {
+ uint16 x = (g_system->getWidth() - videoDecoder->getWidth()) / 2;
+ uint16 y = (g_system->getHeight() - videoDecoder->getHeight()) / 2;
+
+ while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo()) {
+ if (videoDecoder->needsUpdate()) {
+ Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+ if (frame) {
+ g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+
+ if (videoDecoder->hasDirtyPalette())
+ videoDecoder->setSystemPalette();
+
+ g_system->updateScreen();
+ }
+ }
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event))
+ ;
+
+ g_system->delayMillis(10);
+ }
+
+ delete videoDecoder;
g_sci->_gfxScreen->kernelSyncWithFramebuffer();
+ }
if (reshowCursor)
g_sci->_gfxCursor->kernelShow();
diff --git a/engines/sci/video/seq_decoder.cpp b/engines/sci/video/seq_decoder.cpp
index ccce873a15..2c117ae329 100644
--- a/engines/sci/video/seq_decoder.cpp
+++ b/engines/sci/video/seq_decoder.cpp
@@ -35,10 +35,6 @@
namespace Sci {
-// SEQ videos always run at 320x200
-#define SCREEN_WIDTH 320
-#define SCREEN_HEIGHT 200
-
enum seqPalTypes {
kSeqPalVariable = 0,
kSeqPalConstant = 1
@@ -49,26 +45,24 @@ enum seqFrameTypes {
kSeqFrameDiff = 1
};
-SeqDecoder::~SeqDecoder() {
- closeFile();
+SeqDecoder::SeqDecoder() {
+ _fileStream = 0;
+ _surface = 0;
+ _dirtyPalette = false;
}
-bool SeqDecoder::loadFile(const char *fileName, int frameDelay) {
- closeFile();
+SeqDecoder::~SeqDecoder() {
+ close();
+}
- _fileStream = SearchMan.createReadStreamForMember(fileName);
- if (!_fileStream)
- return false;
+bool SeqDecoder::load(Common::SeekableReadStream &stream) {
+ close();
- // Seek to the first frame
- _videoInfo.currentFrame = -1;
+ _fileStream = &stream;
+ _surface = new Graphics::Surface();
+ _surface->create(SEQ_SCREEN_WIDTH, SEQ_SCREEN_HEIGHT, 1);
- _videoInfo.width = SCREEN_WIDTH;
- _videoInfo.height = SCREEN_HEIGHT;
- _videoInfo.frameCount = _fileStream->readUint16LE();
- // Our frameDelay is calculated in 1/100 ms, so we convert it here
- _videoInfo.frameDelay = 100 * frameDelay * 1000 / 60;
- _videoFrameBuffer = new byte[_videoInfo.width * _videoInfo.height];
+ _frameCount = _fileStream->readUint16LE();
// Set palette
int paletteSize = _fileStream->readUint32LE();
@@ -81,39 +75,38 @@ bool SeqDecoder::loadFile(const char *fileName, int frameDelay) {
uint16 palColorStart = READ_LE_UINT16(paletteData + 25);
uint16 palColorCount = READ_LE_UINT16(paletteData + 29);
- byte palette[256 * 4];
int palOffset = 37;
for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
if (palFormat == kSeqPalVariable)
palOffset++;
- palette[colorNo * 4 + 0] = paletteData[palOffset++];
- palette[colorNo * 4 + 1] = paletteData[palOffset++];
- palette[colorNo * 4 + 2] = paletteData[palOffset++];
- palette[colorNo * 4 + 3] = 0;
+ _palette[colorNo * 3 + 0] = paletteData[palOffset++];
+ _palette[colorNo * 3 + 1] = paletteData[palOffset++];
+ _palette[colorNo * 3 + 2] = paletteData[palOffset++];
}
- g_system->setPalette(palette, 0, 256);
-
+ _dirtyPalette = true;
delete[] paletteData;
-
- _videoInfo.firstframeOffset = _fileStream->pos();
-
return true;
}
-void SeqDecoder::closeFile() {
+void SeqDecoder::close() {
if (!_fileStream)
return;
+ _frameDelay = 0;
+
delete _fileStream;
_fileStream = 0;
- delete[] _videoFrameBuffer;
- _videoFrameBuffer = 0;
+ _surface->free();
+ delete _surface;
+ _surface = 0;
+
+ reset();
}
-bool SeqDecoder::decodeNextFrame() {
+Graphics::Surface *SeqDecoder::decodeNextFrame() {
int16 frameWidth = _fileStream->readUint16LE();
int16 frameHeight = _fileStream->readUint16LE();
int16 frameLeft = _fileStream->readUint16LE();
@@ -129,42 +122,41 @@ bool SeqDecoder::decodeNextFrame() {
_fileStream->seek(offset);
- _videoInfo.currentFrame++;
-
- if (_videoInfo.currentFrame == 0)
- _videoInfo.startTime = g_system->getMillis();
-
if (frameType == kSeqFrameFull) {
- byte *dst = _videoFrameBuffer + frameTop * SCREEN_WIDTH + frameLeft;
+ byte *dst = (byte *)_surface->pixels + frameTop * SEQ_SCREEN_WIDTH + frameLeft;
byte *linebuf = new byte[frameWidth];
do {
_fileStream->read(linebuf, frameWidth);
memcpy(dst, linebuf, frameWidth);
- dst += SCREEN_WIDTH;
+ dst += SEQ_SCREEN_WIDTH;
} while (--frameHeight);
delete[] linebuf;
} else {
byte *buf = new byte[frameSize];
_fileStream->read(buf, frameSize);
- decodeFrame(buf, rleSize, buf + rleSize, frameSize - rleSize, _videoFrameBuffer + SCREEN_WIDTH * frameTop, frameLeft, frameWidth, frameHeight, colorKey);
+ decodeFrame(buf, rleSize, buf + rleSize, frameSize - rleSize, (byte *)_surface->pixels + SEQ_SCREEN_WIDTH * frameTop, frameLeft, frameWidth, frameHeight, colorKey);
delete[] buf;
}
- return !endOfVideo();
+ if (_curFrame == -1)
+ _startTime = g_system->getMillis();
+
+ _curFrame++;
+ return _surface;
}
#define WRITE_TO_BUFFER(n) \
- if (writeRow * SCREEN_WIDTH + writeCol + (n) > SCREEN_WIDTH * height) { \
+ if (writeRow * SEQ_SCREEN_WIDTH + writeCol + (n) > SEQ_SCREEN_WIDTH * height) { \
warning("SEQ player: writing out of bounds, aborting"); \
return false; \
} \
if (litPos + (n) > litSize) { \
warning("SEQ player: reading out of bounds, aborting"); \
} \
- memcpy(dest + writeRow * SCREEN_WIDTH + writeCol, litData + litPos, n);
+ memcpy(dest + writeRow * SEQ_SCREEN_WIDTH + writeCol, litData + litPos, n);
bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) {
int writeRow = 0;
diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h
index 7c810db05d..416abb78fa 100644
--- a/engines/sci/video/seq_decoder.h
+++ b/engines/sci/video/seq_decoder.h
@@ -26,40 +26,50 @@
#ifndef SEQ_DECODER_H
#define SEQ_DECODER_H
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
namespace Sci {
/**
* Implementation of the Sierra SEQ decoder, used in KQ6 DOS floppy/CD and GK1 DOS
*/
-class SeqDecoder : public Graphics::VideoDecoder {
+class SeqDecoder : public Graphics::FixedRateVideoDecoder {
public:
- SeqDecoder() {}
+ SeqDecoder();
virtual ~SeqDecoder();
- /**
- * Load a SEQ encoded video file
- * @param filename the filename to load
- */
- bool loadFile(const char *fileName) { return loadFile(fileName, 10); }
+ bool load(Common::SeekableReadStream &stream);
+ void close();
- /**
- * Load a SEQ encoded video file
- * @param filename the filename to load
- * @param frameDelay the delay between frames, in ticks
- */
- bool loadFile(const char *fileName, int frameDelay);
+ void setFrameDelay(int frameDelay) { _frameDelay = frameDelay; }
- /**
- * Close a SEQ encoded video file
- */
- void closeFile();
-
- bool decodeNextFrame();
+ bool isVideoLoaded() const { return _fileStream != 0; }
+ uint16 getWidth() const { return SEQ_SCREEN_WIDTH; }
+ uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; }
+ uint32 getFrameCount() const { return _frameCount; }
+ Graphics::Surface *decodeNextFrame();
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
+ byte *getPalette() { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
+
+protected:
+ Common::Rational getFrameRate() const { assert(_frameDelay); return Common::Rational(60, _frameDelay); }
private:
+ enum {
+ SEQ_SCREEN_WIDTH = 320,
+ SEQ_SCREEN_HEIGHT = 200
+ };
+
bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey);
+
+ uint16 _width, _height;
+ uint16 _frameDelay;
+ Common::SeekableReadStream *_fileStream;
+ byte _palette[256 * 3];
+ bool _dirtyPalette;
+ uint32 _frameCount;
+ Graphics::Surface *_surface;
};
} // End of namespace Sci
diff --git a/engines/sci/video/vmd_decoder.cpp b/engines/sci/video/vmd_decoder.cpp
index 9e95521ebb..93132bc5d6 100644
--- a/engines/sci/video/vmd_decoder.cpp
+++ b/engines/sci/video/vmd_decoder.cpp
@@ -27,7 +27,6 @@
#include "sci/video/vmd_decoder.h"
-#include "common/archive.h"
#include "common/endian.h"
#include "common/util.h"
#include "common/stream.h"
@@ -42,54 +41,39 @@ namespace Sci {
VMDDecoder::VMDDecoder(Audio::Mixer *mixer) : _mixer(mixer) {
_vmdDecoder = new Graphics::Vmd(new Graphics::PaletteLUT(5, Graphics::PaletteLUT::kPaletteYUV));
+ _surface = 0;
+ _dirtyPalette = false;
+ _fileStream = 0;
}
VMDDecoder::~VMDDecoder() {
- closeFile();
-}
-
-uint32 VMDDecoder::getFrameWaitTime() {
- return _vmdDecoder->getFrameWaitTime();
+ close();
}
-bool VMDDecoder::loadFile(const char *fileName) {
- closeFile();
+bool VMDDecoder::load(Common::SeekableReadStream &stream) {
+ close();
- _fileStream = SearchMan.createReadStreamForMember(fileName);
- if (!_fileStream)
+ if (!_vmdDecoder->load(stream))
return false;
- if (!_vmdDecoder->load(*_fileStream))
- return false;
+ _fileStream = &stream;
- if (_vmdDecoder->getFeatures() & Graphics::CoktelVideo::kFeaturesPalette) {
- getPalette();
- setPalette(_palette);
- }
+ if (_vmdDecoder->getFeatures() & Graphics::CoktelVideo::kFeaturesPalette)
+ loadPaletteFromVMD();
if (_vmdDecoder->getFeatures() & Graphics::CoktelVideo::kFeaturesSound)
_vmdDecoder->enableSound(*_mixer);
- _videoInfo.width = _vmdDecoder->getWidth();
- _videoInfo.height = _vmdDecoder->getHeight();
- _videoInfo.frameCount = _vmdDecoder->getFramesCount();
- _videoInfo.frameRate = _vmdDecoder->getFrameRate();
- _videoInfo.frameDelay = _videoInfo.frameRate * 100;
- _videoInfo.currentFrame = -1;
- _videoInfo.firstframeOffset = 0; // not really necessary for VMDs
-
if (_vmdDecoder->hasExtraData())
warning("This VMD video has extra embedded data, which is currently not handled");
- _videoFrameBuffer = new byte[_videoInfo.width * _videoInfo.height];
- memset(_videoFrameBuffer, 0, _videoInfo.width * _videoInfo.height);
-
- _vmdDecoder->setVideoMemory(_videoFrameBuffer, _videoInfo.width, _videoInfo.height);
-
+ _surface = new Graphics::Surface();
+ _surface->create(_vmdDecoder->getWidth(), _vmdDecoder->getHeight(), 1);
+ _vmdDecoder->setVideoMemory((byte *)_surface->pixels, _surface->w, _surface->h);
return true;
}
-void VMDDecoder::closeFile() {
+void VMDDecoder::close() {
if (!_fileStream)
return;
@@ -98,27 +82,27 @@ void VMDDecoder::closeFile() {
delete _fileStream;
_fileStream = 0;
- delete[] _videoFrameBuffer;
- _videoFrameBuffer = 0;
-}
-
-bool VMDDecoder::decodeNextFrame() {
- _videoInfo.currentFrame++;
+ _surface->free();
+ delete _surface;
+ _surface = 0;
- if (_videoInfo.currentFrame == 0)
- _videoInfo.startTime = g_system->getMillis();
+ reset();
+}
+Graphics::Surface *VMDDecoder::decodeNextFrame() {
Graphics::CoktelVideo::State state = _vmdDecoder->nextFrame();
- if (state.flags & Graphics::CoktelVideo::kStatePalette) {
- getPalette();
- setPalette(_palette);
- }
+ if (state.flags & Graphics::CoktelVideo::kStatePalette)
+ loadPaletteFromVMD();
+
+ if (_curFrame == -1)
+ _startTime = g_system->getMillis();
- return !endOfVideo();
+ _curFrame++;
+ return _surface;
}
-void VMDDecoder::getPalette() {
+void VMDDecoder::loadPaletteFromVMD() {
const byte *pal = _vmdDecoder->getPalette();
for (int i = 0; i < 256; i++) {
@@ -126,6 +110,8 @@ void VMDDecoder::getPalette() {
_palette[i * 3 + 1] = pal[i * 3 + 1] << 2;
_palette[i * 3 + 2] = pal[i * 3 + 2] << 2;
}
+
+ _dirtyPalette = true;
}
} // End of namespace Graphics
diff --git a/engines/sci/video/vmd_decoder.h b/engines/sci/video/vmd_decoder.h
index 628be24e82..231da9202e 100644
--- a/engines/sci/video/vmd_decoder.h
+++ b/engines/sci/video/vmd_decoder.h
@@ -29,7 +29,7 @@
#define GRAPHICS_VIDEO_VMD_DECODER_H
#include "graphics/video/coktelvideo/coktelvideo.h"
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
#include "sound/mixer.h"
namespace Sci {
@@ -49,32 +49,37 @@ namespace Sci {
* - Shivers 2: Harvest of Souls
* - Torin's Passage
*/
-class VMDDecoder : public Graphics::VideoDecoder {
+class VMDDecoder : public Graphics::FixedRateVideoDecoder {
public:
VMDDecoder(Audio::Mixer *mixer);
virtual ~VMDDecoder();
uint32 getFrameWaitTime();
- /**
- * Load a VMD encoded video file
- * @param filename the filename to load
- */
- bool loadFile(const char *filename);
+ bool load(Common::SeekableReadStream &stream);
+ void close();
- /**
- * Close a VMD encoded video file
- */
- void closeFile();
+ bool isVideoLoaded() const { return _fileStream != 0; }
+ uint16 getWidth() const { return _surface->w; }
+ uint16 getHeight() const { return _surface->h; }
+ uint32 getFrameCount() const { return _vmdDecoder->getFramesCount(); }
+ Graphics::Surface *decodeNextFrame();
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); }
+ byte *getPalette() { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
- bool decodeNextFrame();
+protected:
+ Common::Rational getFrameRate() const { return _vmdDecoder->getFrameRate(); }
private:
Graphics::Vmd *_vmdDecoder;
Audio::Mixer *_mixer;
+ Graphics::Surface *_surface;
+ Common::SeekableReadStream *_fileStream;
byte _palette[256 * 3];
+ bool _dirtyPalette;
- void getPalette();
+ void loadPaletteFromVMD();
};
} // End of namespace Graphics
diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp
index 5bd60d32e3..9f1bf22c38 100644
--- a/engines/scumm/he/animation_he.cpp
+++ b/engines/scumm/he/animation_he.cpp
@@ -46,23 +46,21 @@ int MoviePlayer::getImageNum() {
}
int MoviePlayer::load(const char *filename, int flags, int image) {
- if (isVideoLoaded()) {
- closeFile();
- }
+ if (isVideoLoaded())
+ close();
if (!loadFile(filename)) {
warning("Failed to load video file %s", filename);
return -1;
}
+
debug(1, "Playing video %s", filename);
- if (flags & 2) {
+ if (flags & 2)
_vm->_wiz->createWizEmptyImage(image, 0, 0, getWidth(), getHeight());
- }
_flags = flags;
_wizResNum = image;
-
return 0;
}
@@ -70,7 +68,11 @@ void MoviePlayer::copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint
uint h = getHeight();
uint w = getWidth();
- byte *src = _videoFrameBuffer;
+ Graphics::Surface *surface = decodeNextFrame();
+ byte *src = (byte *)surface->pixels;
+
+ if (hasDirtyPalette())
+ _vm->setPaletteFromPtr(getPalette(), 256);
if (_vm->_game.features & GF_16BIT_COLOR) {
dst += y * pitch + x * 2;
@@ -102,14 +104,11 @@ void MoviePlayer::copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint
}
void MoviePlayer::handleNextFrame() {
- if (!isVideoLoaded()) {
+ if (!isVideoLoaded())
return;
- }
VirtScreen *pvs = &_vm->_virtscr[kMainVirtScreen];
- decodeNextFrame();
-
if (_flags & 2) {
uint8 *dstPtr = _vm->getResourceAddress(rtImage, _wizResNum);
assert(dstPtr);
@@ -129,11 +128,7 @@ void MoviePlayer::handleNextFrame() {
}
if (endOfVideo())
- closeFile();
-}
-
-void MoviePlayer::setPalette(byte *pal) {
- _vm->setPaletteFromPtr(pal, 256);
+ close();
}
} // End of namespace Scumm
diff --git a/engines/scumm/he/animation_he.h b/engines/scumm/he/animation_he.h
index 86ded31940..34794b35ac 100644
--- a/engines/scumm/he/animation_he.h
+++ b/engines/scumm/he/animation_he.h
@@ -56,9 +56,6 @@ public:
void copyFrameToBuffer(byte *dst, int dstType, uint x, uint y, uint pitch);
void handleNextFrame();
-
-protected:
- virtual void setPalette(byte *pal);
};
} // End of namespace Scumm
diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index e32409fe85..3555f55d95 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -2254,7 +2254,7 @@ void ScummEngine_v100he::o100_videoOps() {
}
} else if (_videoParams.status == 19) {
// Stop video
- _moviePlay->closeFile();
+ _moviePlay->close();
}
break;
default:
diff --git a/engines/scumm/he/script_v90he.cpp b/engines/scumm/he/script_v90he.cpp
index 091bf5027b..6acc16a804 100644
--- a/engines/scumm/he/script_v90he.cpp
+++ b/engines/scumm/he/script_v90he.cpp
@@ -1437,7 +1437,7 @@ void ScummEngine_v90he::o90_videoOps() {
}
} else if (_videoParams.status == 165) {
// Stop video
- _moviePlay->closeFile();
+ _moviePlay->close();
}
break;
default:
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index 221a20ba45..c0e7be7758 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -68,9 +68,10 @@ static const char *sequenceList[20] = {
///////////////////////////////////////////////////////////////////////////////
MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType)
- : _vm(vm), _textMan(textMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system), VideoPlayer(decoder) {
+ : _vm(vm), _textMan(textMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) {
_bgSoundStream = NULL;
_decoderType = decoderType;
+ _decoder = decoder;
}
MoviePlayer::~MoviePlayer() {
@@ -86,11 +87,10 @@ bool MoviePlayer::load(uint32 id) {
Common::File f;
char filename[20];
- if (_decoderType == kVideoDecoderDXA) {
+ if (_decoderType == kVideoDecoderDXA)
_bgSoundStream = Audio::SeekableAudioStream::openStreamFile(sequenceList[id]);
- } else {
+ else
_bgSoundStream = NULL;
- }
if (SwordEngine::_systemVars.showText) {
sprintf(filename, "%s.txt", sequenceList[id]);
@@ -146,9 +146,9 @@ bool MoviePlayer::load(uint32 id) {
}
void MoviePlayer::play() {
- if (_bgSoundStream) {
+ if (_bgSoundStream)
_snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream);
- }
+
bool terminated = false;
_textX = 0;
@@ -179,7 +179,7 @@ void MoviePlayer::play() {
void MoviePlayer::performPostProcessing(byte *screen) {
if (!_movieTexts.empty()) {
- if (_decoder->getCurFrame() + 1 == _movieTexts[0]->_startFrame) {
+ if (_decoder->getCurFrame() == _movieTexts[0]->_startFrame) {
_textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL);
FrameHeader *frame = _textMan->giveSpriteData(2);
@@ -188,7 +188,7 @@ void MoviePlayer::performPostProcessing(byte *screen) {
_textX = 320 - _textWidth / 2;
_textY = 420 - _textHeight;
}
- if (_decoder->getCurFrame() + 1 == _movieTexts[0]->_endFrame) {
+ if (_decoder->getCurFrame() == _movieTexts[0]->_endFrame) {
_textMan->releaseText(2, false);
delete _movieTexts.remove_at(0);
}
@@ -205,10 +205,10 @@ void MoviePlayer::performPostProcessing(byte *screen) {
for (x = 0; x < _textWidth; x++) {
switch (src[x]) {
case BORDER_COL:
- dst[x] = _decoder->getBlack();
+ dst[x] = findBlackPalIndex();
break;
case LETTER_COL:
- dst[x] = _decoder->getWhite();
+ dst[x] = findWhitePalIndex();
break;
}
}
@@ -228,12 +228,12 @@ void MoviePlayer::performPostProcessing(byte *screen) {
for (y = 0; y < _textHeight; y++) {
if (_textY + y < frameY || _textY + y >= frameY + frameHeight) {
- memset(dst + _textX, _decoder->getBlack(), _textWidth);
+ memset(dst + _textX, findBlackPalIndex(), _textWidth);
} else {
if (frameX > _textX)
- memset(dst + _textX, _decoder->getBlack(), frameX - _textX);
+ memset(dst + _textX, findBlackPalIndex(), frameX - _textX);
if (frameX + frameWidth < _textX + _textWidth)
- memset(dst + frameX + frameWidth, _decoder->getBlack(), _textX + _textWidth - (frameX + frameWidth));
+ memset(dst + frameX + frameWidth, findBlackPalIndex(), _textX + _textWidth - (frameX + frameWidth));
}
dst += _system->getWidth();
@@ -244,25 +244,51 @@ void MoviePlayer::performPostProcessing(byte *screen) {
}
}
-DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
- : _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
+bool MoviePlayer::playVideo() {
+ uint16 x = (g_system->getWidth() - _decoder->getWidth()) / 2;
+ uint16 y = (g_system->getHeight() - _decoder->getHeight()) / 2;
+
+ while (!_vm->shouldQuit() && !_decoder->endOfVideo()) {
+ if (_decoder->needsUpdate()) {
+ Graphics::Surface *frame = _decoder->decodeNextFrame();
+ if (frame)
+ _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+
+ if (_decoder->hasDirtyPalette())
+ _decoder->setSystemPalette();
+
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+ performPostProcessing((byte *)screen->pixels);
+ _vm->_system->unlockScreen();
+ _vm->_system->updateScreen();
+ }
+
+ Common::Event event;
+ while (_vm->_system->getEventManager()->pollEvent(event))
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
+ return false;
+ }
+
+ return !_vm->shouldQuit();
}
-int32 DXADecoderWithSound::getAudioLag() {
- if (!_fileStream)
- return 0;
+byte MoviePlayer::findBlackPalIndex() {
+ return 0;
+}
- if (!_mixer->isSoundHandleActive(*_bgSoundHandle))
- return 0;
+byte MoviePlayer::findWhitePalIndex() {
+ return 0xff;
+}
- int32 frameDelay = getFrameDelay();
- int32 videoTime = (_videoInfo.currentFrame + 1) * frameDelay;
- int32 audioTime;
+DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
+ : _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
+}
- const Audio::Timestamp ts = _mixer->getElapsedTime(*_bgSoundHandle);
- audioTime = ts.convertToFramerate(100000).totalNumberOfFrames();
+uint32 DXADecoderWithSound::getElapsedTime() const {
+ if (_mixer->isSoundHandleActive(*_bgSoundHandle))
+ return _mixer->getSoundElapsedTime(*_bgSoundHandle);
- return videoTime - audioTime;
+ return VideoDecoder::getElapsedTime();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index e97fc083f6..82343f2800 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -28,7 +28,7 @@
#include "graphics/video/dxa_decoder.h"
#include "graphics/video/smk_decoder.h"
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
#include "common/array.h"
@@ -64,18 +64,20 @@ public:
DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle);
~DXADecoderWithSound() {}
- int32 getAudioLag();
+ uint32 getElapsedTime() const;
+
private:
Audio::Mixer *_mixer;
Audio::SoundHandle *_bgSoundHandle;
};
-class MoviePlayer : public Graphics::VideoPlayer {
+class MoviePlayer {
public:
MoviePlayer(SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType);
virtual ~MoviePlayer();
bool load(uint32 id);
void play();
+
protected:
SwordEngine *_vm;
Text *_textMan;
@@ -85,10 +87,15 @@ protected:
int _textX, _textY, _textWidth, _textHeight;
DecoderType _decoderType;
+ Graphics::VideoDecoder *_decoder;
Audio::SoundHandle *_bgSoundHandle;
Audio::AudioStream *_bgSoundStream;
+ bool playVideo();
void performPostProcessing(byte *screen);
+
+ byte findBlackPalIndex();
+ byte findWhitePalIndex();
};
MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, Audio::Mixer *snd, OSystem *system);
diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp
index 1c5c2e5f8c..c3f3e796b2 100644
--- a/engines/sword2/animation.cpp
+++ b/engines/sword2/animation.cpp
@@ -47,9 +47,10 @@ namespace Sword2 {
///////////////////////////////////////////////////////////////////////////////
MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType)
- : _vm(vm), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system), VideoPlayer(decoder) {
+ : _vm(vm), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) {
_bgSoundStream = NULL;
_decoderType = decoderType;
+ _decoder = decoder;
}
MoviePlayer:: ~MoviePlayer() {
@@ -62,11 +63,10 @@ MoviePlayer:: ~MoviePlayer() {
* @param id the id of the file
*/
bool MoviePlayer::load(const char *name) {
- if (_decoderType == kVideoDecoderDXA) {
+ if (_decoderType == kVideoDecoderDXA)
_bgSoundStream = Audio::SeekableAudioStream::openStreamFile(name);
- } else {
+ else
_bgSoundStream = NULL;
- }
_textSurface = NULL;
@@ -97,13 +97,11 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI
_currentMovieText = 0;
_leadOut = leadOut;
- if (leadIn) {
+ if (leadIn)
_vm->_sound->playMovieSound(leadIn, kLeadInSound);
- }
- if (_bgSoundStream) {
+ if (_bgSoundStream)
_snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream);
- }
bool terminated = false;
@@ -186,12 +184,12 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen) {
for (int y = 0; y < text->_textSprite.h; y++) {
if (_textY + y < frameY || _textY + y >= frameY + frameHeight) {
- memset(dst + _textX, _decoder->getBlack(), text->_textSprite.w);
+ memset(dst + _textX, findBlackPalIndex(), text->_textSprite.w);
} else {
if (frameX > _textX)
- memset(dst + _textX, _decoder->getBlack(), frameX - _textX);
+ memset(dst + _textX, findBlackPalIndex(), frameX - _textX);
if (frameX + frameWidth < _textX + text->_textSprite.w)
- memset(dst + frameX + frameWidth, _decoder->getBlack(), _textX + text->_textSprite.w - (frameX + frameWidth));
+ memset(dst + frameX + frameWidth, findBlackPalIndex(), _textX + text->_textSprite.w - (frameX + frameWidth));
}
dst += _system->getWidth();
@@ -207,8 +205,8 @@ void MoviePlayer::closeTextObject(uint32 index, byte *screen) {
void MoviePlayer::drawTextObject(uint32 index, byte *screen) {
MovieText *text = &_movieTexts[index];
- byte white = _decoder->getWhite();
- byte black = _decoder->getBlack();
+ byte white = findWhitePalIndex();
+ byte black = findBlackPalIndex();
if (text->_textMem && _textSurface) {
byte *src = text->_textSprite.data;
@@ -240,7 +238,7 @@ void MoviePlayer::drawTextObject(uint32 index, byte *screen) {
void MoviePlayer::performPostProcessing(byte *screen) {
MovieText *text;
- int frame = _decoder->getCurFrame() + 1;
+ int frame = _decoder->getCurFrame();
if (_currentMovieText < _numMovieTexts) {
text = &_movieTexts[_currentMovieText];
@@ -272,25 +270,51 @@ void MoviePlayer::performPostProcessing(byte *screen) {
}
}
-DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
- : _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
+bool MoviePlayer::playVideo() {
+ uint16 x = (g_system->getWidth() - _decoder->getWidth()) / 2;
+ uint16 y = (g_system->getHeight() - _decoder->getHeight()) / 2;
+
+ while (!_vm->shouldQuit() && !_decoder->endOfVideo()) {
+ if (_decoder->needsUpdate()) {
+ Graphics::Surface *frame = _decoder->decodeNextFrame();
+ if (frame)
+ _vm->_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+
+ if (_decoder->hasDirtyPalette())
+ _decoder->setSystemPalette();
+
+ Graphics::Surface *screen = _vm->_system->lockScreen();
+ performPostProcessing((byte *)screen->pixels);
+ _vm->_system->unlockScreen();
+ _vm->_system->updateScreen();
+ }
+
+ Common::Event event;
+ while (_vm->_system->getEventManager()->pollEvent(event))
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
+ return false;
+ }
+
+ return !_vm->shouldQuit();
}
-int32 DXADecoderWithSound::getAudioLag() {
- if (!_fileStream)
- return 0;
+byte MoviePlayer::findBlackPalIndex() {
+ return 0;
+}
- if (!_mixer->isSoundHandleActive(*_bgSoundHandle))
- return 0;
+byte MoviePlayer::findWhitePalIndex() {
+ return 0xff;
+}
- int32 frameDelay = getFrameDelay();
- int32 videoTime = _videoInfo.currentFrame * frameDelay;
- int32 audioTime;
+DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
+ : _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
+}
- const Audio::Timestamp ts = _mixer->getElapsedTime(*_bgSoundHandle);
- audioTime = ts.convertToFramerate(100000).totalNumberOfFrames();
+uint32 DXADecoderWithSound::getElapsedTime() const {
+ if (_mixer->isSoundHandleActive(*_bgSoundHandle))
+ return _mixer->getSoundElapsedTime(*_bgSoundHandle);
- return videoTime - audioTime;
+ return VideoDecoder::getElapsedTime();
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h
index 7f9ae0ff2d..bbf83e264c 100644
--- a/engines/sword2/animation.h
+++ b/engines/sword2/animation.h
@@ -30,7 +30,7 @@
#include "graphics/video/dxa_decoder.h"
#include "graphics/video/smk_decoder.h"
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
#include "sound/mixer.h"
#include "sword2/screen.h"
@@ -63,13 +63,13 @@ public:
DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle);
~DXADecoderWithSound() {}
- int32 getAudioLag();
+ uint32 getElapsedTime() const;
private:
Audio::Mixer *_mixer;
Audio::SoundHandle *_bgSoundHandle;
};
-class MoviePlayer : public Graphics::VideoPlayer {
+class MoviePlayer {
public:
MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Graphics::VideoDecoder *decoder, DecoderType decoderType);
virtual ~MoviePlayer();
@@ -89,6 +89,7 @@ protected:
int _textX, _textY;
DecoderType _decoderType;
+ Graphics::VideoDecoder *_decoder;
Audio::SoundHandle *_bgSoundHandle;
Audio::AudioStream *_bgSoundStream;
@@ -96,10 +97,14 @@ protected:
int _leadOutFrame;
void performPostProcessing(byte *screen);
+ bool playVideo();
void openTextObject(uint32 index);
void closeTextObject(uint32 index, byte *screen);
void drawTextObject(uint32 index, byte *screen);
+
+ byte findBlackPalIndex();
+ byte findWhitePalIndex();
};
MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system);
diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp
index 02cc695e7c..68f5301a80 100644
--- a/engines/tucker/sequences.cpp
+++ b/engines/tucker/sequences.cpp
@@ -537,9 +537,9 @@ void AnimationSequencePlayer::mainLoop() {
}
// budttle2.flc is shorter in french version ; start the background music
// earlier and skip any sounds effects
- if (_seqNum == 19 && _flicPlayer[0].getFrameCount() == 126) {
+ if (_seqNum == 19 && _flicPlayer[0].getFrameCount() == 127) {
_soundSeqDataIndex = 6;
- _frameCounter = 80;
+ _frameCounter = 79;
}
}
(this->*(_updateFunc[_updateFuncIndex].play))();
@@ -766,19 +766,21 @@ void AnimationSequencePlayer::openAnimation(int index, const char *fileName) {
}
bool AnimationSequencePlayer::decodeNextAnimationFrame(int index) {
- bool framesLeft = _flicPlayer[index].decodeNextFrame();
+ ::Graphics::Surface *surface = _flicPlayer[index].decodeNextFrame();
+
if (_seqNum == 19) {
- _flicPlayer[index].copyFrameToBuffer(_offscreenBuffer, 0, 0, kScreenWidth);
+ for (uint16 y = 0; (y < surface->h) && (y < kScreenHeight); y++)
+ memcpy(_offscreenBuffer + y * kScreenWidth, (byte *)surface->pixels + y * surface->pitch, surface->w);
} else {
_flicPlayer[index].copyDirtyRectsToBuffer(_offscreenBuffer, kScreenWidth);
}
+
++_frameCounter;
- if (index == 0) {
- if (_flicPlayer[index].paletteChanged()) {
- getRGBPalette(index);
- }
- }
- return framesLeft;
+
+ if (index == 0 && _flicPlayer[index].hasDirtyPalette())
+ getRGBPalette(index);
+
+ return !_flicPlayer[index].endOfVideo();
}
void AnimationSequencePlayer::loadIntroSeq17_18() {
@@ -803,20 +805,23 @@ void AnimationSequencePlayer::playIntroSeq19_20() {
// The intro credits animation. This uses 2 animations: the foreground one, which
// is the actual intro credits, and the background one, which is an animation of
// cogs, and is being replayed when an intro credit appears
- if (_flicPlayer[0].getCurFrame() >= 116) {
- if (!_flicPlayer[1].decodeNextFrame()) {
+ ::Graphics::Surface *surface = 0;
+
+ if (_flicPlayer[0].getCurFrame() >= 117) {
+ surface = _flicPlayer[1].decodeNextFrame();
+ if (_flicPlayer[1].endOfVideo())
_flicPlayer[1].reset();
- }
}
+
bool framesLeft = decodeNextAnimationFrame(0);
- for (int i = 0; i < kScreenWidth * kScreenHeight; ++i) {
- if (_offscreenBuffer[i] == 0) {
- _offscreenBuffer[i] = _flicPlayer[1].getPixel(i);
- }
- }
- if (!framesLeft) {
+
+ if (surface)
+ for (int i = 0; i < kScreenWidth * kScreenHeight; ++i)
+ if (_offscreenBuffer[i] == 0)
+ _offscreenBuffer[i] = *((byte *)surface->pixels + i);
+
+ if (!framesLeft)
_changeToNextSequence = true;
- }
}
void AnimationSequencePlayer::displayLoadingScreen() {
@@ -870,7 +875,7 @@ void AnimationSequencePlayer::loadIntroSeq3_4() {
void AnimationSequencePlayer::playIntroSeq3_4() {
if (!_updateScreenPicture) {
bool framesLeft = decodeNextAnimationFrame(0);
- if (_flicPlayer[0].getCurFrame() == 706) {
+ if (_flicPlayer[0].getCurFrame() == 707) {
initPicPart4();
}
if (!framesLeft) {
@@ -909,13 +914,21 @@ void AnimationSequencePlayer::drawPic2Part10() {
}
void AnimationSequencePlayer::drawPic1Part10() {
+ ::Graphics::Surface *surface = _flicPlayer[0].decodeNextFrame();
+ _flicPlayer[0].copyDirtyRectsToBuffer(_offscreenBuffer, kScreenWidth);
+ ++_frameCounter;
+
+ if (_flicPlayer[0].hasDirtyPalette())
+ getRGBPalette(0);
+
int offset = 0;
for (int y = 0; y < kScreenHeight; ++y) {
for (int x = 0; x < kScreenWidth; ++x) {
- byte color = _flicPlayer[0].getPixel(offset);
- if (color == 0) {
+ byte color = *((byte *)surface->pixels + offset);
+
+ if (color == 0)
color = _picBufPtr[800 + y * 640 + _updateScreenWidth + x];
- }
+
_offscreenBuffer[offset++] = color;
}
}
@@ -930,22 +943,22 @@ void AnimationSequencePlayer::loadIntroSeq9_10() {
}
void AnimationSequencePlayer::playIntroSeq9_10() {
- bool framesLeft = decodeNextAnimationFrame(0);
- if (_flicPlayer[0].getCurFrame() >= 264 && _flicPlayer[0].getCurFrame() <= 295) {
+ if (_flicPlayer[0].getCurFrame() >= 265 && _flicPlayer[0].getCurFrame() <= 296) {
drawPic1Part10();
_updateScreenWidth += 6;
- } else if (_flicPlayer[0].getCurFrame() == 984) {
+ } else if (_flicPlayer[0].getCurFrame() == 985) {
+ decodeNextAnimationFrame(0);
drawPic2Part10();
- } else if (_flicPlayer[0].getCurFrame() >= 988 && _flicPlayer[0].getCurFrame() <= 996) {
+ } else if (_flicPlayer[0].getCurFrame() >= 989 && _flicPlayer[0].getCurFrame() <= 997) {
drawPic1Part10();
_updateScreenWidth -= 25;
if (_updateScreenWidth < 0) {
_updateScreenWidth = 0;
}
}
- if (!framesLeft) {
+
+ if (_flicPlayer[0].endOfVideo())
_changeToNextSequence = true;
- }
}
void AnimationSequencePlayer::loadIntroSeq21_22() {
diff --git a/graphics/module.mk b/graphics/module.mk
index 15fbf092b3..ff6d7f8f60 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -26,7 +26,7 @@ MODULE_OBJS := \
video/flic_decoder.o \
video/mpeg_player.o \
video/smk_decoder.o \
- video/video_player.o \
+ video/video_decoder.o \
video/codecs/msrle.o \
video/codecs/msvideo1.o \
video/coktelvideo/indeo3.o \
diff --git a/graphics/video/avi_decoder.cpp b/graphics/video/avi_decoder.cpp
index 1e0fb389b3..944c9700bd 100644
--- a/graphics/video/avi_decoder.cpp
+++ b/graphics/video/avi_decoder.cpp
@@ -23,7 +23,6 @@
*
*/
-#include "common/archive.h"
#include "common/endian.h"
#include "common/file.h"
#include "common/stream.h"
@@ -49,6 +48,7 @@ AviDecoder::AviDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) :
_audStream = NULL;
_fileStream = NULL;
_audHandle = new Audio::SoundHandle();
+ _dirtyPalette = false;
memset(_palette, 0, sizeof(_palette));
memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT));
memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER));
@@ -58,7 +58,7 @@ AviDecoder::AviDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) :
}
AviDecoder::~AviDecoder() {
- closeFile();
+ close();
delete _audHandle;
}
@@ -190,7 +190,7 @@ void AviDecoder::handleStreamHeader() {
/*_palette[i * 4 + 3] = */_fileStream->readByte();
}
- setPalette(_palette);
+ _dirtyPalette = true;
}
} else if (sHeader.streamType == ID_AUDS) {
_audsHeader = sHeader;
@@ -204,24 +204,16 @@ void AviDecoder::handleStreamHeader() {
}
}
-bool AviDecoder::loadFile(const char *fileName) {
- closeFile();
-
- _fileStream = SearchMan.createReadStreamForMember(fileName);
- if (!_fileStream)
- return false;
+bool AviDecoder::load(Common::SeekableReadStream &stream) {
+ close();
+ _fileStream = &stream;
_decodedHeader = false;
- // Seek to the first frame
- _videoInfo.currentFrame = -1;
// Read chunks until we have decoded the header
while (!_decodedHeader)
runHandle(_fileStream->readUint32BE());
- _videoFrameBuffer = new byte[_header.width * _header.height];
- memset(_videoFrameBuffer, 0, _header.width * _header.height);
-
uint32 nextTag = _fileStream->readUint32BE();
// Throw out any JUNK section
@@ -247,34 +239,24 @@ bool AviDecoder::loadFile(const char *fileName) {
_mixer->playStream(_soundType, _audHandle, _audStream);
debug (0, "Frames = %d, Dimensions = %d x %d", _header.totalFrames, _header.width, _header.height);
- debug (0, "Frame Rate = %d", getFrameRate());
+ debug (0, "Frame Rate = %d", _vidsHeader.rate / _vidsHeader.scale);
if ((_audsHeader.scale != 0) && (_header.flags & AVIF_ISINTERLEAVED))
debug (0, "Sound Rate = %d", AUDIO_RATE);
debug (0, "Video Codec = \'%s\'", tag2str(_vidsHeader.streamHandler));
- _videoInfo.firstframeOffset = _fileStream->pos();
- _videoInfo.width = _header.width;
- _videoInfo.height = _header.height;
- _videoInfo.frameCount = _header.totalFrames;
- // Our frameDelay is calculated in 1/100 ms, so we convert it here
- _videoInfo.frameDelay = _header.microSecondsPerFrame / 10;
-
if (!_videoCodec)
return false;
return true;
}
-void AviDecoder::closeFile() {
+void AviDecoder::close() {
if (!_fileStream)
return;
delete _fileStream;
_fileStream = 0;
- delete[] _videoFrameBuffer;
- _videoFrameBuffer = 0;
-
// Deinitialize sound
_mixer->stopHandle(*_audHandle);
_audStream = 0;
@@ -293,14 +275,26 @@ void AviDecoder::closeFile() {
memset(&_vidsHeader, 0, sizeof(AVIStreamHeader));
memset(&_audsHeader, 0, sizeof(AVIStreamHeader));
memset(&_ixInfo, 0, sizeof(AVIOLDINDEX));
+
+ reset();
}
-Surface *AviDecoder::getNextFrame() {
+uint32 AviDecoder::getElapsedTime() const {
+ if (_audStream)
+ return _mixer->getSoundElapsedTime(*_audHandle);
+
+ return VideoDecoder::getElapsedTime();
+}
+
+Surface *AviDecoder::decodeNextFrame() {
uint32 nextTag = _fileStream->readUint32BE();
if (_fileStream->eos())
return NULL;
+ if (_curFrame == -1)
+ _startTime = g_system->getMillis();
+
if (nextTag == ID_LIST) {
// A list of audio/video chunks
uint32 listSize = _fileStream->readUint32LE() - 4;
@@ -312,7 +306,7 @@ Surface *AviDecoder::getNextFrame() {
// Decode chunks in the list and see if we get a frame
Surface *frame = NULL;
while (_fileStream->pos() < startPos + (int32)listSize) {
- Surface *temp = getNextFrame();
+ Surface *temp = decodeNextFrame();
if (temp)
frame = temp;
}
@@ -335,7 +329,7 @@ Surface *AviDecoder::getNextFrame() {
} else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id' ||
getStreamType(nextTag) == 'AM' || getStreamType(nextTag) == '32') {
// Compressed Frame
- _videoInfo.currentFrame++;
+ _curFrame++;
uint32 chunkSize = _fileStream->readUint32LE();
if (chunkSize == 0) // Keep last frame on screen
@@ -364,7 +358,7 @@ Surface *AviDecoder::getNextFrame() {
_fileStream->readByte(); // Flags that don't serve us any purpose
}
- setPalette(_palette);
+ _dirtyPalette = true;
// No alignment necessary. It's always even.
} else if (nextTag == ID_JUNK) {
@@ -372,56 +366,11 @@ Surface *AviDecoder::getNextFrame() {
} else if (nextTag == ID_IDX1) {
runHandle(ID_IDX1);
} else
- error ("Tag = \'%s\', %d", tag2str(nextTag), _fileStream->pos());
+ error("Tag = \'%s\', %d", tag2str(nextTag), _fileStream->pos());
return NULL;
}
-bool AviDecoder::decodeNextFrame() {
- Surface *surface = NULL;
-
- int32 curFrame = _videoInfo.currentFrame;
-
- while (!surface && !endOfVideo() && !_fileStream->eos())
- surface = getNextFrame();
-
- if (curFrame == _videoInfo.currentFrame) {
- warning("No video frame found");
- _videoInfo.currentFrame++;
- }
-
- if (surface)
- memcpy(_videoFrameBuffer, surface->pixels, _header.width * _header.height);
-
- if (_videoInfo.currentFrame == 0)
- _videoInfo.startTime = g_system->getMillis();
-
- return !endOfVideo();
-}
-
-int32 AviDecoder::getAudioLag() {
- if (!_fileStream)
- return 0;
-
- int32 frameDelay = getFrameDelay();
- int32 videoTime = (_videoInfo.currentFrame + 1) * frameDelay;
- int32 audioTime;
-
- if (!_audStream) {
- /* No audio.
- Calculate the lag by how much time has gone by since the first frame
- and how much time *should* have passed.
- */
-
- audioTime = (g_system->getMillis() - _videoInfo.startTime) * 100;
- } else {
- const Audio::Timestamp ts = _mixer->getElapsedTime(*_audHandle);
- audioTime = ts.convertToFramerate(100000).totalNumberOfFrames();
- }
-
- return videoTime - audioTime;
-}
-
Codec *AviDecoder::createCodec() {
switch (_vidsHeader.streamHandler) {
case ID_CRAM:
@@ -437,11 +386,14 @@ Codec *AviDecoder::createCodec() {
return NULL;
}
-Audio::QueuingAudioStream *AviDecoder::createAudioStream() {
+PixelFormat AviDecoder::getPixelFormat() const {
+ assert(_videoCodec);
+ return _videoCodec->getPixelFormat();
+}
- if (_wvInfo.tag == AVI_WAVE_FORMAT_PCM) {
+Audio::QueuingAudioStream *AviDecoder::createAudioStream() {
+ if (_wvInfo.tag == AVI_WAVE_FORMAT_PCM)
return Audio::makeQueuingAudioStream(AUDIO_RATE, false);
- }
if (_wvInfo.tag != 0) // No sound
warning ("Unsupported AVI audio format %d", _wvInfo.tag);
diff --git a/graphics/video/avi_decoder.h b/graphics/video/avi_decoder.h
index 0f0431c70b..5f09992647 100644
--- a/graphics/video/avi_decoder.h
+++ b/graphics/video/avi_decoder.h
@@ -26,7 +26,7 @@
#ifndef GRAPHICS_AVI_PLAYER_H
#define GRAPHICS_AVI_PLAYER_H
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
#include "graphics/video/codecs/codec.h"
#include "sound/audiostream.h"
#include "sound/mixer.h"
@@ -172,26 +172,27 @@ struct AVIStreamHeader {
Common::Rect frame;
};
-class AviDecoder : public VideoDecoder {
+class AviDecoder : public FixedRateVideoDecoder {
public:
AviDecoder(Audio::Mixer *mixer,
Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
virtual ~AviDecoder();
- /**
- * Load an AVI video file
- * @param filename the filename to load
- */
- bool loadFile(const char *fileName);
+ bool load(Common::SeekableReadStream &stream);
+ void close();
- /**
- * Close an AVI video file
- */
- void closeFile();
+ bool isVideoLoaded() const { return _fileStream != 0; }
+ uint16 getWidth() const { return _header.width; }
+ uint16 getHeight() const { return _header.height; }
+ uint32 getFrameCount() const { return _header.totalFrames; }
+ uint32 getElapsedTime() const;
+ Surface *decodeNextFrame();
+ PixelFormat getPixelFormat() const;
+ byte *getPalette() { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
- bool decodeNextFrame();
- int32 getAudioLag();
- int32 getFrameRate() { return _vidsHeader.rate / _vidsHeader.scale; }
+protected:
+ Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); }
private:
Audio::Mixer *_mixer;
@@ -202,7 +203,9 @@ private:
AVIStreamHeader _vidsHeader;
AVIStreamHeader _audsHeader;
byte _palette[3 * 256];
+ bool _dirtyPalette;
+ Common::SeekableReadStream *_fileStream;
bool _decodedHeader;
Codec *_videoCodec;
@@ -223,8 +226,6 @@ private:
static byte char2num(char c);
static byte getStreamNum(uint32 tag);
static uint16 getStreamType(uint32 tag);
-
- Surface *getNextFrame();
};
} // End of namespace Graphics
diff --git a/graphics/video/codecs/codec.h b/graphics/video/codecs/codec.h
index 124d1bc49d..4a280a81df 100644
--- a/graphics/video/codecs/codec.h
+++ b/graphics/video/codecs/codec.h
@@ -28,6 +28,7 @@
#include "common/stream.h"
#include "graphics/surface.h"
+#include "graphics/pixelformat.h"
namespace Graphics {
@@ -35,7 +36,9 @@ class Codec {
public:
Codec() {}
virtual ~Codec() {}
+
virtual Surface *decodeImage(Common::SeekableReadStream *stream) = 0;
+ virtual PixelFormat getPixelFormat() const = 0;
};
} // End of namespace Graphics
diff --git a/graphics/video/codecs/msrle.h b/graphics/video/codecs/msrle.h
index 634fe754ba..819e66a0bd 100644
--- a/graphics/video/codecs/msrle.h
+++ b/graphics/video/codecs/msrle.h
@@ -36,6 +36,7 @@ public:
~MSRLEDecoder();
Surface *decodeImage(Common::SeekableReadStream *stream);
+ PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
private:
byte _bitsPerPixel;
diff --git a/graphics/video/codecs/msvideo1.cpp b/graphics/video/codecs/msvideo1.cpp
index 16596926fd..f37bdbbf95 100644
--- a/graphics/video/codecs/msvideo1.cpp
+++ b/graphics/video/codecs/msvideo1.cpp
@@ -125,7 +125,7 @@ void MSVideo1Decoder::decode8(Common::SeekableReadStream *stream) {
}
}
-Graphics::Surface *MSVideo1Decoder::decodeImage(Common::SeekableReadStream *stream) {
+Surface *MSVideo1Decoder::decodeImage(Common::SeekableReadStream *stream) {
if (_bitsPerPixel == 8)
decode8(stream);
else {
diff --git a/graphics/video/codecs/msvideo1.h b/graphics/video/codecs/msvideo1.h
index ff6ffc6549..e07267476d 100644
--- a/graphics/video/codecs/msvideo1.h
+++ b/graphics/video/codecs/msvideo1.h
@@ -36,6 +36,7 @@ public:
~MSVideo1Decoder();
Surface *decodeImage(Common::SeekableReadStream *stream);
+ PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
private:
byte _bitsPerPixel;
diff --git a/graphics/video/dxa_decoder.cpp b/graphics/video/dxa_decoder.cpp
index 86f2415922..3f26012f5e 100644
--- a/graphics/video/dxa_decoder.cpp
+++ b/graphics/video/dxa_decoder.cpp
@@ -39,11 +39,12 @@ namespace Graphics {
DXADecoder::DXADecoder() {
_fileStream = 0;
+ _surface = 0;
+ _dirtyPalette = false;
_frameBuffer1 = 0;
_frameBuffer2 = 0;
_scaledBuffer = 0;
- _videoFrameBuffer = 0;
_inBuffer = 0;
_inBufferSize = 0;
@@ -51,67 +52,59 @@ DXADecoder::DXADecoder() {
_decompBuffer = 0;
_decompBufferSize = 0;
- _videoInfo.width = 0;
- _videoInfo.height = 0;
+ _width = 0;
+ _height = 0;
_frameSize = 0;
- _videoInfo.frameCount = 0;
- _videoInfo.currentFrame = -1;
- _videoInfo.frameRate = 0;
- _videoInfo.frameDelay = 0;
+ _frameCount = 0;
+ _frameRate = 0;
_scaleMode = S_NONE;
}
DXADecoder::~DXADecoder() {
- closeFile();
+ close();
}
-bool DXADecoder::loadFile(const char *fileName) {
- uint32 tag;
- int32 frameRate;
+bool DXADecoder::load(Common::SeekableReadStream &stream) {
+ close();
- closeFile();
+ _fileStream = &stream;
- _fileStream = SearchMan.createReadStreamForMember(fileName);
- if (!_fileStream)
- return false;
-
- tag = _fileStream->readUint32BE();
+ uint32 tag = _fileStream->readUint32BE();
assert(tag == MKID_BE('DEXA'));
uint8 flags = _fileStream->readByte();
- _videoInfo.frameCount = _fileStream->readUint16BE();
- frameRate = _fileStream->readSint32BE();
-
- if (frameRate > 0) {
- _videoInfo.frameRate = 1000 / frameRate;
- _videoInfo.frameDelay = frameRate * 100;
- } else if (frameRate < 0) {
- _videoInfo.frameRate = 100000 / (-frameRate);
- _videoInfo.frameDelay = -frameRate;
- } else {
- _videoInfo.frameRate = 10;
- _videoInfo.frameDelay = 10000;
- }
+ _frameCount = _fileStream->readUint16BE();
+ int32 frameRate = _fileStream->readSint32BE();
+
+ if (frameRate > 0)
+ _frameRate = 1000 / frameRate;
+ else if (frameRate < 0)
+ _frameRate = 100000 / (-frameRate);
+ else
+ _frameRate = 10;
- _videoInfo.width = _fileStream->readUint16BE();
- _videoInfo.height = _fileStream->readUint16BE();
+ _width = _fileStream->readUint16BE();
+ _height = _fileStream->readUint16BE();
if (flags & 0x80) {
_scaleMode = S_INTERLACED;
- _curHeight = _videoInfo.height / 2;
+ _curHeight = _height / 2;
} else if (flags & 0x40) {
_scaleMode = S_DOUBLE;
- _curHeight = _videoInfo.height / 2;
+ _curHeight = _height / 2;
} else {
_scaleMode = S_NONE;
- _curHeight = _videoInfo.height;
+ _curHeight = _height;
}
- debug(2, "flags 0x0%x framesCount %d width %d height %d rate %d ticks %d", flags, getFrameCount(), getWidth(), getHeight(), getFrameRate(), getFrameDelay());
+ _surface = new Graphics::Surface();
+ _surface->bytesPerPixel = 1;
- _frameSize = _videoInfo.width * _videoInfo.height;
+ debug(2, "flags 0x0%x framesCount %d width %d height %d rate %d", flags, getFrameCount(), getWidth(), getHeight(), getFrameRate().toInt());
+
+ _frameSize = _width * _height;
_decompBufferSize = _frameSize;
_frameBuffer1 = (uint8 *)malloc(_frameSize);
memset(_frameBuffer1, 0, _frameSize);
@@ -135,9 +128,10 @@ bool DXADecoder::loadFile(const char *fileName) {
do {
tag = _fileStream->readUint32BE();
- if (tag != 0) {
+
+ if (tag != 0)
size = _fileStream->readUint32BE();
- }
+
switch (tag) {
case 0: // No more tags
break;
@@ -159,20 +153,19 @@ bool DXADecoder::loadFile(const char *fileName) {
// Read the sound header
_soundTag = _fileStream->readUint32BE();
- _videoInfo.currentFrame = -1;
-
- _videoInfo.firstframeOffset = _fileStream->pos();
-
return true;
}
-void DXADecoder::closeFile() {
+void DXADecoder::close() {
if (!_fileStream)
return;
delete _fileStream;
_fileStream = 0;
+ delete _surface;
+ _surface = 0;
+
free(_frameBuffer1);
free(_frameBuffer2);
free(_scaledBuffer);
@@ -181,6 +174,8 @@ void DXADecoder::closeFile() {
_inBuffer = 0;
_decompBuffer = 0;
+
+ reset();
}
void DXADecoder::decodeZlib(byte *data, int size, int totalSize) {
@@ -208,10 +203,10 @@ void DXADecoder::decode12(int size) {
memcpy(_frameBuffer2, _frameBuffer1, _frameSize);
- for (uint32 by = 0; by < _videoInfo.height; by += BLOCKH) {
- for (uint32 bx = 0; bx < _videoInfo.width; bx += BLOCKW) {
+ for (uint32 by = 0; by < _height; by += BLOCKH) {
+ for (uint32 bx = 0; bx < _width; bx += BLOCKW) {
byte type = *dat++;
- byte *b2 = _frameBuffer1 + bx + by * _videoInfo.width;
+ byte *b2 = _frameBuffer1 + bx + by * _width;
switch (type) {
case 0:
@@ -243,7 +238,7 @@ void DXADecoder::decode12(int size) {
}
diffMap <<= 1;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -254,7 +249,7 @@ void DXADecoder::decode12(int size) {
for (int xc = 0; xc < BLOCKW; xc++) {
b2[xc] = color;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -263,7 +258,7 @@ void DXADecoder::decode12(int size) {
for (int xc = 0; xc < BLOCKW; xc++) {
b2[xc] = *dat++;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -275,11 +270,11 @@ void DXADecoder::decode12(int size) {
int my = mbyte & 0x07;
if (mbyte & 0x08)
my = -my;
- byte *b1 = _frameBuffer2 + (bx+mx) + (by+my) * _videoInfo.width;
+ byte *b1 = _frameBuffer2 + (bx+mx) + (by+my) * _width;
for (int yc = 0; yc < BLOCKH; yc++) {
memcpy(b2, b1, BLOCKW);
- b1 += _videoInfo.width;
- b2 += _videoInfo.width;
+ b1 += _width;
+ b2 += _width;
}
break;
}
@@ -309,7 +304,7 @@ void DXADecoder::decode13(int size) {
memcpy(_frameBuffer2, _frameBuffer1, _frameSize);
- int codeSize = _videoInfo.width * _curHeight / 16;
+ int codeSize = _width * _curHeight / 16;
int dataSize, motSize, maskSize;
dataSize = READ_BE_UINT32(&_decompBuffer[0]);
@@ -322,9 +317,9 @@ void DXADecoder::decode13(int size) {
maskBuf = &motBuf[motSize];
for (uint32 by = 0; by < _curHeight; by += BLOCKH) {
- for (uint32 bx = 0; bx < _videoInfo.width; bx += BLOCKW) {
+ for (uint32 bx = 0; bx < _width; bx += BLOCKW) {
uint8 type = *codeBuf++;
- uint8 *b2 = (uint8*)_frameBuffer1 + bx + by * _videoInfo.width;
+ uint8 *b2 = (uint8*)_frameBuffer1 + bx + by * _width;
switch (type) {
case 0:
@@ -341,7 +336,7 @@ void DXADecoder::decode13(int size) {
}
diffMap <<= 1;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -352,7 +347,7 @@ void DXADecoder::decode13(int size) {
for (int xc = 0; xc < BLOCKW; xc++) {
b2[xc] = color;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -361,7 +356,7 @@ void DXADecoder::decode13(int size) {
for (int xc = 0; xc < BLOCKW; xc++) {
b2[xc] = *dataBuf++;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -375,11 +370,11 @@ void DXADecoder::decode13(int size) {
if (mbyte & 0x08)
my = -my;
- uint8 *b1 = (uint8*)_frameBuffer2 + (bx+mx) + (by+my) * _videoInfo.width;
+ uint8 *b1 = (uint8*)_frameBuffer2 + (bx+mx) + (by+my) * _width;
for (int yc = 0; yc < BLOCKH; yc++) {
memcpy(b2, b1, BLOCKW);
- b1 += _videoInfo.width;
- b2 += _videoInfo.width;
+ b1 += _width;
+ b2 += _width;
}
break;
}
@@ -391,7 +386,7 @@ void DXADecoder::decode13(int size) {
for (int subBlock = 0; subBlock < 4; subBlock++) {
int sx = bx + subX[subBlock], sy = by + subY[subBlock];
- b2 = (uint8*)_frameBuffer1 + sx + sy * _videoInfo.width;
+ b2 = (uint8*)_frameBuffer1 + sx + sy * _width;
switch (subMask & 0xC0) {
// 00: skip
case 0x00:
@@ -403,7 +398,7 @@ void DXADecoder::decode13(int size) {
for (int xc = 0; xc < BLOCKW / 2; xc++) {
b2[xc] = subColor;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -419,11 +414,11 @@ void DXADecoder::decode13(int size) {
if (mbyte & 0x08)
my = -my;
- uint8 *b1 = (uint8*)_frameBuffer2 + (sx+mx) + (sy+my) * _videoInfo.width;
+ uint8 *b1 = (uint8*)_frameBuffer2 + (sx+mx) + (sy+my) * _width;
for (int yc = 0; yc < BLOCKH / 2; yc++) {
memcpy(b2, b1, BLOCKW / 2);
- b1 += _videoInfo.width;
- b2 += _videoInfo.width;
+ b1 += _width;
+ b2 += _width;
}
break;
}
@@ -433,7 +428,7 @@ void DXADecoder::decode13(int size) {
for (int xc = 0; xc < BLOCKW / 2; xc++) {
b2[xc] = *dataBuf++;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
break;
}
@@ -458,7 +453,7 @@ void DXADecoder::decode13(int size) {
b2[xc] = pixels[code & 1];
code >>= 1;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
} else {
uint32 code = READ_BE_UINT32(maskBuf);
@@ -468,7 +463,7 @@ void DXADecoder::decode13(int size) {
b2[xc] = pixels[code & 3];
code >>= 2;
}
- b2 += _videoInfo.width;
+ b2 += _width;
}
}
break;
@@ -481,20 +476,11 @@ void DXADecoder::decode13(int size) {
#endif
}
-bool DXADecoder::decodeNextFrame() {
- uint32 tag;
-
- _videoInfo.currentFrame++;
-
- if (_videoInfo.currentFrame == 0)
- _videoInfo.startTime = g_system->getMillis();
-
- tag = _fileStream->readUint32BE();
+Surface *DXADecoder::decodeNextFrame() {
+ uint32 tag = _fileStream->readUint32BE();
if (tag == MKID_BE('CMAP')) {
- byte rgb[768];
-
- _fileStream->read(rgb, ARRAYSIZE(rgb));
- setPalette(rgb);
+ _fileStream->read(_palette, 256 * 3);
+ _dirtyPalette = true;
}
tag = _fileStream->readUint32BE();
@@ -531,8 +517,8 @@ bool DXADecoder::decodeNextFrame() {
if (type == 3) {
for (uint32 j = 0; j < _curHeight; ++j) {
- for (uint32 i = 0; i < _videoInfo.width; ++i) {
- const int offs = j * _videoInfo.width + i;
+ for (uint32 i = 0; i < _width; ++i) {
+ const int offs = j * _width + i;
_frameBuffer1[offs] ^= _frameBuffer2[offs];
}
}
@@ -542,24 +528,34 @@ bool DXADecoder::decodeNextFrame() {
switch (_scaleMode) {
case S_INTERLACED:
for (int cy = 0; cy < _curHeight; cy++) {
- memcpy(&_scaledBuffer[2 * cy * _videoInfo.width], &_frameBuffer1[cy * _videoInfo.width], _videoInfo.width);
- memset(&_scaledBuffer[((2 * cy) + 1) * _videoInfo.width], 0, _videoInfo.width);
+ memcpy(&_scaledBuffer[2 * cy * _width], &_frameBuffer1[cy * _width], _width);
+ memset(&_scaledBuffer[((2 * cy) + 1) * _width], 0, _width);
}
- _videoFrameBuffer = _scaledBuffer;
+ _surface->pixels = _scaledBuffer;
break;
case S_DOUBLE:
for (int cy = 0; cy < _curHeight; cy++) {
- memcpy(&_scaledBuffer[2 * cy * _videoInfo.width], &_frameBuffer1[cy * _videoInfo.width], _videoInfo.width);
- memcpy(&_scaledBuffer[((2 * cy) + 1) * _videoInfo.width], &_frameBuffer1[cy * _videoInfo.width], _videoInfo.width);
+ memcpy(&_scaledBuffer[2 * cy * _width], &_frameBuffer1[cy * _width], _width);
+ memcpy(&_scaledBuffer[((2 * cy) + 1) * _width], &_frameBuffer1[cy * _width], _width);
}
- _videoFrameBuffer = _scaledBuffer;
+ _surface->pixels = _scaledBuffer;
break;
case S_NONE:
- _videoFrameBuffer = _frameBuffer1;
+ _surface->pixels = _frameBuffer1;
break;
}
- return !endOfVideo();
+ // Copy in the relevant info to the Surface
+ _surface->w = getWidth();
+ _surface->h = getHeight();
+ _surface->pitch = getWidth();
+
+ _curFrame++;
+
+ if (_curFrame == 0)
+ _startTime = g_system->getMillis();
+
+ return _surface;
}
} // End of namespace Graphics
diff --git a/graphics/video/dxa_decoder.h b/graphics/video/dxa_decoder.h
index 3edcc75ca9..0312828195 100644
--- a/graphics/video/dxa_decoder.h
+++ b/graphics/video/dxa_decoder.h
@@ -26,7 +26,7 @@
#ifndef GRAPHICS_VIDEO_DXA_PLAYER_H
#define GRAPHICS_VIDEO_DXA_PLAYER_H
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
namespace Graphics {
@@ -38,29 +38,33 @@ namespace Graphics {
* - sword1
* - sword2
*/
-class DXADecoder : public VideoDecoder {
+class DXADecoder : public FixedRateVideoDecoder {
public:
DXADecoder();
virtual ~DXADecoder();
- /**
- * Load a DXA encoded video file
- * @param filename the filename to load
- */
- bool loadFile(const char *fileName);
-
- /**
- * Close a DXA encoded video file
- */
- void closeFile();
-
- bool decodeNextFrame();
+ bool load(Common::SeekableReadStream &stream);
+ void close();
+
+ bool isVideoLoaded() const { return _fileStream != 0; }
+ uint16 getWidth() const { return _width; }
+ uint16 getHeight() const { return _height; }
+ uint32 getFrameCount() const { return _frameCount; }
+ Surface *decodeNextFrame();
+ PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
+ byte *getPalette() { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
/**
* Get the sound chunk tag of the loaded DXA file
*/
uint32 getSoundTag() { return _soundTag; }
+protected:
+ Common::Rational getFrameRate() const { return _frameRate; }
+
+ Common::SeekableReadStream *_fileStream;
+
private:
void decodeZlib(byte *data, int size, int totalSize);
void decode12(int size);
@@ -72,6 +76,10 @@ private:
S_DOUBLE
};
+ Graphics::Surface *_surface;
+ byte _palette[256 * 3];
+ bool _dirtyPalette;
+
byte *_frameBuffer1;
byte *_frameBuffer2;
byte *_scaledBuffer;
@@ -83,6 +91,9 @@ private:
uint32 _frameSize;
ScaleMode _scaleMode;
uint32 _soundTag;
+ uint16 _width, _height;
+ uint32 _frameRate;
+ uint32 _frameCount;
};
} // End of namespace Graphics
diff --git a/graphics/video/flic_decoder.cpp b/graphics/video/flic_decoder.cpp
index 14d062562f..bb5b4f219b 100644
--- a/graphics/video/flic_decoder.cpp
+++ b/graphics/video/flic_decoder.cpp
@@ -34,20 +34,17 @@ namespace Graphics {
FlicDecoder::FlicDecoder() {
_paletteChanged = false;
_fileStream = 0;
- _videoFrameBuffer = 0;
- memset(&_videoInfo, 0, sizeof(_videoInfo));
+ _surface = 0;
}
FlicDecoder::~FlicDecoder() {
- closeFile();
+ close();
}
-bool FlicDecoder::loadFile(const char *fileName) {
- closeFile();
+bool FlicDecoder::load(Common::SeekableReadStream &stream) {
+ close();
- _fileStream = SearchMan.createReadStreamForMember(fileName);
- if (!_fileStream)
- return false;
+ _fileStream = &stream;
/* uint32 frameSize = */ _fileStream->readUint32LE();
uint16 frameType = _fileStream->readUint16LE();
@@ -60,9 +57,10 @@ bool FlicDecoder::loadFile(const char *fileName) {
return false;
}
- _videoInfo.frameCount = _fileStream->readUint16LE();
- _videoInfo.width = _fileStream->readUint16LE();
- _videoInfo.height = _fileStream->readUint16LE();
+
+ _frameCount = _fileStream->readUint16LE();
+ uint16 width = _fileStream->readUint16LE();
+ uint16 height = _fileStream->readUint16LE();
uint16 colorDepth = _fileStream->readUint16LE();
if (colorDepth != 8) {
warning("FlicDecoder::FlicDecoder(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", frameType);
@@ -70,45 +68,48 @@ bool FlicDecoder::loadFile(const char *fileName) {
_fileStream = 0;
return false;
}
+
_fileStream->readUint16LE(); // flags
// Note: The normal delay is a 32-bit integer (dword), whereas the overriden delay is a 16-bit integer (word)
// frameDelay is the FLIC "speed", in milliseconds. Our frameDelay is calculated in 1/100 ms, so we convert it here
- _videoInfo.frameDelay = 100 * _fileStream->readUint32LE();
- _videoInfo.frameRate = 100 * 1000 / _videoInfo.frameDelay;
+ uint32 frameDelay = 100 * _fileStream->readUint32LE();
+ _frameRate = 100 * 1000 / frameDelay;
_fileStream->seek(80);
_offsetFrame1 = _fileStream->readUint32LE();
_offsetFrame2 = _fileStream->readUint32LE();
- _videoFrameBuffer = new byte[_videoInfo.width * _videoInfo.height];
+ _surface = new Graphics::Surface();
+ _surface->create(width, height, 1);
_palette = (byte *)malloc(3 * 256);
memset(_palette, 0, 3 * 256);
_paletteChanged = false;
// Seek to the first frame
- _videoInfo.currentFrame = -1;
_fileStream->seek(_offsetFrame1);
return true;
}
-void FlicDecoder::closeFile() {
+void FlicDecoder::close() {
if (!_fileStream)
return;
delete _fileStream;
_fileStream = 0;
- delete[] _videoFrameBuffer;
- _videoFrameBuffer = 0;
+ _surface->free();
+ delete _surface;
+ _surface = 0;
free(_palette);
-
_dirtyRects.clear();
+
+ reset();
}
void FlicDecoder::decodeByteRun(uint8 *data) {
- byte *ptr = (uint8 *)_videoFrameBuffer;
- while ((uint32)(ptr - _videoFrameBuffer) < (_videoInfo.width * _videoInfo.height)) {
+ byte *ptr = (byte *)_surface->pixels;
+ while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) {
int chunks = *data++;
while (chunks--) {
int count = (int8)*data++;
@@ -125,7 +126,7 @@ void FlicDecoder::decodeByteRun(uint8 *data) {
// Redraw
_dirtyRects.clear();
- _dirtyRects.push_back(Common::Rect(0, 0, _videoInfo.width, _videoInfo.height));
+ _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight()));
}
#define OP_PACKETCOUNT 0
@@ -152,8 +153,8 @@ void FlicDecoder::decodeDeltaFLC(uint8 *data) {
case OP_UNDEFINED:
break;
case OP_LASTPIXEL:
- _videoFrameBuffer[currentLine * _videoInfo.width + _videoInfo.width - 1] = (opcode & 0xFF);
- _dirtyRects.push_back(Common::Rect(_videoInfo.width - 1, currentLine, _videoInfo.width, currentLine + 1));
+ *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF);
+ _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1));
break;
case OP_LINESKIPCOUNT:
currentLine += -(int16)opcode;
@@ -168,14 +169,14 @@ void FlicDecoder::decodeDeltaFLC(uint8 *data) {
column += *data++;
int rleCount = (int8)*data++;
if (rleCount > 0) {
- memcpy(_videoFrameBuffer + (currentLine * _videoInfo.width) + column, data, rleCount * 2);
+ memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + column, data, rleCount * 2);
data += rleCount * 2;
_dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1));
} else if (rleCount < 0) {
rleCount = -rleCount;
uint16 dataWord = READ_UINT16(data); data += 2;
for (int i = 0; i < rleCount; ++i) {
- WRITE_UINT16(_videoFrameBuffer + currentLine * _videoInfo.width + column + i * 2, dataWord);
+ WRITE_UINT16((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord);
}
_dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1));
} else { // End of cutscene ?
@@ -194,34 +195,40 @@ void FlicDecoder::decodeDeltaFLC(uint8 *data) {
#define PSTAMP 18
#define FRAME_TYPE 0xF1FA
-bool FlicDecoder::decodeNextFrame() {
+Surface *FlicDecoder::decodeNextFrame() {
// Read chunk
uint32 frameSize = _fileStream->readUint32LE();
uint16 frameType = _fileStream->readUint16LE();
uint16 chunkCount = 0;
switch (frameType) {
- case FRAME_TYPE: {
- chunkCount = _fileStream->readUint16LE();
- // Note: The overriden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
- // frameDelay is the FLIC "speed", in milliseconds. Our frameDelay is calculated in 1/100 ms, so we convert it here
- uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds
- if (newFrameDelay > 0) {
- _videoInfo.frameDelay = 100 * newFrameDelay;
- _videoInfo.frameRate = 100 * 1000 / _videoInfo.frameDelay;
- }
- _fileStream->readUint16LE(); // reserved, always 0
- uint16 newWidth = _fileStream->readUint16LE();
- uint16 newHeight = _fileStream->readUint16LE();
- if (newWidth > 0)
- _videoInfo.width = newWidth;
- if (newHeight > 0)
- _videoInfo.height = newHeight;
-
- _videoInfo.currentFrame++;
-
- if (_videoInfo.currentFrame == 0)
- _videoInfo.startTime = g_system->getMillis();
+ case FRAME_TYPE:
+ {
+ // FIXME: FLIC should be switched over to a variable frame rate VideoDecoder to handle
+ // this properly.
+
+ chunkCount = _fileStream->readUint16LE();
+ // Note: The overriden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
+ // frameDelay is the FLIC "speed", in milliseconds. Our frameDelay is calculated in 1/100 ms, so we convert it here
+ uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds
+ if (newFrameDelay > 0)
+ _frameRate = 1000 / newFrameDelay;
+
+ _fileStream->readUint16LE(); // reserved, always 0
+ uint16 newWidth = _fileStream->readUint16LE();
+ uint16 newHeight = _fileStream->readUint16LE();
+
+ if ((newWidth != 0) && (newHeight != 0)) {
+ if (newWidth == 0)
+ newWidth = _surface->w;
+ if (newHeight == 0)
+ newHeight = _surface->h;
+
+ _surface->free();
+ delete _surface;
+ _surface = new Graphics::Surface();
+ _surface->create(newWidth, newHeight, 1);
+ }
}
break;
default:
@@ -239,7 +246,6 @@ bool FlicDecoder::decodeNextFrame() {
switch (frameType) {
case FLI_SETPAL:
unpackPalette(data);
- setPalette(_palette);
_paletteChanged = true;
break;
case FLI_SS2:
@@ -259,19 +265,25 @@ bool FlicDecoder::decodeNextFrame() {
delete[] data;
}
}
+
+ _curFrame++;
+
+ if (_curFrame == 0)
+ _startTime = g_system->getMillis();
// If we just processed the ring frame, set the next frame
- if (_videoInfo.currentFrame == (int32)_videoInfo.frameCount) {
- _videoInfo.currentFrame = 0;
+ if (_curFrame == (int32)_frameCount) {
+ _curFrame = 0;
_fileStream->seek(_offsetFrame2);
}
- return !endOfVideo();
+ return _surface;
}
void FlicDecoder::reset() {
- _videoInfo.currentFrame = -1;
- _fileStream->seek(_offsetFrame1);
+ VideoDecoder::reset();
+ if (_fileStream)
+ _fileStream->seek(_offsetFrame1);
}
void FlicDecoder::unpackPalette(uint8 *data) {
@@ -303,7 +315,7 @@ void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
for (int y = (*it).top; y < (*it).bottom; ++y) {
const int x = (*it).left;
- memcpy(dst + y * pitch + x, _videoFrameBuffer + y * _videoInfo.width + x, (*it).right - x);
+ memcpy(dst + y * pitch + x, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x);
}
}
_dirtyRects.clear();
diff --git a/graphics/video/flic_decoder.h b/graphics/video/flic_decoder.h
index b0a2b771b1..60d68889a2 100644
--- a/graphics/video/flic_decoder.h
+++ b/graphics/video/flic_decoder.h
@@ -23,10 +23,10 @@
*
*/
-#ifndef GRAPHICS_VIDEO_FlicDecoder_H
-#define GRAPHICS_VIDEO_FlicDecoder_H
+#ifndef GRAPHICS_VIDEO_FLICDECODER_H
+#define GRAPHICS_VIDEO_FLICDECODER_H
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
#include "common/list.h"
#include "common/rect.h"
@@ -42,35 +42,42 @@ namespace Graphics {
* Video decoder used in engines:
* - tucker
*/
-class FlicDecoder : public VideoDecoder {
+class FlicDecoder : public FixedRateVideoDecoder {
public:
FlicDecoder();
virtual ~FlicDecoder();
/**
- * Load a FLIC encoded video file
- * @param filename the filename to load
+ * Load a video file
+ * @param stream the stream to load
*/
- bool loadFile(const char *fileName);
+ bool load(Common::SeekableReadStream &stream);
+ void close();
/**
- * Close a FLIC encoded video file
+ * Decode the next frame and return the frame's surface
+ * @note the return surface should *not* be freed
+ * @note this may return 0, in which case the last frame should be kept on screen
*/
- void closeFile();
+ Surface *decodeNextFrame();
- /**
- * Decode the next frame
- */
- bool decodeNextFrame();
+ bool isVideoLoaded() const { return _fileStream != 0; }
+ uint16 getWidth() const { return _surface->w; }
+ uint16 getHeight() const { return _surface->h; }
+ uint32 getFrameCount() const { return _frameCount; }
+ PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; }
void clearDirtyRects() { _dirtyRects.clear(); }
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
- const byte *getPalette() { _paletteChanged = false; return _palette; }
- bool paletteChanged() { return _paletteChanged; }
+ byte *getPalette() { _paletteChanged = false; return _palette; }
+ bool hasDirtyPalette() { return _paletteChanged; }
void reset();
+protected:
+ Common::Rational getFrameRate() const { return _frameRate; }
+
private:
uint16 _offsetFrame1;
uint16 _offsetFrame2;
@@ -81,8 +88,12 @@ private:
void decodeDeltaFLC(uint8 *data);
void unpackPalette(uint8 *mem);
- Common::List<Common::Rect> _dirtyRects;
+ Common::SeekableReadStream *_fileStream;
+ Surface *_surface;
+ uint32 _frameCount;
+ uint32 _frameRate;
+ Common::List<Common::Rect> _dirtyRects;
};
} // End of namespace Graphics
diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp
index 2f796c4a65..68fac32aae 100644
--- a/graphics/video/smk_decoder.cpp
+++ b/graphics/video/smk_decoder.cpp
@@ -351,52 +351,28 @@ uint32 BigHuffmanTree::getCode(BitStream &bs) {
SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType)
: _audioStarted(false), _audioStream(0), _mixer(mixer), _soundType(soundType) {
+ _surface = 0;
+ _fileStream = 0;
+ _dirtyPalette = false;
}
SmackerDecoder::~SmackerDecoder() {
- closeFile();
+ close();
}
-int SmackerDecoder::getHeight() {
- if (!_fileStream)
- return 0;
- return (_header.flags ? 2 : 1) * _videoInfo.height;
-}
-
-int32 SmackerDecoder::getAudioLag() {
- if (!_fileStream)
- return 0;
+uint32 SmackerDecoder::getElapsedTime() const {
+ if (_audioStream)
+ return _mixer->getSoundElapsedTime(_audioHandle);
- int32 frameDelay = getFrameDelay();
- int32 videoTime = (_videoInfo.currentFrame + 1) * frameDelay;
- int32 audioTime;
-
- if (!_audioStream) {
- /* No audio.
- Calculate the lag by how much time has gone by since the first frame
- and how much time *should* have passed.
- */
-
- audioTime = (g_system->getMillis() - _videoInfo.startTime) * 100;
- } else {
- const Audio::Timestamp ts = _mixer->getElapsedTime(_audioHandle);
- audioTime = ts.convertToFramerate(100000).totalNumberOfFrames();
- }
-
- return videoTime - audioTime;
+ return VideoDecoder::getElapsedTime();
}
-bool SmackerDecoder::loadFile(const char *fileName) {
- int32 frameRate;
-
- closeFile();
+bool SmackerDecoder::load(Common::SeekableReadStream &stream) {
+ close();
- _fileStream = SearchMan.createReadStreamForMember(fileName);
- if (!_fileStream)
- return false;
+ _fileStream = &stream;
// Seek to the first frame
- _videoInfo.currentFrame = -1;
_header.signature = _fileStream->readUint32BE();
// No BINK support available
@@ -408,21 +384,17 @@ bool SmackerDecoder::loadFile(const char *fileName) {
assert(_header.signature == MKID_BE('SMK2') || _header.signature == MKID_BE('SMK4'));
- _videoInfo.width = _fileStream->readUint32LE();
- _videoInfo.height = _fileStream->readUint32LE();
- _videoInfo.frameCount = _fileStream->readUint32LE();
- frameRate = _fileStream->readSint32LE();
-
- if (frameRate > 0) {
- _videoInfo.frameRate = 1000 / frameRate;
- _videoInfo.frameDelay = frameRate * 100;
- } else if (frameRate < 0) {
- _videoInfo.frameRate = 100000 / (-frameRate);
- _videoInfo.frameDelay = -frameRate;
- } else {
- _videoInfo.frameRate = 10;
- _videoInfo.frameDelay = 10000;
- }
+ uint32 width = _fileStream->readUint32LE();
+ uint32 height = _fileStream->readUint32LE();
+ _frameCount = _fileStream->readUint32LE();
+ int32 frameRate = _fileStream->readSint32LE();
+
+ if (frameRate > 0)
+ _frameRate = 1000 / frameRate;
+ else if (frameRate < 0)
+ _frameRate = 100000 / (-frameRate);
+ else
+ _frameRate = 10;
// Flags are determined by which bit is set, which can be one of the following:
// 0 - set to 1 if file contains a ring frame.
@@ -447,7 +419,6 @@ bool SmackerDecoder::loadFile(const char *fileName) {
_header.fullSize = _fileStream->readUint32LE();
_header.typeSize = _fileStream->readUint32LE();
- uint32 audioInfo;
for (i = 0; i < 7; ++i) {
// AudioRate - Frequency and format information for each sound track, up to 7 audio tracks.
// The 32 constituent bits have the following meaning:
@@ -458,7 +429,7 @@ bool SmackerDecoder::loadFile(const char *fileName) {
// * bits 27-26 - if both set to zero - use v2 sound decompression
// * bits 25-24 - unused
// * bits 23-0 - audio sample rate
- audioInfo = _fileStream->readUint32LE();
+ uint32 audioInfo = _fileStream->readUint32LE();
_header.audioInfo[i].isCompressed = audioInfo & 0x80000000;
_header.audioInfo[i].hasAudio = audioInfo & 0x40000000;
_header.audioInfo[i].is16Bits = audioInfo & 0x20000000;
@@ -467,19 +438,18 @@ bool SmackerDecoder::loadFile(const char *fileName) {
!(audioInfo & 0x4000000);
_header.audioInfo[i].sampleRate = audioInfo & 0xFFFFFF;
- if (_header.audioInfo[i].hasAudio && i == 0) {
+ if (_header.audioInfo[i].hasAudio && i == 0)
_audioStream = Audio::makeQueuingAudioStream(_header.audioInfo[0].sampleRate, _header.audioInfo[0].isStereo);
- }
}
_header.dummy = _fileStream->readUint32LE();
- _frameSizes = (uint32 *)malloc(_videoInfo.frameCount * sizeof(uint32));
- for (i = 0; i < _videoInfo.frameCount; ++i)
+ _frameSizes = new uint32[_frameCount];
+ for (i = 0; i < _frameCount; ++i)
_frameSizes[i] = _fileStream->readUint32LE();
- _frameTypes = (byte *)malloc(_videoInfo.frameCount);
- for (i = 0; i < _videoInfo.frameCount; ++i)
+ _frameTypes = new byte[_frameCount];
+ for (i = 0; i < _frameCount; ++i)
_frameTypes[i] = _fileStream->readByte();
byte *huffmanTrees = new byte[_header.treesSize];
@@ -494,17 +464,17 @@ bool SmackerDecoder::loadFile(const char *fileName) {
delete[] huffmanTrees;
- _videoFrameBuffer = (byte *)malloc(2 * _videoInfo.width * _videoInfo.height);
- memset(_videoFrameBuffer, 0, 2 * _videoInfo.width * _videoInfo.height);
- _palette = (byte *)malloc(3 * 256);
- memset(_palette, 0, 3 * 256);
+ _surface = new Graphics::Surface();
- _videoInfo.firstframeOffset = _fileStream->pos();
+ // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled)
+ _surface->create(width, height * (_header.flags ? 2 : 1), 1);
+ _palette = (byte *)malloc(3 * 256);
+ memset(_palette, 0, 3 * 256);
return true;
}
-void SmackerDecoder::closeFile() {
+void SmackerDecoder::close() {
if (!_fileStream)
return;
@@ -517,40 +487,42 @@ void SmackerDecoder::closeFile() {
delete _fileStream;
_fileStream = 0;
+ _surface->free();
+ delete _surface;
+ _surface = 0;
+
delete _MMapTree;
delete _MClrTree;
delete _FullTree;
delete _TypeTree;
- free(_frameSizes);
- free(_frameTypes);
- free(_videoFrameBuffer);
+ delete[] _frameSizes;
+ delete[] _frameTypes;
free(_palette);
+
+ reset();
}
-bool SmackerDecoder::decodeNextFrame() {
+Surface *SmackerDecoder::decodeNextFrame() {
uint i;
uint32 chunkSize = 0;
uint32 dataSizeUnpacked = 0;
uint32 startPos = _fileStream->pos();
- _videoInfo.currentFrame++;
-
- if (_videoInfo.currentFrame == 0)
- _videoInfo.startTime = g_system->getMillis();
+ _curFrame++;
// Check if we got a frame with palette data, and
// call back the virtual setPalette function to set
// the current palette
- if (_frameTypes[_videoInfo.currentFrame] & 1) {
+ if (_frameTypes[_curFrame] & 1) {
unpackPalette();
- setPalette(_palette);
+ _dirtyPalette = true;
}
// Load audio tracks
for (i = 0; i < 7; ++i) {
- if (!(_frameTypes[_videoInfo.currentFrame] & (2 << i)))
+ if (!(_frameTypes[_curFrame] & (2 << i)))
continue;
chunkSize = _fileStream->readUint32LE();
@@ -598,10 +570,10 @@ bool SmackerDecoder::decodeNextFrame() {
}
}
- uint32 frameSize = _frameSizes[_videoInfo.currentFrame] & ~3;
+ uint32 frameSize = _frameSizes[_curFrame] & ~3;
if (_fileStream->pos() - startPos > frameSize)
- exit(1);
+ error("Smacker actual frame size exceeds recorded frame size");
uint32 frameDataSize = frameSize - (_fileStream->pos() - startPos);
@@ -615,13 +587,14 @@ bool SmackerDecoder::decodeNextFrame() {
_FullTree->reset();
_TypeTree->reset();
- uint bw = _videoInfo.width / 4;
- uint bh = _videoInfo.height / 4;
- uint stride = _videoInfo.width;
- uint block = 0, blocks = bw*bh;
-
+ // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled)
uint doubleY = _header.flags ? 2 : 1;
+ uint bw = getWidth() / 4;
+ uint bh = getHeight() / doubleY / 4;
+ uint stride = getWidth();
+ uint block = 0, blocks = bw*bh;
+
byte *out;
uint type, run, j, mode;
uint32 p1, p2, clr, map;
@@ -636,7 +609,7 @@ bool SmackerDecoder::decodeNextFrame() {
while (run-- && block < blocks) {
clr = _MClrTree->getCode(bs);
map = _MMapTree->getCode(bs);
- out = _videoFrameBuffer + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
+ out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
hi = clr >> 8;
lo = clr & 0xff;
for (i = 0; i < 4; i++) {
@@ -669,7 +642,7 @@ bool SmackerDecoder::decodeNextFrame() {
}
while (run-- && block < blocks) {
- out = _videoFrameBuffer + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
+ out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
switch (mode) {
case 0:
for (i = 0; i < 4; ++i) {
@@ -735,7 +708,7 @@ bool SmackerDecoder::decodeNextFrame() {
uint32 col;
mode = type >> 8;
while (run-- && block < blocks) {
- out = _videoFrameBuffer + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
+ out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
col = mode * 0x01010101;
for (i = 0; i < 4 * doubleY; ++i) {
out[0] = out[1] = out[2] = out[3] = col;
@@ -751,7 +724,10 @@ bool SmackerDecoder::decodeNextFrame() {
free(_frameData);
- return !endOfVideo();
+ if (_curFrame == 0)
+ _startTime = g_system->getMillis();
+
+ return _surface;
}
void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
@@ -806,15 +782,12 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
// If the sample is stereo, the data is stored for the left and right channel, respectively
// (the exact opposite to the base values)
if (!is16Bits) {
-
for (int k = 0; k < (isStereo ? 2 : 1); k++) {
bases[k] += (int8) ((int16) audioTrees[k]->getCode(audioBS));
*curPointer++ = CLIP<int>(bases[k], 0, 255) ^ 0x80;
curPos++;
}
-
} else {
-
for (int k = 0; k < (isStereo ? 2 : 1); k++) {
bases[k] += (int16) (audioTrees[k * 2]->getCode(audioBS) |
(audioTrees[k * 2 + 1]->getCode(audioBS) << 8));
@@ -887,7 +860,6 @@ void SmackerDecoder::unpackPalette() {
}
_fileStream->seek(startPos + len);
-
free(chunk);
}
diff --git a/graphics/video/smk_decoder.h b/graphics/video/smk_decoder.h
index 443d063138..437f47f2d6 100644
--- a/graphics/video/smk_decoder.h
+++ b/graphics/video/smk_decoder.h
@@ -26,7 +26,7 @@
#ifndef GRAPHICS_VIDEO_SMK_PLAYER_H
#define GRAPHICS_VIDEO_SMK_PLAYER_H
-#include "graphics/video/video_player.h"
+#include "graphics/video/video_decoder.h"
#include "sound/mixer.h"
namespace Audio {
@@ -51,27 +51,28 @@ class BigHuffmanTree;
* - sword1
* - sword2
*/
-class SmackerDecoder : public VideoDecoder {
+class SmackerDecoder : public FixedRateVideoDecoder {
public:
SmackerDecoder(Audio::Mixer *mixer,
Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType);
virtual ~SmackerDecoder();
- int getHeight();
- int32 getAudioLag();
+ bool load(Common::SeekableReadStream &stream);
+ void close();
- /**
- * Load an SMK encoded video file
- * @param filename the filename to load
- */
- bool loadFile(const char *filename);
+ bool isVideoLoaded() const { return _fileStream != 0; }
+ uint16 getWidth() const { return _surface->w; }
+ uint16 getHeight() const { return _surface->h; }
+ uint32 getFrameCount() const { return _frameCount; }
+ uint32 getElapsedTime() const;
+ Surface *decodeNextFrame();
+ PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
+ byte *getPalette() { _dirtyPalette = false; return _palette; }
+ bool hasDirtyPalette() const { return _dirtyPalette; }
- /**
- * Close an SMK encoded video file
- */
- void closeFile();
-
- bool decodeNextFrame();
+protected:
+ Common::Rational getFrameRate() const { return _frameRate; }
+ Common::SeekableReadStream *_fileStream;
private:
void unpackPalette();
@@ -111,6 +112,11 @@ private:
byte *_frameData;
// The RGB palette
byte *_palette;
+ bool _dirtyPalette;
+
+ uint32 _frameRate;
+ uint32 _frameCount;
+ Surface *_surface;
Audio::Mixer::SoundType _soundType;
Audio::Mixer *_mixer;
diff --git a/graphics/video/video_decoder.cpp b/graphics/video/video_decoder.cpp
new file mode 100644
index 0000000000..a3f63921a8
--- /dev/null
+++ b/graphics/video/video_decoder.cpp
@@ -0,0 +1,101 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "graphics/video/video_decoder.h"
+
+#include "common/file.h"
+#include "common/system.h"
+
+namespace Graphics {
+
+VideoDecoder::VideoDecoder() {
+ reset();
+}
+
+bool VideoDecoder::loadFile(const Common::String &filename) {
+ Common::File *file = new Common::File();
+
+ if (!file->open(filename)) {
+ delete file;
+ return false;
+ }
+
+ return load(*file);
+}
+
+uint32 VideoDecoder::getElapsedTime() const {
+ return g_system->getMillis() - _startTime;
+}
+
+void VideoDecoder::setSystemPalette() {
+ byte *vidPalette = getPalette();
+ byte *sysPalette = new byte[256 * 4];
+
+ for (uint16 i = 0; i < 256; i++) {
+ sysPalette[i * 4] = vidPalette[i * 3];
+ sysPalette[i * 4 + 1] = vidPalette[i * 3 + 1];
+ sysPalette[i * 4 + 2] = vidPalette[i * 3 + 2];
+ sysPalette[i * 4 + 3] = 0;
+ }
+
+ g_system->setPalette(sysPalette, 0, 256);
+ delete[] sysPalette;
+}
+
+bool VideoDecoder::needsUpdate() const {
+ return !endOfVideo() && getTimeToNextFrame() == 0;
+}
+
+void VideoDecoder::reset() {
+ _curFrame = -1;
+ _startTime = 0;
+}
+
+bool VideoDecoder::endOfVideo() const {
+ return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1);
+}
+
+uint32 FixedRateVideoDecoder::getTimeToNextFrame() const {
+ if (endOfVideo() || _curFrame < 0)
+ return 0;
+
+ uint32 elapsedTime = getElapsedTime();
+ uint32 nextFrameStartTime = getFrameBeginTime(_curFrame + 1);
+
+ // If the time that the next frame should be shown has past
+ // the frame should be shown ASAP.
+ if (nextFrameStartTime <= elapsedTime)
+ return 0;
+
+ return nextFrameStartTime - elapsedTime;
+}
+
+uint32 FixedRateVideoDecoder::getFrameBeginTime(uint32 frame) const {
+ Common::Rational beginTime = frame * 1000;
+ beginTime /= getFrameRate();
+ return beginTime.toInt();
+}
+
+} // End of namespace Graphics
diff --git a/graphics/video/video_decoder.h b/graphics/video/video_decoder.h
new file mode 100644
index 0000000000..62aa496148
--- /dev/null
+++ b/graphics/video/video_decoder.h
@@ -0,0 +1,184 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef GRAPHICS_VIDEO_PLAYER_H
+#define GRAPHICS_VIDEO_PLAYER_H
+
+#include "common/events.h"
+#include "common/list.h"
+#include "common/rational.h"
+#include "common/stream.h"
+
+#include "graphics/surface.h"
+#include "graphics/pixelformat.h"
+
+namespace Common {
+ class SeekableReadStream;
+}
+
+namespace Graphics {
+
+/**
+ * Implementation of a generic video decoder
+ */
+class VideoDecoder {
+public:
+ VideoDecoder();
+ virtual ~VideoDecoder() {}
+
+ /**
+ * Returns the width of the video
+ * @return the width of the video
+ */
+ virtual uint16 getWidth() const = 0;
+
+ /**
+ * Returns the height of the video
+ * @return the height of the video
+ */
+ virtual uint16 getHeight() const = 0;
+
+ /**
+ * Returns the current frame number of the video
+ * @return the last frame decoded by the video
+ */
+ virtual int32 getCurFrame() const { return _curFrame; }
+
+ /**
+ * Returns the amount of frames in the video
+ * @return the amount of frames in the video
+ */
+ virtual uint32 getFrameCount() const = 0;
+
+ /**
+ * Returns the time (in ms) that the video has been running
+ */
+ virtual uint32 getElapsedTime() const;
+
+ /**
+ * Returns whether a frame should be decoded or not
+ * @return whether a frame should be decoded or not
+ */
+ virtual bool needsUpdate() const;
+
+ /**
+ * Load a video file
+ * @param filename the filename to load
+ */
+ virtual bool loadFile(const Common::String &filename);
+
+ /**
+ * Load a video file
+ * @param stream the stream to load
+ */
+ virtual bool load(Common::SeekableReadStream &stream) = 0;
+
+ /**
+ * Close a video file
+ */
+ virtual void close() = 0;
+
+ /**
+ * Returns if a video file is loaded or not
+ */
+ virtual bool isVideoLoaded() const = 0;
+
+ /**
+ * Decode the next frame and return the frame's surface
+ * @note the return surface should *not* be freed
+ * @note this may return 0, in which case the last frame should be kept on screen
+ */
+ virtual Surface *decodeNextFrame() = 0;
+
+ /**
+ * Get the pixel format of the video
+ */
+ virtual PixelFormat getPixelFormat() const = 0;
+
+ /**
+ * Get the palette for the video in RGB format (if 8bpp or less)
+ */
+ virtual byte *getPalette() { return 0; }
+
+ /**
+ * Returns if the palette is dirty or not
+ */
+ virtual bool hasDirtyPalette() const { return false; }
+
+ /**
+ * Add the time the video has been paused to maintain sync
+ */
+ virtual void addPauseTime(uint32 ms) { _startTime += ms; }
+
+ /**
+ * Returns if the video is finished or not
+ */
+ virtual bool endOfVideo() const;
+
+ /**
+ * Set the current palette to the system palette
+ */
+ void setSystemPalette();
+
+ /**
+ * Return the time until the next frame (in ms)
+ */
+ virtual uint32 getTimeToNextFrame() const = 0;
+
+protected:
+ /**
+ * Resets _curFrame and _startTime. Should be called from every close() function.
+ */
+ void reset();
+
+ int32 _curFrame;
+ uint32 _startTime;
+};
+
+/**
+ * A VideoDecoder wrapper that implements getTimeToNextFrame() based on getFrameRate().
+ */
+class FixedRateVideoDecoder : public VideoDecoder {
+public:
+ FixedRateVideoDecoder() {}
+ virtual ~FixedRateVideoDecoder() {}
+
+ uint32 getTimeToNextFrame() const;
+
+protected:
+ /**
+ * Return the frame rate in frames per second
+ * This returns a Rational because videos can have rates that are not integers and
+ * there are some videos with frame rates < 1.
+ */
+ virtual Common::Rational getFrameRate() const = 0;
+
+private:
+ uint32 getFrameBeginTime(uint32 frame) const;
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/video/video_player.cpp b/graphics/video/video_player.cpp
deleted file mode 100644
index a8676ed594..0000000000
--- a/graphics/video/video_player.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "common/archive.h"
-#include "common/debug.h"
-#include "common/events.h"
-#include "common/system.h"
-#include "common/util.h"
-#include "common/array.h"
-#include "common/endian.h"
-
-#include "graphics/video/video_player.h"
-#include "graphics/surface.h"
-
-namespace Graphics {
-
-VideoDecoder::VideoDecoder() : _fileStream(0) {
- _curFrameBlack = 0;
- _curFrameWhite = 255;
- _videoInfo.currentFrame = -1;
-}
-
-VideoDecoder::~VideoDecoder() {
-}
-
-int VideoDecoder::getWidth() {
- if (!_fileStream)
- return 0;
- return _videoInfo.width;
-}
-
-int VideoDecoder::getHeight() {
- if (!_fileStream)
- return 0;
- return _videoInfo.height;
-}
-
-int32 VideoDecoder::getCurFrame() const {
- return _videoInfo.currentFrame;
-}
-
-int32 VideoDecoder::getFrameCount() const {
- if (!_fileStream)
- return 0;
- return _videoInfo.frameCount;
-}
-
-int32 VideoDecoder::getFrameRate() {
- if (!_fileStream)
- return 0;
- return _videoInfo.frameRate;
-}
-
-int32 VideoDecoder::getFrameDelay() {
- if (!_fileStream)
- return 0;
- return _videoInfo.frameDelay;
-}
-
-int32 VideoDecoder::getAudioLag() {
- if (!_fileStream)
- return 0;
-
- /* No audio.
- Calculate the lag by how much time has gone by since the first frame
- and how much time *should* have passed.
- */
- int32 audioTime = (g_system->getMillis() - _videoInfo.startTime) * 100;
- int32 videoTime = _videoInfo.currentFrame * getFrameDelay();
-
- return videoTime - audioTime;
-}
-
-uint32 VideoDecoder::getFrameWaitTime() {
- int32 waitTime = (getFrameDelay() + getAudioLag()) / 100;
-
- if (waitTime < 0)
- return 0;
-
- return waitTime;
-}
-
-void VideoDecoder::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) {
- uint h = getHeight();
- uint w = getWidth();
-
- byte *src = _videoFrameBuffer;
- dst += y * pitch + x;
-
- do {
- memcpy(dst, src, w);
- dst += pitch;
- src += w;
- } while (--h);
-}
-
-void VideoDecoder::setPalette(byte *pal) {
- byte videoPalette[256 * 4];
-
- uint32 maxWeight = 0;
- uint32 minWeight = 0xFFFFFFFF;
- uint32 weight = 0;
- byte r, g, b;
-
- for (int i = 0; i < 256; i++) {
- videoPalette[i * 4 + 0] = *pal++;
- videoPalette[i * 4 + 1] = *pal++;
- videoPalette[i * 4 + 2] = *pal++;
- videoPalette[i * 4 + 3] = 0;
-
- // Try and find the white and black colors for the current palette
- r = videoPalette[i * 4 + 0];
- g = videoPalette[i * 4 + 1];
- b = videoPalette[i * 4 + 2];
-
- weight = 3 * r * r + 6 * g * g + 2 * b * b;
-
- if (weight >= maxWeight) {
- _curFrameWhite = i;
- maxWeight = weight;
- }
-
- if (weight <= minWeight) {
- _curFrameBlack = i;
- minWeight = i;
- }
- }
-
- g_system->setPalette(videoPalette, 0, 256);
-}
-
-bool VideoDecoder::endOfVideo() const {
- return !isVideoLoaded() || getCurFrame() >= (int32)getFrameCount() - 1;
-}
-
-
-/*
- * VideoPlayer
- */
-
-void VideoPlayer::processVideoEvents(Common::List<Common::Event> &stopEvents) {
- Common::Event curEvent;
- Common::EventManager *eventMan = g_system->getEventManager();
-
- // Process events, and skip video if esc is pressed
- while (eventMan->pollEvent(curEvent)) {
- if (curEvent.type == Common::EVENT_RTL || curEvent.type == Common::EVENT_QUIT) {
- _skipVideo = true;
- }
-
- for (Common::List<Common::Event>::const_iterator iter = stopEvents.begin(); iter != stopEvents.end(); ++iter) {
- if (curEvent.type == iter->type) {
- if (iter->type == Common::EVENT_KEYDOWN || iter->type == Common::EVENT_KEYUP) {
- if (curEvent.kbd.keycode == iter->kbd.keycode) {
- _skipVideo = true;
- break;
- }
- } else {
- _skipVideo = true;
- break;
- }
- }
- }
- }
-}
-
-bool VideoPlayer::playVideo(Common::List<Common::Event> &stopEvents) {
- _skipVideo = false;
- debug(0, "Playing video");
-
- g_system->fillScreen(0);
-
- int frameX = (g_system->getWidth() - _decoder->getWidth()) / 2;
- int frameY = (g_system->getHeight() - _decoder->getHeight()) / 2;
-
- while (!_decoder->endOfVideo() && !_skipVideo) {
- processVideoEvents(stopEvents);
-
- uint32 startTime = 0;
- _decoder->decodeNextFrame();
-
- Graphics::Surface *screen = g_system->lockScreen();
- _decoder->copyFrameToBuffer((byte *)screen->pixels, frameX, frameY, g_system->getWidth());
- performPostProcessing((byte *)screen->pixels);
- g_system->unlockScreen();
-
- uint32 waitTime = _decoder->getFrameWaitTime();
-
- if (!waitTime) {
- warning("dropped frame %i", _decoder->getCurFrame());
- continue;
- }
-
- // Update the screen
- g_system->updateScreen();
-
- startTime = g_system->getMillis();
-
- // Wait before showing the next frame
- while (g_system->getMillis() < startTime + waitTime && !_skipVideo) {
- processVideoEvents(stopEvents);
- g_system->delayMillis(10);
- }
- }
-
- return !_skipVideo;
-}
-
-bool VideoPlayer::playVideo() {
- Common::Event stopEvent;
- Common::List<Common::Event> stopEvents;
- stopEvents.clear();
- stopEvent.type = Common::EVENT_KEYDOWN;
- stopEvent.kbd = Common::KEYCODE_ESCAPE;
- stopEvents.push_back(stopEvent);
-
- return playVideo(stopEvents);
-}
-
-void VideoPlayer::performPostProcessing(byte *screen) {
-}
-
-} // End of namespace Graphics
diff --git a/graphics/video/video_player.h b/graphics/video/video_player.h
deleted file mode 100644
index 4f38bd9740..0000000000
--- a/graphics/video/video_player.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/* 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef GRAPHICS_VIDEO_PLAYER_H
-#define GRAPHICS_VIDEO_PLAYER_H
-
-#include "common/events.h"
-#include "common/list.h"
-#include "common/stream.h"
-
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Graphics {
-
-/**
- * Implementation of a generic video decoder
- */
-class VideoDecoder {
-public:
- VideoDecoder();
- virtual ~VideoDecoder();
-
- /**
- * Returns the width of the video
- * @return the width of the video
- */
- virtual int getWidth();
-
- /**
- * Returns the height of the video
- * @return the height of the video
- */
- virtual int getHeight();
-
- /**
- * Returns the current frame number of the video
- * @return the current frame number of the video
- */
- virtual int32 getCurFrame() const;
-
- /**
- * Returns the amount of frames in the video
- * @return the amount of frames in the video
- */
- virtual int32 getFrameCount() const;
-
- /**
- * Returns the frame rate of the video
- * @return the frame rate of the video
- */
- virtual int32 getFrameRate();
-
- /**
- * Returns the time to wait for each frame in 1/100 ms (to avoid rounding errors)
- * @return the time to wait for each frame in 1/100 ms (to avoid rounding errors)
- */
- virtual int32 getFrameDelay();
-
- /**
- * Returns the current A/V lag in 1/100 ms (to avoid rounding errors)
- * If > 0, audio lags behind
- * If < 0, video lags behind
- * @return the current A/V lag in 1/100 ms (to avoid rounding errors)
- */
- virtual int32 getAudioLag();
-
- /**
- * Returns the time to wait until the next frame in ms, minding any lag
- * @return the time to wait until the next frame in ms
- */
- virtual uint32 getFrameWaitTime();
-
- /**
- * Load a video file
- * @param filename the filename to load
- */
- virtual bool loadFile(const char *filename) = 0;
-
- /**
- * Close a video file
- */
- virtual void closeFile() = 0;
-
- /**
- * Returns if a video file is loaded or not
- */
- bool isVideoLoaded() const { return (_fileStream != NULL); }
-
- /**
- * Set RGB palette, based on current frame
- * @param pal the RGB palette data
- */
- virtual void setPalette(byte *pal);
-
- /**
- * Gets the value of the pixel at the specified x and y coordinates
- * Note: This method assumes that the video's pitch equals its width, and that
- * the video has an 8bpp palette
- * @param x the x coordinate of the pixel
- * @param y the y coordinate of the pixel
- */
- byte getPixel(int x, int y) {
- return *(_videoFrameBuffer + y * _videoInfo.width + x * 1);
- }
-
- /**
- * Gets the value of the pixel at the specified offset
- * @param offset the offset of the pixel in the video buffer
- */
- byte getPixel(int offset) { return getPixel(offset, 0); }
-
- /**
- * Return the black palette color for the current frame
- */
- byte getBlack() { return _curFrameBlack; }
-
- /**
- * Return the white palette color for the current frame
- */
- byte getWhite() { return _curFrameWhite; }
-
- /**
- * Copy current frame into the specified position of the destination
- * buffer.
- * @param dst the buffer
- * @param x the x position of the buffer
- * @param y the y position of the buffer
- * @param pitch the pitch of buffer
- */
- void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch);
-
- /**
- * Decode the next frame to _videoFrameBuffer
- */
- virtual bool decodeNextFrame() = 0;
-
- /**
- * Returns if the video is finished or not
- */
- virtual bool endOfVideo() const;
-
-protected:
- struct {
- uint32 width;
- uint32 height;
- uint32 frameCount;
- int32 frameRate;
- int32 frameDelay; // 1/100 ms (to avoid rounding errors)
- uint32 firstframeOffset;
- int32 currentFrame;
- uint32 startTime;
- } _videoInfo;
-
- byte _curFrameBlack, _curFrameWhite;
-
- Common::SeekableReadStream *_fileStream;
- byte *_videoFrameBuffer;
-};
-
-class VideoPlayer {
-public:
- VideoPlayer(VideoDecoder* decoder) : _skipVideo(false), _decoder(decoder)
- { }
- virtual ~VideoPlayer() { }
- /**
- * A default implementation of a video player
- * Plays a non-interactive full screen video till it's stopped by a
- * specific event
- * @param filename the name of the file to play
- * @param stopEvents a list of events that can stop the video
- *
- * Returns true if the video was played to the end, false if skipped
- */
- bool playVideo(Common::List<Common::Event> &stopEvents);
-
- /**
- * Provides the same functionality as the video player, and it adds the
- * event of skipping the video with the escape key by default
- */
- bool playVideo();
-
-protected:
- /**
- * Perform postprocessing once the frame data is copied to the screen,
- * right before the frame is drawn. Called by playVideo()
- */
- virtual void performPostProcessing(byte *screen);
-
- bool _skipVideo;
- VideoDecoder* _decoder;
-
- void processVideoEvents(Common::List<Common::Event> &stopEvents);
-};
-
-} // End of namespace Graphics
-
-#endif