VOYEUR: Simply RL2 video decoder, and add proper seeking support

This commit is contained in:
Paul Gilbert 2014-01-25 18:46:26 -05:00
parent 0f9cfc373f
commit ee26919e90
3 changed files with 35 additions and 18 deletions

View File

@ -81,7 +81,7 @@ bool RL2Decoder::loadStream(Common::SeekableReadStream *stream) {
addTrack(new RL2VideoTrack(_header, audioTrack, stream));
// Load the offset/sizes of the video's audio data
//_soundFrames.reserve(header._numFrames);
_soundFrames.reserve(_header._numFrames);
for (int frameNumber = 0; frameNumber < _header._numFrames; ++frameNumber) {
int offset = _header._frameOffsets[frameNumber];
int size = _header._frameSoundSizes[frameNumber];
@ -145,6 +145,15 @@ void RL2Decoder::readNextPacket() {
}
}
bool RL2Decoder::seek(const Audio::Timestamp &where) {
// TODO: Ideally, I need a way to clear the audio track's QueuingAudioStream when
// a seek is done. Otherwise, as current, seeking can only be done correctly when
// the video is first loaded.
_soundFrameNumber = -1;
return VideoDecoder::seek(where);
}
void RL2Decoder::close() {
VideoDecoder::close();
delete _fileStream;
@ -215,16 +224,16 @@ bool RL2Decoder::RL2FileHeader::isValid() const {
return _signature == MKTAG('R','L','V','2') || _signature != MKTAG('R','L','V','3');
}
double RL2Decoder::RL2FileHeader::getFrameRate() const {
return (_soundRate > 0) ? _rate / _defSoundSize : 11025 / 1103;
}
/*------------------------------------------------------------------------*/
RL2Decoder::RL2VideoTrack::RL2VideoTrack(const RL2FileHeader &header, RL2AudioTrack *audioTrack,
Common::SeekableReadStream *stream):
_header(header), _audioTrack(audioTrack), _fileStream(stream) {
// Calculate the frame rate
int fps = (header._soundRate > 0) ? header._rate / header._defSoundSize : 11025 / 1103;
_frameDelay = 1000 / fps;
// Set up surfaces
_surface = new Graphics::Surface();
_surface->create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
@ -239,7 +248,7 @@ RL2Decoder::RL2VideoTrack::RL2VideoTrack(const RL2FileHeader &header, RL2AudioTr
_dirtyPalette = header._colorCount > 0;
_curFrame = 0;
_nextFrameStartTime = 0;
_initialFrame = true;
}
RL2Decoder::RL2VideoTrack::~RL2VideoTrack() {
@ -261,10 +270,13 @@ bool RL2Decoder::RL2VideoTrack::endOfTrack() const {
return getCurFrame() >= getFrameCount();
}
bool RL2Decoder::RL2VideoTrack::rewind() {
_curFrame = 0;
_nextFrameStartTime = 0;
bool RL2Decoder::RL2VideoTrack::seek(const Audio::Timestamp &time) {
int frame = time.totalNumberOfFrames();
if (frame < 0 || frame >= _header._numFrames)
return false;
_curFrame = frame;
return true;
}
@ -281,7 +293,7 @@ Graphics::PixelFormat RL2Decoder::RL2VideoTrack::getPixelFormat() const {
}
const Graphics::Surface *RL2Decoder::RL2VideoTrack::decodeNextFrame() {
if (_curFrame == 0 && _hasBackFrame) {
if (_initialFrame && _hasBackFrame) {
// Read in the initial background frame
_fileStream->seek(0x324);
rl2DecodeFrameWithoutTransparency(0);
@ -289,6 +301,7 @@ const Graphics::Surface *RL2Decoder::RL2VideoTrack::decodeNextFrame() {
Common::copy((byte *)_surface->getPixels(), (byte *)_surface->getPixels() + (320 * 200),
(byte *)_backSurface->getPixels());
_dirtyRects.push_back(Common::Rect(0, 0, _surface->w, _surface->h));
_initialFrame = false;
}
// Move to the next frame data
@ -306,7 +319,6 @@ const Graphics::Surface *RL2Decoder::RL2VideoTrack::decodeNextFrame() {
}
_curFrame++;
_nextFrameStartTime += _frameDelay;
return _surface;
}

View File

@ -26,6 +26,7 @@
#include "video/video_decoder.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "audio/timestamp.h"
#include "common/array.h"
#include "common/list.h"
#include "common/rect.h"
@ -72,6 +73,7 @@ private:
~RL2FileHeader();
void load(Common::SeekableReadStream *stream);
bool isValid() const;
double getFrameRate() const;
};
class SoundFrame {
@ -96,19 +98,19 @@ private:
Audio::Mixer::SoundType getSoundType() const { return _soundType; }
int numQueuedStreams() const { return _audStream->numQueuedStreams(); }
virtual bool isSeekable() const { return true; }
virtual bool seek(const Audio::Timestamp &time) { return true; }
void queueSound(Common::SeekableReadStream *stream, int size);
};
class RL2VideoTrack : public VideoTrack {
class RL2VideoTrack : public FixedRateVideoTrack {
public:
RL2VideoTrack(const RL2FileHeader &header, RL2AudioTrack *audioTrack,
Common::SeekableReadStream *stream);
~RL2VideoTrack();
bool endOfTrack() const;
bool isRewindable() const { return true; }
bool rewind();
uint16 getWidth() const;
uint16 getHeight() const;
@ -117,7 +119,6 @@ private:
Graphics::PixelFormat getPixelFormat() const;
int getCurFrame() const { return _curFrame; }
int getFrameCount() const { return _header._numFrames; }
uint32 getNextFrameStartTime() const { return _nextFrameStartTime; }
const Graphics::Surface *decodeNextFrame();
const byte *getPalette() const { _dirtyPalette = false; return _header._palette; }
int getPaletteCount() const { return _header._colorCount; }
@ -126,6 +127,9 @@ private:
void clearDirtyRects() { _dirtyRects.clear(); }
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
virtual Common::Rational getFrameRate() const { return _header.getFrameRate(); }
virtual bool isSeekable() const { return true; }
virtual bool seek(const Audio::Timestamp &time);
private:
Common::SeekableReadStream *_fileStream;
const RL2FileHeader &_header;
@ -136,11 +140,10 @@ private:
mutable bool _dirtyPalette;
bool _initialFrame;
int _curFrame;
uint32 _videoBase;
uint32 *_frameOffsets;
uint32 _frameDelay;
uint32 _nextFrameStartTime;
Common::List<Common::Rect> _dirtyRects;
@ -167,6 +170,7 @@ public:
virtual void readNextPacket();
virtual void close();
virtual bool seek(const Audio::Timestamp &where);
const Common::List<Common::Rect> *getDirtyRects() const;
void clearDirtyRects();
@ -175,6 +179,7 @@ public:
RL2AudioTrack *getAudioTrack();
int getPaletteStart() const { return _paletteStart; }
int getPaletteCount() const { return _header._colorCount; }
const RL2FileHeader &getHeader() { return _header; }
};
} // End of namespace Video

View File

@ -558,7 +558,7 @@ void VoyeurEngine::playAVideoDuration(int videoId, int duration) {
decoder.loadVideo(videoId);
decoder.start();
decoder.seek(Audio::Timestamp(_voy._vocSecondsOffset * 1000));
decoder.seek(Audio::Timestamp(_voy._vocSecondsOffset * 1000, decoder.getHeader().getFrameRate()));
int endFrame = decoder.getCurFrame() + totalFrames;
while (!shouldQuit() && !decoder.endOfVideo() && !_eventsManager._mouseClicked &&