aboutsummaryrefslogtreecommitdiff
path: root/engines/zvision/video
diff options
context:
space:
mode:
authorPaul Gilbert2015-05-31 14:45:10 -0400
committerPaul Gilbert2015-05-31 14:45:10 -0400
commite5296ebf8dd09f603499b1894a33865ec71bb28f (patch)
treed7de032efd54dfdb3159cbc778a0c9ce8cd8aa91 /engines/zvision/video
parent673537bad93f0b440172a0cc263ebf19cc95ffc0 (diff)
parent141ff4d08dc24b6bb17098bd71801e2a58e6a38f (diff)
downloadscummvm-rg350-e5296ebf8dd09f603499b1894a33865ec71bb28f.tar.gz
scummvm-rg350-e5296ebf8dd09f603499b1894a33865ec71bb28f.tar.bz2
scummvm-rg350-e5296ebf8dd09f603499b1894a33865ec71bb28f.zip
Merge branch 'master' into phantom
Diffstat (limited to 'engines/zvision/video')
-rw-r--r--engines/zvision/video/rlf_decoder.cpp313
-rw-r--r--engines/zvision/video/rlf_decoder.h134
-rw-r--r--engines/zvision/video/video.cpp164
-rw-r--r--engines/zvision/video/zork_avi_decoder.cpp29
-rw-r--r--engines/zvision/video/zork_avi_decoder.h28
5 files changed, 564 insertions, 104 deletions
diff --git a/engines/zvision/video/rlf_decoder.cpp b/engines/zvision/video/rlf_decoder.cpp
new file mode 100644
index 0000000000..3bbf22edff
--- /dev/null
+++ b/engines/zvision/video/rlf_decoder.cpp
@@ -0,0 +1,313 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "common/scummsys.h"
+
+#include "zvision/video/rlf_decoder.h"
+
+#include "common/str.h"
+#include "common/file.h"
+#include "common/textconsole.h"
+#include "common/debug.h"
+#include "common/endian.h"
+
+namespace ZVision {
+
+RLFDecoder::~RLFDecoder() {
+ close();
+}
+
+bool RLFDecoder::loadStream(Common::SeekableReadStream *stream) {
+ close();
+
+ // Check if the stream is valid
+ if (stream && !stream->err() && stream->readUint32BE() == MKTAG('F', 'E', 'L', 'R')) {
+ addTrack(new RLFVideoTrack(stream));
+ return true;
+ } else {
+ return false;
+ }
+}
+
+RLFDecoder::RLFVideoTrack::RLFVideoTrack(Common::SeekableReadStream *stream)
+ : _readStream(stream),
+ _lastFrameRead(0),
+ _frameCount(0),
+ _width(0),
+ _height(0),
+ _frameTime(0),
+ _frames(0),
+ _displayedFrame(-1),
+ _frameBufferByteSize(0) {
+
+ if (!readHeader()) {
+ warning("Not a RLF animation file. Wrong magic number");
+ return;
+ }
+
+ _currentFrameBuffer.create(_width, _height, getPixelFormat());
+ _frameBufferByteSize = _width * _height * sizeof(uint16);
+
+ _frames = new Frame[_frameCount];
+
+ // Read in each frame
+ for (uint i = 0; i < _frameCount; ++i) {
+ _frames[i] = readNextFrame();
+ }
+}
+
+RLFDecoder::RLFVideoTrack::~RLFVideoTrack() {
+ for (uint i = 0; i < _frameCount; ++i) {
+ delete[] _frames[i].encodedData;
+ }
+ delete[] _frames;
+ delete _readStream;
+ _currentFrameBuffer.free();
+}
+
+bool RLFDecoder::RLFVideoTrack::readHeader() {
+ // Read the header
+ _readStream->readUint32LE(); // Size1
+ _readStream->readUint32LE(); // Unknown1
+ _readStream->readUint32LE(); // Unknown2
+ _frameCount = _readStream->readUint32LE(); // Frame count
+
+ // Since we don't need any of the data, we can just seek right to the
+ // entries we need rather than read in all the individual entries.
+ _readStream->seek(136, SEEK_CUR);
+
+ //// Read CIN header
+ //_readStream->readUint32BE(); // Magic number FNIC
+ //_readStream->readUint32LE(); // Size2
+ //_readStream->readUint32LE(); // Unknown3
+ //_readStream->readUint32LE(); // Unknown4
+ //_readStream->readUint32LE(); // Unknown5
+ //_readStream->seek(0x18, SEEK_CUR); // VRLE
+ //_readStream->readUint32LE(); // LRVD
+ //_readStream->readUint32LE(); // Unknown6
+ //_readStream->seek(0x18, SEEK_CUR); // HRLE
+ //_readStream->readUint32LE(); // ELHD
+ //_readStream->readUint32LE(); // Unknown7
+ //_readStream->seek(0x18, SEEK_CUR); // HKEY
+ //_readStream->readUint32LE(); // ELRH
+
+ //// Read MIN info header
+ //_readStream->readUint32BE(); // Magic number FNIM
+ //_readStream->readUint32LE(); // Size3
+ //_readStream->readUint32LE(); // OEDV
+ //_readStream->readUint32LE(); // Unknown8
+ //_readStream->readUint32LE(); // Unknown9
+ //_readStream->readUint32LE(); // Unknown10
+ _width = _readStream->readUint32LE(); // Width
+ _height = _readStream->readUint32LE(); // Height
+
+ // Read time header
+ _readStream->readUint32BE(); // Magic number EMIT
+ _readStream->readUint32LE(); // Size4
+ _readStream->readUint32LE(); // Unknown11
+ _frameTime = _readStream->readUint32LE() / 10; // Frame time in microseconds
+
+ return true;
+}
+
+RLFDecoder::RLFVideoTrack::Frame RLFDecoder::RLFVideoTrack::readNextFrame() {
+ RLFDecoder::RLFVideoTrack::Frame frame;
+
+ _readStream->readUint32BE(); // Magic number MARF
+ uint32 size = _readStream->readUint32LE(); // Size
+ _readStream->readUint32LE(); // Unknown1
+ _readStream->readUint32LE(); // Unknown2
+ uint32 type = _readStream->readUint32BE(); // Either ELHD or ELRH
+ uint32 headerSize = _readStream->readUint32LE(); // Offset from the beginning of this frame to the frame data. Should always be 28
+ _readStream->readUint32LE(); // Unknown3
+
+ frame.encodedSize = size - headerSize;
+ frame.encodedData = new int8[frame.encodedSize];
+ _readStream->read(frame.encodedData, frame.encodedSize);
+
+ if (type == MKTAG('E', 'L', 'H', 'D')) {
+ frame.type = Masked;
+ } else if (type == MKTAG('E', 'L', 'R', 'H')) {
+ frame.type = Simple;
+ _completeFrames.push_back(_lastFrameRead);
+ } else {
+ warning("Frame %u doesn't have type that can be decoded", _lastFrameRead);
+ }
+
+ _lastFrameRead++;
+ return frame;
+}
+
+bool RLFDecoder::RLFVideoTrack::seek(const Audio::Timestamp &time) {
+ uint frame = getFrameAtTime(time);
+ assert(frame < _frameCount);
+
+ if ((uint)_displayedFrame == frame)
+ return true;
+
+ int closestFrame = _displayedFrame;
+ int distance = (int)frame - closestFrame;
+
+ if (distance < 0) {
+ for (uint i = 0; i < _completeFrames.size(); ++i) {
+ if (_completeFrames[i] > frame)
+ break;
+ closestFrame = _completeFrames[i];
+ }
+ } else {
+ for (uint i = 0; i < _completeFrames.size(); ++i) {
+ int newDistance = (int)frame - (int)(_completeFrames[i]);
+ if (newDistance < 0)
+ break;
+ if (newDistance < distance) {
+ closestFrame = _completeFrames[i];
+ distance = newDistance;
+ }
+ }
+ }
+
+ for (uint i = closestFrame; i < frame; ++i) {
+ applyFrameToCurrent(i);
+ }
+
+ _displayedFrame = frame - 1;
+
+ return true;
+}
+
+const Graphics::Surface *RLFDecoder::RLFVideoTrack::decodeNextFrame() {
+ if (_displayedFrame >= (int)_frameCount)
+ return NULL;
+
+ _displayedFrame++;
+ applyFrameToCurrent(_displayedFrame);
+
+ return &_currentFrameBuffer;
+}
+
+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) {
+ decodeSimpleRunLengthEncoding(_frames[frameNumber].encodedData, (int8 *)_currentFrameBuffer.getPixels(), _frames[frameNumber].encodedSize, _frameBufferByteSize);
+ }
+}
+
+void RLFDecoder::RLFVideoTrack::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const {
+ uint32 sourceOffset = 0;
+ uint32 destOffset = 0;
+ int16 numberOfCopy = 0;
+
+ while (sourceOffset < sourceSize) {
+ int8 numberOfSamples = source[sourceOffset];
+ sourceOffset++;
+
+ // If numberOfSamples is negative, the next abs(numberOfSamples) samples should
+ // be copied directly from source to dest
+ if (numberOfSamples < 0) {
+ numberOfCopy = -numberOfSamples;
+
+ while (numberOfCopy > 0) {
+ if (sourceOffset + 1 >= sourceSize) {
+ return;
+ } else if (destOffset + 1 >= destSize) {
+ debug(2, "Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize);
+ return;
+ }
+
+ WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset));
+
+ sourceOffset += 2;
+ destOffset += 2;
+ numberOfCopy--;
+ }
+
+ // If numberOfSamples is >= 0, move destOffset forward ((numberOfSamples * 2) + 2)
+ // This function assumes the dest buffer has been memset with 0's.
+ } else {
+ if (sourceOffset + 1 >= sourceSize) {
+ return;
+ } else if (destOffset + 1 >= destSize) {
+ debug(2, "Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize);
+ return;
+ }
+
+ destOffset += (numberOfSamples * 2) + 2;
+ }
+ }
+}
+
+void RLFDecoder::RLFVideoTrack::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const {
+ uint32 sourceOffset = 0;
+ uint32 destOffset = 0;
+ int16 numberOfCopy = 0;
+
+ while (sourceOffset < sourceSize) {
+ int8 numberOfSamples = source[sourceOffset];
+ sourceOffset++;
+
+ // If numberOfSamples is negative, the next abs(numberOfSamples) samples should
+ // be copied directly from source to dest
+ if (numberOfSamples < 0) {
+ numberOfCopy = -numberOfSamples;
+
+ while (numberOfCopy > 0) {
+ if (sourceOffset + 1 >= sourceSize) {
+ return;
+ } else if (destOffset + 1 >= destSize) {
+ debug(2, "Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize);
+ return;
+ }
+
+ WRITE_UINT16(dest + destOffset, READ_LE_UINT16(source + sourceOffset));
+
+ sourceOffset += 2;
+ destOffset += 2;
+ numberOfCopy--;
+ }
+
+ // If numberOfSamples is >= 0, copy one sample from source to the
+ // next (numberOfSamples + 2) dest spots
+ } else {
+ if (sourceOffset + 1 >= sourceSize) {
+ return;
+ }
+
+ uint16 sampleColor = READ_LE_UINT16(source + sourceOffset);
+ sourceOffset += 2;
+
+ numberOfCopy = numberOfSamples + 2;
+ while (numberOfCopy > 0) {
+ if (destOffset + 1 >= destSize) {
+ debug(2, "Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize);
+ return;
+ }
+
+ WRITE_UINT16(dest + destOffset, sampleColor);
+ destOffset += 2;
+ numberOfCopy--;
+ }
+ }
+ }
+}
+
+} // End of namespace ZVision
diff --git a/engines/zvision/video/rlf_decoder.h b/engines/zvision/video/rlf_decoder.h
new file mode 100644
index 0000000000..8b8cbaecd5
--- /dev/null
+++ b/engines/zvision/video/rlf_decoder.h
@@ -0,0 +1,134 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ZVISION_RLF_DECODER_H
+#define ZVISION_RLF_DECODER_H
+
+#include "common/file.h"
+#include "video/video_decoder.h"
+
+#include "graphics/surface.h"
+
+namespace ZVision {
+
+class RLFDecoder : public Video::VideoDecoder {
+public:
+ RLFDecoder() {}
+ ~RLFDecoder();
+
+ bool loadStream(Common::SeekableReadStream *stream);
+
+private:
+ 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, 5, 5, 0, 10, 5, 0, 0); /* RGB 555 */ }
+ int getCurFrame() const { return _displayedFrame; }
+ 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(1000, _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 _displayedFrame;
+ Graphics::Surface _currentFrameBuffer;
+ uint32 _frameBufferByteSize;
+
+ Common::SeekableReadStream *_readStream;
+ }; // RLFVideoTrack
+};
+
+} // End of namespace ZVision
+
+#endif
diff --git a/engines/zvision/video/video.cpp b/engines/zvision/video/video.cpp
index d1fff30408..1cfd0f4197 100644
--- a/engines/zvision/video/video.cpp
+++ b/engines/zvision/video/video.cpp
@@ -8,12 +8,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
@@ -21,107 +21,78 @@
*/
#include "common/scummsys.h"
-
-#include "zvision/zvision.h"
-
-#include "zvision/utility/clock.h"
-#include "zvision/graphics/render_manager.h"
-
#include "common/system.h"
-
#include "video/video_decoder.h"
-
+#ifdef USE_MPEG2
+#include "video/mpegps_decoder.h"
+#endif
#include "engines/util.h"
-
#include "graphics/surface.h"
+#include "zvision/zvision.h"
+#include "zvision/core/clock.h"
+#include "zvision/graphics/render_manager.h"
+#include "zvision/scripting/script_manager.h"
+#include "zvision/text/subtitles.h"
+#include "zvision/video/rlf_decoder.h"
+#include "zvision/video/zork_avi_decoder.h"
namespace ZVision {
-// Taken/modified from SCI
-void scaleBuffer(const byte *src, byte *dst, uint32 srcWidth, uint32 srcHeight, byte bytesPerPixel, uint scaleAmount) {
- assert(bytesPerPixel == 1 || bytesPerPixel == 2);
-
- const uint32 newWidth = srcWidth * scaleAmount;
- const uint32 pitch = newWidth * bytesPerPixel;
- const byte *srcPtr = src;
-
- if (bytesPerPixel == 1) {
- for (uint32 y = 0; y < srcHeight; ++y) {
- for (uint32 x = 0; x < srcWidth; ++x) {
- const byte color = *srcPtr++;
-
- for (uint i = 0; i < scaleAmount; ++i) {
- dst[i] = color;
- dst[pitch + i] = color;
- }
- dst += scaleAmount;
- }
- dst += pitch;
- }
- } else if (bytesPerPixel == 2) {
- for (uint32 y = 0; y < srcHeight; ++y) {
- for (uint32 x = 0; x < srcWidth; ++x) {
- const byte color = *srcPtr++;
- const byte color2 = *srcPtr++;
-
- for (uint i = 0; i < scaleAmount; ++i) {
- uint index = i *2;
-
- dst[index] = color;
- dst[index + 1] = color2;
- dst[pitch + index] = color;
- dst[pitch + index + 1] = color2;
- }
- dst += 2 * scaleAmount;
- }
- dst += pitch;
- }
- }
+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();
+#ifdef USE_MPEG2
+ else if (tmpFileName.hasSuffix(".vob"))
+ animation = new Video::MPEGPSDecoder();
+#endif
+ else
+ error("Unknown suffix for animation %s", fileName.c_str());
+
+ Common::File *_file = getSearchManager()->openFile(tmpFileName);
+ if (!_file)
+ error("Error opening %s", tmpFileName.c_str());
+
+ bool loaded = animation->loadStream(_file);
+ if (!loaded)
+ error("Error loading animation %s", tmpFileName.c_str());
+
+ return animation;
}
-void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect, bool skippable) {
- byte bytesPerPixel = videoDecoder.getPixelFormat().bytesPerPixel;
-
- uint16 origWidth = videoDecoder.getWidth();
- uint16 origHeight = videoDecoder.getHeight();
-
- uint scale = 1;
+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
- if (destRect.isEmpty()) {
- // Most videos are very small. Therefore we do a simple 2x scale
- if (origWidth * 2 <= 640 && origHeight * 2 <= 480) {
- scale = 2;
- }
- } else {
- // Assume bilinear scaling. AKA calculate the scale from just the width.
- // Also assume that the scaling is in integral intervals. AKA no 1.5x scaling
- // TODO: Test ^these^ assumptions
- scale = destRect.width() / origWidth;
-
- // TODO: Test if we need to support downscale.
- }
-
- uint16 pitch = origWidth * bytesPerPixel;
+ if (dst.isEmpty())
+ dst = Common::Rect(vid.getWidth(), vid.getHeight());
- uint16 finalWidth = origWidth * scale;
- uint16 finalHeight = origHeight * scale;
+ Graphics::Surface *scaled = NULL;
- byte *scaledVideoFrameBuffer = 0;
- if (scale != 1) {
- scaledVideoFrameBuffer = new byte[finalWidth * finalHeight * bytesPerPixel];
+ if (vid.getWidth() != dst.width() || vid.getHeight() != dst.height()) {
+ scaled = new Graphics::Surface;
+ scaled->create(dst.width(), dst.height(), vid.getPixelFormat());
}
- uint16 x = ((WINDOW_WIDTH - finalWidth) / 2) + destRect.left;
- uint16 y = ((WINDOW_HEIGHT - finalHeight) / 2) + destRect.top;
+ uint16 x = _workingWindow.left + dst.left;
+ uint16 y = _workingWindow.top + dst.top;
+ uint16 finalWidth = dst.width() < _workingWindow.width() ? dst.width() : _workingWindow.width();
+ uint16 finalHeight = dst.height() < _workingWindow.height() ? dst.height() : _workingWindow.height();
+ bool showSubs = (_scriptManager->getStateValue(StateKey_Subtitles) == 1);
_clock.stop();
- videoDecoder.start();
+ vid.start();
+ _videoIsPlaying = true;
// Only continue while the video is still playing
- while (!shouldQuit() && !videoDecoder.endOfVideo() && videoDecoder.isPlaying()) {
+ while (!shouldQuit() && !vid.endOfVideo() && vid.isPlaying()) {
// Check for engine quit and video stop key presses
- while (!videoDecoder.endOfVideo() && videoDecoder.isPlaying() && _eventMan->pollEvent(_event)) {
+ while (_eventMan->pollEvent(_event)) {
switch (_event.type) {
case Common::EVENT_KEYDOWN:
switch (_event.kbd.keycode) {
@@ -131,7 +102,7 @@ void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &d
break;
case Common::KEYCODE_SPACE:
if (skippable) {
- videoDecoder.stop();
+ vid.stop();
}
break;
default:
@@ -142,29 +113,34 @@ void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &d
}
}
- if (videoDecoder.needsUpdate()) {
- const Graphics::Surface *frame = videoDecoder.decodeNextFrame();
+ if (vid.needsUpdate()) {
+ const Graphics::Surface *frame = vid.decodeNextFrame();
+ if (sub && showSubs)
+ sub->process(vid.getCurFrame());
if (frame) {
- if (scale != 1) {
- scaleBuffer((const byte *)frame->getPixels(), scaledVideoFrameBuffer, origWidth, origHeight, bytesPerPixel, scale);
- _system->copyRectToScreen(scaledVideoFrameBuffer, pitch * 2, x, y, finalWidth, finalHeight);
- } else {
- _system->copyRectToScreen((const byte *)frame->getPixels(), pitch, x, y, finalWidth, finalHeight);
+ if (scaled) {
+ _renderManager->scaleBuffer(frame->getPixels(), scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, scaled->w, scaled->h);
+ frame = scaled;
}
+ Common::Rect rect = Common::Rect(x, y, x + finalWidth, y + finalHeight);
+ _renderManager->copyToScreen(*frame, rect, 0, 0);
+ _renderManager->processSubs(0);
}
}
// Always update the screen so the mouse continues to render
_system->updateScreen();
- _system->delayMillis(videoDecoder.getTimeToNextFrame());
+ _system->delayMillis(vid.getTimeToNextFrame() / 2);
}
+ _videoIsPlaying = false;
_clock.start();
- if (scale != 1) {
- delete[] scaledVideoFrameBuffer;
+ if (scaled) {
+ scaled->free();
+ delete scaled;
}
}
diff --git a/engines/zvision/video/zork_avi_decoder.cpp b/engines/zvision/video/zork_avi_decoder.cpp
index f22a4203ab..cf8505ec82 100644
--- a/engines/zvision/video/zork_avi_decoder.cpp
+++ b/engines/zvision/video/zork_avi_decoder.cpp
@@ -29,7 +29,7 @@
#include "common/stream.h"
#include "audio/audiostream.h"
-
+#include "audio/decoders/raw.h"
namespace ZVision {
@@ -39,14 +39,39 @@ Video::AVIDecoder::AVIAudioTrack *ZorkAVIDecoder::createAudioTrack(Video::AVIDec
}
void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *stream) {
+ bool updateCurChunk = true;
if (_audStream) {
if (_wvInfo.tag == kWaveFormatZorkPCM) {
assert(_wvInfo.size == 8);
- _audStream->queueAudioStream(makeRawZorkStream(stream, _wvInfo.samplesPerSec, _audStream->isStereo(), DisposeAfterUse::YES), DisposeAfterUse::YES);
+ RawChunkStream::RawChunk chunk = decoder->readNextChunk(stream);
+ delete stream;
+
+ if (chunk.data) {
+ byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO;
+#ifdef SCUMM_LITTLE_ENDIAN
+ // RawChunkStream produces native endianness int16
+ flags |= Audio::FLAG_LITTLE_ENDIAN;
+#endif
+ _audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, flags);
+ }
+ } else {
+ updateCurChunk = false;
+ AVIAudioTrack::queueSound(stream);
}
} else {
delete stream;
}
+
+ // The superclass always updates _curChunk, whether or not audio has
+ // been queued, so we should do that too. Unless the superclass already
+ // has done it for us.
+ if (updateCurChunk) {
+ _curChunk++;
+ }
+}
+
+void ZorkAVIDecoder::ZorkAVIAudioTrack::resetStream() {
+ decoder->init();
}
} // End of namespace ZVision
diff --git a/engines/zvision/video/zork_avi_decoder.h b/engines/zvision/video/zork_avi_decoder.h
index c47f007f9b..89c0d1e4b9 100644
--- a/engines/zvision/video/zork_avi_decoder.h
+++ b/engines/zvision/video/zork_avi_decoder.h
@@ -8,41 +8,53 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
- *
+
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
+ *
*/
#ifndef ZORK_AVI_DECODER_H
#define ZORK_AVI_DECODER_H
#include "video/avi_decoder.h"
-
+#include "zvision/sound/zork_raw.h"
namespace ZVision {
class ZorkAVIDecoder : public Video::AVIDecoder {
public:
ZorkAVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType) :
- Video::AVIDecoder(soundType) {}
+ Video::AVIDecoder(soundType) {}
- virtual ~ZorkAVIDecoder() {}
+ virtual ~ZorkAVIDecoder() {}
private:
class ZorkAVIAudioTrack : public Video::AVIDecoder::AVIAudioTrack {
public:
ZorkAVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) :
- Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType) {}
- virtual ~ZorkAVIAudioTrack() {}
+ Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType),
+ decoder(NULL) {
+ if (_audStream) {
+ decoder = new RawChunkStream(_audStream->isStereo());
+ }
+ }
+ virtual ~ZorkAVIAudioTrack() {
+ if (decoder)
+ delete decoder;
+ }
void queueSound(Common::SeekableReadStream *stream);
+ void resetStream();
+ private:
+ RawChunkStream *decoder;
};
Video::AVIDecoder::AVIAudioTrack *createAudioTrack(Video::AVIDecoder::AVIStreamHeader sHeader, Video::AVIDecoder::PCMWaveFormat wvInfo);
@@ -50,7 +62,7 @@ private:
private:
// Audio Codecs
enum {
- kWaveFormatZorkPCM = 17 // special Zork PCM audio format (clashes with MS IMA ADPCM)
+ kWaveFormatZorkPCM = 17 // special Zork PCM audio format (clashes with MS IMA ADPCM)
};
};