diff options
| -rw-r--r-- | video/video_decoder.cpp | 44 | ||||
| -rw-r--r-- | video/video_decoder.h | 26 | 
2 files changed, 63 insertions, 7 deletions
| diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index ab12cfd971..ebe15c5fc1 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 5fec52cf42..d0a6e08005 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; }  	};  	/** | 
