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
|
// Seek to where we shall start searching
|
||||||
_fileStream->seek(status.chunkSearchOffset);
|
_fileStream->seek(status.chunkSearchOffset);
|
||||||
|
bool isReversed = false;
|
||||||
|
AVIVideoTrack *videoTrack = nullptr;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// If there's no more to search, bail out
|
// If there's no more to search, bail out
|
||||||
|
@ -511,7 +513,8 @@ void AVIDecoder::handleNextPacket(TrackStatus &status) {
|
||||||
if (!shouldQueueAudio(status))
|
if (!shouldQueueAudio(status))
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
AVIVideoTrack *videoTrack = (AVIVideoTrack *)status.track;
|
videoTrack = (AVIVideoTrack *)status.track;
|
||||||
|
isReversed = videoTrack->isReversed();
|
||||||
|
|
||||||
if (getStreamType(nextTag) == kStreamTypePaletteChange) {
|
if (getStreamType(nextTag) == kStreamTypePaletteChange) {
|
||||||
// Palette Change
|
// Palette Change
|
||||||
|
@ -524,8 +527,15 @@ void AVIDecoder::handleNextPacket(TrackStatus &status) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isReversed) {
|
||||||
// Start us off in this position next time
|
// Start us off in this position next time
|
||||||
status.chunkSearchOffset = _fileStream->pos();
|
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) {
|
bool AVIDecoder::shouldQueueAudio(TrackStatus& status) {
|
||||||
|
@ -566,6 +576,8 @@ uint AVIDecoder::getVideoTrackOffset(uint trackIndex, uint frameNumber) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||||
|
uint frame;
|
||||||
|
|
||||||
// Can't seek beyond the end
|
// Can't seek beyond the end
|
||||||
if (time > getDuration())
|
if (time > getDuration())
|
||||||
return false;
|
return false;
|
||||||
|
@ -574,10 +586,11 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||||
AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
|
AVIVideoTrack *videoTrack = (AVIVideoTrack *)_videoTracks[0].track;
|
||||||
uint32 videoIndex = _videoTracks[0].index;
|
uint32 videoIndex = _videoTracks[0].index;
|
||||||
|
|
||||||
// If we seek directly to the end, just mark the tracks as over
|
|
||||||
if (time == getDuration()) {
|
if (time == getDuration()) {
|
||||||
videoTrack->setCurFrame(videoTrack->getFrameCount() - 1);
|
videoTrack->setCurFrame(videoTrack->getFrameCount() - 1);
|
||||||
|
|
||||||
|
if (!videoTrack->isReversed()) {
|
||||||
|
// Since we're at the end, just mark the tracks as over
|
||||||
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
|
for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
|
||||||
if ((*it)->getTrackType() == Track::kTrackTypeAudio)
|
if ((*it)->getTrackType() == Track::kTrackTypeAudio)
|
||||||
((AVIAudioTrack *)*it)->resetStream();
|
((AVIAudioTrack *)*it)->resetStream();
|
||||||
|
@ -585,8 +598,11 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame = videoTrack->getFrameCount() - 1;
|
||||||
|
} else {
|
||||||
// Get the frame we should be on at this time
|
// Get the frame we should be on at this time
|
||||||
uint frame = videoTrack->getFrameAtTime(time);
|
frame = videoTrack->getFrameAtTime(time);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset any palette, if necessary
|
// Reset any palette, if necessary
|
||||||
videoTrack->useInitialPalette();
|
videoTrack->useInitialPalette();
|
||||||
|
@ -821,6 +837,7 @@ AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &
|
||||||
_videoCodec = createCodec();
|
_videoCodec = createCodec();
|
||||||
_lastFrame = 0;
|
_lastFrame = 0;
|
||||||
_curFrame = -1;
|
_curFrame = -1;
|
||||||
|
_reversed = false;
|
||||||
|
|
||||||
useInitialPalette();
|
useInitialPalette();
|
||||||
}
|
}
|
||||||
|
@ -840,7 +857,12 @@ void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete stream;
|
delete stream;
|
||||||
|
|
||||||
|
if (!_reversed) {
|
||||||
_curFrame++;
|
_curFrame++;
|
||||||
|
} else {
|
||||||
|
_curFrame--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const {
|
Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const {
|
||||||
|
@ -923,6 +945,23 @@ bool AVIDecoder::AVIVideoTrack::hasDirtyPalette() const {
|
||||||
return _dirtyPalette;
|
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 {
|
bool AVIDecoder::AVIVideoTrack::canDither() const {
|
||||||
return _videoCodec && _videoCodec->canDither(Image::Codec::kDitherTypeVFW);
|
return _videoCodec && _videoCodec->canDither(Image::Codec::kDitherTypeVFW);
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,6 +210,25 @@ protected:
|
||||||
bool isRewindable() const { return true; }
|
bool isRewindable() const { return true; }
|
||||||
bool rewind();
|
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:
|
protected:
|
||||||
Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); }
|
Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); }
|
||||||
|
|
||||||
|
@ -220,6 +239,7 @@ protected:
|
||||||
byte *_initialPalette;
|
byte *_initialPalette;
|
||||||
mutable bool _dirtyPalette;
|
mutable bool _dirtyPalette;
|
||||||
int _frameCount, _curFrame;
|
int _frameCount, _curFrame;
|
||||||
|
bool _reversed;
|
||||||
|
|
||||||
Image::Codec *_videoCodec;
|
Image::Codec *_videoCodec;
|
||||||
const Graphics::Surface *_lastFrame;
|
const Graphics::Surface *_lastFrame;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue