[Scummvm-cvs-logs] scummvm master -> d1628feb761acc9f4607f64de3eb620fea53bcc9

clone2727 clone2727 at gmail.com
Mon Dec 12 18:38:23 CET 2011


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
35a0fb089a VIDEO: Fix QuickTime audio track ends
b367772b5f VIDEO: Add support for QuickTime video track edit lists
8cd55a11a0 MOHAWK: Fix Stoneship's hologram projector
d1628feb76 MOHAWK: Fix Myst ME Mac picture file names


Commit: 35a0fb089a12991be52a14e02977202263a7dbee
    https://github.com/scummvm/scummvm/commit/35a0fb089a12991be52a14e02977202263a7dbee
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-12-12T09:28:48-08:00

Commit Message:
VIDEO: Fix QuickTime audio track ends

Fixes videos where the audio track length is smaller than the video track length.

Changed paths:
    video/qt_decoder.cpp



diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 74bf533..058dd6b 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -298,9 +298,17 @@ bool QuickTimeDecoder::endOfVideo() const {
 }
 
 uint32 QuickTimeDecoder::getElapsedTime() const {
-	if (_audStream)
-		return g_system->getMixer()->getSoundElapsedTime(_audHandle) + _audioStartOffset.msecs();
+	if (_audStream) {
+		// Use the audio time if present and the audio track's time is less than the
+		// total length of the audio track. The audio track can end before the video
+		// track, so we need to fall back on the getMillis() time tracking in that
+		// case.
+		uint32 time = g_system->getMixer()->getSoundElapsedTime(_audHandle) + _audioStartOffset.msecs();
+		if (time < _tracks[_audioTrackIndex]->duration * 1000 / _tracks[_audioTrackIndex]->timeScale)
+			return time;
+	}
 
+	// Just use time elapsed since the beginning
 	return SeekableVideoDecoder::getElapsedTime();
 }
 


Commit: b367772b5f6966ef99ea0914b8e10644b18652ea
    https://github.com/scummvm/scummvm/commit/b367772b5f6966ef99ea0914b8e10644b18652ea
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-12-12T09:28:48-08:00

Commit Message:
VIDEO: Add support for QuickTime video track edit lists

Changed paths:
    audio/decoders/quicktime.cpp
    common/quicktime.cpp
    common/quicktime.h
    video/qt_decoder.cpp
    video/qt_decoder.h



diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp
index 8cf0305..e737bf8 100644
--- a/audio/decoders/quicktime.cpp
+++ b/audio/decoders/quicktime.cpp
@@ -87,6 +87,9 @@ void QuickTimeAudioDecoder::init() {
 
 			// Initialize the codec (if necessary)
 			entry->initCodec();
+
+			if (_tracks[_audioTrackIndex]->editCount != 1)
+				warning("Multiple edit list entries in an audio track. Things may go awry");
 		}
 	}
 }
@@ -414,7 +417,9 @@ public:
 	}
 
 	Timestamp getLength() const {
-		return Timestamp(0, _tracks[_audioTrackIndex]->duration, _tracks[_audioTrackIndex]->timeScale);
+		// TODO: Switch to the other one when audio edits are supported
+		//return Timestamp(0, _tracks[_audioTrackIndex]->duration, _timeScale);
+		return Timestamp(0, _tracks[_audioTrackIndex]->mediaDuration, _tracks[_audioTrackIndex]->timeScale);
 	}
 };
 
