diff options
-rw-r--r-- | video/avi_decoder.cpp | 63 | ||||
-rw-r--r-- | video/avi_decoder.h | 20 |
2 files changed, 71 insertions, 12 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 7041f428ab..fc73cfaeac 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -458,6 +458,8 @@ void AVIDecoder::handleNextPacket(TrackStatus &status) { // Seek to where we shall start searching _fileStream->seek(status.chunkSearchOffset); + bool isReversed = false; + AVIVideoTrack *videoTrack = nullptr; for (;;) { // If there's no more to search, bail out @@ -511,7 +513,8 @@ void AVIDecoder::handleNextPacket(TrackStatus &status) { if (!shouldQueueAudio(status)) break; } else { - AVIVideoTrack *videoTrack = (AVIVideoTrack *)status.track; + videoTrack = (AVIVideoTrack *)status.track; + isReversed = videoTrack->isReversed(); if (getStreamType(nextTag) == kStreamTypePaletteChange) { // Palette Change @@ -524,8 +527,15 @@ void AVIDecoder::handleNextPacket(TrackStatus &status) { } } - // Start us off in this position next time - status.chunkSearchOffset = _fileStream->pos(); + if (!isReversed) { + // Start us off in this position next time + status.chunkSearchOffset = _fileStream->pos(); + } else { + // Seek to the prior frame + assert(videoTrack); + Audio::Timestamp time = videoTrack->getFrameTime(getCurFrame()); + seekIntern(time); + } } bool AVIDecoder::shouldQueueAudio(TrackStatus& status) { @@ -566,6 +576,8 @@ uint AVIDecoder::getVideoTrackOffset(uint trackIndex, uint frameNumber) { } bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { + uint frame; + // Can't seek beyond the end if (time > getDuration()) return false; @@ -574,19 +586,23 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track; uint32 videoIndex = _videoTracks[0].index; - // If we seek directly to the end, just mark the tracks as over if (time == getDuration()) { videoTrack->setCurFrame(videoTrack->getFrameCount() - 1); - for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) - if ((*it)->getTrackType() == Track::kTrackTypeAudio) - ((AVIAudioTrack *)*it)->resetStream(); + if (!videoTrack->isReversed()) { + // Since we're at the end, just mark the tracks as over + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AVIAudioTrack *)*it)->resetStream(); - return true; - } + return true; + } - // Get the frame we should be on at this time - uint frame = videoTrack->getFrameAtTime(time); + frame = videoTrack->getFrameCount() - 1; + } else { + // Get the frame we should be on at this time + frame = videoTrack->getFrameAtTime(time); + } // Reset any palette, if necessary videoTrack->useInitialPalette(); @@ -821,6 +837,7 @@ AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader & _videoCodec = createCodec(); _lastFrame = 0; _curFrame = -1; + _reversed = false; useInitialPalette(); } @@ -840,7 +857,12 @@ void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) } delete stream; - _curFrame++; + + if (!_reversed) { + _curFrame++; + } else { + _curFrame--; + } } Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const { @@ -923,6 +945,23 @@ bool AVIDecoder::AVIVideoTrack::hasDirtyPalette() const { return _dirtyPalette; } +bool AVIDecoder::AVIVideoTrack::setReverse(bool reverse) { + if (isRewindable()) { + // Track is rewindable, so reversing is allowed + _reversed = reverse; + return true; + } + + return !reverse; +} + +bool AVIDecoder::AVIVideoTrack::endOfTrack() const { + if (_reversed) + return _curFrame < 0; + + return _curFrame >= (getFrameCount() - 1); +} + bool AVIDecoder::AVIVideoTrack::canDither() const { return _videoCodec && _videoCodec->canDither(Image::Codec::kDitherTypeVFW); } diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 4bba07e98f..cc5c2c4d42 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -210,6 +210,25 @@ protected: bool isRewindable() const { return true; } bool rewind(); + /** + * 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); + + /** + * Is the video track set to play in reverse? + */ + virtual bool isReversed() const { return _reversed; } + + /** + * Returns true if at the end of the video track + */ + virtual bool endOfTrack() const; protected: Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); } @@ -220,6 +239,7 @@ protected: byte *_initialPalette; mutable bool _dirtyPalette; int _frameCount, _curFrame; + bool _reversed; Image::Codec *_videoCodec; const Graphics::Surface *_lastFrame; |