mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-20 00:41:12 +00:00
VOYEUR: Simply RL2 video decoder, and add proper seeking support
This commit is contained in:
parent
0f9cfc373f
commit
ee26919e90
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 &&
|
||||
|
Loading…
Reference in New Issue
Block a user