aboutsummaryrefslogtreecommitdiff
path: root/engines/zvision/video
diff options
context:
space:
mode:
authorFilippos Karapetis2014-12-16 00:48:16 +0200
committerFilippos Karapetis2014-12-16 01:58:55 +0200
commit7f61a094781256f7c2734aa08637494c1dfac6bf (patch)
tree2dd89d28d338daeb8bdf06e41bcc9e5768cf9885 /engines/zvision/video
parent67bd78a95f6efab6d0da4b3bef1b0cebc79c537c (diff)
downloadscummvm-rg350-7f61a094781256f7c2734aa08637494c1dfac6bf.tar.gz
scummvm-rg350-7f61a094781256f7c2734aa08637494c1dfac6bf.tar.bz2
scummvm-rg350-7f61a094781256f7c2734aa08637494c1dfac6bf.zip
ZVISION: Make the RLF decoder a subclass of the common video decoder
This way, the redundant MetaAnimation class can now be removed
Diffstat (limited to 'engines/zvision/video')
-rw-r--r--engines/zvision/video/rlf_decoder.cpp141
-rw-r--r--engines/zvision/video/rlf_decoder.h224
-rw-r--r--engines/zvision/video/video.cpp20
3 files changed, 157 insertions, 228 deletions
diff --git a/engines/zvision/video/rlf_decoder.cpp b/engines/zvision/video/rlf_decoder.cpp
index a4f16af9b0..bdb5dc18bc 100644
--- a/engines/zvision/video/rlf_decoder.cpp
+++ b/engines/zvision/video/rlf_decoder.cpp
@@ -34,75 +34,46 @@
namespace ZVision {
-RLFDecoder::RLFDecoder(const Common::String &fileName, bool stream)
- : _stream(stream),
- _readStream(NULL),
- _lastFrameRead(0),
- _frameCount(0),
- _width(0),
- _height(0),
- _frameTime(0),
- _frames(0),
- _nextFrame(0),
- _frameBufferByteSize(0) {
-
- Common::File *_file = new Common::File;
- if (!_file->open(fileName)) {
- warning("RLF animation file %s could not be opened", fileName.c_str());
- return;
- }
-
- _readStream = _file;
-
- if (!readHeader()) {
- warning("%s is not a RLF animation file. Wrong magic number", fileName.c_str());
- return;
- }
+RLFDecoder::~RLFDecoder() {
+ close();
+}
- _currentFrameBuffer.create(_width, _height, Graphics::createPixelFormat<565>());
- _frameBufferByteSize = _width * _height * sizeof(uint16);
+bool RLFDecoder::loadStream(Common::SeekableReadStream *stream) {
+ close();
- if (!stream) {
- _frames = new Frame[_frameCount];
+ addTrack(new RLFVideoTrack(stream));
- // Read in each frame
- for (uint i = 0; i < _frameCount; ++i) {
- _frames[i] = readNextFrame();
- }
- }
+ return true;
}
-RLFDecoder::RLFDecoder(Common::SeekableReadStream *rstream, bool stream)
- : _stream(stream),
- _readStream(rstream),
+RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
+ : _readStream(stream),
_lastFrameRead(0),
_frameCount(0),
_width(0),
_height(0),
_frameTime(0),
_frames(0),
- _nextFrame(0),
+ _curFrame(0),
_frameBufferByteSize(0) {
if (!readHeader()) {
- warning("Stream is not a RLF animation. Wrong magic number");
+ warning("Not a RLF animation file. Wrong magic number");
return;
}
_currentFrameBuffer.create(_width, _height, Graphics::createPixelFormat<565>());
_frameBufferByteSize = _width * _height * sizeof(uint16);
- if (!stream) {
- _frames = new Frame[_frameCount];
+ _frames = new Frame[_frameCount];
- // Read in each frame
- for (uint i = 0; i < _frameCount; ++i) {
- _frames[i] = readNextFrame();
- }
+ // Read in each frame
+ for (uint i = 0; i < _frameCount; ++i) {
+ _frames[i] = readNextFrame();
}
}
-RLFDecoder::~RLFDecoder() {
+RLFDecoder::RLFVideoTrack::~RLFVideoTrack() {
for (uint i = 0; i < _frameCount; ++i) {
delete[] _frames[i].encodedData;
}
@@ -111,7 +82,7 @@ RLFDecoder::~RLFDecoder() {
_currentFrameBuffer.free();
}
-bool RLFDecoder::readHeader() {
+bool RLFDecoder::RLFVideoTrack::readHeader() {
if (_readStream->readUint32BE() != MKTAG('F', 'E', 'L', 'R')) {
return false;
}
@@ -160,8 +131,8 @@ bool RLFDecoder::readHeader() {
return true;
}
-RLFDecoder::Frame RLFDecoder::readNextFrame() {
- RLFDecoder::Frame frame;
+RLFDecoder::RLFVideoTrack::Frame RLFDecoder::RLFVideoTrack::readNextFrame() {
+ RLFDecoder::RLFVideoTrack::Frame frame;
_readStream->readUint32BE(); // Magic number MARF
uint32 size = _readStream->readUint32LE(); // Size
@@ -188,30 +159,30 @@ RLFDecoder::Frame RLFDecoder::readNextFrame() {
return frame;
}
-void RLFDecoder::seekToFrame(int frameNumber) {
- assert(!_stream);
- assert(frameNumber < (int)_frameCount || frameNumber >= -1);
+bool RLFDecoder::RLFVideoTrack::seek(const Audio::Timestamp &time) {
+ uint frame = getFrameAtTime(time);
+ assert(frame < (int)_frameCount);
- if (_nextFrame == frameNumber)
- return;
+ if ((uint)_curFrame == frame)
+ return true;
- if (frameNumber < 0) {
- _nextFrame = 0;
- return;
+ if (frame < 0) {
+ _curFrame = 0;
+ return false;
}
- int closestFrame = _nextFrame;
- int distance = (int)frameNumber - _nextFrame;
+ int closestFrame = _curFrame;
+ int distance = (int)frame - _curFrame;
if (distance < 0) {
for (uint i = 0; i < _completeFrames.size(); ++i) {
- if ((int)_completeFrames[i] > frameNumber)
+ if ((int)_completeFrames[i] > frame)
break;
closestFrame = _completeFrames[i];
}
} else {
for (uint i = 0; i < _completeFrames.size(); ++i) {
- int newDistance = (int)frameNumber - (int)(_completeFrames[i]);
+ int newDistance = (int)frame - (int)(_completeFrames[i]);
if (newDistance < 0)
break;
if (newDistance < distance) {
@@ -221,43 +192,27 @@ void RLFDecoder::seekToFrame(int frameNumber) {
}
}
- for (int i = closestFrame; i < frameNumber; ++i) {
+ for (uint i = closestFrame; i < frame; ++i) {
applyFrameToCurrent(i);
}
- _nextFrame = frameNumber;
-}
-
-const Graphics::Surface *RLFDecoder::getFrameData(uint frameNumber) {
- assert(!_stream);
- assert(frameNumber < _frameCount);
+ _curFrame = frame;
- // Since this method is so expensive, first check to see if we can use
- // decodeNextFrame() it's cheap.
- if ((int)frameNumber == _nextFrame - 1) {
- return &_currentFrameBuffer;
- } else if (_nextFrame == (int)frameNumber) {
- return decodeNextFrame();
- }
-
- seekToFrame(frameNumber);
- return decodeNextFrame();
+ return true;
}
-const Graphics::Surface *RLFDecoder::decodeNextFrame() {
- assert(_nextFrame < (int)_frameCount);
+const Graphics::Surface *RLFDecoder::RLFVideoTrack::decodeNextFrame() {
+ // When an animation ends, rewind
+ if (_curFrame == (int)_frameCount)
+ seek(Audio::Timestamp(0, getFrameRate().toInt()));
+
+ applyFrameToCurrent(_curFrame);
- if (_stream) {
- applyFrameToCurrent(readNextFrame());
- } else {
- applyFrameToCurrent(_nextFrame);
- }
-
- _nextFrame++;
+ _curFrame++;
return &_currentFrameBuffer;
}
-void RLFDecoder::applyFrameToCurrent(uint frameNumber) {
+void RLFDecoder::RLFVideoTrack::applyFrameToCurrent(uint frameNumber) {
if (_frames[frameNumber].type == Masked) {
decodeMaskedRunLengthEncoding(_frames[frameNumber].encodedData, (int8 *)_currentFrameBuffer.getPixels(), _frames[frameNumber].encodedSize, _frameBufferByteSize);
} else if (_frames[frameNumber].type == Simple) {
@@ -265,15 +220,7 @@ void RLFDecoder::applyFrameToCurrent(uint frameNumber) {
}
}
-void RLFDecoder::applyFrameToCurrent(const RLFDecoder::Frame &frame) {
- if (frame.type == Masked) {
- decodeMaskedRunLengthEncoding(frame.encodedData, (int8 *)_currentFrameBuffer.getPixels(), frame.encodedSize, _frameBufferByteSize);
- } else if (frame.type == Simple) {
- decodeSimpleRunLengthEncoding(frame.encodedData, (int8 *)_currentFrameBuffer.getPixels(), frame.encodedSize, _frameBufferByteSize);
- }
-}
-
-void RLFDecoder::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const {
+void RLFDecoder::RLFVideoTrack::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const {
uint32 sourceOffset = 0;
uint32 destOffset = 0;
int16 numberOfCopy = 0;
@@ -320,7 +267,7 @@ void RLFDecoder::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32
}
}
-void RLFDecoder::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const {
+void RLFDecoder::RLFVideoTrack::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const {
uint32 sourceOffset = 0;
uint32 destOffset = 0;
int16 numberOfCopy = 0;
diff --git a/engines/zvision/video/rlf_decoder.h b/engines/zvision/video/rlf_decoder.h
index dcfd8606c2..f0f31c2128 100644
--- a/engines/zvision/video/rlf_decoder.h
+++ b/engines/zvision/video/rlf_decoder.h
@@ -24,147 +24,109 @@
#define ZVISION_RLF_DECODER_H
#include "common/file.h"
+#include "video/video_decoder.h"
#include "graphics/surface.h"
-namespace Common {
-class String;
-}
-
namespace ZVision {
-class RLFDecoder {
+class RLFDecoder : public Video::VideoDecoder {
public:
- RLFDecoder(const Common::String &fileName, bool stream = true);
- RLFDecoder(Common::SeekableReadStream *rstream, bool stream);
+ RLFDecoder() {}
~RLFDecoder();
-private:
- enum EncodingType {
- Masked,
- Simple
- };
-
- struct Frame {
- EncodingType type;
- int8 *encodedData;
- uint32 encodedSize;
- };
-
-private:
- Common::SeekableReadStream *_readStream;
- bool _stream;
- uint _lastFrameRead;
-
- uint _frameCount;
- uint _width;
- uint _height;
- uint32 _frameTime; // In milliseconds
- Frame *_frames;
- Common::Array<uint> _completeFrames;
-
- int _nextFrame;
- Graphics::Surface _currentFrameBuffer;
- uint32 _frameBufferByteSize;
-
-public:
- uint frameCount() {
- return _frameCount;
- }
- uint width() {
- return _width;
- }
- uint height() {
- return _height;
- }
- uint32 frameTime() {
- return _frameTime;
- }
-
- /**
- * Seeks to the frameNumber and updates the internal Surface with
- * the new frame data. If frameNumber == -1, it only sets _currentFrame,
- * the internal Surface is unchanged. This function requires _stream = false
- *
- * @param frameNumber The frame number to seek to
- */
- void seekToFrame(int frameNumber);
-
- /**
- * Returns the pixel data of the frame specified. It will try to use
- * decodeNextFrame() if possible. If not, it uses seekToFrame() to
- * update the internal Surface and then returns a pointer to it.
- * This function requires _stream = false
- *
- * @param frameNumber The frame number to get data for
- * @return A pointer to the pixel data. Do NOT delete this.
- */
- const Graphics::Surface *getFrameData(uint frameNumber);
- /**
- * Returns the pixel data of current frame and go to next. It is up to the user to
- * check if the current frame is valid before calling this.
- * IE. Use endOfAnimation()
- *
- * @return A pointer to the pixel data. Do NOT delete this.
- */
- const Graphics::Surface *decodeNextFrame();
- /**
- * @return Is the currentFrame is the last frame in the animation?
- */
- bool endOfAnimation() {
- return _nextFrame == (int)_frameCount;
- }
+ bool loadStream(Common::SeekableReadStream *stream);
private:
- /**
- * Reads in the header of the RLF file
- *
- * @return Will return false if the header magic number is wrong
- */
- bool readHeader();
- /**
- * Reads the next frame from the RLF file, stores the data in
- * a Frame object, then returns the object
- *
- * @return A Frame object representing the frame data
- */
- Frame readNextFrame();
-
- /**
- * Applies the frame corresponding to frameNumber on top of _currentFrameBuffer.
- * This function requires _stream = false so it can look up the Frame object
- * referenced by frameNumber.
- *
- * @param frameNumber The frame number to apply to _currentFrameBuffer
- */
- void applyFrameToCurrent(uint frameNumber);
- /**
- * Applies the data from a Frame object on top of a _currentFrameBuffer.
- *
- * @param frame A Frame object to apply to _currentFrameBuffer
- */
- void applyFrameToCurrent(const RLFDecoder::Frame &frame);
-
- /**
- * Decode frame data that uses masked run length encoding. This is the encoding
- * used by P-frames.
- *
- * @param source The source pixel data
- * @param dest The destination buffer
- * @param sourceSize The size of the source pixel data
- * @param destSize The size of the destination buffer
- */
- void decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const;
- /**
- * Decode frame data that uses simple run length encoding. This is the encoding
- * used by I-frames.
- *
- * @param source The source pixel data
- * @param dest The destination buffer
- * @param sourceSize The size of the source pixel data
- * @param destSize The size of the destination buffer
- */
- void decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const;
+ class RLFVideoTrack : public FixedRateVideoTrack {
+ public:
+ RLFVideoTrack(Common::SeekableReadStream *stream);
+ ~RLFVideoTrack();
+
+ uint16 getWidth() const { return _width; }
+ uint16 getHeight() const { return _height; }
+ Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); /*RGB 565*/ }
+ int getCurFrame() const { return _curFrame; }
+ int getFrameCount() const { return _frameCount; }
+ const Graphics::Surface *decodeNextFrame();
+ bool isSeekable() const { return true; }
+ bool seek(const Audio::Timestamp &time);
+
+ protected:
+ Common::Rational getFrameRate() const { return Common::Rational(60, _frameTime); }
+
+ private:
+ enum EncodingType {
+ Masked,
+ Simple
+ };
+
+ struct Frame {
+ EncodingType type;
+ int8 *encodedData;
+ uint32 encodedSize;
+ };
+
+ /**
+ * Reads in the header of the RLF file
+ *
+ * @return Will return false if the header magic number is wrong
+ */
+ bool readHeader();
+
+ /**
+ * Reads the next frame from the RLF file, stores the data in
+ * a Frame object, then returns the object
+ *
+ * @return A Frame object representing the frame data
+ */
+ Frame readNextFrame();
+
+ /**
+ * Applies the frame corresponding to frameNumber on top of _currentFrameBuffer.
+ * This function requires _stream = false so it can look up the Frame object
+ * referenced by frameNumber.
+ *
+ * @param frameNumber The frame number to apply to _currentFrameBuffer
+ */
+ void applyFrameToCurrent(uint frameNumber);
+
+ /**
+ * Decode frame data that uses masked run length encoding. This is the encoding
+ * used by P-frames.
+ *
+ * @param source The source pixel data
+ * @param dest The destination buffer
+ * @param sourceSize The size of the source pixel data
+ * @param destSize The size of the destination buffer
+ */
+ void decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const;
+ /**
+ * Decode frame data that uses simple run length encoding. This is the encoding
+ * used by I-frames.
+ *
+ * @param source The source pixel data
+ * @param dest The destination buffer
+ * @param sourceSize The size of the source pixel data
+ * @param destSize The size of the destination buffer
+ */
+ void decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const;
+
+ uint _lastFrameRead;
+
+ uint _frameCount;
+ uint _width;
+ uint _height;
+ uint32 _frameTime; // In milliseconds
+ Frame *_frames;
+ Common::Array<uint> _completeFrames;
+
+ int _curFrame;
+ Graphics::Surface _currentFrameBuffer;
+ uint32 _frameBufferByteSize;
+
+ Common::SeekableReadStream *_readStream;
+ }; // RLFVideoTrack
};
} // End of namespace ZVision
diff --git a/engines/zvision/video/video.cpp b/engines/zvision/video/video.cpp
index db6161bf0c..c8f968d975 100644
--- a/engines/zvision/video/video.cpp
+++ b/engines/zvision/video/video.cpp
@@ -30,9 +30,29 @@
#include "zvision/utility/clock.h"
#include "zvision/graphics/render_manager.h"
#include "zvision/graphics/subtitles.h"
+#include "zvision/video/rlf_decoder.h"
+#include "zvision/video/zork_avi_decoder.h"
namespace ZVision {
+Video::VideoDecoder *ZVision::loadAnimation(const Common::String &fileName) {
+ Common::String tmpFileName = fileName;
+ tmpFileName.toLowercase();
+ Video::VideoDecoder *animation = NULL;
+
+ if (tmpFileName.hasSuffix(".rlf"))
+ animation = new RLFDecoder();
+ else if (tmpFileName.hasSuffix(".avi"))
+ animation = new ZorkAVIDecoder();
+ else
+ error("Unknown suffix for animation %s", fileName.c_str());
+
+ Common::File *_file = getSearchManager()->openFile(tmpFileName);
+ animation->loadStream(_file);
+
+ return animation;
+}
+
void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect, bool skippable, Subtitle *sub) {
Common::Rect dst = destRect;
// If destRect is empty, no specific scaling was requested. However, we may choose to do scaling anyway