Committing the rest of the VideoDecoder Rewrite from patch #2963496.
svn-id: r49079
This commit is contained in:
parent
f3892a506b
commit
11cbdd0318
41 changed files with 1107 additions and 1214 deletions
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
~JPEGDecoder();
|
||||
|
||||
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
|
||||
Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
|
||||
|
||||
private:
|
||||
Graphics::PixelFormat _pixelFormat;
|
||||
|
|
|
@ -65,6 +65,7 @@ public:
|
|||
~CinepakDecoder();
|
||||
|
||||
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
|
||||
Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
|
||||
|
||||
private:
|
||||
CinepakFrame _curFrame;
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
~QTRLEDecoder();
|
||||
|
||||
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
|
||||
Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
|
||||
|
||||
private:
|
||||
byte _bitsPerPixel;
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
~RPZADecoder() { delete _surface; }
|
||||
|
||||
Graphics::Surface *decodeImage(Common::SeekableReadStream *stream);
|
||||
Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; }
|
||||
|
||||
private:
|
||||
Graphics::Surface *_surface;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -424,6 +424,7 @@ class Scene {
|
|||
int DinoStartProc();
|
||||
int FTA2StartProc();
|
||||
int FTA2EndProc(FTA2Endings whichEnding);
|
||||
void playMovie(const char *filename);
|
||||
|
||||
void IHNMLoadCutaways();
|
||||
bool checkKey();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
close();
|
||||
}
|
||||
|
||||
uint32 VMDDecoder::getFrameWaitTime() {
|
||||
return _vmdDecoder->getFrameWaitTime();
|
||||
}
|
||||
bool VMDDecoder::load(Common::SeekableReadStream &stream) {
|
||||
close();
|
||||
|
||||
bool VMDDecoder::loadFile(const char *fileName) {
|
||||
closeFile();
|
||||
|
||||
_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;
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
_surface = 0;
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
bool VMDDecoder::decodeNextFrame() {
|
||||
_videoInfo.currentFrame++;
|
||||
|
||||
if (_videoInfo.currentFrame == 0)
|
||||
_videoInfo.startTime = g_system->getMillis();
|
||||
|
||||
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();
|
||||
|
||||
return !endOfVideo();
|
||||
if (_curFrame == -1)
|
||||
_startTime = g_system->getMillis();
|
||||
|
||||
_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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2254,7 +2254,7 @@ void ScummEngine_v100he::o100_videoOps() {
|
|||
}
|
||||
} else if (_videoParams.status == 19) {
|
||||
// Stop video
|
||||
_moviePlay->closeFile();
|
||||
_moviePlay->close();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -1437,7 +1437,7 @@ void ScummEngine_v90he::o90_videoOps() {
|
|||
}
|
||||
} else if (_videoParams.status == 165) {
|
||||
// Stop video
|
||||
_moviePlay->closeFile();
|
||||
_moviePlay->close();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -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) {
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
byte MoviePlayer::findBlackPalIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte MoviePlayer::findWhitePalIndex() {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
|
||||
: _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
|
||||
}
|
||||
|
||||
int32 DXADecoderWithSound::getAudioLag() {
|
||||
if (!_fileStream)
|
||||
return 0;
|
||||
uint32 DXADecoderWithSound::getElapsedTime() const {
|
||||
if (_mixer->isSoundHandleActive(*_bgSoundHandle))
|
||||
return _mixer->getSoundElapsedTime(*_bgSoundHandle);
|
||||
|
||||
if (!_mixer->isSoundHandleActive(*_bgSoundHandle))
|
||||
return 0;
|
||||
|
||||
int32 frameDelay = getFrameDelay();
|
||||
int32 videoTime = (_videoInfo.currentFrame + 1) * frameDelay;
|
||||
int32 audioTime;
|
||||
|
||||
const Audio::Timestamp ts = _mixer->getElapsedTime(*_bgSoundHandle);
|
||||
audioTime = ts.convertToFramerate(100000).totalNumberOfFrames();
|
||||
|
||||
return videoTime - audioTime;
|
||||
return VideoDecoder::getElapsedTime();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
byte MoviePlayer::findBlackPalIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte MoviePlayer::findWhitePalIndex() {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle)
|
||||
: _mixer(mixer), _bgSoundHandle(bgSoundHandle) {
|
||||
}
|
||||
|
||||
int32 DXADecoderWithSound::getAudioLag() {
|
||||
if (!_fileStream)
|
||||
return 0;
|
||||
uint32 DXADecoderWithSound::getElapsedTime() const {
|
||||
if (_mixer->isSoundHandleActive(*_bgSoundHandle))
|
||||
return _mixer->getSoundElapsedTime(*_bgSoundHandle);
|
||||
|
||||
if (!_mixer->isSoundHandleActive(*_bgSoundHandle))
|
||||
return 0;
|
||||
|
||||
int32 frameDelay = getFrameDelay();
|
||||
int32 videoTime = _videoInfo.currentFrame * frameDelay;
|
||||
int32 audioTime;
|
||||
|
||||
const Audio::Timestamp ts = _mixer->getElapsedTime(*_bgSoundHandle);
|
||||
audioTime = ts.convertToFramerate(100000).totalNumberOfFrames();
|
||||
|
||||
return videoTime - audioTime;
|
||||
return VideoDecoder::getElapsedTime();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
~MSRLEDecoder();
|
||||
|
||||
Surface *decodeImage(Common::SeekableReadStream *stream);
|
||||
PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
|
||||
|
||||
private:
|
||||
byte _bitsPerPixel;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
~MSVideo1Decoder();
|
||||
|
||||
Surface *decodeImage(Common::SeekableReadStream *stream);
|
||||
PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
|
||||
|
||||
private:
|
||||
byte _bitsPerPixel;
|
||||
|
|
|
@ -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();
|
||||
_frameCount = _fileStream->readUint16BE();
|
||||
int32 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;
|
||||
}
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
case FRAME_TYPE:
|
||||
{
|
||||
// FIXME: FLIC should be switched over to a variable frame rate VideoDecoder to handle
|
||||
// this properly.
|
||||
|
||||
_videoInfo.currentFrame++;
|
||||
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;
|
||||
|
||||
if (_videoInfo.currentFrame == 0)
|
||||
_videoInfo.startTime = g_system->getMillis();
|
||||
_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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
uint32 SmackerDecoder::getElapsedTime() const {
|
||||
if (_audioStream)
|
||||
return _mixer->getSoundElapsedTime(_audioHandle);
|
||||
|
||||
return VideoDecoder::getElapsedTime();
|
||||
}
|
||||
|
||||
int32 SmackerDecoder::getAudioLag() {
|
||||
if (!_fileStream)
|
||||
return 0;
|
||||
bool SmackerDecoder::load(Common::SeekableReadStream &stream) {
|
||||
close();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool SmackerDecoder::loadFile(const char *fileName) {
|
||||
int32 frameRate;
|
||||
|
||||
closeFile();
|
||||
|
||||
_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();
|
||||
uint32 width = _fileStream->readUint32LE();
|
||||
uint32 height = _fileStream->readUint32LE();
|
||||
_frameCount = _fileStream->readUint32LE();
|
||||
int32 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;
|
||||
}
|
||||
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);
|
||||
_surface = new Graphics::Surface();
|
||||
|
||||
// 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);
|
||||
|
||||
_videoInfo.firstframeOffset = _fileStream->pos();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
101
graphics/video/video_decoder.cpp
Normal file
101
graphics/video/video_decoder.cpp
Normal file
|
@ -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
|
184
graphics/video/video_decoder.h
Normal file
184
graphics/video/video_decoder.h
Normal file
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue