diff options
author | Sven Hesse | 2010-08-08 00:42:30 +0000 |
---|---|---|
committer | Sven Hesse | 2010-08-08 00:42:30 +0000 |
commit | 6172fe8ea7cf8046e5048e56a512ad0f847ac324 (patch) | |
tree | 207e7c5e3d83a77b548d3ff591f4f504807be203 | |
parent | f19be90c37c3aa402ea7efdc0fc02595fe68a122 (diff) | |
download | scummvm-rg350-6172fe8ea7cf8046e5048e56a512ad0f847ac324.tar.gz scummvm-rg350-6172fe8ea7cf8046e5048e56a512ad0f847ac324.tar.bz2 scummvm-rg350-6172fe8ea7cf8046e5048e56a512ad0f847ac324.zip |
VIDEO/GOB: Implement IMD frame decoding
Rendering the frame video data is still stubbed out.
svn-id: r51866
-rw-r--r-- | engines/gob/videoplayer.cpp | 8 | ||||
-rw-r--r-- | graphics/video/coktel_decoder.cpp | 171 | ||||
-rw-r--r-- | graphics/video/coktel_decoder.h | 10 |
3 files changed, 177 insertions, 12 deletions
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index 99ea4f0b02..174c3af506 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -365,7 +365,7 @@ void VideoPlayer::checkAbort(Video &video, Properties &properties) { _vm->_util->processInput(); if (_vm->shouldQuit()) { - // video.decoder->disableSound(); + video.decoder->disableSound(); properties.canceled = true; return; @@ -377,7 +377,7 @@ void VideoPlayer::checkAbort(Video &video, Properties &properties) { _vm->_inter->storeKey(_vm->_util->checkKey()); if (VAR(0) == (unsigned) properties.breakKey) { - // video.decoder->disableSound(); + video.decoder->disableSound(); // Seek to the last frame. Some scripts depend on that. video.decoder->seek(properties.endFrame + 1, SEEK_SET, true); @@ -571,12 +571,10 @@ int VideoPlayer::getNextFreeSlot() { } void VideoPlayer::evalBgShading(Video &video) { - /* - if (video.isSoundPlaying()) + if (video.decoder->isSoundPlaying()) _vm->_sound->bgShade(); else _vm->_sound->bgUnshade(); - */ } Common::String VideoPlayer::findFile(const Common::String &file, Properties &properties) { diff --git a/graphics/video/coktel_decoder.cpp b/graphics/video/coktel_decoder.cpp index 2b4b7182f3..ebb1c9492b 100644 --- a/graphics/video/coktel_decoder.cpp +++ b/graphics/video/coktel_decoder.cpp @@ -206,6 +206,10 @@ Common::Rational CoktelDecoder::getFrameRate() const { return _frameRate; } +inline void CoktelDecoder::unsignedToSigned(byte *buffer, int length) { + while (length-- > 0) *buffer++ ^= 0x80; +} + PreIMDDecoder::PreIMDDecoder(uint16 width, uint16 height, Audio::Mixer &mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType), @@ -638,8 +642,9 @@ bool IMDDecoder::assessAudioProperties() { _frameRate = Common::Rational(_soundFreq) / _soundSliceSize; - _hasSound = true; - _soundStage = kSoundLoaded; + _hasSound = true; + _soundEnabled = true; + _soundStage = kSoundLoaded; _audioStream = Audio::makeQueuingAudioStream(_soundFreq, false); } @@ -737,18 +742,170 @@ Surface *IMDDecoder::decodeNextFrame() { } void IMDDecoder::processFrame() { + _curFrame++; - // TODO + _dirtyRects.clear(); + + _paletteDirty = false; + + uint32 cmd = 0; + bool hasNextCmd = false; + bool startSound = false; + + do { + calcFrameCoords(_curFrame); + + cmd = _stream->readUint16LE(); + + if ((cmd & kCommandBreakMask) == kCommandBreak) { + // Flow control + + if (cmd == kCommandBreak) { + _stream->skip(2); + cmd = _stream->readUint16LE(); + } + + // Break + if (cmd == kCommandBreakSkip0) { + continue; + } else if (cmd == kCommandBreakSkip16) { + cmd = _stream->readUint16LE(); + _stream->skip(cmd); + continue; + } else if (cmd == kCommandBreakSkip32) { + cmd = _stream->readUint32LE(); + _stream->skip(cmd); + continue; + } + } + + // Audio + if (_soundStage != kSoundNone) { + if (cmd == kCommandNextSound) { + + nextSoundSlice(hasNextCmd); + cmd = _stream->readUint16LE(); + + } else if (cmd == kCommandStartSound) { + + startSound = initialSoundSlice(hasNextCmd); + cmd = _stream->readUint16LE(); + + } else + emptySoundSlice(hasNextCmd); + } + + // Set palette + if (cmd == kCommandPalette) { + _stream->skip(2); + + _paletteDirty = true; + + _stream->read(_palette, 768); + cmd = _stream->readUint16LE(); + } + + hasNextCmd = false; + + if (cmd == kCommandJump) { + // Jump to frame + + int16 frame = _stream->readSint16LE(); + if (_framePos) { + _curFrame = frame - 1; + _stream->seek(_framePos[frame]); + + hasNextCmd = true; + } + + } else if (cmd == kCommandVideoData) { + videoData(_stream->readUint32LE() + 2); + + } else if (cmd != 0) + videoData(cmd + 2); + else + _dirtyRects.pop_back(); + + } while (hasNextCmd); + + if (startSound && _soundEnabled) { + _mixer->playStream(_soundType, &_audioHandle, _audioStream); + _soundStage = kSoundPlaying; + } + + if ((_curFrame >= (int32)(_frameCount - 1)) && (_soundStage == kSoundPlaying)) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + _audioStream = 0; + _soundStage = kSoundNone; + } - _curFrame++; } -void IMDDecoder::renderFrame() { - _dirtyRects.clear(); +void IMDDecoder::calcFrameCoords(uint32 frame) { + if (frame == 0) + _dirtyRects.push_back(Common::Rect(_x, _y, _x + _width, _y + _height)); + else if (_frameCoords && ((_frameCoords[frame].left != -1))) + _dirtyRects.push_back(Common::Rect(_frameCoords[frame].left , _frameCoords[frame].top, + _frameCoords[frame].right + 1, _frameCoords[frame].bottom + 1)); + else if (_stdX != -1) + _dirtyRects.push_back(Common::Rect(_stdX, _stdY, _stdX + _stdWidth, _stdY + _stdHeight)); + else + _dirtyRects.push_back(Common::Rect(_x, _y, _x + _width, _y + _height)); +} +void IMDDecoder::videoData(uint32 size) { + _stream->read(_frameData, size); + _frameDataLen = size; + + renderFrame(); +} + +void IMDDecoder::renderFrame() { // TODO +} - _dirtyRects.push_back(Common::Rect(_x, _y, _x + _width, _y + _height)); +void IMDDecoder::nextSoundSlice(bool hasNextCmd) { + if (hasNextCmd || !_soundEnabled) { + _stream->skip(_soundSliceSize); + return; + } + + byte *soundBuf = (byte *)malloc(_soundSliceSize); + + _stream->read(soundBuf, _soundSliceSize); + unsignedToSigned(soundBuf, _soundSliceSize); + + _audioStream->queueBuffer(soundBuf, _soundSliceSize, DisposeAfterUse::YES, 0); +} + +bool IMDDecoder::initialSoundSlice(bool hasNextCmd) { + int dataLength = _soundSliceSize * _soundSlicesCount; + + if (hasNextCmd || !_soundEnabled) { + _stream->skip(dataLength); + return false; + } + + byte *soundBuf = (byte *)malloc(dataLength); + + _stream->read(soundBuf, dataLength); + unsignedToSigned(soundBuf, dataLength); + + _audioStream->queueBuffer(soundBuf, dataLength, DisposeAfterUse::YES, 0); + + return _soundStage == kSoundLoaded; +} + +void IMDDecoder::emptySoundSlice(bool hasNextCmd) { + if (hasNextCmd || !_soundEnabled) + return; + + byte *soundBuf = (byte *)malloc(_soundSliceSize); + + memset(soundBuf, 0, _soundSliceSize); + + _audioStream->queueBuffer(soundBuf, _soundSliceSize, DisposeAfterUse::YES, 0); } PixelFormat IMDDecoder::getPixelFormat() const { diff --git a/graphics/video/coktel_decoder.h b/graphics/video/coktel_decoder.h index f4da9624bd..1736132cf4 100644 --- a/graphics/video/coktel_decoder.h +++ b/graphics/video/coktel_decoder.h @@ -159,6 +159,8 @@ protected: void createSurface(); void freeSurface(); + inline void unsignedToSigned(byte *buffer, int length); + // FixedRateVideoDecoder interface Common::Rational getFrameRate() const; }; @@ -273,7 +275,15 @@ private: bool loadFrameTables(uint32 framePosPos, uint32 frameCoordsPos); void processFrame(); + + void calcFrameCoords(uint32 frame); + + void videoData(uint32 size); void renderFrame(); + + void nextSoundSlice(bool hasNextCmd); + bool initialSoundSlice(bool hasNextCmd); + void emptySoundSlice(bool hasNextCmd); }; } // End of namespace Graphics |