aboutsummaryrefslogtreecommitdiff
path: root/graphics/video
diff options
context:
space:
mode:
authorSven Hesse2010-08-08 00:36:19 +0000
committerSven Hesse2010-08-08 00:36:19 +0000
commit167c6e8787811910d2e62393231dc98f14d70d15 (patch)
treecc51a02cea4367998dfc72e1eb4677c8f2c13ec5 /graphics/video
parent59b9b3bc2bd1c057a6b0f56d2b49a46ff37e00b6 (diff)
downloadscummvm-rg350-167c6e8787811910d2e62393231dc98f14d70d15.tar.gz
scummvm-rg350-167c6e8787811910d2e62393231dc98f14d70d15.tar.bz2
scummvm-rg350-167c6e8787811910d2e62393231dc98f14d70d15.zip
VIDEO: Bare PreIMD decoding
Implemented bare PreIMD decoding using the new CoktelDecoder interface. No fancy stuff yet, only basic vieo frames. svn-id: r51854
Diffstat (limited to 'graphics/video')
-rw-r--r--graphics/video/coktel_decoder.cpp171
-rw-r--r--graphics/video/coktel_decoder.h15
2 files changed, 178 insertions, 8 deletions
diff --git a/graphics/video/coktel_decoder.cpp b/graphics/video/coktel_decoder.cpp
index a6c79cc1df..0c5b637c2b 100644
--- a/graphics/video/coktel_decoder.cpp
+++ b/graphics/video/coktel_decoder.cpp
@@ -68,32 +68,191 @@ Common::Rational CoktelDecoder::getFrameRate() const {
PreIMDDecoder::PreIMDDecoder(uint16 width, uint16 height,
- Audio::Mixer &mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType) {
+ Audio::Mixer &mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType),
+ _stream(0), _videoBuffer(0), _videoBufferSize(0) {
_width = width;
_height = height;
}
PreIMDDecoder::~PreIMDDecoder() {
+ close();
}
-bool PreIMDDecoder::seek(uint32 frame, int whence, bool restart) {
- return false;
+bool PreIMDDecoder::seek(int32 frame, int whence, bool restart) {
+ if (!isVideoLoaded())
+ // Nothing to do
+ return false;
+
+ // Find the frame to which to seek
+ if (whence == SEEK_CUR)
+ frame += _curFrame;
+ else if (whence == SEEK_END)
+ frame = _frameCount - frame - 1;
+ else if (whence == SEEK_SET)
+ frame--;
+ else
+ return false;
+
+ if ((frame < -1) || (((uint32) frame) >= _frameCount))
+ // Out of range
+ return false;
+
+ if (frame == _curFrame)
+ // Nothing to do
+ return true;
+
+ // Run through the frames
+ _curFrame = -1;
+ _stream->seek(2);
+ while (_curFrame != frame) {
+ uint16 frameSize = _stream->readUint16LE();
+
+ _stream->skip(frameSize + 2);
+
+ _curFrame++;
+ }
+
+ return true;
}
bool PreIMDDecoder::load(Common::SeekableReadStream &stream) {
- return false;
+ // Since PreIMDs don't have any width and height values stored,
+ // we need them to be specified in the constructor
+ assert((_width > 0) && (_height > 0));
+
+ close();
+
+ _stream = &stream;
+
+ _stream->seek(0);
+
+ _frameCount = _stream->readUint16LE();
+
+ _surface.create(_width, _height, 1);
+
+ _videoBufferSize = _width * _height;
+ _videoBuffer = new byte[_videoBufferSize];
+
+ memset(_videoBuffer, 0, _videoBufferSize);
+
+ return true;
}
void PreIMDDecoder::close() {
+ reset();
+
+ _surface.free();
+
+ delete _stream;
+
+ delete[] _videoBuffer;
+
+ _stream = 0;
+
+ _videoBuffer = 0;
+ _videoBufferSize = 0;
}
bool PreIMDDecoder::isVideoLoaded() const {
- return false;
+ return _stream != 0;
}
Surface *PreIMDDecoder::decodeNextFrame() {
- return 0;
+ if (!isVideoLoaded() || endOfVideo())
+ return 0;
+
+ processFrame();
+ renderFrame();
+
+ _curFrame++;
+
+ return &_surface;
+}
+
+void PreIMDDecoder::processFrame() {
+ uint16 frameSize = _stream->readUint16LE();
+
+ uint32 nextFramePos = _stream->pos() + frameSize + 2;
+
+ byte cmd;
+
+ cmd = _stream->readByte();
+ frameSize--;
+
+ if (cmd == 0) {
+ // Palette. Ignored by Fascination, though
+
+ _stream->skip(768);
+
+ frameSize -= 769;
+
+ cmd = _stream->readByte();
+ }
+
+ if (cmd != 2) {
+ // Partial frame data
+
+ uint32 fSize = frameSize;
+ uint32 vidSize = _videoBufferSize;
+
+ byte *vidBuffer = _videoBuffer;
+
+ while ((fSize > 0) && (vidSize > 0)) {
+ uint32 n = _stream->readByte();
+ fSize--;
+
+ if ((n & 0x80) != 0) {
+ // Data
+
+ n = MIN<uint32>((n & 0x7F) + 1, MIN(fSize, vidSize));
+
+ _stream->read(vidBuffer, n);
+
+ vidBuffer += n;
+ vidSize -= n;
+ fSize -= n;
+
+ } else {
+ // Skip
+
+ n = MIN<uint32>(n + 1, vidSize);
+
+ vidBuffer += n;
+ vidSize -= n;
+ }
+ }
+
+ } else {
+ // Full direct frame
+
+ uint32 vidSize = MIN<uint32>(_videoBufferSize, frameSize);
+
+ _stream->read(_videoBuffer, vidSize);
+ }
+
+ _stream->seek(nextFramePos);
+}
+
+void PreIMDDecoder::renderFrame() {
+ uint16 w = MIN<uint16>(_surface.w, _width);
+ uint16 h = MIN<uint16>(_surface.h, _height);
+
+ const byte *src = _videoBuffer;
+ byte *dst = (byte *) _surface.pixels; // + x/y
+
+ uint32 frameDataSize = _videoBufferSize;
+
+ while (h-- > 0) {
+ uint32 n = MIN<uint32>(w, frameDataSize);
+
+ memcpy(dst, src, n);
+
+ src += _width;
+ dst += _surface.pitch;
+
+ frameDataSize -= n;
+ }
}
PixelFormat PreIMDDecoder::getPixelFormat() const {
diff --git a/graphics/video/coktel_decoder.h b/graphics/video/coktel_decoder.h
index acbd533c00..b354a5cd9d 100644
--- a/graphics/video/coktel_decoder.h
+++ b/graphics/video/coktel_decoder.h
@@ -62,7 +62,7 @@ public:
Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
~CoktelDecoder();
- virtual bool seek(uint32 frame, int whence = SEEK_SET, bool restart = false) = 0;
+ virtual bool seek(int32 frame, int whence = SEEK_SET, bool restart = false) = 0;
// VideoDecoder interface
@@ -98,7 +98,7 @@ public:
Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
~PreIMDDecoder();
- bool seek(uint32 frame, int whence = SEEK_SET, bool restart = false);
+ bool seek(int32 frame, int whence = SEEK_SET, bool restart = false);
// VideoDecoder interface
@@ -110,6 +110,17 @@ public:
Surface *decodeNextFrame();
PixelFormat getPixelFormat() const;
+
+private:
+ Common::SeekableReadStream *_stream;
+
+ byte *_videoBuffer;
+ uint32 _videoBufferSize;
+
+ Surface _surface;
+
+ void processFrame();
+ void renderFrame();
};
} // End of namespace Graphics