diff options
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/video/coktel_decoder.cpp | 171 | ||||
-rw-r--r-- | graphics/video/coktel_decoder.h | 10 |
2 files changed, 174 insertions, 7 deletions
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 |