From 2772a7aaf13b83f8bdb5c27bd0b519127950de20 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Wed, 7 Jan 2009 21:19:00 +0000 Subject: Further merging of the SMK and DXA players (the FLIC player is not done yet): - Added a new class, VideoPlayer(), from which both the SMK and the DXA player inherit. This class provides generic functions and public methods for the inherited video classes. Default implementations have been made for these public methods, and the virtual ones can be overriden in inherited classes - There is now a default implementation of the function that sets the video palette - A basic video player for inherited classes has been added with method playVideo(). This is able to play a fullscreen non-interactive video, which can be skipped with events set by the caller. Postprocessing methods, which draw upon each frame (e.g. subtitles) can be done by implementing performPostProcessing() - The FTA2 movie player now uses the new playVideo() method - The new video player code is compatible with the old one (i.e. no changes to the existing engine code are necessary), but it's now possible to reduce engine code for video playing considerably svn-id: r35772 --- engines/saga/introproc_fta2.cpp | 119 ++++------------------ graphics/module.mk | 3 +- graphics/video/dxa_player.cpp | 186 +++++++++++++--------------------- graphics/video/dxa_player.h | 89 ++--------------- graphics/video/smk_player.cpp | 128 +++++++----------------- graphics/video/smk_player.h | 90 +---------------- graphics/video/video_player.cpp | 216 ++++++++++++++++++++++++++++++++++++++++ graphics/video/video_player.h | 170 +++++++++++++++++++++++++++++++ 8 files changed, 528 insertions(+), 473 deletions(-) create mode 100644 graphics/video/video_player.cpp create mode 100644 graphics/video/video_player.h diff --git a/engines/saga/introproc_fta2.cpp b/engines/saga/introproc_fta2.cpp index 72d824d610..8d2e73b7a6 100644 --- a/engines/saga/introproc_fta2.cpp +++ b/engines/saga/introproc_fta2.cpp @@ -37,110 +37,24 @@ #include "common/events.h" #include "common/system.h" +#include "common/list.h" namespace Saga { -class MoviePlayerSMK : Graphics::SMKPlayer { -protected: - virtual void setPalette(byte *pal); -public: - MoviePlayerSMK(SagaEngine *vm): _vm(vm), SMKPlayer(vm->_mixer), - _eventMan(vm->_system->getEventManager()) { - } - ~MoviePlayerSMK(void) { } - - void playVideo(const char *filename); -private: - void processFrame(); - void processEvents(); - PalEntry _smkPalette[256]; - bool _skipVideo; - SagaEngine *_vm; - Common::EventManager *_eventMan; -}; - -void MoviePlayerSMK::setPalette(byte *pal) { - for (int i = 0; i < 256; i++) { - _smkPalette[i].red = *pal++; - _smkPalette[i].green = *pal++; - _smkPalette[i].blue = *pal++; - } - - _vm->_gfx->setPalette(_smkPalette, true); -} - -void MoviePlayerSMK::processEvents() { - Common::Event curEvent; - // Process events, and skip video if esc is pressed - while (_eventMan->pollEvent(curEvent)) { - switch (curEvent.type) { - case Common::EVENT_KEYDOWN: - if (curEvent.kbd.keycode == Common::KEYCODE_ESCAPE) - _skipVideo = true; - break; - case Common::EVENT_RTL: - case Common::EVENT_QUIT: - _skipVideo = true; - break; - default: - break; - } - } -} - -void MoviePlayerSMK::playVideo(const char *filename) { - _skipVideo = false; - debug(0, "Playing video %s", filename); - - if (!loadFile(filename)) { - warning("Failed to load video file %s", filename); - return; - } - - while (getCurFrame() < getFrameCount() && !_skipVideo && !_vm->shouldQuit()) { - processEvents(); - processFrame(); - } - - closeFile(); -} - -void MoviePlayerSMK::processFrame() { - uint32 startTime = 0; - decodeNextFrame(); - - Graphics::Surface *screen = _vm->_system->lockScreen(); - copyFrameToBuffer((byte *)screen->pixels, - (_vm->getDisplayInfo().width - getWidth()) / 2, - (_vm->getDisplayInfo().height - getHeight()) / 2, - _vm->getDisplayInfo().width); - _vm->_system->unlockScreen(); - - uint32 waitTime = getFrameWaitTime(); - - if (!waitTime) { - warning("dropped frame %i", getCurFrame()); - return; - } - - // Update the screen - _vm->_system->updateScreen(); - - startTime = _vm->_system->getMillis(); - - // Wait before showing the next frame - while (_vm->_system->getMillis() < startTime + waitTime && !_skipVideo && !_vm->shouldQuit()) { - processEvents(); - _vm->_system->delayMillis(10); - } -} +Common::List stopEvents; int Scene::FTA2StartProc() { _vm->_gfx->showCursor(false); - MoviePlayerSMK *smkPlayer = new MoviePlayerSMK(_vm); - smkPlayer->playVideo("trimark.smk"); // Show Ignite logo - smkPlayer->playVideo("intro.smk"); // Play introduction + Common::Event stopEvent; + stopEvents.clear(); + stopEvent.type = Common::EVENT_KEYDOWN; + stopEvent.kbd = Common::KEYCODE_ESCAPE; + stopEvents.push_back(stopEvent); + + Graphics::SMKPlayer *smkPlayer = new Graphics::SMKPlayer(_vm->_mixer); + smkPlayer->playVideo("trimark.smk", &stopEvents); // Show Ignite logo + smkPlayer->playVideo("intro.smk", &stopEvents); // Play introduction delete smkPlayer; // HACK: Forcibly quit here @@ -174,9 +88,16 @@ int Scene::FTA2EndProc(FTA2Endings whichEnding) { _vm->_gfx->showCursor(false); + + Common::Event stopEvent; + stopEvents.clear(); + stopEvent.type = Common::EVENT_KEYDOWN; + stopEvent.kbd = Common::KEYCODE_ESCAPE; + stopEvents.push_back(stopEvent); + // Play ending - MoviePlayerSMK *smkPlayer = new MoviePlayerSMK(_vm); - smkPlayer->playVideo(videoName); + Graphics::SMKPlayer *smkPlayer = new Graphics::SMKPlayer(_vm->_mixer); + smkPlayer->playVideo(videoName, &stopEvents); delete smkPlayer; return SUCCESS; diff --git a/graphics/module.mk b/graphics/module.mk index ea755ac7bd..75aea2b7da 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -21,7 +21,8 @@ MODULE_OBJS := \ video/dxa_player.o \ video/flic_player.o \ video/mpeg_player.o \ - video/smk_player.o + video/smk_player.o \ + video/video_player.o ifndef DISABLE_SCALERS MODULE_OBJS += \ diff --git a/graphics/video/dxa_player.cpp b/graphics/video/dxa_player.cpp index c1d3f6f7cf..89ca280ce1 100644 --- a/graphics/video/dxa_player.cpp +++ b/graphics/video/dxa_player.cpp @@ -40,7 +40,7 @@ DXAPlayer::DXAPlayer() { _frameBuffer1 = 0; _frameBuffer2 = 0; _scaledBuffer = 0; - _drawBuffer = 0; + _videoFrameBuffer = 0; _inBuffer = 0; _inBufferSize = 0; @@ -48,14 +48,14 @@ DXAPlayer::DXAPlayer() { _decompBuffer = 0; _decompBufferSize = 0; - _width = 0; - _height = 0; + _videoInfo.width = 0; + _videoInfo.height = 0; _frameSize = 0; - _framesCount = 0; - _frameNum = 0; - _framesPerSec = 0; - _frameTicks = 0; + _videoInfo.frameCount = 0; + _videoInfo.currentFrame = 0; + _videoInfo.frameRate = 0; + _videoInfo.frameDelay = 0; _scaleMode = S_NONE; } @@ -64,47 +64,12 @@ DXAPlayer::~DXAPlayer() { closeFile(); } -int DXAPlayer::getWidth() { - if (!_fileStream) - return 0; - return _width; -} - -int DXAPlayer::getHeight() { - if (!_fileStream) - return 0; - return _height; -} - -int32 DXAPlayer::getCurFrame() { - if (!_fileStream) - return -1; - return _frameNum; -} - -int32 DXAPlayer::getFrameCount() { - if (!_fileStream) - return 0; - return _framesCount; -} - -int32 DXAPlayer::getFrameRate() { - if (!_fileStream) - return 0; - return _framesPerSec; -} - -int32 DXAPlayer::getFrameDelay() { - if (!_fileStream) - return 0; - - return _frameTicks; -} - bool DXAPlayer::loadFile(const char *fileName) { uint32 tag; int32 frameRate; + closeFile(); + _fileStream = SearchMan.openFile(fileName); if (!_fileStream) return false; @@ -113,38 +78,37 @@ bool DXAPlayer::loadFile(const char *fileName) { assert(tag == MKID_BE('DEXA')); uint8 flags = _fileStream->readByte(); - _framesCount = _fileStream->readUint16BE(); - frameRate = _fileStream->readUint32BE(); - - if (frameRate > 0) - _framesPerSec = 1000 / frameRate; - else if (frameRate < 0) - _framesPerSec = 100000 / (-frameRate); - else - _framesPerSec = 10; - - if (frameRate < 0) - _frameTicks = -frameRate / 100; - else - _frameTicks = frameRate; + _videoInfo.frameCount = _fileStream->readUint16BE(); + frameRate = _fileStream->readSint32BE(); + + if (frameRate > 0) { + _videoInfo.frameRate = 1000 / frameRate; + _videoInfo.frameDelay = frameRate * 100; + } else if (frameRate < 0) { + _videoInfo.frameRate = 100000 / (-frameRate); + _videoInfo.frameDelay = -frameRate; + } else { + _videoInfo.frameRate = 10; + _videoInfo.frameDelay = 10000; + } - _width = _fileStream->readUint16BE(); - _height = _fileStream->readUint16BE(); + _videoInfo.width = _fileStream->readUint16BE(); + _videoInfo.height = _fileStream->readUint16BE(); if (flags & 0x80) { _scaleMode = S_INTERLACED; - _curHeight = _height / 2; + _curHeight = _videoInfo.height / 2; } else if (flags & 0x40) { _scaleMode = S_DOUBLE; - _curHeight = _height / 2; + _curHeight = _videoInfo.height / 2; } else { _scaleMode = S_NONE; - _curHeight = _height; + _curHeight = _videoInfo.height; } debug(2, "flags 0x0%x framesCount %d width %d height %d rate %d ticks %d", flags, getFrameCount(), getWidth(), getHeight(), getFrameRate(), getFrameDelay()); - _frameSize = _width * _height; + _frameSize = _videoInfo.width * _videoInfo.height; _decompBufferSize = _frameSize; _frameBuffer1 = (uint8 *)malloc(_frameSize); _frameBuffer2 = (uint8 *)malloc(_frameSize); @@ -185,7 +149,7 @@ bool DXAPlayer::loadFile(const char *fileName) { } while (tag != 0); } #endif - _frameNum = 0; + _videoInfo.currentFrame = 0; return true; } @@ -207,20 +171,6 @@ void DXAPlayer::closeFile() { _decompBuffer = 0; } -void DXAPlayer::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { - uint h = _height; - uint w = _width; - - byte *src = _drawBuffer; - dst += y * pitch + x; - - do { - memcpy(dst, src, w); - dst += pitch; - src += _width; - } while (--h); -} - void DXAPlayer::decodeZlib(byte *data, int size, int totalSize) { #ifdef USE_ZLIB unsigned long dstLen = totalSize; @@ -245,10 +195,10 @@ void DXAPlayer::decode12(int size) { memcpy(_frameBuffer2, _frameBuffer1, _frameSize); - for (int by = 0; by < _height; by += BLOCKH) { - for (int bx = 0; bx < _width; bx += BLOCKW) { + for (uint32 by = 0; by < _videoInfo.height; by += BLOCKH) { + for (uint32 bx = 0; bx < _videoInfo.width; bx += BLOCKW) { byte type = *dat++; - byte *b2 = _frameBuffer1 + bx + by * _width; + byte *b2 = _frameBuffer1 + bx + by * _videoInfo.width; switch (type) { case 0: @@ -280,7 +230,7 @@ void DXAPlayer::decode12(int size) { } diffMap <<= 1; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -291,7 +241,7 @@ void DXAPlayer::decode12(int size) { for (int xc = 0; xc < BLOCKW; xc++) { b2[xc] = color; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -300,7 +250,7 @@ void DXAPlayer::decode12(int size) { for (int xc = 0; xc < BLOCKW; xc++) { b2[xc] = *dat++; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -312,11 +262,11 @@ void DXAPlayer::decode12(int size) { int my = mbyte & 0x07; if (mbyte & 0x08) my = -my; - byte *b1 = _frameBuffer2 + (bx+mx) + (by+my) * _width; + byte *b1 = _frameBuffer2 + (bx+mx) + (by+my) * _videoInfo.width; for (int yc = 0; yc < BLOCKH; yc++) { memcpy(b2, b1, BLOCKW); - b1 += _width; - b2 += _width; + b1 += _videoInfo.width; + b2 += _videoInfo.width; } break; } @@ -345,7 +295,7 @@ void DXAPlayer::decode13(int size) { memcpy(_frameBuffer2, _frameBuffer1, _frameSize); - int codeSize = _width * _curHeight / 16; + int codeSize = _videoInfo.width * _curHeight / 16; int dataSize, motSize, maskSize; dataSize = READ_BE_UINT32(&_decompBuffer[0]); @@ -357,10 +307,10 @@ void DXAPlayer::decode13(int size) { motBuf = &dataBuf[dataSize]; maskBuf = &motBuf[motSize]; - for (int by = 0; by < _curHeight; by += BLOCKH) { - for (int bx = 0; bx < _width; bx += BLOCKW) { + for (uint32 by = 0; by < _curHeight; by += BLOCKH) { + for (uint32 bx = 0; bx < _videoInfo.width; bx += BLOCKW) { uint8 type = *codeBuf++; - uint8 *b2 = (uint8*)_frameBuffer1 + bx + by * _width; + uint8 *b2 = (uint8*)_frameBuffer1 + bx + by * _videoInfo.width; switch (type) { case 0: @@ -377,7 +327,7 @@ void DXAPlayer::decode13(int size) { } diffMap <<= 1; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -388,7 +338,7 @@ void DXAPlayer::decode13(int size) { for (int xc = 0; xc < BLOCKW; xc++) { b2[xc] = color; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -397,7 +347,7 @@ void DXAPlayer::decode13(int size) { for (int xc = 0; xc < BLOCKW; xc++) { b2[xc] = *dataBuf++; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -411,11 +361,11 @@ void DXAPlayer::decode13(int size) { if (mbyte & 0x08) my = -my; - uint8 *b1 = (uint8*)_frameBuffer2 + (bx+mx) + (by+my) * _width; + uint8 *b1 = (uint8*)_frameBuffer2 + (bx+mx) + (by+my) * _videoInfo.width; for (int yc = 0; yc < BLOCKH; yc++) { memcpy(b2, b1, BLOCKW); - b1 += _width; - b2 += _width; + b1 += _videoInfo.width; + b2 += _videoInfo.width; } break; } @@ -427,7 +377,7 @@ void DXAPlayer::decode13(int size) { for (int subBlock = 0; subBlock < 4; subBlock++) { int sx = bx + subX[subBlock], sy = by + subY[subBlock]; - b2 = (uint8*)_frameBuffer1 + sx + sy * _width; + b2 = (uint8*)_frameBuffer1 + sx + sy * _videoInfo.width; switch (subMask & 0xC0) { // 00: skip case 0x00: @@ -439,7 +389,7 @@ void DXAPlayer::decode13(int size) { for (int xc = 0; xc < BLOCKW / 2; xc++) { b2[xc] = subColor; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -455,11 +405,11 @@ void DXAPlayer::decode13(int size) { if (mbyte & 0x08) my = -my; - uint8 *b1 = (uint8*)_frameBuffer2 + (sx+mx) + (sy+my) * _width; + uint8 *b1 = (uint8*)_frameBuffer2 + (sx+mx) + (sy+my) * _videoInfo.width; for (int yc = 0; yc < BLOCKH / 2; yc++) { memcpy(b2, b1, BLOCKW / 2); - b1 += _width; - b2 += _width; + b1 += _videoInfo.width; + b2 += _videoInfo.width; } break; } @@ -469,7 +419,7 @@ void DXAPlayer::decode13(int size) { for (int xc = 0; xc < BLOCKW / 2; xc++) { b2[xc] = *dataBuf++; } - b2 += _width; + b2 += _videoInfo.width; } break; } @@ -494,7 +444,7 @@ void DXAPlayer::decode13(int size) { b2[xc] = pixels[code & 1]; code >>= 1; } - b2 += _width; + b2 += _videoInfo.width; } } else { uint32 code = READ_BE_UINT32(maskBuf); @@ -504,7 +454,7 @@ void DXAPlayer::decode13(int size) { b2[xc] = pixels[code & 3]; code >>= 2; } - b2 += _width; + b2 += _videoInfo.width; } } break; @@ -517,7 +467,7 @@ void DXAPlayer::decode13(int size) { #endif } -void DXAPlayer::decodeNextFrame() { +bool DXAPlayer::decodeNextFrame() { uint32 tag; tag = _fileStream->readUint32BE(); @@ -560,9 +510,9 @@ void DXAPlayer::decodeNextFrame() { } if (type == 3) { - for (int j = 0; j < _curHeight; ++j) { - for (int i = 0; i < _width; ++i) { - const int offs = j * _width + i; + for (uint32 j = 0; j < _curHeight; ++j) { + for (uint32 i = 0; i < _videoInfo.width; ++i) { + const int offs = j * _videoInfo.width + i; _frameBuffer1[offs] ^= _frameBuffer2[offs]; } } @@ -572,24 +522,24 @@ void DXAPlayer::decodeNextFrame() { switch (_scaleMode) { case S_INTERLACED: for (int cy = 0; cy < _curHeight; cy++) { - memcpy(&_scaledBuffer[2 * cy * _width], &_frameBuffer1[cy * _width], _width); - memset(&_scaledBuffer[((2 * cy) + 1) * _width], 0, _width); + memcpy(&_scaledBuffer[2 * cy * _videoInfo.width], &_frameBuffer1[cy * _videoInfo.width], _videoInfo.width); + memset(&_scaledBuffer[((2 * cy) + 1) * _videoInfo.width], 0, _videoInfo.width); } - _drawBuffer = _scaledBuffer; + _videoFrameBuffer = _scaledBuffer; break; case S_DOUBLE: for (int cy = 0; cy < _curHeight; cy++) { - memcpy(&_scaledBuffer[2 * cy * _width], &_frameBuffer1[cy * _width], _width); - memcpy(&_scaledBuffer[((2 * cy) + 1) * _width], &_frameBuffer1[cy * _width], _width); + 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); } - _drawBuffer = _scaledBuffer; + _videoFrameBuffer = _scaledBuffer; break; case S_NONE: - _drawBuffer = _frameBuffer1; + _videoFrameBuffer = _frameBuffer1; break; } - _frameNum++; + return ++_videoInfo.currentFrame < _videoInfo.frameCount; } } // End of namespace Graphics diff --git a/graphics/video/dxa_player.h b/graphics/video/dxa_player.h index 3239913131..1593658ae7 100644 --- a/graphics/video/dxa_player.h +++ b/graphics/video/dxa_player.h @@ -29,55 +29,15 @@ #include "common/scummsys.h" #include "common/stream.h" -namespace Graphics { +#include "graphics/video/video_player.h" -enum ScaleMode { - S_NONE, - S_INTERLACED, - S_DOUBLE -}; +namespace Graphics { -class DXAPlayer { +class DXAPlayer : public VideoPlayer { public: DXAPlayer(); virtual ~DXAPlayer(); - /** - * Returns the width of the video - * @return the width of the video - */ - int getWidth(); - - /** - * Returns the height of the video - * @return the height of the video - */ - int getHeight(); - - /** - * Returns the current frame number of the video - * @return the current frame number of the video - */ - int32 getCurFrame(); - - /** - * Returns the amount of frames in the video - * @return the amount of frames in the video - */ - int32 getFrameCount(); - - /** - * Returns the frame rate of the video - * @return the frame rate of the video - */ - int32 getFrameRate(); - - /** - * Returns the time to wait for each frame in 1/100 ms - * @return the time to wait for each frame in 1/100 ms - */ - int32 getFrameDelay(); - /** * Load a DXA encoded video file * @param filename the filename to load @@ -89,55 +49,28 @@ public: */ void closeFile(); - /** - * Returns if a video file is loaded or not - */ - bool videoIsLoaded() { return (_fileStream != NULL); } - -protected: - /** - * Set RGB palette, based on current frame - * @param pal the RGB palette data - */ - virtual void setPalette(byte *pal) = 0; - - /** - * 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 - */ - void decodeNextFrame(); + bool decodeNextFrame(); +private: void decodeZlib(byte *data, int size, int totalSize); void decode12(int size); void decode13(int size); - Common::SeekableReadStream *_fileStream; + enum ScaleMode { + S_NONE, + S_INTERLACED, + S_DOUBLE + }; -private: byte *_frameBuffer1; byte *_frameBuffer2; byte *_scaledBuffer; - byte *_drawBuffer; byte *_inBuffer; uint32 _inBufferSize; byte *_decompBuffer; uint32 _decompBufferSize; - uint16 _width; - uint16 _height, _curHeight; - uint16 _framesCount; - uint32 _framesPerSec; - uint16 _frameNum; + uint16 _curHeight; uint32 _frameSize; - uint32 _frameTicks; ScaleMode _scaleMode; }; diff --git a/graphics/video/smk_player.cpp b/graphics/video/smk_player.cpp index 548ed70134..f97555bb15 100644 --- a/graphics/video/smk_player.cpp +++ b/graphics/video/smk_player.cpp @@ -314,59 +314,16 @@ uint32 BigHuffmanTree::getCode(BitStream &bs) { } SMKPlayer::SMKPlayer(Audio::Mixer *mixer) - : _currentSMKFrame(0), _fileStream(0), _audioStarted(false), _audioStream(0), _mixer(mixer) { + : _audioStarted(false), _audioStream(0), _mixer(mixer) { } SMKPlayer::~SMKPlayer() { - closeFile(); -} - -int SMKPlayer::getWidth() { - if (!_fileStream) - return 0; - return _header.width; } int SMKPlayer::getHeight() { if (!_fileStream) return 0; - return (_header.flags ? 2 : 1) * _header.height; -} - -int32 SMKPlayer::getCurFrame() { - if (!_fileStream) - return -1; - return _currentSMKFrame; -} - -int32 SMKPlayer::getFrameCount() { - if (!_fileStream) - return 0; - return _header.frames; -} - -int32 SMKPlayer::getFrameRate() { - if (!_fileStream) - return 0; - - if (_header.frameRate > 0) - return 1000 / _header.frameRate; - else if (_header.frameRate < 0) - return 100000 / (-_header.frameRate); - else - return 10; -} - -int32 SMKPlayer::getFrameDelay() { - if (!_fileStream) - return 0; - - if (_header.frameRate > 0) - return _header.frameRate * 100; - if (_header.frameRate < 0) - return -_header.frameRate; - - return 10000; + return (_header.flags ? 2 : 1) * _videoInfo.height; } int32 SMKPlayer::getAudioLag() { @@ -374,7 +331,7 @@ int32 SMKPlayer::getAudioLag() { return 0; int32 frameDelay = getFrameDelay(); - int32 videoTime = _currentSMKFrame * frameDelay; + int32 videoTime = _videoInfo.currentFrame * frameDelay; int32 audioTime; if (!_audioStream) { @@ -383,23 +340,16 @@ int32 SMKPlayer::getAudioLag() { and how much time *should* have passed. */ - audioTime = (g_system->getMillis() - _startTime) * 100; + audioTime = (g_system->getMillis() - _videoInfo.startTime) * 100; } else audioTime = (((int32) _mixer->getSoundElapsedTime(_audioHandle)) * 100); return videoTime - audioTime; } -uint32 SMKPlayer::getFrameWaitTime() { - int32 waitTime = (getFrameDelay() + getAudioLag()) / 100; - - if (waitTime < 0) - return 0; - - return waitTime; -} - bool SMKPlayer::loadFile(const char *fileName) { + int32 frameRate; + closeFile(); _fileStream = SearchMan.openFile(fileName); @@ -407,7 +357,7 @@ bool SMKPlayer::loadFile(const char *fileName) { return false; // Seek to the first frame - _currentSMKFrame = 0; + _videoInfo.currentFrame = 0; _header.signature = _fileStream->readUint32BE(); // No BINK support available @@ -419,10 +369,22 @@ bool SMKPlayer::loadFile(const char *fileName) { assert(_header.signature == MKID_BE('SMK2') || _header.signature == MKID_BE('SMK4')); - _header.width = _fileStream->readUint32LE(); - _header.height = _fileStream->readUint32LE(); - _header.frames = _fileStream->readUint32LE(); - _header.frameRate = (int32)_fileStream->readUint32LE(); + _videoInfo.width = _fileStream->readUint32LE(); + _videoInfo.height = _fileStream->readUint32LE(); + _videoInfo.frameCount = _fileStream->readUint32LE(); + frameRate = _fileStream->readSint32LE(); + + if (frameRate > 0) { + _videoInfo.frameRate = 1000 / frameRate; + _videoInfo.frameDelay = frameRate * 100; + } else if (frameRate < 0) { + _videoInfo.frameRate = 100000 / (-frameRate); + _videoInfo.frameDelay = -frameRate; + } else { + _videoInfo.frameRate = 10; + _videoInfo.frameDelay = 10000; + } + // 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. // 1 - set to 1 if file is Y-interlaced @@ -481,12 +443,12 @@ bool SMKPlayer::loadFile(const char *fileName) { _header.dummy = _fileStream->readUint32LE(); - _frameSizes = (uint32 *)malloc(_header.frames * sizeof(uint32)); - for (i = 0; i < _header.frames; ++i) + _frameSizes = (uint32 *)malloc(_videoInfo.frameCount * sizeof(uint32)); + for (i = 0; i < _videoInfo.frameCount; ++i) _frameSizes[i] = _fileStream->readUint32LE(); - _frameTypes = (byte *)malloc(_header.frames); - for (i = 0; i < _header.frames; ++i) + _frameTypes = (byte *)malloc(_videoInfo.frameCount); + for (i = 0; i < _videoInfo.frameCount; ++i) _frameTypes[i] = _fileStream->readByte(); Common::Array huffmanTrees; @@ -502,8 +464,8 @@ bool SMKPlayer::loadFile(const char *fileName) { _FullTree = new BigHuffmanTree(bs); _TypeTree = new BigHuffmanTree(bs); - _videoFrameBuffer = (byte *)malloc(2 * _header.width * _header.height); - memset(_videoFrameBuffer, 0, 2 * _header.width * _header.height); + _videoFrameBuffer = (byte *)malloc(2 * _videoInfo.width * _videoInfo.height); + memset(_videoFrameBuffer, 0, 2 * _videoInfo.width * _videoInfo.height); _palette = (byte *)malloc(3 * 256); memset(_palette, 0, 3 * 256); @@ -534,20 +496,6 @@ void SMKPlayer::closeFile() { free(_palette); } -void SMKPlayer::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { - uint h = (_header.flags ? 2 : 1) * _header.height; - uint w = _header.width; - - byte *src = _videoFrameBuffer; - dst += y * pitch + x; - - do { - memcpy(dst, src, w); - dst += pitch; - src += _header.width; - } while (--h); -} - bool SMKPlayer::decodeNextFrame() { uint i; uint32 chunkSize = 0; @@ -555,20 +503,20 @@ bool SMKPlayer::decodeNextFrame() { uint32 startPos = _fileStream->pos(); - if (_currentSMKFrame == 0) - _startTime = g_system->getMillis(); + if (_videoInfo.currentFrame == 0) + _videoInfo.startTime = g_system->getMillis(); // Check if we got a frame with palette data, and // call back the virtual setPalette function to set // the current palette - if (_frameTypes[_currentSMKFrame] & 1) { + if (_frameTypes[_videoInfo.currentFrame] & 1) { unpackPalette(); setPalette(_palette); } // Load audio tracks for (i = 0; i < 7; ++i) { - if (!(_frameTypes[_currentSMKFrame] & (2 << i))) + if (!(_frameTypes[_videoInfo.currentFrame] & (2 << i))) continue; chunkSize = _fileStream->readUint32LE(); @@ -612,7 +560,7 @@ bool SMKPlayer::decodeNextFrame() { } } - uint32 frameSize = _frameSizes[_currentSMKFrame] & ~3; + uint32 frameSize = _frameSizes[_videoInfo.currentFrame] & ~3; if (_fileStream->pos() - startPos > frameSize) exit(1); @@ -631,9 +579,9 @@ bool SMKPlayer::decodeNextFrame() { _FullTree->reset(); _TypeTree->reset(); - uint bw = _header.width / 4; - uint bh = _header.height / 4; - uint stride = _header.width; + uint bw = _videoInfo.width / 4; + uint bh = _videoInfo.height / 4; + uint stride = _videoInfo.width; uint block = 0, blocks = bw*bh; uint doubleY = _header.flags ? 2 : 1; @@ -767,7 +715,7 @@ bool SMKPlayer::decodeNextFrame() { free(_frameData); - return ++_currentSMKFrame < _header.frames; + return ++_videoInfo.currentFrame < _videoInfo.frameCount; } void SMKPlayer::queueCompressedBuffer(byte *buffer, uint32 bufferSize, diff --git a/graphics/video/smk_player.h b/graphics/video/smk_player.h index 93f4457f2b..3ddc12e2d6 100644 --- a/graphics/video/smk_player.h +++ b/graphics/video/smk_player.h @@ -35,6 +35,8 @@ #include "sound/mixer.h" #include "sound/audiostream.h" +#include "graphics/video/video_player.h" + namespace Graphics { class BigHuffmanTree; @@ -42,97 +44,21 @@ class BigHuffmanTree; /** * Implementation of a Smacker v2/v4 video decoder */ -class SMKPlayer { +class SMKPlayer : public Graphics::VideoPlayer { public: SMKPlayer(Audio::Mixer *mixer); virtual ~SMKPlayer(); - /** - * Returns the width of the video - * @return the width of the video - */ - int getWidth(); - - /** - * Returns the height of the video - * @return the height of the video - */ int getHeight(); - - /** - * Returns the current frame number of the video - * @return the current frame number of the video - */ - int32 getCurFrame(); - - /** - * Returns the amount of frames in the video - * @return the amount of frames in the video - */ - int32 getFrameCount(); - - /** - * Returns the frame rate of the video - * @return the frame rate of the video - */ - int32 getFrameRate(); - - /** - * Returns the time to wait for each frame in 1/100 ms - * @return the time to wait for each frame in 1/100 ms - */ - int32 getFrameDelay(); - - /** - * Returns the current A/V lag in 1/100 ms - * If > 0, audio lags behind - * If < 0, video lags behind - * @return the current A/V lag in 1/100 ms - */ 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 - */ - uint32 getFrameWaitTime(); - /** * Load an SMK encoded video file * @param filename the filename to load */ bool loadFile(const char *filename); - - /** - * Close an SMK encoded video file - */ void closeFile(); - /** - * Returns if a video file is loaded or not - */ - bool videoIsLoaded() { return (_fileStream != NULL); } - -protected: - /** - * Set RGB palette, based on current frame - * @param pal the RGB palette data - */ - virtual void setPalette(byte *pal) = 0; - - /** - * 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 - */ bool decodeNextFrame(); private: @@ -152,10 +78,6 @@ private: struct { uint32 signature; - uint32 width; - uint32 height; - uint32 frames; - int32 frameRate; uint32 flags; uint32 audioSize[7]; uint32 treesSize; @@ -182,16 +104,10 @@ private: Audio::AppendableAudioStream *_audioStream; Audio::SoundHandle _audioHandle; - uint32 _currentSMKFrame; - uint32 _startTime; - BigHuffmanTree *_MMapTree; BigHuffmanTree *_MClrTree; BigHuffmanTree *_FullTree; BigHuffmanTree *_TypeTree; - - Common::SeekableReadStream *_fileStream; - byte *_videoFrameBuffer; }; } // End of namespace Graphics diff --git a/graphics/video/video_player.cpp b/graphics/video/video_player.cpp new file mode 100644 index 0000000000..5fc2c72fbf --- /dev/null +++ b/graphics/video/video_player.cpp @@ -0,0 +1,216 @@ +/* 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/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 { + +VideoPlayer::VideoPlayer() : _fileStream(0), _skipVideo(false) { +} + +VideoPlayer::~VideoPlayer() { + closeFile(); +} + +int VideoPlayer::getWidth() { + if (!_fileStream) + return 0; + return _videoInfo.width; +} + +int VideoPlayer::getHeight() { + if (!_fileStream) + return 0; + return _videoInfo.height; +} + +int32 VideoPlayer::getCurFrame() { + if (!_fileStream) + return -1; + return _videoInfo.currentFrame; +} + +int32 VideoPlayer::getFrameCount() { + if (!_fileStream) + return 0; + return _videoInfo.frameCount; +} + +int32 VideoPlayer::getFrameRate() { + if (!_fileStream) + return 0; + return _videoInfo.frameRate; +} + +int32 VideoPlayer::getFrameDelay() { + if (!_fileStream) + return 0; + return _videoInfo.frameDelay; +} + +int32 VideoPlayer::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 VideoPlayer::getFrameWaitTime() { + int32 waitTime = (getFrameDelay() + getAudioLag()) / 100; + + if (waitTime < 0) + return 0; + + return waitTime; +} + +bool VideoPlayer::loadFile(const char *fileName) { + return false; +} + +void VideoPlayer::closeFile() { +} + +void VideoPlayer::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 VideoPlayer::setPalette(byte *pal) { + 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; + } + + g_system->setPalette(_videoPalette, 0, 256); +} + +bool VideoPlayer::decodeNextFrame() { + return false; +} + +void VideoPlayer::performPostProcessing(byte *screen) { +} + +void VideoPlayer::processVideoEvents(Common::List *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::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(const char *filename, Common::List *stopEvents) { + _skipVideo = false; + debug(0, "Playing video %s", filename); + + if (!loadFile(filename)) { + warning("Failed to load video file %s", filename); + return false; + } + + while (getCurFrame() < getFrameCount() && !_skipVideo) { + processVideoEvents(stopEvents); + + uint32 startTime = 0; + decodeNextFrame(); + + Graphics::Surface *screen = g_system->lockScreen(); + copyFrameToBuffer((byte *)screen->pixels, + (g_system->getWidth() - getWidth()) / 2, + (g_system->getHeight() - getHeight()) / 2, + g_system->getWidth()); + performPostProcessing((byte *)screen->pixels); + g_system->unlockScreen(); + + uint32 waitTime = getFrameWaitTime(); + + if (!waitTime) { + warning("dropped frame %i", 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); + } + } + + closeFile(); + + return true; +} + +} // End of namespace Graphics diff --git a/graphics/video/video_player.h b/graphics/video/video_player.h new file mode 100644 index 0000000000..6d346f398d --- /dev/null +++ b/graphics/video/video_player.h @@ -0,0 +1,170 @@ +/* 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/scummsys.h" +#include "common/stream.h" +#include "common/system.h" +#include "common/list.h" +#include "sound/mixer.h" +#include "sound/audiostream.h" + +namespace Graphics { + +/** + * Implementation of a generic video decoder + */ +class VideoPlayer { +public: + VideoPlayer(); + virtual ~VideoPlayer(); + + /** + * 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(); + + /** + * Returns the amount of frames in the video + * @return the amount of frames in the video + */ + virtual int32 getFrameCount(); + + /** + * 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 + * @return the time to wait for each frame in 1/100 ms + */ + virtual int32 getFrameDelay(); + + /** + * Returns the current A/V lag in 1/100 ms + * If > 0, audio lags behind + * If < 0, video lags behind + * @return the current A/V lag in 1/100 ms + */ + 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); + + /** + * Close a video file + */ + virtual void closeFile(); + + /** + * Returns if a video file is loaded or not + */ + bool videoIsLoaded() { return (_fileStream != NULL); } + + /** + * Set RGB palette, based on current frame + * @param pal the RGB palette data + */ + virtual void setPalette(byte *pal); + + /** + * 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 + */ + virtual bool decodeNextFrame(); + + /** + * 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 + */ + bool playVideo(const char *filename, Common::List *stopEvents); + + /** + * Perform postprocessing once the frame data is copied to the screen, + * right before the frame is drawn. Called from playVideo() + */ + virtual void performPostProcessing(byte *screen); + +protected: + struct { + uint32 width; + uint32 height; + uint32 frameCount; + int32 frameRate; + int32 frameDelay; + uint32 currentFrame; + uint32 startTime; + } _videoInfo; + + Common::SeekableReadStream *_fileStream; + byte *_videoFrameBuffer; + byte _videoPalette[256 * 4]; + bool _skipVideo; + +private: + void processVideoEvents(Common::List *stopEvents); +}; + +} // End of namespace Graphics + +#endif -- cgit v1.2.3