[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