[Scummvm-cvs-logs] SF.net SVN: scummvm:[51865] scummvm/trunk

drmccoy at users.sourceforge.net drmccoy at users.sourceforge.net
Sun Aug 8 02:41:56 CEST 2010


Revision: 51865
          http://scummvm.svn.sourceforge.net/scummvm/?rev=51865&view=rev
Author:   drmccoy
Date:     2010-08-08 00:41:56 +0000 (Sun, 08 Aug 2010)

Log Message:
-----------
VIDEO/GOB: Implement IMD loading

Modified Paths:
--------------
    scummvm/trunk/engines/gob/videoplayer.cpp
    scummvm/trunk/graphics/video/coktel_decoder.cpp
    scummvm/trunk/graphics/video/coktel_decoder.h

Modified: scummvm/trunk/engines/gob/videoplayer.cpp
===================================================================
--- scummvm/trunk/engines/gob/videoplayer.cpp	2010-08-08 00:41:22 UTC (rev 51864)
+++ scummvm/trunk/engines/gob/videoplayer.cpp	2010-08-08 00:41:56 UTC (rev 51865)
@@ -156,9 +156,12 @@
 			video->decoder->setSurfaceMemory(video->surface->getVidMem(),
 					video->surface->getWidth(), video->surface->getHeight(), 1);
 
-			if (!ownSurf || (ownSurf && screenSize))
-				video->decoder->setXY(properties.x, properties.y);
-			else
+			if (!ownSurf || (ownSurf && screenSize)) {
+				if ((properties.x >= 0) && (properties.y >= 0))
+					video->decoder->setXY(properties.x, properties.y);
+				else
+					video->decoder->setXY();
+			} else
 				video->decoder->setXY(0, 0);
 		}
 
@@ -172,7 +175,8 @@
 	if (primary)
 		_needBlit = (properties.flags & kFlagUseBackSurfaceContent) && (properties.sprite == Draw::kFrontSurface);
 
-	video->decoder->setFrameRate(_vm->_util->getFrameRate());
+	if (!video->decoder->hasSound())
+		video->decoder->setFrameRate(_vm->_util->getFrameRate());
 
 	WRITE_VAR(7, video->decoder->getFrameCount());
 

Modified: scummvm/trunk/graphics/video/coktel_decoder.cpp
===================================================================
--- scummvm/trunk/graphics/video/coktel_decoder.cpp	2010-08-08 00:41:22 UTC (rev 51864)
+++ scummvm/trunk/graphics/video/coktel_decoder.cpp	2010-08-08 00:41:56 UTC (rev 51865)
@@ -27,6 +27,8 @@
 
 #ifdef GRAPHICS_VIDEO_COKTELDECODER_H
 
