aboutsummaryrefslogtreecommitdiff
path: root/video
diff options
context:
space:
mode:
authorPaul Gilbert2016-12-05 23:15:44 -0500
committerPaul Gilbert2016-12-05 23:15:44 -0500
commit0c200e833efa863ec810e8d7fbefaa59f9f7603d (patch)
tree8b8c7d0dda9b91a55e4b1b068cad8e8c50487193 /video
parente6e7d6e2f790cfc652597affd72179a1f6cd6274 (diff)
downloadscummvm-rg350-0c200e833efa863ec810e8d7fbefaa59f9f7603d.tar.gz
scummvm-rg350-0c200e833efa863ec810e8d7fbefaa59f9f7603d.tar.bz2
scummvm-rg350-0c200e833efa863ec810e8d7fbefaa59f9f7603d.zip
VIDEO: Add reverse playback support to AviDecoder
Diffstat (limited to 'video')
-rw-r--r--video/avi_decoder.cpp63
-rw-r--r--video/avi_decoder.h20
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;