diff --git a/common/quicktime.cpp b/common/quicktime.cpp
index 9ea8c22..e16d3f2 100644
--- a/common/quicktime.cpp
+++ b/common/quicktime.cpp
@@ -386,8 +386,7 @@ int QuickTimeParser::readTKHD(Atom atom) {
 
 	/* track->id = */_fd->readUint32BE(); // track id (NOT 0 !)
 	_fd->readUint32BE(); // reserved
-	//track->startTime = 0; // check
-	(version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // highlevel (considering edits) duration in movie timebase
+	track->duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // highlevel (considering edits) duration in movie timebase
 	_fd->readUint32BE(); // reserved
 	_fd->readUint32BE(); // reserved
 
@@ -410,8 +409,8 @@ int QuickTimeParser::readTKHD(Atom atom) {
 	track->scaleFactorY.debugPrint(1, "readTKHD(): scaleFactorY =");
 
 	// these are fixed-point, 16:16
-	// uint32 tkWidth = _fd->readUint32BE() >> 16; // track width
-	// uint32 tkHeight = _fd->readUint32BE() >> 16; // track height
+	//_fd->readUint32BE() >> 16; // track width
+	//_fd->readUint32BE() >> 16; // track height
 
 	return 0;
 }
@@ -428,17 +427,18 @@ int QuickTimeParser::readELST(Atom atom) {
 
 	debug(2, "Track %d edit list count: %d", _tracks.size() - 1, track->editCount);
 
+	uint32 offset = 0;
+
 	for (uint32 i = 0; i < track->editCount; i++){
 		track->editList[i].trackDuration = _fd->readUint32BE();
 		track->editList[i].mediaTime = _fd->readSint32BE();
 		track->editList[i].mediaRate = Rational(_fd->readUint32BE(), 0x10000);
-		debugN(3, "\tDuration = %d, Media Time = %d, ", track->editList[i].trackDuration, track->editList[i].mediaTime);
+		track->editList[i].timeOffset = offset;
+		debugN(3, "\tDuration = %d (Offset = %d), Media Time = %d, ", track->editList[i].trackDuration, offset, track->editList[i].mediaTime);
 		track->editList[i].mediaRate.debugPrint(3, "Media Rate =");
+		offset += track->editList[i].trackDuration;
 	}
 
-	if (track->editCount != 1)
-		warning("Multiple edit list entries. Things may go awry");
-
 	return 0;
 }
 
@@ -500,7 +500,7 @@ int QuickTimeParser::readMDHD(Atom atom) {
 	}
 
 	track->timeScale = _fd->readUint32BE();
-	track->duration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // duration
+	track->mediaDuration = (version == 1) ? (_fd->readUint32BE(), _fd->readUint32BE()) : _fd->readUint32BE(); // duration
 
 	_fd->readUint16BE(); // language
 	_fd->readUint16BE(); // quality
@@ -793,6 +793,7 @@ QuickTimeParser::Track::Track() {
 	duration = 0;
 	startTime = 0;
 	objectTypeMP4 = 0;
+	mediaDuration = 0;
 }
 
 QuickTimeParser::Track::~Track() {
diff --git a/common/quicktime.h b/common/quicktime.h
index e4c821e..d7e2691 100644
--- a/common/quicktime.h
+++ b/common/quicktime.h
@@ -109,6 +109,7 @@ protected:
 
 	struct EditListEntry {
 		uint32 trackDuration;
+		uint32 timeOffset;
 		int32 mediaTime;
 		Rational mediaRate;
 	};
@@ -163,6 +164,7 @@ protected:
 
 		uint32 frameCount;
 		uint32 duration;
+		uint32 mediaDuration;
 		uint32 startTime;
 		Rational scaleFactorX;
 		Rational scaleFactorY;
diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 058dd6b..4a57ac4 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -56,155 +56,42 @@ namespace Video {
 ////////////////////////////////////////////
 
 QuickTimeDecoder::QuickTimeDecoder() {
-	_curFrame = -1;
-	_startTime = _nextFrameStartTime = 0;
+	_setStartTime = false;
 	_audHandle = Audio::SoundHandle();
 	_scaledSurface = 0;
 	_dirtyPalette = false;
 	_palette = 0;
+	_width = _height = 0;
+	_needUpdate = false;
 }
 
 QuickTimeDecoder::~QuickTimeDecoder() {
 	close();
 }
 
-uint16 QuickTimeDecoder::getWidth() const {
-	if (_videoTrackIndex < 0)
-		return 0;
-
-	return (Common::Rational(_tracks[_videoTrackIndex]->width) / getScaleFactorX()).toInt();
-}
-
-uint16 QuickTimeDecoder::getHeight() const {
-	if (_videoTrackIndex < 0)
-		return 0;
-
-	return (Common::Rational(_tracks[_videoTrackIndex]->height) / getScaleFactorY()).toInt();
-}
-
-uint32 QuickTimeDecoder::getFrameCount() const {
-	if (_videoTrackIndex < 0)
-		return 0;
-
-	return _tracks[_videoTrackIndex]->frameCount;
-}
-
-Common::Rational QuickTimeDecoder::getScaleFactorX() const {
-	if (_videoTrackIndex < 0)
-		return 1;
-
-	return (_scaleFactorX * _tracks[_videoTrackIndex]->scaleFactorX);
-}
-
-Common::Rational QuickTimeDecoder::getScaleFactorY() const {
-	if (_videoTrackIndex < 0)
-		return 1;
+int32 QuickTimeDecoder::getCurFrame() const {
+	// TODO: This is rather simplistic and doesn't take edits that
+	// repeat sections of the media into account. Doing that
+	// over-complicates things and shouldn't be necessary, but
+	// it would be nice to have in the future.
 
-	return (_scaleFactorY * _tracks[_videoTrackIndex]->scaleFactorY);
-}
+	int32 frame = -1;
 
-uint32 QuickTimeDecoder::getFrameDuration() {
-	if (_videoTrackIndex < 0)
-		return 0;
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo)
+			frame += ((VideoTrackHandler *)_handlers[i])->getCurFrame() + 1;
 
-	uint32 curFrameIndex = 0;
-	for (int32 i = 0; i < _tracks[_videoTrackIndex]->timeToSampleCount; i++) {
-		curFrameIndex += _tracks[_videoTrackIndex]->timeToSample[i].count;
-		if ((uint32)_curFrame < curFrameIndex) {
-			// Ok, now we have what duration this frame has.
-			return _tracks[_videoTrackIndex]->timeToSample[i].duration;
-		}
-	}
-
-	// This should never occur
-	error ("Cannot find duration for frame %d", _curFrame);
-	return 0;
-}
-
-Graphics::PixelFormat QuickTimeDecoder::getPixelFormat() const {
-	Codec *codec = findDefaultVideoCodec();
-
-	if (!codec)
-		return Graphics::PixelFormat::createFormatCLUT8();
-
-	return codec->getPixelFormat();
-}
-
-uint32 QuickTimeDecoder::findKeyFrame(uint32 frame) const {
-	for (int i = _tracks[_videoTrackIndex]->keyframeCount - 1; i >= 0; i--)
-		if (_tracks[_videoTrackIndex]->keyframes[i] <= frame)
-				return _tracks[_videoTrackIndex]->keyframes[i];
-
-	// If none found, we'll assume the requested frame is a key frame
 	return frame;
 }
 
-void QuickTimeDecoder::seekToFrame(uint32 frame) {
-	assert(_videoTrackIndex >= 0);
-	assert(frame < _tracks[_videoTrackIndex]->frameCount);
-
-	// Stop all audio (for now)
-	stopAudio();
-
-	// Track down the keyframe
-	_curFrame = findKeyFrame(frame) - 1;
-	while (_curFrame < (int32)frame - 1)
-		decodeNextFrame();
-
-	// Map out the starting point
-	_nextFrameStartTime = 0;
-	uint32 curFrame = 0;
-
-	for (int32 i = 0; i < _tracks[_videoTrackIndex]->timeToSampleCount && curFrame < frame; i++) {
-		for (int32 j = 0; j < _tracks[_videoTrackIndex]->timeToSample[i].count && curFrame < frame; j++) {
-			curFrame++;
-			_nextFrameStartTime += _tracks[_videoTrackIndex]->timeToSample[i].duration;
-		}
-	}
-
-	// Adjust the video starting point
-	const Audio::Timestamp curVideoTime(0, _nextFrameStartTime, _tracks[_videoTrackIndex]->timeScale);
-	_startTime = g_system->getMillis() - curVideoTime.msecs();
-	resetPauseStartTime();
-
-	// Adjust the audio starting point
-	if (_audioTrackIndex >= 0) {
-		_audioStartOffset = curVideoTime;
-
-		// Seek to the new audio location
-		setAudioStreamPos(_audioStartOffset);
-
-		// Restart the audio
-		startAudio();
-
-		// Pause the audio again if we're still paused
-		if (isPaused() && _audStream)
-			g_system->getMixer()->pauseHandle(_audHandle, true);
-	}
-}
-
-void QuickTimeDecoder::seekToTime(Audio::Timestamp time) {
-	// Use makeQuickTimeStream() instead
-	if (_videoTrackIndex < 0)
-		error("Audio-only seeking not supported");
-
-	// Try to find the last frame that should have been decoded
-	uint32 frame = 0;
-	Audio::Timestamp totalDuration(0, _tracks[_videoTrackIndex]->timeScale);
-	bool done = false;
+uint32 QuickTimeDecoder::getFrameCount() const {
+	uint32 count = 0;
 
-	for (int32 i = 0; i < _tracks[_videoTrackIndex]->timeToSampleCount && !done; i++) {
-		for (int32 j = 0; j < _tracks[_videoTrackIndex]->timeToSample[i].count; j++) {
-			totalDuration = totalDuration.addFrames(_tracks[_videoTrackIndex]->timeToSample[i].duration);
-			if (totalDuration > time) {
-				done = true;
-				break;
-			}
-			frame++;
-		}
-	}
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo)
+			count += ((VideoTrackHandler *)_handlers[i])->getFrameCount();
 
-	seekToFrame(frame);
+	return count;
 }
 
 void QuickTimeDecoder::startAudio() {
@@ -224,87 +111,83 @@ void QuickTimeDecoder::pauseVideoIntern(bool pause) {
 		g_system->getMixer()->pauseHandle(_audHandle, pause);
 }
 
-Codec *QuickTimeDecoder::findDefaultVideoCodec() const {
-	if (_videoTrackIndex < 0 || _tracks[_videoTrackIndex]->sampleDescs.empty())
-		return 0;
+QuickTimeDecoder::VideoTrackHandler *QuickTimeDecoder::findNextVideoTrack() const {
+	VideoTrackHandler *bestTrack = 0;
+	int32 num;
+	uint32 bestTime = 0xffffffff;
+
+	for (uint32 i = 0; i < _handlers.size(); i++) {
+		if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) {
+			VideoTrackHandler *track = (VideoTrackHandler *)_handlers[i];
+			uint32 time = track->getNextFrameStartTime();
+
+			if (time < bestTime) {
+				bestTime = time;
+				bestTrack = track;
+				num  = i;
+			}
+		}
+	}
 
-	return ((VideoSampleDesc *)_tracks[_videoTrackIndex]->sampleDescs[0])->_videoCodec;
+	return bestTrack;
 }
 
 const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() {
-	if (_videoTrackIndex < 0 || _curFrame >= (int32)getFrameCount() - 1)
+	if (!_nextVideoTrack)
 		return 0;
 
-	if (_startTime == 0)
-		_startTime = g_system->getMillis();
-
-	_curFrame++;
-	_nextFrameStartTime += getFrameDuration();
-
-	// Update the audio while we're at it
-	updateAudioBuffer();
-
-	// Get the next packet
-	uint32 descId;
-	Common::SeekableReadStream *frameData = getNextFramePacket(descId);
+	const Graphics::Surface *frame = _nextVideoTrack->decodeNextFrame();
 
-	if (!frameData || !descId || descId > _tracks[_videoTrackIndex]->sampleDescs.size())
-		return 0;
-
-	// Find which video description entry we want
-	VideoSampleDesc *entry = (VideoSampleDesc *)_tracks[_videoTrackIndex]->sampleDescs[descId - 1];
+	if (!_setStartTime) {
+		_startTime = g_system->getMillis();
+		_setStartTime = true;
+	}
 
-	if (!entry->_videoCodec)
-		return 0;
+	_nextVideoTrack = findNextVideoTrack();
+	_needUpdate = false;
 
-	const Graphics::Surface *frame = entry->_videoCodec->decodeImage(frameData);
-	delete frameData;
+	// Update audio buffers too
+	// (needs to be done after we find the next track)
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeAudio)
+			((AudioTrackHandler *)_handlers[i])->updateBuffer();
 
-	// Update the palette
-	if (entry->_videoCodec->containsPalette()) {
-		// The codec itself contains a palette
-		if (entry->_videoCodec->hasDirtyPalette()) {
-			_palette = entry->_videoCodec->getPalette();
-			_dirtyPalette = true;
-		}
-	} else {
-		// Check if the video description has been updated
-		byte *palette = entry->_palette;
-
-		if (palette != _palette) {
-			_palette = palette;
-			_dirtyPalette = true;
-		}
+	if (_scaledSurface) {
+		scaleSurface(frame, _scaledSurface, _scaleFactorX, _scaleFactorY);
+		return _scaledSurface;
 	}
 
-	return scaleSurface(frame);
+	return frame;
 }
 
-const Graphics::Surface *QuickTimeDecoder::scaleSurface(const Graphics::Surface *frame) {
-	if (getScaleFactorX() == 1 && getScaleFactorY() == 1)
-		return frame;
-
-	assert(_scaledSurface);
-
-	for (int32 j = 0; j < _scaledSurface->h; j++)
-		for (int32 k = 0; k < _scaledSurface->w; k++)
-			memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr((k * getScaleFactorX()).toInt() , (j * getScaleFactorY()).toInt()), frame->format.bytesPerPixel);
+void QuickTimeDecoder::scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, Common::Rational scaleFactorX, Common::Rational scaleFactorY) {
+	assert(src && dst);
 
-	return _scaledSurface;
+	for (int32 j = 0; j < dst->h; j++)
+		for (int32 k = 0; k < dst->w; k++)
+			memcpy(dst->getBasePtr(k, j), src->getBasePtr((k * scaleFactorX).toInt() , (j * scaleFactorY).toInt()), src->format.bytesPerPixel);
 }
 
 bool QuickTimeDecoder::endOfVideo() const {
-	return (!_audStream || _audStream->endOfData()) && (!findDefaultVideoCodec() || SeekableVideoDecoder::endOfVideo());
+	if (!isVideoLoaded())
+		return true;
+
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		if (!_handlers[i]->endOfTrack())
+			return false;
+
+	return true;
 }
 
 uint32 QuickTimeDecoder::getElapsedTime() const {
+	// TODO: Convert to multi-track
 	if (_audStream) {
 		// Use the audio time if present and the audio track's time is less than the
 		// total length of the audio track. The audio track can end before the video
 		// track, so we need to fall back on the getMillis() time tracking in that
 		// case.
 		uint32 time = g_system->getMixer()->getSoundElapsedTime(_audHandle) + _audioStartOffset.msecs();
-		if (time < _tracks[_audioTrackIndex]->duration * 1000 / _tracks[_audioTrackIndex]->timeScale)
+		if (time < _tracks[_audioTrackIndex]->mediaDuration * 1000 / _tracks[_audioTrackIndex]->timeScale)
 			return time;
 	}
 
@@ -313,17 +196,24 @@ uint32 QuickTimeDecoder::getElapsedTime() const {
 }
 
 uint32 QuickTimeDecoder::getTimeToNextFrame() const {
-	if (endOfVideo() || _curFrame < 0)
+	if (_needUpdate)
 		return 0;
 
-	// Convert from the QuickTime rate base to 1000
-	uint32 nextFrameStartTime = _nextFrameStartTime * 1000 / _tracks[_videoTrackIndex]->timeScale;
-	uint32 elapsedTime = getElapsedTime();
+	if (_nextVideoTrack) {
+		uint32 nextFrameStartTime = _nextVideoTrack->getNextFrameStartTime();
 
-	if (nextFrameStartTime <= elapsedTime)
-		return 0;
+		if (nextFrameStartTime == 0)
+			return 0;
+
+		// TODO: Add support for rate modification
+
+		uint32 elapsedTime = getElapsedTime();
 
-	return nextFrameStartTime - elapsedTime;
+		if (elapsedTime < nextFrameStartTime)
+			return nextFrameStartTime - elapsedTime;
+	}
+
+	return 0;
 }
 
 bool QuickTimeDecoder::loadFile(const Common::String &filename) {
@@ -345,30 +235,49 @@ bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) {
 void QuickTimeDecoder::init() {
 	Audio::QuickTimeAudioDecoder::init();
 
-	_videoTrackIndex = -1;
 	_startTime = 0;
-
-	// Find video streams
-	for (uint32 i = 0; i < _tracks.size(); i++)
-		if (_tracks[i]->codecType == CODEC_TYPE_VIDEO && _videoTrackIndex < 0)
-			_videoTrackIndex = i;
+	_setStartTime = false;
 
 	// Start the audio codec if we've got one that we can handle
 	if (_audStream) {
 		startAudio();
 		_audioStartOffset = Audio::Timestamp(0);
+
+		// TODO: Support multiple audio tracks
+		// For now, just push back a handler for the first audio track
+		_handlers.push_back(new AudioTrackHandler(this, _tracks[_audioTrackIndex]));
+	}
+
+	// Initialize all the video tracks
+	for (uint32 i = 0; i < _tracks.size(); i++) {
+		if (_tracks[i]->codecType == CODEC_TYPE_VIDEO) {
+			for (uint32 j = 0; j < _tracks[i]->sampleDescs.size(); j++)
+				((VideoSampleDesc *)_tracks[i]->sampleDescs[j])->initCodec();
+
+			_handlers.push_back(new VideoTrackHandler(this, _tracks[i]));
+		}
 	}
 
-	// Initialize video, if present
-	if (_videoTrackIndex >= 0) {
-		for (uint32 i = 0; i < _tracks[_videoTrackIndex]->sampleDescs.size(); i++)
-			((VideoSampleDesc *)_tracks[_videoTrackIndex]->sampleDescs[i])->initCodec();
+	// Prepare the first video track
+	_nextVideoTrack = findNextVideoTrack();
 
-		if (getScaleFactorX() != 1 || getScaleFactorY() != 1) {
+	if (_nextVideoTrack) {
+		// Initialize the scaled surface
+		if (_scaleFactorX != 1 || _scaleFactorY != 1) {
 			// We have to initialize the scaled surface
 			_scaledSurface = new Graphics::Surface();
-			_scaledSurface->create(getWidth(), getHeight(), getPixelFormat());
+			_scaledSurface->create((_nextVideoTrack->getWidth() / _scaleFactorX).toInt(),
+					(_nextVideoTrack->getHeight() / _scaleFactorY).toInt(), getPixelFormat());
+			_width = _scaledSurface->w;
+			_height = _scaledSurface->h;
+		} else {
+			_width = _nextVideoTrack->getWidth().toInt();
+			_height = _nextVideoTrack->getHeight().toInt();
 		}
+
+		_needUpdate = true;
+	} else {
+		_needUpdate = false;
 	}
 }
 
@@ -472,6 +381,7 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *tra
 
 void QuickTimeDecoder::close() {
 	stopAudio();
+	freeAllTrackHandlers();
 
 	if (_scaledSurface) {
 		_scaledSurface->free();
@@ -479,93 +389,46 @@ void QuickTimeDecoder::close() {
 		_scaledSurface = 0;
 	}
 
+	_width = _height = 0;
+
 	Common::QuickTimeParser::close();
 	SeekableVideoDecoder::reset();
 }
 
-Common::SeekableReadStream *QuickTimeDecoder::getNextFramePacket(uint32 &descId) {
-	if (_videoTrackIndex < 0)
-		return NULL;
-
-	// First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for.
-	int32 totalSampleCount = 0;
-	int32 sampleInChunk = 0;
-	int32 actualChunk = -1;
-	uint32 sampleToChunkIndex = 0;
-
-	for (uint32 i = 0; i < _tracks[_videoTrackIndex]->chunkCount; i++) {
-		if (sampleToChunkIndex < _tracks[_videoTrackIndex]->sampleToChunkCount && i >= _tracks[_videoTrackIndex]->sampleToChunk[sampleToChunkIndex].first)
-			sampleToChunkIndex++;
-
-		totalSampleCount += _tracks[_videoTrackIndex]->sampleToChunk[sampleToChunkIndex - 1].count;
-
-		if (totalSampleCount > getCurFrame()) {
-			actualChunk = i;
-			descId = _tracks[_videoTrackIndex]->sampleToChunk[sampleToChunkIndex - 1].id;
-			sampleInChunk = _tracks[_videoTrackIndex]->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + getCurFrame();
-			break;
-		}
-	}
-
-	if (actualChunk < 0) {
-		warning ("Could not find data for frame %d", getCurFrame());
-		return NULL;
-	}
-
-	// Next seek to that frame
-	_fd->seek(_tracks[_videoTrackIndex]->chunkOffsets[actualChunk]);
+void QuickTimeDecoder::freeAllTrackHandlers() {
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		delete _handlers[i];
 
-	// Then, if the chunk holds more than one frame, seek to where the frame we want is located
-	for (int32 i = getCurFrame() - sampleInChunk; i < getCurFrame(); i++) {
-		if (_tracks[_videoTrackIndex]->sampleSize != 0)
-			_fd->skip(_tracks[_videoTrackIndex]->sampleSize);
-		else
-			_fd->skip(_tracks[_videoTrackIndex]->sampleSizes[i]);
-	}
+	_handlers.clear();
+}
 
-	// Finally, read in the raw data for the frame
-	//printf ("Frame Data[%d]: Offset = %d, Size = %d\n", getCurFrame(), _fd->pos(), _tracks[_videoTrackIndex]->sampleSizes[getCurFrame()]);
+void QuickTimeDecoder::seekToTime(Audio::Timestamp time) {
+	// Sets all tracks to this time
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		_handlers[i]->seekToTime(time);
 
-	if (_tracks[_videoTrackIndex]->sampleSize != 0)
-		return _fd->readStream(_tracks[_videoTrackIndex]->sampleSize);
+	// Reset our start time
+	_startTime = g_system->getMillis() - time.msecs();
+	_setStartTime = true;
+	resetPauseStartTime();
 
-	return _fd->readStream(_tracks[_videoTrackIndex]->sampleSizes[getCurFrame()]);
+	// Reset the next video track too
+	_nextVideoTrack = findNextVideoTrack();
+	_needUpdate = _nextVideoTrack != 0;
 }
 
 void QuickTimeDecoder::updateAudioBuffer() {
-	if (!_audStream)
-		return;
-
-	uint32 numberOfChunksNeeded = 0;
-
-	if (_videoTrackIndex < 0 || _curFrame == (int32)_tracks[_videoTrackIndex]->frameCount - 1) {
-		// If we have no video, there's nothing to base our buffer against
-		// However, one must ask why a QuickTimeDecoder is being used instead of the nice makeQuickTimeStream() function
-
-		// If we're on the last frame, make sure all audio remaining is buffered
-		numberOfChunksNeeded = _tracks[_audioTrackIndex]->chunkCount;
-	} else {
-		Audio::QuickTimeAudioDecoder::AudioSampleDesc *entry = (Audio::QuickTimeAudioDecoder::AudioSampleDesc *)_tracks[_audioTrackIndex]->sampleDescs[0];
-
-		// Calculate the amount of chunks we need in memory until the next frame
-		uint32 timeToNextFrame = getTimeToNextFrame();
-		uint32 timeFilled = 0;
-		uint32 curAudioChunk = _curAudioChunk - _audStream->numQueuedStreams();
-
-		for (; timeFilled < timeToNextFrame && curAudioChunk < _tracks[_audioTrackIndex]->chunkCount; numberOfChunksNeeded++, curAudioChunk++) {
-			uint32 sampleCount = entry->getAudioChunkSampleCount(curAudioChunk);
-			assert(sampleCount);
-
-			timeFilled += sampleCount * 1000 / entry->_sampleRate;
-		}
+	// Updates the audio buffers for all audio tracks
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeAudio)
+			((AudioTrackHandler *)_handlers[i])->updateBuffer();
+}
 
-		// Add a couple extra to ensure we don't underrun
-		numberOfChunksNeeded += 3;
-	}
+Graphics::PixelFormat QuickTimeDecoder::getPixelFormat() const {
+	if (_nextVideoTrack)
+		return _nextVideoTrack->getPixelFormat();
 
-	// Keep three streams in buffer so that if/when the first two end, it goes right into the next
-	while (_audStream->numQueuedStreams() < numberOfChunksNeeded && _curAudioChunk < _tracks[_audioTrackIndex]->chunkCount)
-		queueNextAudioChunk();
+	return Graphics::PixelFormat();
 }
 
 QuickTimeDecoder::VideoSampleDesc::VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag) : Common::QuickTimeParser::SampleDesc(parentTrack, codecTag) {
@@ -620,4 +483,383 @@ void QuickTimeDecoder::VideoSampleDesc::initCodec() {
 	}
 }
 
+bool QuickTimeDecoder::endOfVideoTracks() const {
+	for (uint32 i = 0; i < _handlers.size(); i++)
+		if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack())	
+			return false;
+
+	return true;
+}
+
+QuickTimeDecoder::TrackHandler::TrackHandler(QuickTimeDecoder *decoder, Track *parent) : _decoder(decoder), _parent(parent), _fd(_decoder->_fd) {
+	_curEdit = 0;
+}
+
+bool QuickTimeDecoder::TrackHandler::endOfTrack() {
+	// A track is over when we've finished going through all edits
+	return _curEdit == _parent->editCount;
+}
+
+QuickTimeDecoder::AudioTrackHandler::AudioTrackHandler(QuickTimeDecoder *decoder, Track *parent) : TrackHandler(decoder, parent) {
+}
+
+void QuickTimeDecoder::AudioTrackHandler::updateBuffer() {
+	if (!_decoder->_audStream)
+		return;
+
+	uint32 numberOfChunksNeeded = 0;
+
+	if (_decoder->endOfVideoTracks()) {
+		// If we have no video left (or no video), there's nothing to base our buffer against
+		numberOfChunksNeeded = _parent->chunkCount;
+	} else {
+		Audio::QuickTimeAudioDecoder::AudioSampleDesc *entry = (Audio::QuickTimeAudioDecoder::AudioSampleDesc *)_parent->sampleDescs[0];
+
+		// Calculate the amount of chunks we need in memory until the next frame
+		uint32 timeToNextFrame = _decoder->getTimeToNextFrame();
+		uint32 timeFilled = 0;
+		uint32 curAudioChunk = _decoder->_curAudioChunk - _decoder->_audStream->numQueuedStreams();
+
+		for (; timeFilled < timeToNextFrame && curAudioChunk < _parent->chunkCount; numberOfChunksNeeded++, curAudioChunk++) {
+			uint32 sampleCount = entry->getAudioChunkSampleCount(curAudioChunk);
+			assert(sampleCount);
+
+			timeFilled += sampleCount * 1000 / entry->_sampleRate;
+		}
+
+		// Add a couple extra to ensure we don't underrun
+		numberOfChunksNeeded += 3;
+	}
+
+	// Keep three streams in buffer so that if/when the first two end, it goes right into the next
+	while (_decoder->_audStream->numQueuedStreams() < numberOfChunksNeeded && _decoder->_curAudioChunk < _parent->chunkCount)
+		_decoder->queueNextAudioChunk();
+}
+
+bool QuickTimeDecoder::AudioTrackHandler::endOfTrack() {
+	// TODO: Handle edits
+	return (_decoder->_curAudioChunk == _parent->chunkCount) && _decoder->_audStream->endOfData();
+}
+
+void QuickTimeDecoder::AudioTrackHandler::seekToTime(Audio::Timestamp time) {
+	if (_decoder->_audStream) {
+		// Stop all audio
+		_decoder->stopAudio();
+
+		_decoder->_audioStartOffset = time;
+
+		// Seek to the new audio location
+		_decoder->setAudioStreamPos(_decoder->_audioStartOffset);
+
+		// Restart the audio
+		_decoder->startAudio();
+
+		// Pause the audio again if we're still paused
+		if (_decoder->isPaused() && _decoder->_audStream)
+			g_system->getMixer()->pauseHandle(_decoder->_audHandle, true);
+	}
+}
+
+QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : TrackHandler(decoder, parent) {
+	if (_parent->scaleFactorX != 1 || _parent->scaleFactorY != 1) {
+		_scaledSurface = new Graphics::Surface();
+		_scaledSurface->create(getWidth().toInt(), getHeight().toInt(), getPixelFormat());
+	} else {
+		_scaledSurface = 0;
+	}
+
+	enterNewEditList(false);
+
+	_holdNextFrameStartTime = false;
+	_curFrame = -1;
+	_durationOverride = -1;
+
+}
+
+QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
+	if (_scaledSurface) {
+		_scaledSurface->free();
+		delete _scaledSurface;
+	}
+}
+
+const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() {
+	if (endOfTrack())
+		return 0;
+
+	const Graphics::Surface *frame = bufferNextFrame();
+
+	if (_holdNextFrameStartTime) {
+		// Don't set the next frame start time here; we just did a seek
+		_holdNextFrameStartTime = false;
+	} else if (_durationOverride >= 0) {
+		// Use our own duration from the edit list calculation
+		_nextFrameStartTime += _durationOverride;
+		_durationOverride = -1;
+	} else {
+		_nextFrameStartTime += getFrameDuration();
+	}
+
+	// Update the edit list, if applicable
+	// HACK: We're also accepting the time minus one because edit lists
+	// aren't as accurate as one would hope.
+	if (!endOfTrack() && getRateAdjustedFrameTime() >= getCurEditTimeOffset() + getCurEditTrackDuration() - 1) {
+		_curEdit++;
+
+		if (!endOfTrack())
+			enterNewEditList(true);
+	}
+
+	if (_scaledSurface) {
+		_decoder->scaleSurface(frame, _scaledSurface, _parent->scaleFactorX, _parent->scaleFactorY);
+		return _scaledSurface;
+	}
+
+	return frame;
+}
+
+void QuickTimeDecoder::VideoTrackHandler::enterNewEditList(bool bufferFrames) {
+	// Bypass all empty edit lists first
+	while (!endOfTrack() && _parent->editList[_curEdit].mediaTime == -1)
+		_curEdit++;
+
+	if (endOfTrack())
+		return;
+
+	uint32 frameNum = 0;
+	bool done = false;
+	uint32 totalDuration = 0;
+	uint32 prevDuration = 0;
+
+	// Track down where the mediaTime is in the media
+	for (int32 i = 0; i < _parent->timeToSampleCount && !done; i++) {
+		for (int32 j = 0; j < _parent->timeToSample[i].count; j++) {
+			if (totalDuration == (uint32)_parent->editList[_curEdit].mediaTime) {
+				done = true;
+				prevDuration = totalDuration;
+				break;
+			} else if (totalDuration > (uint32)_parent->editList[_curEdit].mediaTime) {
+				done = true;
+				frameNum--;
+				break;
+			}
+
+			prevDuration = totalDuration;
+			totalDuration += _parent->timeToSample[i].duration;
+			frameNum++;
+		}
+	}
+
+	if (bufferFrames) {
+		// Track down the keyframe
+		_curFrame = findKeyFrame(frameNum) - 1;
+		while (_curFrame < (int32)frameNum - 1)
+			bufferNextFrame();
+	} else {
+		_curFrame = frameNum - 1;
+	}
+
+	_nextFrameStartTime = getCurEditTimeOffset();
+
+	// Set an override for the duration since we came up in-between two frames
+	if (prevDuration != totalDuration)
+		_durationOverride = totalDuration - prevDuration;
+}
+
+const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame() {
+	_curFrame++;
+
+	// Get the next packet
+	uint32 descId;
+	Common::SeekableReadStream *frameData = getNextFramePacket(descId);
+
+	if (!frameData || !descId || descId > _parent->sampleDescs.size())
+		return 0;
+
+	// Find which video description entry we want
+	VideoSampleDesc *entry = (VideoSampleDesc *)_parent->sampleDescs[descId - 1];
+
+	if (!entry->_videoCodec)
+		return 0;
+
+	const Graphics::Surface *frame = entry->_videoCodec->decodeImage(frameData);
+	delete frameData;
+
+	// Update the palette
+	if (entry->_videoCodec->containsPalette()) {
+		// The codec itself contains a palette
+		if (entry->_videoCodec->hasDirtyPalette()) {
+			_decoder->_palette = entry->_videoCodec->getPalette();
+			_decoder->_dirtyPalette = true;
+		}
+	} else {
+		// Check if the video description has been updated
+		byte *palette = entry->_palette;
+
+		if (palette !=_decoder-> _palette) {
+			_decoder->_palette = palette;
+			_decoder->_dirtyPalette = true;
+		}
+	}
+
+	return frame;
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() {
+	if (endOfTrack())
+		return 0;
+
+	// Convert to milliseconds so the tracks can be compared
+	return getRateAdjustedFrameTime() * 1000 / _parent->timeScale;
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getFrameCount() {
+	return _parent->frameCount;
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() {
+	uint32 curFrameIndex = 0;
+	for (int32 i = 0; i < _parent->timeToSampleCount; i++) {
+		curFrameIndex += _parent->timeToSample[i].count;
+		if ((uint32)_curFrame < curFrameIndex) {
+			// Ok, now we have what duration this frame has.
+			return _parent->timeToSample[i].duration;
+		}
+	}
+
+	// This should never occur
+	error("Cannot find duration for frame %d", _curFrame);
+	return 0;
+}
+
+Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePacket(uint32 &descId) {
+	// First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for.
+	int32 totalSampleCount = 0;
+	int32 sampleInChunk = 0;
+	int32 actualChunk = -1;
+	uint32 sampleToChunkIndex = 0;
+
+	for (uint32 i = 0; i < _parent->chunkCount; i++) {
+		if (sampleToChunkIndex < _parent->sampleToChunkCount && i >= _parent->sampleToChunk[sampleToChunkIndex].first)
+			sampleToChunkIndex++;
+
+		totalSampleCount += _parent->sampleToChunk[sampleToChunkIndex - 1].count;
+
+		if (totalSampleCount > _curFrame) {
+			actualChunk = i;
+			descId = _parent->sampleToChunk[sampleToChunkIndex - 1].id;
+			sampleInChunk = _parent->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + _curFrame;
+			break;
+		}
+	}
+
+	if (actualChunk < 0) {
+		warning("Could not find data for frame %d", _curFrame);
+		return 0;
+	}
+
+	// Next seek to that frame
+	_fd->seek(_parent->chunkOffsets[actualChunk]);
+
+	// Then, if the chunk holds more than one frame, seek to where the frame we want is located
+	for (int32 i = _curFrame - sampleInChunk; i < _curFrame; i++) {
+		if (_parent->sampleSize != 0)
+			_fd->skip(_parent->sampleSize);
+		else
+			_fd->skip(_parent->sampleSizes[i]);
+	}
+
+	// Finally, read in the raw data for the frame
+	//debug("Frame Data[%d]: Offset = %d, Size = %d", _curFrame, _fd->pos(), _parent->sampleSizes[_curFrame]);
+
+	if (_parent->sampleSize != 0)
+		return _fd->readStream(_parent->sampleSize);
+
+	return _fd->readStream(_parent->sampleSizes[_curFrame]);
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const {
+	for (int i = _parent->keyframeCount - 1; i >= 0; i--)
+		if (_parent->keyframes[i] <= frame)
+			return _parent->keyframes[i];
+
+	// If none found, we'll assume the requested frame is a key frame
+	return frame;
+}
+
+void QuickTimeDecoder::VideoTrackHandler::seekToTime(Audio::Timestamp time) {
+	// First, figure out what edit we're in
+	time = time.convertToFramerate(_parent->timeScale);
+
+	// Continue until we get to where we need to be
+	for (_curEdit = 0; !endOfTrack(); _curEdit++)
+		if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration())
+			break;
+
+	// This track is done
+	if (endOfTrack())
+		return;
+
+	enterNewEditList(false);
+
+	// One extra check for the end of a track
+	if (endOfTrack())
+		return;
+
+	// Now we're in the edit and need to figure out what frame we need
+	while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) {
+		_curFrame++;
+		if (_durationOverride >= 0) {
+			_nextFrameStartTime += _durationOverride;
+			_durationOverride = -1;
+		} else {
+			_nextFrameStartTime += getFrameDuration();
+		}
+	}
+
+	// All that's left is to figure out what our starting time is going to be
+	// Compare the starting point for the frame to where we need to be
+	_holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames();
+
+	// If we went past the time, go back a frame
+	if (_holdNextFrameStartTime)
+		_curFrame--;
+
+	// Handle the keyframe here
+	int32 destinationFrame = _curFrame + 1;
+
+	assert(destinationFrame < (int32)_parent->frameCount);
+	_curFrame = findKeyFrame(destinationFrame) - 1;
+	while (_curFrame < destinationFrame - 1)
+		bufferNextFrame();
+}
+
+Common::Rational QuickTimeDecoder::VideoTrackHandler::getWidth() const {
+	return Common::Rational(_parent->width) / _parent->scaleFactorX;
+}
+
+Common::Rational QuickTimeDecoder::VideoTrackHandler::getHeight() const {
+	return Common::Rational(_parent->height) / _parent->scaleFactorY;
+}
+
+Graphics::PixelFormat QuickTimeDecoder::VideoTrackHandler::getPixelFormat() const {
+	return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat();
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getRateAdjustedFrameTime() const {
+	// Figure out what time the next frame is at taking the edit list rate into account
+	uint32 convertedTime =  (Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate).toInt();
+	return convertedTime + getCurEditTimeOffset();
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getCurEditTimeOffset() const {
+	// Need to convert to the track scale
+	return _parent->editList[_curEdit].timeOffset * _parent->timeScale / _decoder->_timeScale;
+}
+
+uint32 QuickTimeDecoder::VideoTrackHandler::getCurEditTrackDuration() const {
+	// Need to convert to the track scale
+	return _parent->editList[_curEdit].trackDuration * _parent->timeScale / _decoder->_timeScale;
+}
+
 } // End of namespace Video
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index b51fd04..b2d7153 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -31,14 +31,14 @@
 #ifndef VIDEO_QT_DECODER_H
 #define VIDEO_QT_DECODER_H
 
+#include "audio/mixer.h"
+#include "audio/decoders/quicktime_intern.h"
 #include "common/scummsys.h"
 #include "common/rational.h"
+#include "graphics/pixelformat.h"
 
 #include "video/video_decoder.h"
 
-#include "audio/mixer.h"
-#include "audio/decoders/quicktime_intern.h"
-
 namespace Common {
 	class Rational;
 }
@@ -63,13 +63,13 @@ public:
 	 * Returns the width of the video
 	 * @return the width of the video
 	 */
-	uint16 getWidth() const;
+	uint16 getWidth() const { return _width; }
 
 	/**
 	 * Returns the height of the video
 	 * @return the height of the video
 	 */
-	uint16 getHeight() const;
+	uint16 getHeight() const { return _height; }
 
 	/**
 	 * Returns the amount of frames in the video
@@ -101,6 +101,8 @@ public:
 	const byte *getPalette() { _dirtyPalette = false; return _palette; }
 	bool hasDirtyPalette() const { return _dirtyPalette; }
 
+	int32 getCurFrame() const;
+
 	bool isVideoLoaded() const { return isOpen(); }
 	const Graphics::Surface *decodeNextFrame();
 	bool endOfVideo() const;
@@ -132,8 +134,6 @@ protected:
 	Common::QuickTimeParser::SampleDesc *readSampleDesc(Track *track, uint32 format);
 
 private:
-	Common::SeekableReadStream *getNextFramePacket(uint32 &descId);
-	uint32 getFrameDuration();
 	void init();
 
 	void startAudio();
@@ -144,20 +144,108 @@ private:
 	Audio::Timestamp _audioStartOffset;
 
 	Codec *createCodec(uint32 codecTag, byte bitsPerPixel);
-	Codec *findDefaultVideoCodec() const;
-	uint32 _nextFrameStartTime;
-	int _videoTrackIndex;
 	uint32 findKeyFrame(uint32 frame) const;
 
 	bool _dirtyPalette;
 	const byte *_palette;
+	bool _setStartTime;
+	bool _needUpdate;
+
+	uint16 _width, _height;
 
 	Graphics::Surface *_scaledSurface;
-	const Graphics::Surface *scaleSurface(const Graphics::Surface *frame);
-	Common::Rational getScaleFactorX() const;
-	Common::Rational getScaleFactorY() const;
+	void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst,
+			Common::Rational scaleFactorX, Common::Rational scaleFactorY);
 
 	void pauseVideoIntern(bool pause);
+	bool endOfVideoTracks() const;
+
+	// The TrackHandler is a class that wraps around a QuickTime Track
+	// and handles playback in this decoder class.
+	class TrackHandler {
+	public:
+		TrackHandler(QuickTimeDecoder *decoder, Track *parent);
+		virtual ~TrackHandler() {}
+
+		enum TrackType {
+			kTrackTypeAudio,
+			kTrackTypeVideo
+		};
+
+		virtual TrackType getTrackType() const = 0;
+
+		virtual void seekToTime(Audio::Timestamp time) = 0;
+
+		virtual bool endOfTrack();
+
+	protected:
+		uint32 _curEdit;
+		QuickTimeDecoder *_decoder;
+		Common::SeekableReadStream *_fd;
+		Track *_parent;
+	};
+
+	// The AudioTrackHandler is currently just a wrapper around some
+	// QuickTimeDecoder functions. Eventually this can be made to
+	// handle multiple audio tracks, but I haven't seen a video with
+	// that yet.
+	class AudioTrackHandler : public TrackHandler {
+	public:
+		AudioTrackHandler(QuickTimeDecoder *decoder, Track *parent);
+		TrackType getTrackType() const { return kTrackTypeAudio; }
+
+		void updateBuffer();
+		void seekToTime(Audio::Timestamp time);
+		bool endOfTrack();
+	};
+
+	// The VideoTrackHandler is the bridge between the time of playback
+	// and the media for the given track. It calculates when to start
+	// tracks and at what rate to play the media using the edit list.
+	class VideoTrackHandler : public TrackHandler {
+	public:
+		VideoTrackHandler(QuickTimeDecoder *decoder, Track *parent);
+		~VideoTrackHandler();
+
+		TrackType getTrackType() const { return kTrackTypeVideo; }
+
+		const Graphics::Surface *decodeNextFrame();
+
+		uint32 getNextFrameStartTime();
+
+		uint32 getFrameCount();
+
+		int32 getCurFrame() { return _curFrame; }
+
+		Graphics::PixelFormat getPixelFormat() const;
+
+		void seekToTime(Audio::Timestamp time);
+
+		Common::Rational getWidth() const;
+		Common::Rational getHeight() const;
+
+	private:
+		int32 _curFrame;
+		uint32 _nextFrameStartTime;
+		Graphics::Surface *_scaledSurface;
+		bool _holdNextFrameStartTime;
+		int32 _durationOverride;
+
+		Common::SeekableReadStream *getNextFramePacket(uint32 &descId);
+		uint32 getFrameDuration();
+		uint32 findKeyFrame(uint32 frame) const;
+		void enterNewEditList(bool bufferFrames);
+		const Graphics::Surface *bufferNextFrame();
+		uint32 getRateAdjustedFrameTime() const;
+		uint32 getCurEditTimeOffset() const;
+		uint32 getCurEditTrackDuration() const;
+	};
+
+	Common::Array<TrackHandler *> _handlers;
+	VideoTrackHandler *_nextVideoTrack;
+	VideoTrackHandler *findNextVideoTrack() const;
+
+	void freeAllTrackHandlers();
 };
 
 } // End of namespace Video


Commit: 8cd55a11a07a1004bf14e63a42caad9e8039a36c
    https://github.com/scummvm/scummvm/commit/8cd55a11a07a1004bf14e63a42caad9e8039a36c
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-12-12T09:28:48-08:00

Commit Message:
MOHAWK: Fix Stoneship's hologram projector

Changed paths:
    engines/mohawk/myst_stacks/stoneship.cpp
    engines/mohawk/video.cpp
    engines/mohawk/video.h



diff --git a/engines/mohawk/myst_stacks/stoneship.cpp b/engines/mohawk/myst_stacks/stoneship.cpp
index 4c715b5..6d54d0c 100644
--- a/engines/mohawk/myst_stacks/stoneship.cpp
+++ b/engines/mohawk/myst_stacks/stoneship.cpp
@@ -623,7 +623,7 @@ void Stoneship::o_hologramSelectionMove(uint16 op, uint16 var, uint16 argc, uint
 		uint16 selectionPos = position * 1500 / 243;
 
 		VideoHandle handleMovie = _hologramSelection->playMovie();
-		_vm->_video->setVideoBounds(handleMovie, Audio::Timestamp(0, selectionPos, 600), Audio::Timestamp(0, selectionPos, 600));
+		_vm->_video->drawVideoFrame(handleMovie, Audio::Timestamp(0, selectionPos, 600));
 
 		_hologramDisplayPos = position * 1450 / 243 + 350;
 
@@ -631,7 +631,7 @@ void Stoneship::o_hologramSelectionMove(uint16 op, uint16 var, uint16 argc, uint
 		if (_hologramTurnedOn) {
 			_hologramDisplay->setBlocking(false);
 			VideoHandle displayMovie = _hologramDisplay->playMovie();
-			_vm->_video->setVideoBounds(displayMovie, Audio::Timestamp(0, _hologramDisplayPos, 600), Audio::Timestamp(0, _hologramDisplayPos, 600));
+			_vm->_video->drawVideoFrame(displayMovie, Audio::Timestamp(0, _hologramDisplayPos, 600));
 		}
 	}
 }
diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp
index cd8fc8e..7958906 100644
--- a/engines/mohawk/video.cpp
+++ b/engines/mohawk/video.cpp
@@ -529,6 +529,15 @@ void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Au
 	_videoStreams[handle]->seekToTime(start);
 }
 
+void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) {
+	assert(handle != NULL_VID_HANDLE);
+	_videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1);
+	_videoStreams[handle]->seekToTime(time);
+	updateMovies();
+	delete _videoStreams[handle].video;
+	_videoStreams[handle].clear();
+}
+
 void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) {
 	assert(handle != NULL_VID_HANDLE);
 	_videoStreams[handle]->seekToTime(time);
diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h
index efa81ed..34c2874 100644
--- a/engines/mohawk/video.h
+++ b/engines/mohawk/video.h
@@ -104,6 +104,7 @@ public:
 	uint32 getDuration(VideoHandle videoHandle);
 	bool endOfVideo(VideoHandle handle);
 	void setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end);
+	void drawVideoFrame(VideoHandle handle, Audio::Timestamp time);
 	void seekToTime(VideoHandle handle, Audio::Timestamp time);
 	void setVideoLooping(VideoHandle handle, bool loop);
 	void waitUntilMovieEnds(VideoHandle videoHandle);


Commit: d1628feb761acc9f4607f64de3eb620fea53bcc9
    https://github.com/scummvm/scummvm/commit/d1628feb761acc9f4607f64de3eb620fea53bcc9
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2011-12-12T09:28:49-08:00

Commit Message:
MOHAWK: Fix Myst ME Mac picture file names

Changed paths:
    engines/mohawk/graphics.cpp



diff --git a/engines/mohawk/graphics.cpp b/engines/mohawk/graphics.cpp
index c4326d1..dcb0c79 100644
--- a/engines/mohawk/graphics.cpp
+++ b/engines/mohawk/graphics.cpp
@@ -308,16 +308,19 @@ MystGraphics::~MystGraphics() {
 	delete _backBuffer;
 }
 
-static const char* picFileNames[] = {
+static const char *s_picFileNames[] = {
 	"CHpics",
 	"",
+	"",
 	"DUpics",
 	"INpics",
+	"",
 	"MEpics",
 	"MYpics",
 	"SEpics",
-	"STpics",
-	""
+	"",
+	"",
+	"STpics"
 };
 
 void MystGraphics::loadExternalPictureFile(uint16 stack) {
@@ -328,11 +331,11 @@ void MystGraphics::loadExternalPictureFile(uint16 stack) {
 		_pictureFile.picFile.close();
 	delete[] _pictureFile.entries;
 
-	if (!scumm_stricmp(picFileNames[stack], ""))
+	if (!scumm_stricmp(s_picFileNames[stack], ""))
 		return;
 
-	if (!_pictureFile.picFile.open(picFileNames[stack]))
-		error ("Could not open external picture file \'%s\'", picFileNames[stack]);
+	if (!_pictureFile.picFile.open(s_picFileNames[stack]))
+		error ("Could not open external picture file \'%s\'", s_picFileNames[stack]);
 
 	_pictureFile.pictureCount = _pictureFile.picFile.readUint32BE();
 	_pictureFile.entries = new PictureFile::PictureEntry[_pictureFile.pictureCount];






More information about the Scummvm-git-logs mailing list