[Scummvm-cvs-logs] SF.net SVN: scummvm:[49081] scummvm/trunk/engines/mohawk/video

mthreepwood at users.sourceforge.net mthreepwood at users.sourceforge.net
Tue May 18 16:59:20 CEST 2010


Revision: 49081
          http://scummvm.svn.sourceforge.net/scummvm/?rev=49081&view=rev
Author:   mthreepwood
Date:     2010-05-18 14:59:20 +0000 (Tue, 18 May 2010)

Log Message:
-----------
Have QTPlayer inherit from VideoDecoder. The video downscaling (QuickTime is insane) has also been moved to the QTPlayer class.

Modified Paths:
--------------
    scummvm/trunk/engines/mohawk/video/qt_player.cpp
    scummvm/trunk/engines/mohawk/video/qt_player.h
    scummvm/trunk/engines/mohawk/video/video.cpp

Modified: scummvm/trunk/engines/mohawk/video/qt_player.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/video/qt_player.cpp	2010-05-18 14:57:02 UTC (rev 49080)
+++ scummvm/trunk/engines/mohawk/video/qt_player.cpp	2010-05-18 14:59:20 UTC (rev 49081)
@@ -56,36 +56,38 @@
 // QTPlayer
 ////////////////////////////////////////////
 
-QTPlayer::QTPlayer() {
+QTPlayer::QTPlayer() : Graphics::VideoDecoder() {
 	_audStream = NULL;
 	_beginOffset = 0;
 	_videoCodec = NULL;
-	_noCodecFound = false;
 	_curFrame = -1;
-	_lastFrameStart = _nextFrameStart = 0;
+	_startTime = _nextFrameStartTime = 0;
 	_audHandle = Audio::SoundHandle();
 	_numStreams = 0;
+	_fd = 0;
+	_scaledSurface = 0;
+	_dirtyPalette = false;
 }
 
 QTPlayer::~QTPlayer() {
-	stop();
+	close();
 }
 
-uint16 QTPlayer::getWidth() {
+uint16 QTPlayer::getWidth() const {
 	if (_videoStreamIndex < 0)
 		return 0;
 
-	return _streams[_videoStreamIndex]->width;
+	return _streams[_videoStreamIndex]->width / getScaleMode();
 }
 
-uint16 QTPlayer::getHeight() {
+uint16 QTPlayer::getHeight() const {
 	if (_videoStreamIndex < 0)
 		return 0;
 
-	return _streams[_videoStreamIndex]->height;
+	return _streams[_videoStreamIndex]->height / getScaleMode();
 }
 
-uint32 QTPlayer::getFrameCount() {
+uint32 QTPlayer::getFrameCount() const {
 	if (_videoStreamIndex < 0)
 		return 0;
 
@@ -106,7 +108,7 @@
 	return _streams[_videoStreamIndex]->codec_tag;
 }
 
-ScaleMode QTPlayer::getScaleMode() {
+ScaleMode QTPlayer::getScaleMode() const {
 	if (_videoStreamIndex < 0)
 		return kScaleNormal;
 
@@ -121,8 +123,8 @@
 	for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count; i++) {
 		curFrameIndex += _streams[_videoStreamIndex]->stts_data[i].count;
 		if ((uint32)_curFrame < curFrameIndex) {
-			// Ok, now we have what duration this frame has. Now, we have to convert the duration to 1/100 ms.
-			return _streams[_videoStreamIndex]->stts_data[i].duration * 1000 * 100 / _streams[_videoStreamIndex]->time_scale;
+			// Ok, now we have what duration this frame has.
+			return _streams[_videoStreamIndex]->stts_data[i].duration;
 		}
 	}
 
@@ -131,20 +133,17 @@
 	return 0;
 }
 
-void QTPlayer::stop() {
-	stopAudio();
+Graphics::PixelFormat QTPlayer::getPixelFormat() const {
+	if (!_videoCodec)
+		return Graphics::PixelFormat::createFormatCLUT8();
 
-	if (!_noCodecFound)
-		delete _videoCodec;
-
-	closeFile();
+	return _videoCodec->getPixelFormat();
 }
 
-void QTPlayer::reset() {
+void QTPlayer::rewind() {
 	delete _videoCodec; _videoCodec = NULL;
-	_noCodecFound = false;
 	_curFrame = -1;
-	_lastFrameStart = _nextFrameStart = 0;
+	_startTime = _nextFrameStartTime = 0;
 
 	// Restart the audio too
 	stopAudio();
@@ -207,57 +206,82 @@
 	_audStream = NULL; // the mixer automatically frees the stream
 }
 
-Graphics::Surface *QTPlayer::getNextFrame() {
-	if (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1)
+Graphics::Surface *QTPlayer::decodeNextFrame() {
+	if (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1)
 		return NULL;
 
-	if (_nextFrameStart == 0)
-		_nextFrameStart = g_system->getMillis() * 100;
+	if (_startTime == 0)
+		_startTime = g_system->getMillis();
 
-	_lastFrameStart = _nextFrameStart;
 	_curFrame++;
-	_nextFrameStart = getFrameDuration() + _lastFrameStart;
+	_nextFrameStartTime += getFrameDuration();
 
 	Common::SeekableReadStream *frameData = getNextFramePacket();
 
-	if (!_videoCodec) {
-		_videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
-		// If we don't get it still, the codec is unsupported ;)
-		if (!_videoCodec) {
-			_noCodecFound = true;
-			return NULL;
-		}
-	}
-
 	if (frameData) {
 		Graphics::Surface *frame = _videoCodec->decodeImage(frameData);
 		delete frameData;
-		return frame;
+		return scaleSurface(frame);
 	}
 
 	return NULL;
 }
 
-bool QTPlayer::endOfVideo() {
-	return (!_audStream || _audStream->endOfData()) && (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1);
+Graphics::Surface *QTPlayer::scaleSurface(Graphics::Surface *frame) {
+	if (getScaleMode() == kScaleNormal)
+		return frame;
+
+	assert(_scaledSurface);
+
+	for (uint32 j = 0; j < _scaledSurface->h; j++)
+		for (uint32 k = 0; k < _scaledSurface->w; k++)
+			memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr(k * getScaleMode(), j * getScaleMode()), frame->bytesPerPixel);
+
+	return _scaledSurface;
 }
 
-bool QTPlayer::needsUpdate() {
-	if (endOfVideo())
-		return false;
+bool QTPlayer::endOfVideo() const {
+	return (!_audStream || _audStream->endOfData()) && (!_videoCodec || _curFrame >= (int32)getFrameCount() - 1);
+}
 
-	if (_curFrame == -1)
-		return true;
+void QTPlayer::addPauseTime(uint32 p) {
+	Graphics::VideoDecoder::addPauseTime(p);
+	if (_videoStreamIndex >= 0)
+		_nextFrameStartTime += p * _streams[_videoStreamIndex]->time_scale / 1000;
+}
 
-	return (g_system->getMillis() * 100 - _lastFrameStart) >= getFrameDuration();
+bool QTPlayer::needsUpdate() const {
+	return !endOfVideo() && getTimeToNextFrame() == 0;
 }
 
-bool QTPlayer::loadFile(Common::SeekableReadStream *stream) {
-	_fd = stream;
+uint32 QTPlayer::getElapsedTime() const {
+	if (_audStream)
+		return g_system->getMixer()->getSoundElapsedTime(_audHandle);
+
+	return g_system->getMillis() - _startTime;
+}
+
+uint32 QTPlayer::getTimeToNextFrame() const {
+	if (endOfVideo() || _curFrame < 0)
+		return 0;
+
+	// Convert from the Sega FILM base to 1000
+	uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _streams[_videoStreamIndex]->time_scale;
+	uint32 elapsedTime = getElapsedTime();
+
+	if (nextFrameStartTime <= elapsedTime)
+		return 0;
+
+	return nextFrameStartTime - elapsedTime;
+}
+
+bool QTPlayer::load(Common::SeekableReadStream &stream) {
+	_fd = &stream;
 	_foundMOOV = _foundMDAT = false;
 	_numStreams = 0;
 	_partial = 0;
 	_videoStreamIndex = _audioStreamIndex = -1;
+	_startTime = 0;
 
 	initParseTable();
 
@@ -313,8 +337,20 @@
 		// Make sure the bits per sample transfers to the sample size
 		if (_streams[_audioStreamIndex]->codec_tag == MKID_BE('raw ') || _streams[_audioStreamIndex]->codec_tag == MKID_BE('twos'))
 			_streams[_audioStreamIndex]->sample_size = (_streams[_audioStreamIndex]->bits_per_sample / 8) * _streams[_audioStreamIndex]->channels;
+
+		startAudio();
 	}
 
+	if (_videoStreamIndex >= 0) {
+		_videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
+
+		if (getScaleMode() != kScaleNormal) {
+			// We have to initialize the scaled surface
+			_scaledSurface = new Graphics::Surface();
+			_scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel);
+		}
+	}
+
 	return true;
 }
 
@@ -785,6 +821,8 @@
 
 			// if the depth is 2, 4, or 8 bpp, file is palettized
 			if (colorDepth == 2 || colorDepth == 4 || colorDepth == 8) {
+				_dirtyPalette = true;
+
 				if (colorGreyscale) {
 					debug(0, "Greyscale palette");
 
@@ -1078,14 +1116,26 @@
 	return 0;
 }
 
-void QTPlayer::closeFile() {
+void QTPlayer::close() {
+	stopAudio();
+
+	delete _videoCodec; _videoCodec = 0;
+
 	for (uint32 i = 0; i < _numStreams; i++)
 		delete _streams[i];
 
 	delete _fd;
 
+	if (_scaledSurface) {
+		_scaledSurface->free();
+		delete _scaledSurface;
+		_scaledSurface = 0;
+	}
+
 	// The audio stream is deleted automatically
 	_audStream = NULL;
+
+	Graphics::VideoDecoder::reset();
 }
 
 Common::SeekableReadStream *QTPlayer::getNextFramePacket() {

Modified: scummvm/trunk/engines/mohawk/video/qt_player.h
===================================================================
--- scummvm/trunk/engines/mohawk/video/qt_player.h	2010-05-18 14:57:02 UTC (rev 49080)
+++ scummvm/trunk/engines/mohawk/video/qt_player.h	2010-05-18 14:59:20 UTC (rev 49081)
@@ -36,7 +36,10 @@
 
 #include "common/scummsys.h"
 #include "common/queue.h"
+
+#include "graphics/video/video_decoder.h"
 #include "graphics/video/codecs/codec.h"
+
 #include "sound/audiostream.h"
 #include "sound/mixer.h"
 
@@ -52,7 +55,7 @@
 	kScaleQuarter = 4
 };
 
-class QTPlayer {
+class QTPlayer : public Graphics::VideoDecoder {
 public:
 	QTPlayer();
 	virtual ~QTPlayer();
@@ -61,54 +64,37 @@
 	 * Returns the width of the video
 	 * @return the width of the video
 	 */
-	uint16 getWidth();
+	uint16 getWidth() const;
 
 	/**
 	 * Returns the height of the video
 	 * @return the height of the video
 	 */
-	uint16 getHeight();
+	uint16 getHeight() const;
 
 	/**
 	 * Returns the amount of frames in the video
 	 * @return the amount of frames in the video
 	 */
-	uint32 getFrameCount();
+	uint32 getFrameCount() const;
 
 	/**
-	 * Returns the bits per pixel of the video
-	 * @return the bits per pixel of the video
-	 */
-	byte getBitsPerPixel();
-
-	/**
-	 * Returns the codec tag of the video
-	 * @return the codec tag of the video
-	 */
-	uint32 getCodecTag();
-
-	/**
 	 * Load a QuickTime video file from a SeekableReadStream
 	 * @param stream	the stream to load
 	 */
-	bool loadFile(Common::SeekableReadStream* stream);
+	bool load(Common::SeekableReadStream &stream);
 
 	/**
 	 * Close a QuickTime encoded video file
 	 */
-	void closeFile();
+	void close();
 
 	/**
-	 * Returns the downscale mode of the video
-	 * @return the downscale mode of the video
-	 */
-	ScaleMode getScaleMode();
-
-	/**
 	 * Returns the palette of the video
 	 * @return the palette of the video
 	 */
-	byte *getPalette() { return _palette; }
+	byte *getPalette() { _dirtyPalette = false; return _palette; }
+	bool hasDirtyPalette() const { return _dirtyPalette; }
 
 	/**
 	 * Set the beginning offset of the video so we can modify the offsets in the stco
@@ -117,18 +103,22 @@
 	 */
 	void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; }
 
-	int32 getCurFrame() { return _curFrame; }
-	void addPauseTime(uint32 p) { _lastFrameStart += p; _nextFrameStart += p; }
-	Graphics::Surface *getNextFrame();
-	void updateAudioBuffer();
-	void startAudio();
-	void stopAudio();
+	bool isVideoLoaded() const { return _fd != 0; }
+	void addPauseTime(uint32 p);
+	Graphics::Surface *decodeNextFrame();
+	bool needsUpdate() const;
+	bool endOfVideo() const;
+	uint32 getElapsedTime() const;
+	uint32 getTimeToNextFrame() const;
+	Graphics::PixelFormat getPixelFormat() const;
+
+	void rewind(); // For a future RewindableVideoDecoder class
+
+	// TODO: These audio functions need to be removed from the public and/or added to
+	// the VideoDecoder API directly.
+	void updateAudioBuffer(); // This is going to be problematic.
 	void pauseAudio();
 	void resumeAudio();
-	bool needsUpdate();
-	bool endOfVideo();
-	void stop();
-	void reset();
 
 protected:
 	// This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream.
@@ -238,26 +228,33 @@
 	ScaleMode _scaleMode;
 	MOVStreamContext *_streams[20];
 	byte _palette[256 * 4];
+	bool _dirtyPalette;
+	uint32 _beginOffset;
 
 	void initParseTable();
 	Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream);
 	bool checkAudioCodecSupport(uint32 tag);
 	Common::SeekableReadStream *getNextFramePacket();
 	uint32 getFrameDuration();
+	uint32 getCodecTag();
+	byte getBitsPerPixel();
 
 	Audio::QueuingAudioStream *_audStream;
-	int8 _videoStreamIndex;
+	void startAudio();
+	void stopAudio();
 	int8 _audioStreamIndex;
 	uint _curAudioChunk;
-	uint32 _beginOffset;
+	Audio::SoundHandle _audHandle;
 
 	Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
 	Graphics::Codec *_videoCodec;
-	bool _noCodecFound;
-	int32 _curFrame;
-	uint32 _lastFrameStart, _nextFrameStart; // In 1/100 ms
-	Audio::SoundHandle _audHandle;
+	uint32 _nextFrameStartTime;
+	int8 _videoStreamIndex;
 
+	Graphics::Surface *_scaledSurface;
+	Graphics::Surface *scaleSurface(Graphics::Surface *frame);
+	ScaleMode getScaleMode() const;
+
 	int readDefault(MOVatom atom);
 	int readLeaf(MOVatom atom);
 	int readELST(MOVatom atom);

Modified: scummvm/trunk/engines/mohawk/video/video.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/video/video.cpp	2010-05-18 14:57:02 UTC (rev 49080)
+++ scummvm/trunk/engines/mohawk/video/video.cpp	2010-05-18 14:59:20 UTC (rev 49081)
@@ -126,7 +126,7 @@
 		_vm->_system->delayMillis(10);
 	}
 
-	_videoStreams[videoHandle]->stop();
+	_videoStreams[videoHandle]->close();
 	_videoStreams.clear();
 }
 
@@ -155,7 +155,7 @@
 		// Remove any videos that are over
 		if (_videoStreams[i]->endOfVideo()) {
 			if (_videoStreams[i].loop) {
-				_videoStreams[i]->reset();
+				_videoStreams[i]->rewind();
 			} else {
 				delete _videoStreams[i].video;
 				memset(&_videoStreams[i], 0, sizeof(VideoEntry));
@@ -166,7 +166,7 @@
 
 		// Check if we need to draw a frame
 		if (_videoStreams[i]->needsUpdate()) {
-			Graphics::Surface *frame = _videoStreams[i]->getNextFrame();
+			Graphics::Surface *frame = _videoStreams[i]->decodeNextFrame();
 			bool deleteFrame = false;
 
 			if (frame && _videoStreams[i].enabled) {
@@ -196,27 +196,11 @@
 					deleteFrame = true;
 				}
 
-				// Check if we're drawing at a 2x or 4x resolution (because of
-				// evil QuickTime scaling it first).
-				if (_videoStreams[i]->getScaleMode() == kScaleHalf || _videoStreams[i]->getScaleMode() == kScaleQuarter) {
-					byte scaleFactor = (_videoStreams[i]->getScaleMode() == kScaleHalf) ? 2 : 4;
+				// Clip the width/height to make sure we stay on the screen (Myst does this a few times)
+				uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x);
+				uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y);
+				_vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height);
 
-					Graphics::Surface scaledSurf;
-					scaledSurf.create(_videoStreams[i]->getWidth() / scaleFactor, _videoStreams[i]->getHeight() / scaleFactor, frame->bytesPerPixel);
-
-					for (uint32 j = 0; j < scaledSurf.h; j++)
-						for (uint32 k = 0; k < scaledSurf.w; k++)
-							memcpy(scaledSurf.getBasePtr(k, j), frame->getBasePtr(k * scaleFactor, j * scaleFactor), frame->bytesPerPixel);
-
-					_vm->_system->copyRectToScreen((byte*)scaledSurf.pixels, scaledSurf.pitch, _videoStreams[i].x, _videoStreams[i].y, scaledSurf.w, scaledSurf.h);
-					scaledSurf.free();
-				} else {
-					// Clip the width/height to make sure we stay on the screen (Myst does this a few times)
-					uint16 width = MIN<int32>(_videoStreams[i]->getWidth(), _vm->_system->getWidth() - _videoStreams[i].x);
-					uint16 height = MIN<int32>(_videoStreams[i]->getHeight(), _vm->_system->getHeight() - _videoStreams[i].y);
-					_vm->_system->copyRectToScreen((byte*)frame->pixels, frame->pitch, _videoStreams[i].x, _videoStreams[i].y, width, height);
-				}
-
 				// We've drawn something to the screen, make sure we update it
 				updateScreen = true;
 
@@ -346,8 +330,7 @@
 	entry.loop = loop;
 	entry.enabled = true;
 	entry->setChunkBeginOffset(_vm->getResourceOffset(ID_TMOV, id));
-	entry->loadFile(_vm->getRawData(ID_TMOV, id));
-	entry->startAudio();
+	entry->load(*_vm->getRawData(ID_TMOV, id));
 
 	// Search for any deleted videos so we can take a formerly used slot
 	for (uint32 i = 0; i < _videoStreams.size(); i++)
@@ -383,8 +366,7 @@
 		return NULL_VID_HANDLE;
 	}
 	
-	entry->loadFile(file);
-	entry->startAudio();
+	entry->load(*file);
 	
 	// Search for any deleted videos so we can take a formerly used slot
 	for (uint32 i = 0; i < _videoStreams.size(); i++)


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