+#include "sound/audiostream.h"
+
 namespace Graphics {
 
 CoktelDecoder::State::State() : flags(0), speechId(0) {
@@ -34,8 +36,10 @@
 
 
 CoktelDecoder::CoktelDecoder(Audio::Mixer &mixer, Audio::Mixer::SoundType soundType) :
-	_mixer(&mixer), _soundType(soundType), _width(0), _height(0), _x(0), _y(0), _frameCount(0),
-	_paletteDirty(false), _ownSurface(true), _frameRate(12) {
+	_mixer(&mixer), _soundType(soundType), _width(0), _height(0), _x(0), _y(0),
+	_defaultX(0), _defaultY(0), _features(0), _frameCount(0), _paletteDirty(false),
+	_ownSurface(true), _frameRate(12), _hasSound(false), _soundEnabled(false),
+	_soundStage(kSoundNone), _audioStream(0) {
 
 	memset(_palette, 0, 768);
 }
@@ -97,21 +101,85 @@
 	_y = y;
 }
 
+void CoktelDecoder::setXY() {
+	setXY(_defaultX, _defaultY);
+}
+
 void CoktelDecoder::setFrameRate(Common::Rational frameRate) {
 	_frameRate = frameRate;
 }
 
+uint16 CoktelDecoder::getDefaultX() const {
+	return _defaultX;
+}
+
+uint16 CoktelDecoder::getDefaultY() const {
+	return _defaultY;
+}
+
 const Common::List<Common::Rect> &CoktelDecoder::getDirtyRects() const {
 	return _dirtyRects;
 }
 
+bool CoktelDecoder::hasSound() const {
+	return _hasSound;
+}
+
+bool CoktelDecoder::isSoundEnabled() const {
+	return _soundEnabled;
+}
+
+bool CoktelDecoder::isSoundPlaying() const {
+	return _audioStream && _mixer->isSoundHandleActive(_audioHandle);
+}
+
+void CoktelDecoder::enableSound() {
+	if (!hasSound() || isSoundEnabled())
+		return;
+
+	// Sanity check
+	if (_mixer->getOutputRate() == 0)
+		return;
+
+	// Only possible on the first frame
+	if (_curFrame > -1)
+		return;
+
+	_soundEnabled = true;
+}
+
+void CoktelDecoder::disableSound() {
+	if (_audioStream) {
+
+		if (_soundStage == kSoundPlaying) {
+			_audioStream->finish();
+			_mixer->stopHandle(_audioHandle);
+		} else
+			delete _audioStream;
+
+	}
+
+	_soundEnabled = false;
+	_soundStage   = kSoundNone;
+
+	_audioStream  = 0;
+}
+
 void CoktelDecoder::close() {
+	disableSound();
 	freeSurface();
 
 	_x = 0;
 	_y = 0;
 
+	_defaultX = 0;
+	_defaultY = 0;
+
+	_features = 0;
+
 	_frameCount = 0;
+
+	_hasSound = false;
 }
 
 uint16 CoktelDecoder::getWidth() const {
@@ -131,7 +199,7 @@
 }
 
 bool CoktelDecoder::hasDirtyPalette() const {
-	return _paletteDirty;
+	return (_features & kFeaturesPalette) && _paletteDirty;
 }
 
 Common::Rational CoktelDecoder::getFrameRate() const {
@@ -237,8 +305,6 @@
 	processFrame();
 	renderFrame();
 
-	_curFrame++;
-
 	if (_curFrame == 0)
 		_startTime = g_system->getMillis();
 
@@ -307,6 +373,8 @@
 	}
 
 	_stream->seek(nextFramePos);
+
+	_curFrame++;
 }
 
 void PreIMDDecoder::renderFrame() {
@@ -340,7 +408,12 @@
 
 
 IMDDecoder::IMDDecoder(Audio::Mixer &mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType),
-	_stream(0), _videoBuffer(0), _videoBufferSize(0) {
+	_stream(0), _version(0), _stdX(-1), _stdY(-1), _stdWidth(-1), _stdHeight(-1),
+	_flags(0), _firstFramePos(0), _framePos(0), _frameCoords(0),
+	_frameData(0), _frameDataSize(0), _frameDataLen(0),
+	_videoBuffer(0), _videoBufferSize(0),
+	_soundFlags(0), _soundFreq(0), _soundSliceSize(0), _soundSlicesCount(0) {
+
 }
 
 IMDDecoder::~IMDDecoder() {
@@ -370,8 +443,38 @@
 		// Nothing to do
 		return true;
 
-	// TODO
+	// Try every possible way to find a file offset to that frame
+	uint32 framePos = 0;
+	if (frame == -1) {
 
+		framePos = _firstFramePos;
+
+	} else if (frame == 0) {
+
+		framePos = _firstFramePos;
+		_stream->seek(framePos);
+		framePos += _stream->readUint16LE() + 4;
+
+	} else if (_framePos) {
+
+		framePos = _framePos[frame + 1];
+
+	} else if (restart && (_soundStage == kSoundNone)) {
+
+		for (int i = ((frame > _curFrame) ? _curFrame : 0); i <= frame; i++)
+			processFrame();
+
+		return true;
+
+	} else {
+		warning("Imd::seek(): Frame %d is not directly accessible", frame + 1);
+		return false;
+	}
+
+	// Seek
+	_stream->seek(framePos);
+	_curFrame = frame;
+
 	return true;
 }
 
@@ -380,13 +483,194 @@
 
 	_stream = &stream;
 
-	warning("IMDDecoder::load()");
+	uint16 handle;
 
-	// TODO
+	handle   = _stream->readUint16LE();
+	_version = _stream->readByte();
 
-	return false;
+	// Version checking
+	if ((handle != 0) || (_version < 2)) {
+		warning("IMDDecoder::load(): Version incorrect (%d, 0x%X)", handle, _version);
+		close();
+		return false;
+	}
+
+	// Rest header
+	_features      = _stream->readByte();
+	_frameCount    = _stream->readUint16LE();
+	_defaultX      = _stream->readSint16LE();
+	_defaultY      = _stream->readSint16LE();
+	_width         = _stream->readSint16LE();
+	_height        = _stream->readSint16LE();
+	_flags         = _stream->readUint16LE();
+	_firstFramePos = _stream->readUint16LE();
+
+	_x = _defaultX;
+	_y = _defaultY;
+
+	// IMDs always have video
+	_features |= kFeaturesVideo;
+	// IMDs always have palettes
+	_features |= kFeaturesPalette;
+
+	// Palette
+	_stream->read((byte *) _palette, 768);
+
+	_paletteDirty = true;
+
+	if (!loadCoordinates()) {
+		close();
+		return false;
+	}
+
+	uint32 framePosPos, frameCoordsPos;
+	if (!loadFrameTableOffsets(framePosPos, frameCoordsPos)) {
+		close();
+		return false;
+	}
+
+	if (!assessAudioProperties()) {
+		close();
+		return false;
+	}
+
+	if (!assessVideoProperties()) {
+		close();
+		return false;
+	}
+
+	if (!loadFrameTables(framePosPos, frameCoordsPos)) {
+		close();
+		return false;
+	}
+
+	// Seek to the first frame
+	_stream->seek(_firstFramePos);
+
+	return true;
 }
 
+bool IMDDecoder::loadCoordinates() {
+	// Standard coordinates
+	if (_version >= 3) {
+		uint16 count = _stream->readUint16LE();
+		if (count > 1) {
+			warning("IMD: More than one standard coordinate quad found (%d)", count );
+			return false;
+		}
+
+		if (count != 0) {
+			_stdX      = _stream->readSint16LE();
+			_stdY      = _stream->readSint16LE();
+			_stdWidth  = _stream->readSint16LE();
+			_stdHeight = _stream->readSint16LE();
+			_features |= kFeaturesStdCoords;
+		} else
+			_stdX = _stdY = _stdWidth = _stdHeight = -1;
+
+	} else
+		_stdX = _stdY = _stdWidth = _stdHeight = -1;
+
+	return true;
+}
+
+bool IMDDecoder::loadFrameTableOffsets(uint32 &framePosPos, uint32 &frameCoordsPos) {
+	framePosPos    = 0;
+	frameCoordsPos = 0;
+
+	// Frame positions
+	if (_version >= 4) {
+		framePosPos = _stream->readUint32LE();
+		if (framePosPos != 0) {
+			_framePos  = new uint32[_frameCount];
+			_features |= kFeaturesFramePos;
+		}
+	}
+
+	// Frame coordinates
+	if (_features & kFeaturesFrameCoords)
+		frameCoordsPos = _stream->readUint32LE();
+
+	return true;
+}
+
+bool IMDDecoder::assessVideoProperties() {
+	// Sizes of the frame data and extra video buffer
+	if (_features & kFeaturesDataSize) {
+		_frameDataSize = _stream->readUint16LE();
+		if (_frameDataSize == 0) {
+			_frameDataSize   = _stream->readUint32LE();
+			_videoBufferSize = _stream->readUint32LE();
+		} else
+			_videoBufferSize = _stream->readUint16LE();
+	} else {
+		_frameDataSize = _width * _height + 500;
+		if (!(_flags & 0x100) || (_flags & 0x1000))
+			_videoBufferSize = _frameDataSize;
+	}
+
+	// Allocating working memory
+	_frameData = new byte[_frameDataSize + 500];
+	memset(_frameData, 0, _frameDataSize + 500);
+
+	_videoBuffer = new byte[_videoBufferSize + 500];
+	memset(_videoBuffer, 0, _videoBufferSize + 500);
+
+	return true;
+}
+
+bool IMDDecoder::assessAudioProperties() {
+	if (_features & kFeaturesSound) {
+		_soundFreq        = _stream->readSint16LE();
+		_soundSliceSize   = _stream->readSint16LE();
+		_soundSlicesCount = _stream->readSint16LE();
+
+		if (_soundFreq < 0)
+			_soundFreq = -_soundFreq;
+
+		if (_soundSlicesCount < 0)
+			_soundSlicesCount = -_soundSlicesCount - 1;
+
+		if (_soundSlicesCount > 40) {
+			warning("IMDDecoder::assessAudioProperties(): More than 40 sound slices found (%d)", _soundSlicesCount);
+			return false;
+		}
+
+		_frameRate = Common::Rational(_soundFreq) / _soundSliceSize;
+
+		_hasSound   = true;
+		_soundStage = kSoundLoaded;
+
+		_audioStream = Audio::makeQueuingAudioStream(_soundFreq, false);
+	}
+
+	return true;
+}
+
+bool IMDDecoder::loadFrameTables(uint32 framePosPos, uint32 frameCoordsPos) {
+	// Positions table
+	if (_framePos) {
+		_stream->seek(framePosPos);
+		for (uint32 i = 0; i < _frameCount; i++)
+			_framePos[i] = _stream->readUint32LE();
+	}
+
+	// Coordinates table
+	if (_features & kFeaturesFrameCoords) {
+		_stream->seek(frameCoordsPos);
+		_frameCoords = new Coord[_frameCount];
+		assert(_frameCoords);
+		for (uint32 i = 0; i < _frameCount; i++) {
+			_frameCoords[i].left   = _stream->readSint16LE();
+			_frameCoords[i].top    = _stream->readSint16LE();
+			_frameCoords[i].right  = _stream->readSint16LE();
+			_frameCoords[i].bottom = _stream->readSint16LE();
+		}
+	}
+
+	return true;
+}
+
 void IMDDecoder::close() {
 	reset();
 
@@ -394,12 +678,43 @@
 
 	delete _stream;
 
+	delete[] _framePos;
+	delete[] _frameCoords;
+
+	delete[] _frameData;
+
 	delete[] _videoBuffer;
 
 	_stream = 0;
 
+	_version = 0;
+
+	_stdX      = -1;
+	_stdY      = -1;
+	_stdWidth  = -1;
+	_stdHeight = -1;
+
+	_flags         = 0;
+
+	_firstFramePos = 0;
+	_framePos      = 0;
+	_frameCoords   = 0;
+
+	_frameData     = 0;
+	_frameDataSize = 0;
+	_frameDataLen  = 0;
+
 	_videoBuffer     = 0;
 	_videoBufferSize = 0;
+
+	_soundFlags       = 0;
+	_soundFreq        = 0;
+	_soundSliceSize   = 0;
+	_soundSlicesCount = 0;
+
+	_hasSound     = false;
+	_soundEnabled = false;
+	_soundStage   = kSoundNone;
 }
 
 bool IMDDecoder::isVideoLoaded() const {
@@ -415,8 +730,6 @@
 	processFrame();
 	renderFrame();
 
-	_curFrame++;
-
 	if (_curFrame == 0)
 		_startTime = g_system->getMillis();
 
@@ -424,13 +737,18 @@
 }
 
 void IMDDecoder::processFrame() {
+
 	// TODO
+
+	_curFrame++;
 }
 
 void IMDDecoder::renderFrame() {
 	_dirtyRects.clear();
 
 	// TODO
+
+	_dirtyRects.push_back(Common::Rect(_x, _y, _x + _width, _y + _height));
 }
 
 PixelFormat IMDDecoder::getPixelFormat() const {

Modified: scummvm/trunk/graphics/video/coktel_decoder.h
===================================================================
--- scummvm/trunk/graphics/video/coktel_decoder.h	2010-08-08 00:41:22 UTC (rev 51864)
+++ scummvm/trunk/graphics/video/coktel_decoder.h	2010-08-08 00:41:56 UTC (rev 51865)
@@ -40,6 +40,10 @@
 
 #include "sound/mixer.h"
 
+namespace Audio {
+	class QueuingAudioStream;
+}
+
 namespace Graphics {
 
 class CoktelDecoder : public FixedRateVideoDecoder {
@@ -65,14 +69,28 @@
 	void setSurfaceMemory();
 
 	/** Draw the video starting at this position within the video memory. */
-	void setXY(uint16 x, uint16 y);
+	virtual void setXY(uint16 x, uint16 y);
+	/** Draw the video at the default position. */
+	void setXY();
 
 	/** Override the video's frame rate. */
 	void setFrameRate(Common::Rational frameRate);
 
+	/** Get the video's default X position. */
+	uint16 getDefaultX() const;
+	/** Get the video's default Y position. */
+	uint16 getDefaultY() const;
+
 	/** Return a list of rectangles that changed in the last frame. */
 	const Common::List<Common::Rect> &getDirtyRects() const;
 
+	bool hasSound()       const;
+	bool isSoundEnabled() const;
+	bool isSoundPlaying() const;
+
+	void enableSound();
+	void disableSound();
+
 	// VideoDecoder interface
 
 	void close();
@@ -86,6 +104,23 @@
 	bool  hasDirtyPalette() const;
 
 protected:
+	enum SoundStage {
+		kSoundNone    = 0, ///< No sound.
+		kSoundLoaded  = 1, ///< Sound loaded.
+		kSoundPlaying = 2  ///< Sound is playing.
+	};
+
+	enum Features {
+		kFeaturesNone        = 0x0000,
+		kFeaturesPalette     = 0x0008, ///< Has an own palette.
+		kFeaturesDataSize    = 0x0020, ///< Suggests a data size.
+		kFeaturesSound       = 0x0040, ///< Has sound.
+		kFeaturesFrameCoords = 0x0080, ///< Has specific frame coordinates.
+		kFeaturesStdCoords   = 0x0100, ///< Has general standard coordinates.
+		kFeaturesFramePos    = 0x0200, ///< Has a frame positions table.
+		kFeaturesVideo       = 0x0400  ///< Has video.
+	};
+
 	Audio::Mixer *_mixer;
 	Audio::Mixer::SoundType _soundType;
 
@@ -95,6 +130,11 @@
 	uint16 _x;
 	uint16 _y;
 
+	uint16 _defaultX;
+	uint16 _defaultY;
+
+	uint32 _features;
+
 	uint32 _frameCount;
 
 	byte _palette[768];
@@ -107,6 +147,14 @@
 
 	Common::Rational _frameRate;
 
+	// Current sound state
+	bool       _hasSound;
+	bool       _soundEnabled;
+	SoundStage _soundStage;
+
+	Audio::QueuingAudioStream *_audioStream;
+	Audio::SoundHandle _audioHandle;
+
 	bool hasSurface();
 	void createSurface();
 	void freeSurface();
@@ -137,6 +185,7 @@
 private:
 	Common::SeekableReadStream *_stream;
 
+	// Buffer for processed frame data
 	byte  *_videoBuffer;
 	uint32 _videoBufferSize;
 
@@ -163,11 +212,66 @@
 	PixelFormat getPixelFormat() const;
 
 private:
+	enum Command {
+		kCommandNextSound   = 0xFF00,
+		kCommandStartSound  = 0xFF01,
+
+		kCommandBreak       = 0xFFF0,
+		kCommandBreakSkip0  = 0xFFF1,
+		kCommandBreakSkip16 = 0xFFF2,
+		kCommandBreakSkip32 = 0xFFF3,
+		kCommandBreakMask   = 0xFFF8,
+
+		kCommandPalette     = 0xFFF4,
+		kCommandVideoData   = 0xFFFC,
+
+		kCommandJump        = 0xFFFD
+	};
+
+	struct Coord {
+		int16 left;
+		int16 top;
+		int16 right;
+		int16 bottom;
+	};
+
 	Common::SeekableReadStream *_stream;
 
+	byte _version;
+
+	// Standard coordinates gives by the header
+	int16 _stdX;
+	int16 _stdY;
+	int16 _stdWidth;
+	int16 _stdHeight;
+
+	uint32 _flags;
+
+	uint32  _firstFramePos; ///< Position of the first frame's data within the stream.
+	uint32 *_framePos;      ///< Positions of all frames.
+	Coord  *_frameCoords;   ///< Coordinates of all frames.
+
+	// Buffer for raw frame data
+	byte  *_frameData;
+	uint32 _frameDataSize;
+	uint32 _frameDataLen;
+
+	// Buffer for processed frame data
 	byte  *_videoBuffer;
 	uint32 _videoBufferSize;
 
+	// Sound properties
+	uint16 _soundFlags;
+	 int16 _soundFreq;
+	 int16 _soundSliceSize;
+	 int16 _soundSlicesCount;
+
+	bool loadCoordinates();
+	bool loadFrameTableOffsets(uint32 &framePosPos, uint32 &frameCoordsPos);
+	bool assessVideoProperties();
+	bool assessAudioProperties();
+	bool loadFrameTables(uint32 framePosPos, uint32 frameCoordsPos);
+
 	void processFrame();
 	void renderFrame();
 };


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list