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

clone2727 clone2727 at gmail.com
Sun Dec 16 03:25:11 CET 2012


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

Summary:
9ae56146bb VIDEO: Add API changes to allow videos to be played backwards
ce1268b73d VIDEO: Allow for QuickTime movies to be played backwards
bf51a7e6a6 PEGASUS: Fix playback of pressure door levels dropping video


Commit: 9ae56146bbe1daab3f8919ec67dc458d864651cb
    https://github.com/scummvm/scummvm/commit/9ae56146bbe1daab3f8919ec67dc458d864651cb
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-12-15T17:41:41-08:00

Commit Message:
VIDEO: Add API changes to allow videos to be played backwards

Changed paths:
    video/video_decoder.cpp
    video/video_decoder.h



diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp
index ab12cfd..ebe15c5 100644
--- a/video/video_decoder.cpp
+++ b/video/video_decoder.cpp
@@ -188,6 +188,25 @@ const Graphics::Surface *VideoDecoder::decodeNextFrame() {
 	return frame;
 }
 
+bool VideoDecoder::setReverse(bool reverse) {
+	// Can only reverse video-only videos
+	if (reverse && hasAudio())
+		return false;
+
+	// Attempt to make sure all the tracks are in the requested direction
+	for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
+		if ((*it)->getTrackType() == Track::kTrackTypeVideo && ((VideoTrack *)*it)->isReversed() != reverse) {
+			if (!((VideoTrack *)*it)->setReverse(reverse))
+				return false;
+
+			_needsUpdate = true; // force an update
+		}
+	}
+
+	findNextVideoTrack();
+	return true;
+}
+
 const byte *VideoDecoder::getPalette() {
 	_dirtyPalette = false;
 	return _palette;
@@ -218,7 +237,7 @@ uint32 VideoDecoder::getTime() const {
 		return _lastTimeChange.msecs();
 
 	if (isPaused())
-		return (_playbackRate * (_pauseStartTime - _startTime)).toInt();
+		return MAX<int>((_playbackRate * (_pauseStartTime - _startTime)).toInt(), 0);
 
 	if (useAudioSync()) {
 		for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
@@ -231,20 +250,29 @@ uint32 VideoDecoder::getTime() const {
 		}
 	}
 
-	return (_playbackRate * (g_system->getMillis() - _startTime)).toInt();
+	return MAX<int>((_playbackRate * (g_system->getMillis() - _startTime)).toInt(), 0);
 }
 
 uint32 VideoDecoder::getTimeToNextFrame() const {
 	if (endOfVideo() || _needsUpdate || !_nextVideoTrack)
 		return 0;
 
-	uint32 elapsedTime = getTime();
+	uint32 currentTime = getTime();
 	uint32 nextFrameStartTime = _nextVideoTrack->getNextFrameStartTime();
 
-	if (nextFrameStartTime <= elapsedTime)
+	if (_nextVideoTrack->isReversed()) {
+		// For reversed videos, we need to handle the time difference the opposite way.
+		if (nextFrameStartTime >= currentTime)
+			return 0;
+
+		return currentTime - nextFrameStartTime;
+	}
+
+	// Otherwise, handle it normally.
+	if (nextFrameStartTime <= currentTime)
 		return 0;
 
-	return nextFrameStartTime - elapsedTime;
+	return nextFrameStartTime - currentTime;
 }
 
 bool VideoDecoder::endOfVideo() const {
@@ -402,9 +430,11 @@ void VideoDecoder::setRate(const Common::Rational &rate) {
 
 	Common::Rational targetRate = rate;
 
-	if (rate < 0) {
-		// TODO: Implement support for this
+	// Attempt to set the reverse
+	if (!setReverse(rate < 0)) {
+		assert(rate < 0); // We shouldn't fail for forward.
 		warning("Cannot set custom rate to backwards");
+		setReverse(false);
 		targetRate = 1;
 
 		if (_playbackRate == targetRate)
diff --git a/video/video_decoder.h b/video/video_decoder.h
index 5fec52c..d0a6e08 100644
--- a/video/video_decoder.h
+++ b/video/video_decoder.h
@@ -353,6 +353,17 @@ public:
 	 */
 	void setDefaultHighColorFormat(const Graphics::PixelFormat &format) { _defaultHighColorFormat = format; }
 
+	/**
+	 * Set the video to decode frames in reverse.
+	 *
+	 * By default, VideoDecoder will decode forward.
+	 *
+	 * @note This is used by setRate()
+	 * @note This will not work if an audio track is present
+	 * @param reverse true for reverse, false for forward
+	 * @return true on success, false otherwise
+	 */
+	bool setReverse(bool reverse);
 
 	/////////////////////////////////////////
 	// Audio Control
@@ -551,6 +562,21 @@ protected:
 		 * should only be used by VideoDecoder::seekToFrame().
 		 */
 		virtual Audio::Timestamp getFrameTime(uint frame) const;
+
+		/**
+		 * Set the video track to play in reverse or forward.
+		 *
+		 * By default, a VideoTrack must decode forward.
+		 *
+		 * @param reverse true for reverse, false for forward
+		 * @return true for success, false for failure
+		 */
+		virtual bool setReverse(bool reverse) { return !reverse; }
+
+		/**
+		 * Is the video track set to play in reverse?
+		 */
+		virtual bool isReversed() const { return false; }
 	};
 
 	/**


Commit: ce1268b73d3e8f17e6bb7e048849cb69372809cd
    https://github.com/scummvm/scummvm/commit/ce1268b73d3e8f17e6bb7e048849cb69372809cd
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-12-15T17:43:43-08:00

Commit Message:
VIDEO: Allow for QuickTime movies to be played backwards

Still doesn't handle videos with multiple edits

Changed paths:
    video/qt_decoder.cpp
    video/qt_decoder.h



diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp
index 93e57f9..9e26e96 100644
--- a/video/qt_decoder.cpp
+++ b/video/qt_decoder.cpp
@@ -333,6 +333,7 @@ QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder
 	_scaledSurface = 0;
 	_curPalette = 0;
 	_dirtyPalette = false;
+	_reversed = false;
 }
 
 QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
@@ -344,26 +345,26 @@ QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() {
 
 bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const {
 	// A track is over when we've finished going through all edits
-	return _curEdit == _parent->editCount;
+	return _reversed ? (_curEdit == 0 && _curFrame < 0) : atLastEdit();
 }
 
 bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requestedTime) {
 	uint32 convertedFrames = requestedTime.convertToFramerate(_decoder->_timeScale).totalNumberOfFrames();
-	for (_curEdit = 0; !endOfTrack(); _curEdit++)
+	for (_curEdit = 0; !atLastEdit(); _curEdit++)
 		if (convertedFrames >= _parent->editList[_curEdit].timeOffset && convertedFrames < _parent->editList[_curEdit].timeOffset + _parent->editList[_curEdit].trackDuration)
 			break;
 
 	// If we did reach the end of the track, break out
-	if (endOfTrack())
+	if (atLastEdit())
 		return true;
 
 	// If this track is in an empty edit, position us at the next non-empty
 	// edit. There's nothing else to do after this.
 	if (_parent->editList[_curEdit].mediaTime == -1) {
-		while (!endOfTrack() && _parent->editList[_curEdit].mediaTime == -1)
+		while (!atLastEdit() && _parent->editList[_curEdit].mediaTime == -1)
 			_curEdit++;
 
-		if (!endOfTrack())
+		if (!atLastEdit())
 			enterNewEditList(true);
 
 		return true;
@@ -372,7 +373,7 @@ bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requested
 	enterNewEditList(false);
 
 	// One extra check for the end of a track
-	if (endOfTrack())
+	if (atLastEdit())
 		return true;
 
 	// Now we're in the edit and need to figure out what frame we need
@@ -391,17 +392,24 @@ bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requested
 	// 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 we went past the time, go back a frame. _curFrame before this point is at the frame
+	// that should be displayed. This adjustment ensures it is on the frame before the one that
+	// should be displayed.
 	if (_holdNextFrameStartTime)
 		_curFrame--;
 
-	// Handle the keyframe here
-	int32 destinationFrame = _curFrame + 1;
+	if (_reversed) {
+		// Call setReverse again to update
+		setReverse(true);
+	} else {
+		// Handle the keyframe here
+		int32 destinationFrame = _curFrame + 1;
 
-	assert(destinationFrame < (int32)_parent->frameCount);
-	_curFrame = findKeyFrame(destinationFrame) - 1;
-	while (_curFrame < destinationFrame - 1)
-		bufferNextFrame();
+		assert(destinationFrame < (int32)_parent->frameCount);
+		_curFrame = findKeyFrame(destinationFrame) - 1;
+		while (_curFrame < destinationFrame - 1)
+			bufferNextFrame();
+	}
 
 	return true;
 }
@@ -438,27 +446,54 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
 	if (endOfTrack())
 		return 0;
 
+	if (_reversed) {
+		// Subtract one to place us on the frame before the current displayed frame.
+		_curFrame--;
+
+		// We have one "dummy" frame at the end to so the last frame is displayed
+		// for the right amount of time.
+		if (_curFrame < 0)
+			return 0;
+
+		// Decode from the last key frame to the frame before the one we need.
+		// TODO: Probably would be wise to do some caching
+		int targetFrame = _curFrame;
+		_curFrame = findKeyFrame(targetFrame) - 1;
+		while (_curFrame != targetFrame - 1)
+			bufferNextFrame();
+	}
+
 	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;
+	if (_reversed) {
+		if (_holdNextFrameStartTime) {
+			// Don't set the next frame start time here; we just did a seek
+			_holdNextFrameStartTime = false;
+		} else {
+			// Just need to subtract the time
+			_nextFrameStartTime -= getFrameDuration();
+		}
 	} else {
-		_nextFrameStartTime += getFrameDuration();
-	}
+		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++;
+		// 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 (!atLastEdit() && getRateAdjustedFrameTime() >= getCurEditTimeOffset() + getCurEditTrackDuration() - 1) {
+			_curEdit++;
 
-		if (!endOfTrack())
-			enterNewEditList(true);
+			if (!atLastEdit())
+				enterNewEditList(true);
+		}
 	}
 
 	if (frame && (_parent->scaleFactorX != 1 || _parent->scaleFactorY != 1)) {
@@ -474,6 +509,68 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame()
 	return frame;
 }
 
+bool QuickTimeDecoder::VideoTrackHandler::setReverse(bool reverse) {
+	_reversed = reverse;
+
+	if (_reversed) {
+		if (_parent->editCount != 1) {
+			// TODO: Myst's holo.mov needs this :(
+			warning("Can only set reverse without edits");
+			return false;
+		}
+
+		if (atLastEdit()) {
+			// If we're at the end of the video, go to the penultimate edit.
+			// The current frame is set to one beyond the last frame here;
+			// one "past" the currently displayed frame.
+			_curEdit = _parent->editCount - 1;
+			_curFrame = _parent->frameCount;
+			_nextFrameStartTime = _parent->editList[_curEdit].trackDuration + _parent->editList[_curEdit].timeOffset;
+		} else if (_holdNextFrameStartTime) {
+			// We just seeked, so "pivot" around the frame that should be displayed
+			_curFrame++;
+			_nextFrameStartTime -= getFrameDuration();
+			_curFrame++;
+		} else {
+			// We need to put _curFrame to be the one after the one that should be displayed.
+			// Since we're on the frame that should be displaying right now, add one.
+			_curFrame++;
+		}
+	} else {
+		// 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 (!atLastEdit() && getRateAdjustedFrameTime() >= getCurEditTimeOffset() + getCurEditTrackDuration() - 1) {
+			_curEdit++;
+
+			if (atLastEdit())
+				return true;
+		}
+
+		if (_holdNextFrameStartTime) {
+			// We just seeked, so "pivot" around the frame that should be displayed
+			_curFrame--;
+			_nextFrameStartTime += getFrameDuration();
+		}
+
+		// We need to put _curFrame to be the one before the one that should be displayed.
+		// Since we're on the frame that should be displaying right now, subtract one.
+		// (As long as the current frame isn't -1, of course)
+		if (_curFrame > 0) {
+			// We then need to handle the keyframe situation
+			int targetFrame = _curFrame - 1;
+			_curFrame = findKeyFrame(targetFrame) - 1;
+			while (_curFrame < targetFrame)
+				bufferNextFrame();
+		} else if (_curFrame == 0) {
+			// Make us start at the first frame (no keyframe needed)
+			_curFrame--;
+		}
+	}
+
+	return true;
+}
+
 Common::Rational QuickTimeDecoder::VideoTrackHandler::getScaledWidth() const {
 	return Common::Rational(_parent->width) / _parent->scaleFactorX;
 }
@@ -555,10 +652,10 @@ uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const {
 
 void QuickTimeDecoder::VideoTrackHandler::enterNewEditList(bool bufferFrames) {
 	// Bypass all empty edit lists first
-	while (!endOfTrack() && _parent->editList[_curEdit].mediaTime == -1)
+	while (!atLastEdit() && _parent->editList[_curEdit].mediaTime == -1)
 		_curEdit++;
 
-	if (endOfTrack())
+	if (atLastEdit())
 		return;
 
 	uint32 frameNum = 0;
@@ -675,4 +772,8 @@ uint32 QuickTimeDecoder::VideoTrackHandler::getCurEditTrackDuration() const {
 	return _parent->editList[_curEdit].trackDuration * _parent->timeScale / _decoder->_timeScale;
 }
 
+bool QuickTimeDecoder::VideoTrackHandler::atLastEdit() const {
+	return _curEdit == _parent->editCount;
+}
+
 } // End of namespace Video
diff --git a/video/qt_decoder.h b/video/qt_decoder.h
index 135da91..28314f2 100644
--- a/video/qt_decoder.h
+++ b/video/qt_decoder.h
@@ -136,6 +136,8 @@ private:
 		const Graphics::Surface *decodeNextFrame();
 		const byte *getPalette() const { _dirtyPalette = false; return _curPalette; }
 		bool hasDirtyPalette() const { return _curPalette; }
+		bool setReverse(bool reverse);
+		bool isReversed() const { return _reversed; }
 
 		Common::Rational getScaledWidth() const;
 		Common::Rational getScaledHeight() const;
@@ -151,6 +153,7 @@ private:
 		int32 _durationOverride;
 		const byte *_curPalette;
 		mutable bool _dirtyPalette;
+		bool _reversed;
 
 		Common::SeekableReadStream *getNextFramePacket(uint32 &descId);
 		uint32 getFrameDuration();
@@ -160,6 +163,7 @@ private:
 		uint32 getRateAdjustedFrameTime() const;
 		uint32 getCurEditTimeOffset() const;
 		uint32 getCurEditTrackDuration() const;
+		bool atLastEdit() const;
 	};
 };
 


Commit: bf51a7e6a6e3987d8122c42109274f90db8dd2a1
    https://github.com/scummvm/scummvm/commit/bf51a7e6a6e3987d8122c42109274f90db8dd2a1
Author: Matthew Hoops (clone2727 at gmail.com)
Date: 2012-12-15T18:14:39-08:00

Commit Message:
PEGASUS: Fix playback of pressure door levels dropping video

Changed paths:
    engines/pegasus/neighborhood/norad/pressuredoor.cpp



diff --git a/engines/pegasus/neighborhood/norad/pressuredoor.cpp b/engines/pegasus/neighborhood/norad/pressuredoor.cpp
index d137856..a12e971 100644
--- a/engines/pegasus/neighborhood/norad/pressuredoor.cpp
+++ b/engines/pegasus/neighborhood/norad/pressuredoor.cpp
@@ -323,7 +323,8 @@ void PressureDoor::receiveNotification(Notification *notification, const Notific
 				_robotState = kRobotDead;
 				_levelsMovie.stop();
 				_levelsMovie.setSegment((kNormalSubRoomPressure + kPressureBase) * _levelsScale,
-						(GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
+						(GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale + 1);
+				_levelsMovie.setTime((GameState.getNoradSubRoomPressure() + kPressureBase) * _levelsScale);
 				_pressureCallBack.setCallBackFlag(kPressureDroppingFlag);
 				_pressureCallBack.scheduleCallBack(kTriggerAtStart, 0, 0);
 				_typeMovie.stop();
@@ -335,7 +336,7 @@ void PressureDoor::receiveNotification(Notification *notification, const Notific
 				_downButton.setCurrentFrameIndex(1);
 				_gameState = kGameOver;
 				allowInput(false);
-				_levelsMovie.setRate(Common::Rational(0x5555, 0x10000) - 1); // Should match door tracker.
+				_levelsMovie.setRate(Common::Rational(-4, 3)); // Should match door tracker.
 				break;
 			case kRobotDead:
 				allowInput(true);






More information about the Scummvm-git-logs mailing list