aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/VectorRenderer.cpp4
-rw-r--r--graphics/VectorRendererSpec.cpp4
-rw-r--r--graphics/colormasks.h24
-rw-r--r--graphics/jpeg.cpp2
-rw-r--r--graphics/pict.cpp104
-rw-r--r--graphics/pict.h8
-rw-r--r--graphics/surface.cpp80
-rw-r--r--graphics/video/avi_decoder.cpp26
-rw-r--r--graphics/video/avi_decoder.h5
-rw-r--r--graphics/video/codecs/indeo3.cpp189
-rw-r--r--graphics/video/codecs/indeo3.h2
-rw-r--r--graphics/video/codecs/qdm2.cpp2
-rw-r--r--graphics/video/coktel_decoder.cpp40
-rw-r--r--graphics/video/qt_decoder.cpp68
-rw-r--r--graphics/video/qt_decoder.h15
-rw-r--r--graphics/video/smk_decoder.cpp94
-rw-r--r--graphics/video/smk_decoder.h5
17 files changed, 414 insertions, 258 deletions
diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp
index 725d7f173b..0237712f13 100644
--- a/graphics/VectorRenderer.cpp
+++ b/graphics/VectorRenderer.cpp
@@ -103,7 +103,7 @@ void VectorRenderer::stepGetPositions(const DrawStep &step, const Common::Rect &
break;
default:
- error("Vertical alignment in horizontal data.");
+ error("Vertical alignment in horizontal data");
}
} else {
in_x = area.left;
@@ -132,7 +132,7 @@ void VectorRenderer::stepGetPositions(const DrawStep &step, const Common::Rect &
break;
default:
- error("Horizontal alignment in vertical data.");
+ error("Horizontal alignment in vertical data");
}
} else {
in_y = area.top;
diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp
index 666a59b888..0ee13033af 100644
--- a/graphics/VectorRendererSpec.cpp
+++ b/graphics/VectorRendererSpec.cpp
@@ -164,7 +164,7 @@ inline frac_t fp_sqroot(uint32 x) {
x--; px -= pitch; \
} \
a2 = (T >> 8); \
- a1 = ~a2; \
+ a1 = ~a2 >> 4; \
}
@@ -255,7 +255,7 @@ void VectorRendererSpec<PixelType>::
fillSurface() {
byte *ptr = (byte *)_activeSurface->getBasePtr(0, 0);
- int h = _activeSurface->h ;
+ int h = _activeSurface->h;
int pitch = _activeSurface->pitch;
if (Base::_fillMode == kFillBackground) {
diff --git a/graphics/colormasks.h b/graphics/colormasks.h
index 1ab78fccc5..824d980ca3 100644
--- a/graphics/colormasks.h
+++ b/graphics/colormasks.h
@@ -168,6 +168,30 @@ struct ColorMasks<1555> {
};
template<>
+struct ColorMasks<5551> {
+ enum {
+ kBytesPerPixel = 2,
+
+ kAlphaBits = 1,
+ kRedBits = 5,
+ kGreenBits = 5,
+ kBlueBits = 5,
+
+ kAlphaShift = 0,
+ kRedShift = kGreenBits+kBlueBits+kAlphaBits,
+ kGreenShift = kBlueBits+kAlphaBits,
+ kBlueShift = kAlphaBits,
+
+ kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
+ kRedMask = ((1 << kRedBits) - 1) << kRedShift,
+ kGreenMask = ((1 << kGreenBits) - 1) << kGreenShift,
+ kBlueMask = ((1 << kBlueBits) - 1) << kBlueShift,
+
+ kRedBlueMask = kRedMask | kBlueMask
+ };
+};
+
+template<>
struct ColorMasks<4444> {
enum {
kBytesPerPixel = 2,
diff --git a/graphics/jpeg.cpp b/graphics/jpeg.cpp
index 1c7ad64646..fbc81b5db2 100644
--- a/graphics/jpeg.cpp
+++ b/graphics/jpeg.cpp
@@ -198,7 +198,7 @@ bool JPEG::readJFIF() {
byte majorVersion = _str->readByte();
byte minorVersion = _str->readByte();
if(majorVersion != 1 || minorVersion != 1)
- warning("JPEG::readJFIF() Non-v1.1 JPEGs may not be handled correctly!");
+ warning("JPEG::readJFIF() Non-v1.1 JPEGs may not be handled correctly");
/* byte densityUnits = */ _str->readByte();
/* uint16 xDensity = */ _str->readUint16BE();
/* uint16 yDensity = */ _str->readUint16BE();
diff --git a/graphics/pict.cpp b/graphics/pict.cpp
index f0dd7bbc6f..ebf643439b 100644
--- a/graphics/pict.cpp
+++ b/graphics/pict.cpp
@@ -48,6 +48,8 @@ PictDecoder::~PictDecoder() {
Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *palette) {
assert(stream);
+ _outputSurface = 0;
+
uint16 fileSize = stream->readUint16BE();
// If we have no file size here, we probably have a PICT from a file
@@ -61,9 +63,6 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale
_imageRect.bottom = stream->readUint16BE();
_imageRect.right = stream->readUint16BE();
_imageRect.debugPrint(0, "PICT Rect:");
-
- Graphics::Surface *image = new Graphics::Surface();
- image->create(_imageRect.width(), _imageRect.height(), _pixelFormat.bytesPerPixel);
_isPaletted = false;
// NOTE: This is only a subset of the full PICT format.
@@ -96,10 +95,10 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale
} else if (opcode == 0x001E) { // DefHilite
// Ignore, Contains no Data
} else if (opcode == 0x0098) { // PackBitsRect
- decodeDirectBitsRect(stream, image, true);
+ decodeDirectBitsRect(stream, _imageRect.width(), _imageRect.height(), true);
_isPaletted = true;
} else if (opcode == 0x009A) { // DirectBitsRect
- decodeDirectBitsRect(stream, image, false);
+ decodeDirectBitsRect(stream, _imageRect.width(), _imageRect.height(), false);
} else if (opcode == 0x00A1) { // LongComment
stream->readUint16BE();
uint16 dataSize = stream->readUint16BE();
@@ -119,7 +118,7 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale
origResRect.right = stream->readUint16BE();
stream->readUint32BE(); // Reserved
} else if (opcode == 0x8200) { // CompressedQuickTime
- decodeCompressedQuickTime(stream, image);
+ decodeCompressedQuickTime(stream);
break;
} else {
warning("Unknown PICT opcode %04x", opcode);
@@ -130,7 +129,7 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale
if (palette && _isPaletted)
memcpy(palette, _palette, 256 * 4);
- return image;
+ return _outputSurface;
}
PictDecoder::PixMap PictDecoder::readPixMap(Common::SeekableReadStream *stream, bool hasBaseAddr) {
@@ -163,7 +162,7 @@ struct DirectBitsRectData {
uint16 mode;
};
-void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette) {
+void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, uint16 width, uint16 height, bool hasPalette) {
static const PixelFormat directBitsFormat16 = PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
// Clear the palette
@@ -197,11 +196,18 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surfa
directBitsData.dstRect.right = stream->readUint16BE();
directBitsData.mode = stream->readUint16BE();
- if (directBitsData.pixMap.pixelSize != 8 && directBitsData.pixMap.pixelSize != 16 && directBitsData.pixMap.pixelSize != 32)
- error("Unhandled DirectBitsRect bitsPerPixel %d", directBitsData.pixMap.pixelSize);
+ byte bytesPerPixel = 0;
- byte bytesPerPixel = (directBitsData.pixMap.pixelSize == 32) ? 3 : directBitsData.pixMap.pixelSize / 8;
- byte *buffer = new byte[image->w * image->h * bytesPerPixel];
+ if (directBitsData.pixMap.pixelSize <= 8)
+ bytesPerPixel = 1;
+ else if (directBitsData.pixMap.pixelSize == 32)
+ bytesPerPixel = 3;
+ else
+ bytesPerPixel = directBitsData.pixMap.pixelSize / 8;
+
+ _outputSurface = new Graphics::Surface();
+ _outputSurface->create(width, height, (bytesPerPixel == 1) ? 1 : _pixelFormat.bytesPerPixel);
+ byte *buffer = new byte[width * height * bytesPerPixel];
// Read in amount of data per row
for (uint16 i = 0; i < directBitsData.pixMap.bounds.height(); i++) {
@@ -217,37 +223,37 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surfa
error("Unpacked DirectBitsRect data (not padded)");
} else if (directBitsData.pixMap.packType == 0 || directBitsData.pixMap.packType > 2) { // Packed
uint16 byteCount = (directBitsData.pixMap.rowBytes > 250) ? stream->readUint16BE() : stream->readByte();
- decodeDirectBitsLine(buffer + i * image->w * bytesPerPixel, directBitsData.pixMap.rowBytes, stream->readStream(byteCount), bytesPerPixel);
+ decodeDirectBitsLine(buffer + i * _outputSurface->w * bytesPerPixel, directBitsData.pixMap.rowBytes, stream->readStream(byteCount), directBitsData.pixMap.pixelSize, bytesPerPixel);
}
}
if (bytesPerPixel == 1) {
// Just copy to the image
- memcpy(image->pixels, buffer, image->w * image->h);
+ memcpy(_outputSurface->pixels, buffer, _outputSurface->w * _outputSurface->h);
} else if (bytesPerPixel == 2) {
// Convert from 16-bit to whatever surface we need
- for (uint16 y = 0; y < image->h; y++) {
- for (uint16 x = 0; x < image->w; x++) {
+ for (uint16 y = 0; y < _outputSurface->h; y++) {
+ for (uint16 x = 0; x < _outputSurface->w; x++) {
byte r = 0, g = 0, b = 0;
- uint32 color = READ_BE_UINT16(buffer + (y * image->w + x) * bytesPerPixel);
+ uint32 color = READ_BE_UINT16(buffer + (y * _outputSurface->w + x) * bytesPerPixel);
directBitsFormat16.colorToRGB(color, r, g, b);
if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint16 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
else
- *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
}
}
} else {
// Convert from 24-bit (planar!) to whatever surface we need
- for (uint16 y = 0; y < image->h; y++) {
- for (uint16 x = 0; x < image->w; x++) {
- byte r = *(buffer + y * image->w * 3 + x);
- byte g = *(buffer + y * image->w * 3 + image->w + x);
- byte b = *(buffer + y * image->w * 3 + image->w * 2 + x);
+ for (uint16 y = 0; y < _outputSurface->h; y++) {
+ for (uint16 x = 0; x < _outputSurface->w; x++) {
+ byte r = *(buffer + y * _outputSurface->w * 3 + x);
+ byte g = *(buffer + y * _outputSurface->w * 3 + _outputSurface->w + x);
+ byte b = *(buffer + y * _outputSurface->w * 3 + _outputSurface->w * 2 + x);
if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint16 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
else
- *((uint32 *)image->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint32 *)_outputSurface->getBasePtr(x, y)) = _pixelFormat.RGBToColor(r, g, b);
}
}
}
@@ -255,7 +261,7 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, Surfa
delete[] buffer;
}
-void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel) {
+void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel) {
uint32 dataDecoded = 0;
byte bytesPerDecode = (bytesPerPixel == 2) ? 2 : 1;
@@ -270,14 +276,17 @@ void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::Seekabl
if (bytesPerDecode == 2) {
WRITE_BE_UINT16(out, value);
out += 2;
- } else
- *out++ = value;
+ } else {
+ outputPixelBuffer(out, value, bitsPerPixel);
+ }
}
dataDecoded += runSize * bytesPerDecode;
} else {
uint32 runSize = (op + 1) * bytesPerDecode;
+
for (uint32 i = 0; i < runSize; i++)
- *out++ = data->readByte();
+ outputPixelBuffer(out, data->readByte(), bitsPerPixel);
+
dataDecoded += runSize;
}
}
@@ -292,12 +301,31 @@ void PictDecoder::decodeDirectBitsLine(byte *out, uint32 length, Common::Seekabl
delete data;
}
+void PictDecoder::outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel) {
+ switch (bitsPerPixel) {
+ case 1:
+ for (int i = 7; i >= 0; i--)
+ *out++ = (value >> i) & 1;
+ break;
+ case 2:
+ for (int i = 6; i >= 0; i -= 2)
+ *out++ = (value >> i) & 3;
+ break;
+ case 4:
+ *out++ = (value >> 4) & 0xf;
+ *out++ = value & 0xf;
+ break;
+ default:
+ *out++ = value;
+ }
+}
+
// Compressed QuickTime details can be found here:
// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/B-Chapter/2TheImageCompression.html
// http://developer.apple.com/documentation/QuickTime/Rm/CompressDecompress/ImageComprMgr/F-Chapter/6WorkingwiththeImage.html
// I'm just ignoring that because Myst ME uses none of that extra stuff. The offset is always the same.
-void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream, Graphics::Surface *image) {
+void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream) {
uint32 dataSize = stream->readUint32BE();
uint32 startPos = stream->pos();
@@ -310,23 +338,21 @@ void PictDecoder::decodeCompressedQuickTime(Common::SeekableReadStream *stream,
Surface *uComponent = _jpeg->getComponent(2);
Surface *vComponent = _jpeg->getComponent(3);
- Surface jpegImage;
- jpegImage.create(yComponent->w, yComponent->h, _pixelFormat.bytesPerPixel);
+ _outputSurface = new Graphics::Surface();
+ _outputSurface->create(yComponent->w, yComponent->h, _pixelFormat.bytesPerPixel);
- for (uint16 i = 0; i < jpegImage.h; i++) {
- for (uint16 j = 0; j < jpegImage.w; j++) {
+ for (uint16 i = 0; i < _outputSurface->h; i++) {
+ for (uint16 j = 0; j < _outputSurface->w; j++) {
byte r = 0, g = 0, b = 0;
YUV2RGB(*((byte *)yComponent->getBasePtr(j, i)), *((byte *)uComponent->getBasePtr(j, i)), *((byte *)vComponent->getBasePtr(j, i)), r, g, b);
if (_pixelFormat.bytesPerPixel == 2)
- *((uint16 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint16 *)_outputSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
else
- *((uint32 *)jpegImage.getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
+ *((uint32 *)_outputSurface->getBasePtr(j, i)) = _pixelFormat.RGBToColor(r, g, b);
}
}
- image->copyFrom(jpegImage);
stream->seek(startPos + dataSize);
- jpegImage.free();
delete jpegStream;
}
diff --git a/graphics/pict.h b/graphics/pict.h
index 12681f6128..a9ea170292 100644
--- a/graphics/pict.h
+++ b/graphics/pict.h
@@ -72,10 +72,12 @@ private:
JPEG *_jpeg;
byte _palette[256 * 4];
bool _isPaletted;
+ Graphics::Surface *_outputSurface;
- void decodeDirectBitsRect(Common::SeekableReadStream *stream, Surface *image, bool hasPalette);
- void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bytesPerPixel);
- void decodeCompressedQuickTime(Common::SeekableReadStream *stream, Surface *image);
+ void decodeDirectBitsRect(Common::SeekableReadStream *stream, uint16 width, uint16 height, bool hasPalette);
+ void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel);
+ void decodeCompressedQuickTime(Common::SeekableReadStream *stream);
+ void outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel);
};
} // End of namespace Graphics
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index 353803c23a..f06c24c2cd 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -24,6 +24,7 @@
#include "common/algorithm.h"
#include "common/util.h"
+#include "common/endian.h"
#include "graphics/primitives.h"
#include "graphics/surface.h"
@@ -143,8 +144,10 @@ void Surface::fillRect(Common::Rect r, uint32 color) {
lineLen *= 2;
if ((uint16)color != ((color & 0xff) | (color & 0xff) << 8))
useMemset = false;
+ } else if (bytesPerPixel == 4) {
+ useMemset = false;
} else if (bytesPerPixel != 1) {
- error("Surface::fillRect: bytesPerPixel must be 1 or 2");
+ error("Surface::fillRect: bytesPerPixel must be 1, 2 or 4");
}
if (useMemset) {
@@ -154,10 +157,18 @@ void Surface::fillRect(Common::Rect r, uint32 color) {
ptr += pitch;
}
} else {
- uint16 *ptr = (uint16 *)getBasePtr(r.left, r.top);
- while (height--) {
- Common::set_to(ptr, ptr + width, (uint16)color);
- ptr += pitch/2;
+ if (bytesPerPixel == 2) {
+ uint16 *ptr = (uint16 *)getBasePtr(r.left, r.top);
+ while (height--) {
+ Common::set_to(ptr, ptr + width, (uint16)color);
+ ptr += pitch/2;
+ }
+ } else {
+ uint32 *ptr = (uint32 *)getBasePtr(r.left, r.top);
+ while (height--) {
+ Common::set_to(ptr, ptr + width, color);
+ ptr += pitch / 4;
+ }
}
}
}
@@ -169,65 +180,72 @@ void Surface::frameRect(const Common::Rect &r, uint32 color) {
vLine(r.right-1, r.top, r.bottom-1, color);
}
-// FIXME: LordHoto asks why is this in Surface, since this
-// just supports 8bpp surfaces. Looks like someone wants
-// to subclass Surface to add this or it should be extended
-// to support 16bpp (or marked as just working for 8bpp
-// surfaces).
void Surface::move(int dx, int dy, int height) {
- // This function currently just works with 8bpp surfaces
- assert(bytesPerPixel == 1);
-
// Short circuit check - do we have to do anything anyway?
if ((dx == 0 && dy == 0) || height <= 0)
return;
+ if (bytesPerPixel != 1 && bytesPerPixel != 2)
+ error("Surface::move: bytesPerPixel must be 1 or 2");
+
byte *src, *dst;
int x, y;
// vertical movement
if (dy > 0) {
// move down - copy from bottom to top
- dst = (byte *)pixels + (height - 1) * w;
- src = dst - dy * w;
+ dst = (byte *)pixels + (height - 1) * pitch;
+ src = dst - dy * pitch;
for (y = dy; y < height; y++) {
- memcpy(dst, src, w);
- src -= w;
- dst -= w;
+ memcpy(dst, src, pitch);
+ src -= pitch;
+ dst -= pitch;
}
} else if (dy < 0) {
// move up - copy from top to bottom
dst = (byte *)pixels;
- src = dst - dy * w;
+ src = dst - dy * pitch;
for (y = -dy; y < height; y++) {
- memcpy(dst, src, w);
- src += w;
- dst += w;
+ memcpy(dst, src, pitch);
+ src += pitch;
+ dst += pitch;
}
}
// horizontal movement
if (dx > 0) {
// move right - copy from right to left
- dst = (byte *)pixels + (w - 1);
- src = dst - dx;
+ dst = (byte *)pixels + (pitch - bytesPerPixel);
+ src = dst - (dx * bytesPerPixel);
for (y = 0; y < height; y++) {
for (x = dx; x < w; x++) {
- *dst-- = *src--;
+ if (bytesPerPixel == 1) {
+ *dst-- = *src--;
+ } else if (bytesPerPixel == 2) {
+ *(uint16 *)dst = *(const uint16 *)src;
+ src -= 2;
+ dst -= 2;
+ }
}
- src += w + (w - dx);
- dst += w + (w - dx);
+ src += pitch + (pitch - dx * bytesPerPixel);
+ dst += pitch + (pitch - dx * bytesPerPixel);
}
} else if (dx < 0) {
// move left - copy from left to right
dst = (byte *)pixels;
- src = dst - dx;
+ src = dst - (dx * bytesPerPixel);
for (y = 0; y < height; y++) {
for (x = -dx; x < w; x++) {
- *dst++ = *src++;
+ if (bytesPerPixel == 1) {
+ *dst++ = *src++;
+ } else if (bytesPerPixel == 2) {
+ *(uint16 *)dst = *(const uint16 *)src;
+ src += 2;
+ dst += 2;
+ }
}
- src += w - (w + dx);
- dst += w - (w + dx);
+ src += pitch - (pitch + dx * bytesPerPixel);
+ dst += pitch - (pitch + dx * bytesPerPixel);
}
}
}
diff --git a/graphics/video/avi_decoder.cpp b/graphics/video/avi_decoder.cpp
index 4973cb3eb0..ceca89b8ee 100644
--- a/graphics/video/avi_decoder.cpp
+++ b/graphics/video/avi_decoder.cpp
@@ -42,6 +42,20 @@
namespace Graphics {
+/*
+static byte char2num(char c) {
+ return (c >= 48 && c <= 57) ? c - 48 : 0;
+}
+
+static byte getStreamNum(uint32 tag) {
+ return char2num((char)(tag >> 24)) * 16 + char2num((char)(tag >> 16));
+}
+*/
+
+static uint16 getStreamType(uint32 tag) {
+ return tag & 0xffff;
+}
+
AviDecoder::AviDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) {
_soundType = soundType;
@@ -418,16 +432,4 @@ Audio::QueuingAudioStream *AviDecoder::createAudioStream() {
return NULL;
}
-byte AviDecoder::char2num(char c) {
- return (c >= 48 && c <= 57) ? c - 48 : 0;
-}
-
-byte AviDecoder::getStreamNum(uint32 tag) {
- return char2num((char)(tag >> 24)) * 16 + char2num((char)(tag >> 16));
-}
-
-uint16 AviDecoder::getStreamType(uint32 tag) {
- return tag & 0xffff;
-}
-
} // End of namespace Graphics
diff --git a/graphics/video/avi_decoder.h b/graphics/video/avi_decoder.h
index 72cf2d7ef5..68795149c0 100644
--- a/graphics/video/avi_decoder.h
+++ b/graphics/video/avi_decoder.h
@@ -221,11 +221,6 @@ private:
Audio::SoundHandle *_audHandle;
Audio::QueuingAudioStream *_audStream;
Audio::QueuingAudioStream *createAudioStream();
-
- // Helper functions
- static byte char2num(char c);
- static byte getStreamNum(uint32 tag);
- static uint16 getStreamType(uint32 tag);
};
} // End of namespace Graphics
diff --git a/graphics/video/codecs/indeo3.cpp b/graphics/video/codecs/indeo3.cpp
index f59ae81e81..443340de2f 100644
--- a/graphics/video/codecs/indeo3.cpp
+++ b/graphics/video/codecs/indeo3.cpp
@@ -69,27 +69,22 @@ PixelFormat Indeo3Decoder::getPixelFormat() const {
return _pixelFormat;
}
-bool Indeo3Decoder::isIndeo3(byte *data, uint32 dataLen) {
- // No data, no Indeo 3
- if (!data)
- return false;
-
+bool Indeo3Decoder::isIndeo3(Common::SeekableReadStream &stream) {
// Less than 16 bytes? This can't be right
- if (dataLen < 16)
+ if (stream.size() < 16)
return false;
+ uint32 id0 = stream.readUint32LE();
+ uint32 id1 = stream.readUint32LE();
+ uint32 id2 = stream.readUint32LE();
+ uint32 id3 = stream.readUint32LE();
+
// Unknown, but according to the docs, always 0
- if (READ_LE_UINT32(data + 4) != 0)
+ if (id1 != 0)
return false;
- uint32 id;
- id = READ_LE_UINT32(data ); // frame number
- id ^= READ_LE_UINT32(data + 4); // unknown
- id ^= READ_LE_UINT32(data + 8); // checksum
- id ^= READ_LE_UINT32(data + 12); // frame data length
-
// These 4 uint32s XOR'd need to spell "FRMH"
- if (id != MKID_BE('FRMH'))
+ if ((id0 ^ id1 ^ id2 ^ id3) != MKID_BE('FRMH'))
return false;
return true;
@@ -174,31 +169,23 @@ void Indeo3Decoder::allocFrames() {
}
Surface *Indeo3Decoder::decodeImage(Common::SeekableReadStream *stream) {
- uint32 dataLen = stream->size();
-
- byte *inData = new byte[dataLen];
-
- if (stream->read(inData, dataLen) != dataLen)
- return 0;
-
// Not Indeo 3? Fail
- if (!isIndeo3(inData, dataLen))
+ if (!isIndeo3(*stream))
return 0;
- uint32 frameDataLen = READ_LE_UINT32(inData + 12);
+ stream->seek(12);
+ uint32 frameDataLen = stream->readUint32LE();
// Less data than the frame should have? Fail
- if (dataLen < (frameDataLen - 16))
+ if (stream->size() < (int)(frameDataLen - 16))
return 0;
- Common::MemoryReadStream frame(inData, dataLen);
+ stream->seek(16); // Behind header
+ stream->skip(2); // Unknown
- frame.skip(16); // Header
- frame.skip(2); // Unknown
-
- uint16 flags1 = frame.readUint16LE();
- uint32 flags3 = frame.readUint32LE();
- uint8 flags2 = frame.readByte();
+ uint16 flags1 = stream->readUint16LE();
+ uint32 flags3 = stream->readUint32LE();
+ uint8 flags2 = stream->readByte();
// Finding the reference frame
if (flags1 & 0x200) {
@@ -212,77 +199,153 @@ Surface *Indeo3Decoder::decodeImage(Common::SeekableReadStream *stream) {
if (flags3 == 0x80)
return _surface;
- frame.skip(3);
+ stream->skip(3);
- uint16 fHeight = frame.readUint16LE();
- uint16 fWidth = frame.readUint16LE();
+ uint16 fHeight = stream->readUint16LE();
+ uint16 fWidth = stream->readUint16LE();
uint32 chromaHeight = ((fHeight >> 2) + 3) & 0x7FFC;
uint32 chromaWidth = ((fWidth >> 2) + 3) & 0x7FFC;
uint32 offs;
- uint32 offsY = frame.readUint32LE() + 16;
- uint32 offsU = frame.readUint32LE() + 16;
- uint32 offsV = frame.readUint32LE() + 16;
+ uint32 offsY = stream->readUint32LE() + 16;
+ uint32 offsU = stream->readUint32LE() + 16;
+ uint32 offsV = stream->readUint32LE() + 16;
+
+ stream->skip(4);
+
+ uint32 hPos = stream->pos();
+
+ if (offsY < hPos) {
+ warning("Indeo3Decoder::decodeImage: offsY < hPos");
+ return 0;
+ }
+ if (offsU < hPos) {
+ warning("Indeo3Decoder::decodeImage: offsY < hPos");
+ return 0;
+ }
+ if (offsV < hPos) {
+ warning("Indeo3Decoder::decodeImage: offsY < hPos");
+ return 0;
+ }
- frame.skip(4);
+ uint32 dataSize = stream->size() - hPos;
- uint32 hPos = frame.pos();
+ byte *inData = new byte[dataSize];
+
+ if (stream->read(inData, dataSize) != dataSize) {
+ delete[] inData;
+ return 0;
+ }
- byte *hdr_pos = inData + hPos;
+ byte *hdr_pos = inData;
byte *buf_pos;
// Luminance Y
- frame.seek(offsY);
- buf_pos = inData + offsY + 4;
- offs = frame.readUint32LE();
+ stream->seek(offsY);
+ buf_pos = inData + offsY + 4 - hPos;
+ offs = stream->readUint32LE();
decodeChunk(_cur_frame->Ybuf, _ref_frame->Ybuf, fWidth, fHeight,
buf_pos + offs * 2, flags2, hdr_pos, buf_pos, MIN<int>(fWidth, 160));
// Chrominance U
- frame.seek(offsU);
- buf_pos = inData + offsU + 4;
- offs = frame.readUint32LE();
+ stream->seek(offsU);
+ buf_pos = inData + offsU + 4 - hPos;
+ offs = stream->readUint32LE();
decodeChunk(_cur_frame->Vbuf, _ref_frame->Vbuf, chromaWidth, chromaHeight,
buf_pos + offs * 2, flags2, hdr_pos, buf_pos, MIN<int>(chromaWidth, 40));
// Chrominance V
- frame.seek(offsV);
- buf_pos = inData + offsV + 4;
- offs = frame.readUint32LE();
+ stream->seek(offsV);
+ buf_pos = inData + offsV + 4 - hPos;
+ offs = stream->readUint32LE();
decodeChunk(_cur_frame->Ubuf, _ref_frame->Ubuf, chromaWidth, chromaHeight,
buf_pos + offs * 2, flags2, hdr_pos, buf_pos, MIN<int>(chromaWidth, 40));
+ delete[] inData;
+
// Blit the frame onto the surface
const byte *srcY = _cur_frame->Ybuf;
const byte *srcU = _cur_frame->Ubuf;
const byte *srcV = _cur_frame->Vbuf;
byte *dest = (byte *)_surface->pixels;
+
+ const byte *srcUP = srcU;
+ const byte *srcVP = srcV;
+ const byte *srcUN = srcU + chromaWidth;
+ const byte *srcVN = srcV + chromaWidth;
+
+ uint32 scaleWidth = _surface->w / fWidth;
+ uint32 scaleHeight = _surface->h / fHeight;
+
for (uint32 y = 0; y < fHeight; y++) {
byte *rowDest = dest;
- for (uint32 x = 0; x < fWidth; x++, rowDest += _surface->bytesPerPixel) {
- const byte cY = srcY[x];
- const byte cU = srcU[x >> 2];
- const byte cV = srcV[x >> 2];
+ for (uint32 sH = 0; sH < scaleHeight; sH++) {
+ for (uint32 x = 0; x < fWidth; x++) {
+ uint32 xP = MAX<int32>((x >> 2) - 1, 0);
+ uint32 xN = MIN<int32>((x >> 2) + 1, chromaWidth - 1);
+
+ byte cY = srcY[x];
+ byte cU = srcU[x >> 2];
+ byte cV = srcV[x >> 2];
+
+ if (((x % 4) == 0) && ((y % 4) == 0)) {
+ cU = (((uint32) cU) + ((uint32) srcUP[xP])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcVP[xP])) / 2;
+ } else if (((x % 4) == 3) && ((y % 4) == 0)) {
+ cU = (((uint32) cU) + ((uint32) srcUP[xN])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcVP[xN])) / 2;
+ } else if (((x % 4) == 0) && ((y % 4) == 3)) {
+ cU = (((uint32) cU) + ((uint32) srcUN[xP])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcVN[xP])) / 2;
+ } else if (((x % 4) == 3) && ((y % 4) == 3)) {
+ cU = (((uint32) cU) + ((uint32) srcUN[xN])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcVN[xN])) / 2;
+ } else if ( (x % 4) == 0) {
+ cU = (((uint32) cU) + ((uint32) srcU[xP])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcV[xP])) / 2;
+ } else if ( (x % 4) == 3) {
+ cU = (((uint32) cU) + ((uint32) srcU[xN])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcV[xN])) / 2;
+ } else if ( (y % 4) == 0) {
+ cU = (((uint32) cU) + ((uint32) srcUP[x >> 2])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcVP[x >> 2])) / 2;
+ } else if ( (y % 4) == 3) {
+ cU = (((uint32) cU) + ((uint32) srcUN[x >> 2])) / 2;
+ cV = (((uint32) cV) + ((uint32) srcVN[x >> 2])) / 2;
+ }
+
+ byte r = 0, g = 0, b = 0;
+ YUV2RGB(cY, cU, cV, r, g, b);
- byte r = 0, g = 0, b = 0;
- YUV2RGB(cY, cU, cV, r, g, b);
+ const uint32 color = _pixelFormat.RGBToColor(r, g, b);
- const uint32 color = _pixelFormat.RGBToColor(r, g, b);
+ for (uint32 sW = 0; sW < scaleWidth; sW++, rowDest += _surface->bytesPerPixel) {
+ if (_surface->bytesPerPixel == 1)
+ *((uint8 *)rowDest) = (uint8)color;
+ else if (_surface->bytesPerPixel == 2)
+ *((uint16 *)rowDest) = (uint16)color;
+ }
+ }
- if (_surface->bytesPerPixel == 1)
- *((uint8 *)rowDest) = (uint8)color;
- else if (_surface->bytesPerPixel == 2)
- *((uint16 *)rowDest) = (uint16)color;
+ dest += _surface->pitch;
}
- dest += _surface->pitch;
srcY += fWidth;
if ((y & 3) == 3) {
- srcU += fWidth >> 2;
- srcV += fWidth >> 2;
+ srcU += chromaWidth;
+ srcV += chromaWidth;
+
+ if (y > 0) {
+ srcUP += chromaWidth;
+ srcVP += chromaWidth;
+ }
+ if (y < (fHeight - 4U)) {
+ srcUN += chromaWidth;
+ srcVN += chromaWidth;
+ }
}
}
diff --git a/graphics/video/codecs/indeo3.h b/graphics/video/codecs/indeo3.h
index 8d50b74b1e..319a8e5d42 100644
--- a/graphics/video/codecs/indeo3.h
+++ b/graphics/video/codecs/indeo3.h
@@ -49,7 +49,7 @@ public:
Surface *decodeImage(Common::SeekableReadStream *stream);
PixelFormat getPixelFormat() const;
- static bool isIndeo3(byte *data, uint32 dataLen);
+ static bool isIndeo3(Common::SeekableReadStream &stream);
private:
Surface *_surface;
diff --git a/graphics/video/codecs/qdm2.cpp b/graphics/video/codecs/qdm2.cpp
index 9f151b4ba8..0050b256d1 100644
--- a/graphics/video/codecs/qdm2.cpp
+++ b/graphics/video/codecs/qdm2.cpp
@@ -1775,7 +1775,7 @@ QDM2Stream::QDM2Stream(Common::SeekableReadStream *stream, Common::SeekableReadS
tmp = extraData->readUint32BE();
debug(1, "QDM2Stream::QDM2Stream() extraType: %d", tmp);
if (tmp == MKID_BE('QDMC'))
- warning("QDM2Stream::QDM2Stream() QDMC stream type not supported.");
+ warning("QDM2Stream::QDM2Stream() QDMC stream type not supported");
else if (tmp != MKID_BE('QDM2'))
error("QDM2Stream::QDM2Stream() Unsupported stream type");
diff --git a/graphics/video/coktel_decoder.cpp b/graphics/video/coktel_decoder.cpp
index 0709288091..10be09eb23 100644
--- a/graphics/video/coktel_decoder.cpp
+++ b/graphics/video/coktel_decoder.cpp
@@ -399,11 +399,11 @@ void CoktelDecoder::renderBlockWhole(const byte *src, Common::Rect &rect) {
rect.clip(_surface.w, _surface.h);
- byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left;
+ byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left * _surface.bytesPerPixel;
for (int i = 0; i < rect.height(); i++) {
- memcpy(dst, src, rect.width());
+ memcpy(dst, src, rect.width() * _surface.bytesPerPixel);
- src += srcRect.width();
+ src += srcRect.width() * _surface.bytesPerPixel;
dst += _surface.pitch;
}
}
@@ -581,7 +581,7 @@ uint32 CoktelDecoder::getTimeToNextFrame() const {
// the middle of a long video.
if (!hasSound())
- return Common::Rational(1000, _frameRate).toInt();
+ return (1000 / _frameRate).toInt();
// If there /is/ audio, we do need to keep video and audio
// in sync, though.
@@ -1589,12 +1589,6 @@ bool VMDDecoder::load(Common::SeekableReadStream *stream) {
if (_version & 4)
_bytesPerPixel = handle + 1;
- if (_bytesPerPixel != 1) {
- warning("TODO: _bytesPerPixel = %d", _bytesPerPixel);
- close();
- return false;
- }
-
if (_bytesPerPixel > 3) {
warning("VMDDecoder::load(): Requested %d bytes per pixel (%d, %d, %d)",
_bytesPerPixel, headerLength, handle, _version);
@@ -1696,6 +1690,11 @@ bool VMDDecoder::assessVideoProperties() {
_bytesPerPixel = n;
}
+ if ((_bytesPerPixel > 1) && !_externalCodec) {
+ warning("VMDDecoder::assessVideoProperties(): TODO: Internal _bytesPerPixel == %d", _bytesPerPixel);
+ return false;
+ }
+
if (_hasVideo) {
if ((_frameDataSize == 0) || (_frameDataSize > 1048576))
_frameDataSize = _width * _height + 1000;
@@ -1837,7 +1836,7 @@ bool VMDDecoder::readFiles() {
break;
if (_frames[i].parts[j].type == kPartTypeFile) {
- File file;;
+ File file;
file.offset = _stream->pos() + 20;
file.size = _frames[i].parts[j].size;
@@ -2087,9 +2086,19 @@ bool VMDDecoder::renderFrame(Common::Rect &rect) {
return false;
if (_externalCodec) {
- // TODO
- warning("_external codec");
- return false;
+ if (!_codec)
+ return false;
+
+ Common::MemoryReadStream frameStream(_frameData, _frameDataLen);
+ Surface *codecSurf = _codec->decodeImage(&frameStream);
+ if (!codecSurf)
+ return false;
+
+ rect = Common::Rect(_x, _y, _x + codecSurf->w, _y + codecSurf->h);
+ rect.clip(Common::Rect(_x, _y, _x + _width, _y + _height));
+
+ renderBlockWhole((const byte *) codecSurf->pixels, rect);
+ return true;
}
if (_blitMode > 0) {
@@ -2376,6 +2385,9 @@ byte *VMDDecoder::deADPCM(const byte *data, uint32 &size, int32 init, int32 inde
}
PixelFormat VMDDecoder::getPixelFormat() const {
+ if (_externalCodec && _codec)
+ return _codec->getPixelFormat();
+
return PixelFormat::createFormatCLUT8();
}
diff --git a/graphics/video/qt_decoder.cpp b/graphics/video/qt_decoder.cpp
index 470441dab8..8437f0af43 100644
--- a/graphics/video/qt_decoder.cpp
+++ b/graphics/video/qt_decoder.cpp
@@ -67,6 +67,8 @@ QuickTimeDecoder::QuickTimeDecoder() : VideoDecoder() {
_numStreams = 0;
_fd = 0;
_scaledSurface = 0;
+ _scaleFactorX = 1;
+ _scaleFactorY = 1;
_dirtyPalette = false;
_resFork = new Common::MacResManager();
@@ -82,14 +84,14 @@ uint16 QuickTimeDecoder::getWidth() const {
if (_videoStreamIndex < 0)
return 0;
- return _streams[_videoStreamIndex]->width / getScaleMode();
+ return (Common::Rational(_streams[_videoStreamIndex]->width) / getScaleFactorX()).toInt();
}
uint16 QuickTimeDecoder::getHeight() const {
if (_videoStreamIndex < 0)
return 0;
- return _streams[_videoStreamIndex]->height / getScaleMode();
+ return (Common::Rational(_streams[_videoStreamIndex]->height) / getScaleFactorY()).toInt();
}
uint32 QuickTimeDecoder::getFrameCount() const {
@@ -113,11 +115,18 @@ uint32 QuickTimeDecoder::getCodecTag() {
return _streams[_videoStreamIndex]->codec_tag;
}
-ScaleMode QuickTimeDecoder::getScaleMode() const {
+Common::Rational QuickTimeDecoder::getScaleFactorX() const {
if (_videoStreamIndex < 0)
- return kScaleNormal;
+ return 1;
- return (ScaleMode)(_scaleMode * _streams[_videoStreamIndex]->scaleMode);
+ return (_scaleFactorX * _streams[_videoStreamIndex]->scaleFactorX);
+}
+
+Common::Rational QuickTimeDecoder::getScaleFactorY() const {
+ if (_videoStreamIndex < 0)
+ return 1;
+
+ return (_scaleFactorY * _streams[_videoStreamIndex]->scaleFactorY);
}
uint32 QuickTimeDecoder::getFrameDuration() {
@@ -231,14 +240,14 @@ Surface *QuickTimeDecoder::decodeNextFrame() {
}
Surface *QuickTimeDecoder::scaleSurface(Surface *frame) {
- if (getScaleMode() == kScaleNormal)
+ if (getScaleFactorX() == 1 && getScaleFactorY() == 1)
return frame;
assert(_scaledSurface);
- for (uint32 j = 0; j < _scaledSurface->h; j++)
- for (uint32 k = 0; k < _scaledSurface->w; k++)
- memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr(k * getScaleMode(), j * getScaleMode()), frame->bytesPerPixel);
+ for (int32 j = 0; j < _scaledSurface->h; j++)
+ for (int32 k = 0; k < _scaledSurface->w; k++)
+ memcpy(_scaledSurface->getBasePtr(k, j), frame->getBasePtr((k * getScaleFactorX()).toInt() , (j * getScaleFactorY()).toInt()), frame->bytesPerPixel);
return _scaledSurface;
}
@@ -376,7 +385,7 @@ void QuickTimeDecoder::init() {
if (_videoStreamIndex >= 0) {
_videoCodec = createCodec(getCodecTag(), getBitsPerPixel());
- if (getScaleMode() != kScaleNormal) {
+ if (getScaleFactorX() != 1 || getScaleFactorY() != 1) {
// We have to initialize the scaled surface
_scaledSurface = new Surface();
_scaledSurface->create(getWidth(), getHeight(), getPixelFormat().bytesPerPixel);
@@ -593,17 +602,11 @@ int QuickTimeDecoder::readMVHD(MOVatom atom) {
uint32 yMod = _fd->readUint32BE();
_fd->skip(16);
- if (xMod != yMod)
- error("X and Y resolution modifiers differ");
-
- if (xMod == 0x8000)
- _scaleMode = kScaleHalf;
- else if (xMod == 0x4000)
- _scaleMode = kScaleQuarter;
- else
- _scaleMode = kScaleNormal;
+ _scaleFactorX = Common::Rational(0x10000, xMod);
+ _scaleFactorY = Common::Rational(0x10000, yMod);
- debug(1, "readMVHD(): scaleMode = %d", (int)_scaleMode);
+ _scaleFactorX.debugPrint(1, "readMVHD(): scaleFactorX =");
+ _scaleFactorY.debugPrint(1, "readMVHD(): scaleFactorY =");
_fd->readUint32BE(); // preview time
_fd->readUint32BE(); // preview duration
@@ -688,17 +691,11 @@ int QuickTimeDecoder::readTKHD(MOVatom atom) {
uint32 yMod = _fd->readUint32BE();
_fd->skip(16);
- if (xMod != yMod)
- error("X and Y resolution modifiers differ");
+ st->scaleFactorX = Common::Rational(0x10000, xMod);
+ st->scaleFactorY = Common::Rational(0x10000, yMod);
- if (xMod == 0x8000)
- st->scaleMode = kScaleHalf;
- else if (xMod == 0x4000)
- st->scaleMode = kScaleQuarter;
- else
- st->scaleMode = kScaleNormal;
-
- debug(1, "readTKHD(): scaleMode = %d", (int)_scaleMode);
+ st->scaleFactorX.debugPrint(1, "readTKHD(): scaleFactorX =");
+ st->scaleFactorY.debugPrint(1, "readTKHD(): scaleFactorY =");
// these are fixed-point, 16:16
// uint32 tkWidth = _fd->readUint32BE() >> 16; // track width
@@ -814,6 +811,17 @@ int QuickTimeDecoder::readSTSD(MOVatom atom) {
_fd->readUint16BE(); // index
debug(0, "size=%d 4CC= %s codec_type=%d", size, tag2str(format), st->codec_type);
+
+ if (st->codec_tag && st->codec_tag != format) {
+ // HACK: Multiple FourCC, skip this. FFmpeg does this too and also
+ // skips it with a TODO. However, we really don't need to support
+ // multiple codec tags since the only two videos in Riven DVD that
+ // do this just have a fake second stream (or so it seems).
+ debug(3, "Multiple FourCC not supported");
+ _fd->seek(start_pos + size);
+ continue;
+ }
+
st->codec_tag = format;
if (st->codec_type == CODEC_TYPE_VIDEO) {
diff --git a/graphics/video/qt_decoder.h b/graphics/video/qt_decoder.h
index 196d4c02cb..6dcfc0944d 100644
--- a/graphics/video/qt_decoder.h
+++ b/graphics/video/qt_decoder.h
@@ -36,6 +36,7 @@
#include "common/scummsys.h"
#include "common/queue.h"
+#include "common/rational.h"
#include "graphics/video/video_decoder.h"
#include "graphics/video/codecs/codec.h"
@@ -50,11 +51,6 @@ namespace Common {
namespace Graphics {
-enum ScaleMode {
- kScaleNormal = 1,
- kScaleHalf = 2,
- kScaleQuarter = 4
-};
class QuickTimeDecoder : public RewindableVideoDecoder {
public:
@@ -217,7 +213,8 @@ protected:
uint32 nb_frames;
uint32 duration;
uint32 start_time;
- ScaleMode scaleMode;
+ Common::Rational scaleFactorX;
+ Common::Rational scaleFactorY;
};
const ParseTable *_parseTable;
@@ -230,7 +227,8 @@ protected:
MOVStreamContext *_partial;
uint32 _numStreams;
int _ni;
- ScaleMode _scaleMode;
+ Common::Rational _scaleFactorX;
+ Common::Rational _scaleFactorY;
MOVStreamContext *_streams[20];
byte _palette[256 * 3];
bool _dirtyPalette;
@@ -260,7 +258,8 @@ protected:
Surface *_scaledSurface;
Surface *scaleSurface(Surface *frame);
- ScaleMode getScaleMode() const;
+ Common::Rational getScaleFactorX() const;
+ Common::Rational getScaleFactorY() const;
void pauseVideoIntern(bool pause);
diff --git a/graphics/video/smk_decoder.cpp b/graphics/video/smk_decoder.cpp
index 4d03305cce..71858dd3aa 100644
--- a/graphics/video/smk_decoder.cpp
+++ b/graphics/video/smk_decoder.cpp
@@ -389,12 +389,13 @@ bool SmackerDecoder::load(Common::SeekableReadStream *stream) {
_frameCount = _fileStream->readUint32LE();
int32 frameRate = _fileStream->readSint32LE();
+ // framerate contains 2 digits after the comma, so 1497 is actually 14.97 fps
if (frameRate > 0)
- _frameRate = 1000 / frameRate;
+ _frameRate = Common::Rational(1000, frameRate);
else if (frameRate < 0)
- _frameRate = 100000 / (-frameRate);
+ _frameRate = Common::Rational(100000, -frameRate);
else
- _frameRate = 10;
+ _frameRate = 1000;
// Flags are determined by which bit is set, which can be one of the following:
// 0 - set to 1 if file contains a ring frame.
@@ -540,53 +541,18 @@ Surface *SmackerDecoder::decodeNextFrame() {
chunkSize = _fileStream->readUint32LE();
chunkSize -= 4; // subtract the first 4 bytes (chunk size)
- if (_header.audioInfo[i].compression != kCompressionNone) {
+ if (_header.audioInfo[i].compression == kCompressionNone) {
+ dataSizeUnpacked = chunkSize;
+ } else {
dataSizeUnpacked = _fileStream->readUint32LE();
chunkSize -= 4; // subtract the next 4 bytes (unpacked data size)
- } else {
- dataSizeUnpacked = 0;
}
- if (_header.audioInfo[i].hasAudio && chunkSize > 0 && i == 0) {
- // If it's track 0, play the audio data
- byte *soundBuffer = (byte *)malloc(chunkSize);
-
- _fileStream->read(soundBuffer, chunkSize);
-
- if (_header.audioInfo[i].compression == kCompressionRDFT || _header.audioInfo[i].compression == kCompressionDCT) {
- // TODO: Compressed audio (Bink RDFT/DCT encoded)
- free(soundBuffer);
- continue;
- } else if (_header.audioInfo[i].compression == kCompressionDPCM) {
- // Compressed audio (Huffman DPCM encoded)
- queueCompressedBuffer(soundBuffer, chunkSize, dataSizeUnpacked, i);
- free(soundBuffer);
- } else {
- // Uncompressed audio (PCM)
- byte flags = 0;
- if (_header.audioInfo[0].is16Bits)
- flags = flags | Audio::FLAG_16BITS;
- if (_header.audioInfo[0].isStereo)
- flags = flags | Audio::FLAG_STEREO;
-
- _audioStream->queueBuffer(soundBuffer, chunkSize, DisposeAfterUse::YES, flags);
- // The sound buffer will be deleted by QueuingAudioStream
- }
-
- if (!_audioStarted) {
- _mixer->playStream(_soundType, &_audioHandle, _audioStream, -1, 255);
- _audioStarted = true;
- }
- } else {
- // Ignore the rest of the audio tracks, if they exist
- // TODO: Are there any Smacker videos with more than one audio stream?
- // If yes, we should play the rest of the audio streams as well
- if (chunkSize > 0)
- _fileStream->skip(chunkSize);
- }
+ handleAudioTrack(i, chunkSize, dataSizeUnpacked);
}
uint32 frameSize = _frameSizes[_curFrame] & ~3;
+// uint32 remainder = _frameSizes[_curFrame] & 3;
if (_fileStream->pos() - startPos > frameSize)
error("Smacker actual frame size exceeds recorded frame size");
@@ -746,6 +712,46 @@ Surface *SmackerDecoder::decodeNextFrame() {
return _surface;
}
+void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) {
+ if (_header.audioInfo[track].hasAudio && chunkSize > 0 && track == 0) {
+ // If it's track 0, play the audio data
+ byte *soundBuffer = (byte *)malloc(chunkSize);
+
+ _fileStream->read(soundBuffer, chunkSize);
+
+ if (_header.audioInfo[track].compression == kCompressionRDFT || _header.audioInfo[track].compression == kCompressionDCT) {
+ // TODO: Compressed audio (Bink RDFT/DCT encoded)
+ free(soundBuffer);
+ return;
+ } else if (_header.audioInfo[track].compression == kCompressionDPCM) {
+ // Compressed audio (Huffman DPCM encoded)
+ queueCompressedBuffer(soundBuffer, chunkSize, unpackedSize, track);
+ free(soundBuffer);
+ } else {
+ // Uncompressed audio (PCM)
+ byte flags = 0;
+ if (_header.audioInfo[track].is16Bits)
+ flags = flags | Audio::FLAG_16BITS;
+ if (_header.audioInfo[track].isStereo)
+ flags = flags | Audio::FLAG_STEREO;
+
+ _audioStream->queueBuffer(soundBuffer, chunkSize, DisposeAfterUse::YES, flags);
+ // The sound buffer will be deleted by QueuingAudioStream
+ }
+
+ if (!_audioStarted) {
+ _mixer->playStream(_soundType, &_audioHandle, _audioStream, -1, 255);
+ _audioStarted = true;
+ }
+ } else {
+ // Ignore the rest of the audio tracks, if they exist
+ // TODO: Are there any Smacker videos with more than one audio stream?
+ // If yes, we should play the rest of the audio streams as well
+ if (chunkSize > 0)
+ _fileStream->skip(chunkSize);
+ }
+}
+
void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
uint32 unpackedSize, int streamNum) {
@@ -808,7 +814,7 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize,
bases[k] += (int16) (audioTrees[k * 2]->getCode(audioBS) |
(audioTrees[k * 2 + 1]->getCode(audioBS) << 8));
- WRITE_BE_UINT16(curPointer, CLIP<int32>(bases[k], -32768, 32767));
+ WRITE_BE_UINT16(curPointer, bases[k]);
curPointer += 2;
curPos += 2;
}
diff --git a/graphics/video/smk_decoder.h b/graphics/video/smk_decoder.h
index 43bb84a4f8..5faeab4343 100644
--- a/graphics/video/smk_decoder.h
+++ b/graphics/video/smk_decoder.h
@@ -69,12 +69,13 @@ public:
PixelFormat getPixelFormat() const { return PixelFormat::createFormatCLUT8(); }
byte *getPalette() { _dirtyPalette = false; return _palette; }
bool hasDirtyPalette() const { return _dirtyPalette; }
+ virtual void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize);
protected:
Common::Rational getFrameRate() const { return _frameRate; }
Common::SeekableReadStream *_fileStream;
-private:
+protected:
void unpackPalette();
// Possible runs of blocks
uint getBlockRun(int index) { return (index <= 58) ? index + 1 : 128 << (index - 59); }
@@ -120,7 +121,7 @@ private:
byte *_palette;
bool _dirtyPalette;
- uint32 _frameRate;
+ Common::Rational _frameRate;
uint32 _frameCount;
Surface *_surface;