diff options
author | Sven Hesse | 2007-07-31 18:16:33 +0000 |
---|---|---|
committer | Sven Hesse | 2007-07-31 18:16:33 +0000 |
commit | 2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710 (patch) | |
tree | a379cd851af49d7d2d3df30837d25d54fdfa567a /engines/gob/coktelvideo.cpp | |
parent | cd20f09a9d8085d1082313fd1d58c87deeb30333 (diff) | |
download | scummvm-rg350-2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710.tar.gz scummvm-rg350-2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710.tar.bz2 scummvm-rg350-2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710.zip |
Still partly broken/stubby VMD playing
svn-id: r28363
Diffstat (limited to 'engines/gob/coktelvideo.cpp')
-rw-r--r-- | engines/gob/coktelvideo.cpp | 497 |
1 files changed, 376 insertions, 121 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp index e7eebe602a..0d59bf4993 100644 --- a/engines/gob/coktelvideo.cpp +++ b/engines/gob/coktelvideo.cpp @@ -58,13 +58,16 @@ bool Imd::load(Common::SeekableReadStream &stream) { // Rest header _features = _stream->readByte(); _framesCount = _stream->readUint16LE(); - _x = _stream->readUint16LE(); - _y = _stream->readUint16LE(); - _width = _stream->readUint16LE(); - _height = _stream->readUint16LE(); + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); _flags = _stream->readUint16LE(); _firstFramePos = _stream->readUint16LE(); + // IMDs always have video + _features |= kFeaturesVideo; + // Palette _stream->read((byte *) _palette, 768); @@ -77,10 +80,10 @@ bool Imd::load(Common::SeekableReadStream &stream) { return false; } if (_stdX != 0) { - _stdX = _stream->readUint16LE(); - _stdY = _stream->readUint16LE(); - _stdWidth = _stream->readUint16LE(); - _stdHeight = _stream->readUint16LE(); + _stdX = _stream->readSint16LE(); + _stdY = _stream->readSint16LE(); + _stdWidth = _stream->readSint16LE(); + _stdHeight = _stream->readSint16LE(); _features |= kFeaturesStdCoords; } else _stdX = -1; @@ -92,7 +95,7 @@ bool Imd::load(Common::SeekableReadStream &stream) { if (_version >= 4) { framesPosPos = _stream->readUint32LE(); if (framesPosPos != 0) { - _framesPos = new int32[_framesCount]; + _framesPos = new uint32[_framesCount]; assert(_framesPos); _features |= kFeaturesFramesPos; } @@ -105,9 +108,9 @@ bool Imd::load(Common::SeekableReadStream &stream) { // Sound if (_features & kFeaturesSound) { - _soundFreq = _stream->readUint16LE(); + _soundFreq = _stream->readSint16LE(); _soundSliceSize = _stream->readUint16LE(); - _soundSlicesCount = _stream->readUint16LE(); + _soundSlicesCount = _stream->readSint16LE(); if (_soundFreq < 0) _soundFreq = -_soundFreq; @@ -158,10 +161,10 @@ bool Imd::load(Common::SeekableReadStream &stream) { _frameCoords = new Coord[_framesCount]; assert(_frameCoords); for (int i = 0; i < _framesCount; i++) { - _frameCoords[i].left = _stream->readUint16LE(); - _frameCoords[i].top = _stream->readUint16LE(); - _frameCoords[i].right = _stream->readUint16LE(); - _frameCoords[i].bottom = _stream->readUint16LE(); + _frameCoords[i].left = _stream->readSint16LE(); + _frameCoords[i].top = _stream->readSint16LE(); + _frameCoords[i].right = _stream->readSint16LE(); + _frameCoords[i].bottom = _stream->readSint16LE(); } } @@ -186,9 +189,9 @@ void Imd::unload() { void Imd::setXY(int16 x, int16 y) { // Adjusting the standard coordinates if (_stdX != -1) { - if (x != -1) + if (x >= 0) _stdX = _stdX - _x + x; - if (y != -1) + if (y >= 0) _stdY = _stdY - _y + y; } @@ -196,11 +199,11 @@ void Imd::setXY(int16 x, int16 y) { if (_frameCoords) { for (int i = 0; i < _framesCount; i++) { if (_frameCoords[i].left != -1) { - if (x != -1) { + if (x >= 0) { _frameCoords[i].left = _frameCoords[i].left - _x + x; _frameCoords[i].right = _frameCoords[i].right - _x + x; } - if (y != -1) { + if (y >= 0) { _frameCoords[i].top = _frameCoords[i].top - _y + y; _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y; } @@ -208,9 +211,9 @@ void Imd::setXY(int16 x, int16 y) { } } - if (x != -1) + if (x >= 0) _x = x; - if (y != -1) + if (y >= 0) _y = y; } @@ -259,7 +262,7 @@ void Imd::disableSound() { _mixer = 0; } -void Imd::seekFrame(int16 frame, int16 whence, bool restart) { +void Imd::seekFrame(int32 frame, int16 whence, bool restart) { if (!_stream) // Nothing to do return; @@ -272,7 +275,7 @@ void Imd::seekFrame(int16 frame, int16 whence, bool restart) { else if (whence != SEEK_SET) return; - if ((frame >= _framesCount) || (frame == _curFrame)) + if ((frame < 0) || (frame >= _framesCount) || (frame == _curFrame)) // Nothing to do return; @@ -293,7 +296,7 @@ void Imd::seekFrame(int16 frame, int16 whence, bool restart) { error("Frame %d is not directly accessible", frame); // Seek - _stream->seek(framePos, SEEK_SET); + _stream->seek(framePos); _curFrame = frame; } @@ -426,7 +429,7 @@ void Imd::clear(bool del) { _lastFrameTime = 0; } -CoktelVideo::State Imd::processFrame(int16 frame) { +CoktelVideo::State Imd::processFrame(uint16 frame) { State state; uint32 cmd = 0; int16 xBak, yBak, heightBak, widthBak; @@ -440,7 +443,7 @@ CoktelVideo::State Imd::processFrame(int16 frame) { if (frame != _curFrame) { state.flags |= kStateSeeked; - seekFrame(frame, SEEK_SET); + seekFrame(frame); } state.left = xBak = _x; @@ -559,7 +562,7 @@ CoktelVideo::State Imd::processFrame(int16 frame) { // Jump to frame if (cmd == 0xFFFD) { - frame = _stream->readUint16LE(); + frame = _stream->readSint16LE(); if (_framesPos) { _curFrame = frame; _stream->seek(_framesPos[frame], SEEK_SET); @@ -612,7 +615,7 @@ CoktelVideo::State Imd::processFrame(int16 frame) { state.flags |= _frameData[0]; } else - state.flags |= kStateNoData; + state.flags |= kStateNoVideoData; } while (hasNextCmd); @@ -640,95 +643,6 @@ CoktelVideo::State Imd::processFrame(int16 frame) { return state; } -CoktelVideo::State Imd::peekFrame(int16 frame) { - State state; - uint32 posBak; - uint32 tmp; - uint16 cmd; - int16 frameBak; - - if (!_stream) { - state.flags = kStateBreak; - return state; - } - - posBak = _stream->pos(); - frameBak = _curFrame; - - if (_curFrame != frame) { - state.flags |= kStateSeeked; - seekFrame(frame, SEEK_SET); - } - - do { - if (frame != 0) { - if (_stdX != -1) - state.flags |= kStateStdCoords; - if (_frameCoords && (_frameCoords[frame].left != -1)) - state.flags |= kStateFrameCoords; - } - - cmd = _stream->readUint16LE(); - - if ((cmd & 0xFFF8) == 0xFFF0) { - if (cmd == 0xFFF0) { - _stream->seek(2, SEEK_CUR); - cmd = _stream->readUint16LE(); - } - - if (cmd == 0xFFF1) { - state.flags = kStateBreak; - continue; - } else if (cmd == 0xFFF2) { // Skip (16 bit) - cmd = _stream->readUint16LE(); - _stream->seek(cmd, SEEK_CUR); - state.flags = kStateBreak; - continue; - } else if (cmd == 0xFFF3) { // Skip (32 bit) - tmp = _stream->readUint32LE(); - _stream->seek(cmd, SEEK_CUR); - state.flags = kStateBreak; - continue; - } - } - - // Jump to frame - if (cmd == 0xFFFD) { - frame = _stream->readUint16LE(); - if (_framesPos) { - _stream->seek(_framesPos[frame], SEEK_SET); - state.flags |= kStateJump; - continue; - } - break; - } - - // Next sound slice data - if (cmd == 0xFF00) { - _stream->seek(_soundSliceSize, SEEK_CUR); - cmd = _stream->readUint16LE(); - // Initial sound data (all slices) - } else if (cmd == 0xFF01) { - _stream->seek(_soundSliceSize * _soundSlicesCount, SEEK_CUR); - cmd = _stream->readUint16LE(); - } - - // Frame video data - if (cmd != 0) { - _stream->read(_frameData, 5); - state.flags |= _frameData[0]; - } else - state.flags |= kStateNoData; - - break; - - } while (true); - - _stream->seek(posBak, SEEK_SET); - _curFrame = frameBak; - return state; -} - uint32 Imd::renderFrame() { if (!_frameData || (_width <= 0) || (_height <= 0)) return 0; @@ -763,10 +677,10 @@ uint32 Imd::renderFrame() { srcPtr = _vidBuffer; type &= 0x7F; if ((type == 2) && (imdW == sW)) { - frameUncompressor(imdVidMem, dataPtr); + deLZ77(imdVidMem, dataPtr); return retVal; } else - frameUncompressor(srcPtr, dataPtr); + deLZ77(srcPtr, dataPtr); } uint16 pixCount, pixWritten; @@ -845,7 +759,7 @@ uint32 Imd::renderFrame() { return retVal; } -void Imd::frameUncompressor(byte *dest, byte *src) { +void Imd::deLZ77(byte *dest, byte *src) { int i; byte buf[4370]; uint16 chunkLength; @@ -857,7 +771,7 @@ void Imd::frameUncompressor(byte *dest, byte *src) { uint8 chunkCount; bool mode; - frameLength = READ_LE_UINT16(src); + frameLength = READ_LE_UINT32(src); src += 4; if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) { @@ -932,4 +846,345 @@ void Imd::frameUncompressor(byte *dest, byte *src) { } } +Vmd::Vmd() { + clear(false); +} + +Vmd::~Vmd() { + clear(); +} + +bool Vmd::load(Common::SeekableReadStream &stream) { + unload(); + + _stream = &stream; + + uint16 headerLength = _stream->readUint16LE(); + uint16 handle = _stream->readUint16LE(); + _version = _stream->readUint16LE(); + + // Version checking + if ((headerLength != 814) || (handle != 0) || (_version != 1)) { + warning("IMD Version incorrect (%d, %d, %d)", headerLength, handle, _version); + unload(); + return false; + } + + _framesCount = _stream->readUint16LE(); + + warning("# of frames: %d", _framesCount); + + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); + if ((_width != 0) && (_height != 0)) { + _hasVideo = true; + _features |= kFeaturesVideo; + + warning("%dx%d+%d+%d", _width, _height, _x, _y); + + } else + _hasVideo = false; + + _flags = _stream->readUint16LE(); + _partsPerFrame = _stream->readUint16LE(); + _firstFramePos = _stream->readUint32LE(); + uint32 unknown1 = _stream->readUint32LE(); + + warning("flags: %d (0x%X), #parts: %d, firstFramePos: %d, U1: %d (0x%X)", + _flags, _flags, _partsPerFrame, _firstFramePos, unknown1, unknown1); + + _stream->read((byte *) _palette, 768); + + _frameDataSize = _stream->readUint32LE(); + _vidBufferSize = _stream->readUint32LE(); + + if (_hasVideo) { + if (_frameDataSize == 0) + _frameDataSize = _width * _height + 500; + if (_vidBufferSize) + _vidBufferSize = _frameDataSize; + + _frameData = new byte[_frameDataSize]; + assert(_frameData); + memset(_frameData, 0, _frameDataSize); + _vidBuffer = new byte[_vidBufferSize]; + assert(_vidBuffer); + memset(_vidBuffer, 0, _vidBufferSize); + warning("Sizes: frameData: %d, vidBuffer: %d", _frameDataSize, _vidBufferSize); + } + + _soundFreq = _stream->readSint16LE(); + _soundSliceSize = _stream->readUint16LE(); + _soundSlicesCount = _stream->readSint16LE(); + uint16 soundFlags = _stream->readUint16LE(); + _hasSound = (_soundFreq != 0); + + if (_hasSound) { + _features |= kFeaturesSound; + + _soundSliceLength = 1000 / (_soundFreq / _soundSliceSize); + _frameLength = _soundSliceLength; + + _soundStage = 1; + + _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); + + warning("Sound: Freq: %d, # slices %d, slideSize: %d, flags: %d (0x%X), sliceLen = %d", + _soundFreq, _soundSlicesCount, _soundSliceSize, soundFlags, soundFlags, _soundSliceLength); + + } else + _frameLength = 1000 / 12; // 12 FPS for a video without sound + + uint32 frameInfoOffset = _stream->readUint32LE(); + + warning("frameInfoOffset: %d", frameInfoOffset); + + _stream->seek(frameInfoOffset); + _frames = new Frame[_framesCount]; + for (uint16 i = 0; i < _framesCount; i++) { + _frames[i].parts = new Part[_partsPerFrame]; + _stream->skip(2); + _frames[i].offset = _stream->readUint32LE(); + } + for (uint16 i = 0; i < _framesCount; i++) { + for (uint16 j = 0; j < _partsPerFrame; j++) { + _frames[i].parts[j].type = (PartType) _stream->readByte(); + uint16 Unknown3 = _stream->readByte(); + _frames[i].parts[j].size = _stream->readUint32LE(); + if (_frames[i].parts[j].type == kPartTypeAudio) { + _frames[i].parts[j].flags = _stream->readByte(); + _stream->skip(9); + warning("%d.%d (%d): Audio: %d (0x%X), %d (0x%X)", + i, j, _frames[i].parts[j].size, + Unknown3, Unknown3, _frames[i].parts[j].flags, _frames[i].parts[j].flags); + + } else if (_frames[i].parts[j].type == kPartTypeVideo) { + _frames[i].parts[j].left = _stream->readUint16LE(); + _frames[i].parts[j].top = _stream->readUint16LE(); + _frames[i].parts[j].right = _stream->readUint16LE(); + _frames[i].parts[j].bottom = _stream->readUint16LE(); + uint16 Unknown4 = _stream->readByte(); + _frames[i].parts[j].flags = _stream->readByte(); + warning("%d.%d (%d): Video: %d (0x%X), %d+%d+%d+%d, %d (0x%X), %d (0x%X)", + i, j, _frames[i].parts[j].size, + Unknown3, Unknown3, _frames[i].parts[j].left, + _frames[i].parts[j].top, _frames[i].parts[j].right, + _frames[i].parts[j].bottom, Unknown4, Unknown4, + _frames[i].parts[j].flags, _frames[i].parts[j].flags); + + } else { + warning("VMD: Unknown frame part type found (%d.%d: %d, %d)", + i, j, _frames[i].parts[j].type, _frames[i].parts[j].size); + _stream->skip(10); +// unload(); +// return false; + } + } + } + + return true; +} + +void Vmd::unload() { + clear(); +} + +void Vmd::setXY(int16 x, int16 y) { + + for (int i = 0; i < _framesCount; i++) { + for (int j = 0; j < _partsPerFrame; j++) { + + if (_frames[i].parts[j].type == kPartTypeVideo) { + if (x >= 0) { + _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x; + _frames[i].parts[j].right = _frames[i].parts[j].right - _x + x; + } + if (y >= 0) { + _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y; + _frames[i].parts[j].bottom = _frames[i].parts[j].bottom - _y + y; + } + } + + } + } + + if (x >= 0) + _x = x; + if (y >= 0) + _y = y; +} + +void Vmd::seekFrame(int32 frame, int16 whence, bool restart) { + if (!_stream) + // Nothing to do + return; + + // Find the frame to which to seek + if (whence == SEEK_CUR) + frame += _curFrame; + else if (whence == SEEK_END) + frame = _framesCount - frame - 1; + else if (whence != SEEK_SET) + return; + + if ((frame < 0) || (frame >= _framesCount)) + // Nothing to do + return; + + // Seek + _stream->seek(_frames[frame].offset); + _curFrame = frame; +} + +CoktelVideo::State Vmd::nextFrame() { + State state; + + state = processFrame(_curFrame); + _curFrame++; + return state; +} + +void Vmd::clear(bool del) { + Imd::clear(del); + + if (del) { + delete[] _frames; + } + + _hasVideo = true; + _partsPerFrame = 0; + _frames = 0; +} + +CoktelVideo::State Vmd::processFrame(uint16 frame) { + State state; + int16 xBak, yBak, heightBak, widthBak; + bool startSound = false; + + seekFrame(frame); + + state.flags |= kStateNoVideoData; + state.left = -1; + + for (uint16 i = 0; i < _partsPerFrame; i++) { + Part &part = _frames[frame].parts[i]; + + if (part.type == kPartTypeAudio) { + byte *soundBuf; + + // Next sound slice data + if (part.flags == 1) { + + if (_soundEnabled) { + soundBuf = new byte[part.size]; + assert(soundBuf); + + _stream->read(soundBuf, part.size); + unsignedToSigned(soundBuf, part.size); + + _audioStream->queueBuffer(soundBuf, part.size); + } else + _stream->skip(part.size); + + // Initial sound data (all slices) + } else if (part.flags == 2) { + + if (_soundEnabled) { + uint32 U = _stream->readUint32LE(); + + warning("Mask? %d (0x%X)", U, U); + + soundBuf = new byte[part.size - 4]; + assert(soundBuf); + + _stream->read(soundBuf, part.size - 4); + unsignedToSigned(soundBuf, part.size - 4); + + _audioStream->queueBuffer(soundBuf, part.size - 4); + + if (_soundStage == 1) { + startSound = true; + } + + } else + _stream->skip(part.size); + + // Empty sound slice + } else if (part.flags == 3) { + + if (_soundEnabled && (part.size > 0)) { + soundBuf = new byte[part.size]; + assert(soundBuf); + + memset(soundBuf, 0, part.size); + + _audioStream->queueBuffer(soundBuf, part.size); + } else + _stream->skip(part.size); + } + + } else if (part.type == kPartTypeVideo) { + state.flags &= ~kStateNoVideoData; + + if (state.left == -1) { + state.left = _x = part.left; + state.top = _y = part.top; + state.right = _width = part.right; + state.bottom = _height = part.bottom; + _width -= _x - 1; + _height -= _y - 1; + } else { + _x = part.left; + _y = part.top; + _width = part.right - (_x - 1); + _height = part.bottom - (_y - 1); + state.left = MIN(state.left, part.left); + state.top = MIN(state.top, part.top); + state.right = MAX(state.right, part.right); + state.bottom = MAX(state.bottom, part.bottom); + } + + if (part.flags & 2) { + uint8 index = _stream->readByte(); + uint8 count = _stream->readByte(); + + _stream->read(_palette + index * 3, count + 1); + _stream->skip((255 - count) * 3); + + state.flags |= kStatePalette; + } + + _stream->read(_frameData, part.size); + state.flags |= renderFrame(); + } else { + warning("Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame); + _stream->skip(part.size); + } + } + + if (startSound && _soundEnabled) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream); + _soundStartTime = g_system->getMillis(); + _skipFrames = 0; + _soundStage = 2; + } + + _x = xBak; + _y = yBak; + _width = widthBak; + _height = heightBak; + + if ((_curFrame == (_framesCount - 1)) && (_soundStage == 2)) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + _audioStream = 0; + _soundStage = 0; + } + + _lastFrameTime = g_system->getMillis(); + return state; +} + } // End of namespace Gob |