aboutsummaryrefslogtreecommitdiff
path: root/engines/gob/coktelvideo.cpp
diff options
context:
space:
mode:
authorSven Hesse2007-07-31 18:16:33 +0000
committerSven Hesse2007-07-31 18:16:33 +0000
commit2e9ca7bf85cdaf71f009c689a0aae6cd14e8f710 (patch)
treea379cd851af49d7d2d3df30837d25d54fdfa567a /engines/gob/coktelvideo.cpp
parentcd20f09a9d8085d1082313fd1d58c87deeb30333 (diff)
downloadscummvm-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.cpp497
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