VIDEO: Add reverse playback support to AviDecoder

This commit is contained in:
Paul Gilbert 2016-12-05 23:15:44 -05:00
parent e6e7d6e2f7
commit 0c200e833e
2 changed files with 71 additions and 12 deletions

View file

@ -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,20 +586,24 @@ 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;
}
frame = videoTrack->getFrameCount() - 1;
} else {
// Get the frame we should be on at this time
frame = videoTrack->getFrameAtTime(time);
}
// Get the frame we should be on at this time
uint 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);
}

View file

@ -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;