VIDEO: Add reverse playback support to AviDecoder
This commit is contained in:
parent
e6e7d6e2f7
commit
0c200e833e
2 changed files with 71 additions and 12 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue