aboutsummaryrefslogtreecommitdiff
path: root/video/codecs/svq1.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'video/codecs/svq1.cpp')
-rw-r--r--video/codecs/svq1.cpp55
1 files changed, 35 insertions, 20 deletions
diff --git a/video/codecs/svq1.cpp b/video/codecs/svq1.cpp
index eba0c90305..57e84968a3 100644
--- a/video/codecs/svq1.cpp
+++ b/video/codecs/svq1.cpp
@@ -180,28 +180,29 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
frameData.skip(8);
}
- int yWidth = ALIGN(_frameWidth, 16);
- int yHeight = ALIGN(_frameHeight, 16);
- int uvWidth = ALIGN(yWidth / 4, 16);
- int uvHeight = ALIGN(yHeight / 4, 16);
+ uint yWidth = ALIGN(_frameWidth, 16);
+ uint yHeight = ALIGN(_frameHeight, 16);
+ uint uvWidth = ALIGN(yWidth / 4, 16);
+ uint uvHeight = ALIGN(yHeight / 4, 16);
+ uint uvPitch = uvWidth + 4; // we need at least one extra column and pitch must be divisible by 4
byte *current[3];
// Decode Y, U and V component planes
for (int i = 0; i < 3; i++) {
- int width, height;
+ uint width, height, pitch;
if (i == 0) {
width = yWidth;
height = yHeight;
+ pitch = width;
current[i] = new byte[width * height];
} else {
width = uvWidth;
height = uvHeight;
+ pitch = uvPitch;
- // Add an extra row's worth of data to not go out-of-bounds in the
- // color conversion. Then fill that with "empty" data.
- current[i] = new byte[width * (height + 1)];
- memset(current[i] + width * height, 0x80, width);
+ // Add an extra row here. See below for more information.
+ current[i] = new byte[pitch * (height + 1)];
}
if (frameType == 0) { // I Frame
@@ -209,12 +210,12 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
byte *currentP = current[i];
for (uint16 y = 0; y < height; y += 16) {
for (uint16 x = 0; x < width; x += 16) {
- if (!svq1DecodeBlockIntra(&frameData, &currentP[x], width)) {
+ if (!svq1DecodeBlockIntra(&frameData, &currentP[x], pitch)) {
warning("svq1DecodeBlockIntra decode failure");
return _surface;
}
}
- currentP += 16 * width;
+ currentP += 16 * pitch;
}
} else {
// Delta frame (P or B)
@@ -222,9 +223,9 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
// Prediction Motion Vector
Common::Point *pmv = new Common::Point[(width / 8) + 3];
- byte *previous;
+ byte *previous = 0;
if (frameType == 2) { // B Frame
- warning("B Frame not supported currently");
+ error("SVQ1 Video: B Frames not supported");
//previous = _next[i];
} else {
previous = _last[i];
@@ -233,7 +234,7 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
byte *currentP = current[i];
for (uint16 y = 0; y < height; y += 16) {
for (uint16 x = 0; x < width; x += 16) {
- if (!svq1DecodeDeltaBlock(&frameData, &currentP[x], previous, width, pmv, x, y)) {
+ if (!svq1DecodeDeltaBlock(&frameData, &currentP[x], previous, pitch, pmv, x, y)) {
warning("svq1DecodeDeltaBlock decode failure");
return _surface;
}
@@ -241,7 +242,7 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
pmv[0].x = pmv[0].y = 0;
- currentP += 16 * width;
+ currentP += 16 * pitch;
}
delete[] pmv;
@@ -256,7 +257,21 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
_surface->h = _height;
}
- convertYUV410ToRGB(_surface, current[0], current[1], current[2], yWidth, yHeight, yWidth, uvWidth);
+ // We need to massage the chrominance data a bit to be able to be used by the converter
+ // Since the thing peeks at values one column and one row beyond the data, we need to fill it in
+
+ // First, fill in the column-after-last with the last column's value
+ for (uint i = 0; i < uvHeight; i++) {
+ current[1][i * uvPitch + uvWidth] = current[1][i * uvPitch + uvWidth - 1];
+ current[2][i * uvPitch + uvWidth] = current[2][i * uvPitch + uvWidth - 1];
+ }
+
+ // Then, copy the last row to the one after the last row
+ memcpy(current[1] + uvHeight * uvPitch, current[1] + (uvHeight - 1) * uvPitch, uvWidth + 1);
+ memcpy(current[2] + uvHeight * uvPitch, current[2] + (uvHeight - 1) * uvPitch, uvWidth + 1);
+
+ // Finally, actually do the conversion ;)
+ YUVToRGBMan.convert410(_surface, Graphics::YUVToRGBManager::kScaleFull, current[0], current[1], current[2], yWidth, yHeight, yWidth, uvPitch);
// Store the current surfaces for later and free the old ones
for (int i = 0; i < 3; i++) {
@@ -317,7 +332,7 @@ bool SVQ1Decoder::svq1DecodeBlockIntra(Common::BitStream *s, byte *pixels, int p
for (uint y = 0; y < height; y++)
memset(&dst[y * (pitch / 4)], mean, width);
} else {
- const uint32 *codebook = s_svq1IntraCodebooks[level];
+ const uint32 *codebook = (const uint32 *)s_svq1IntraCodebooks[level];
uint32 bitCache = s->getBits(stages * 4);
// calculate codebook entries for this vector
@@ -336,7 +351,7 @@ bool SVQ1Decoder::svq1DecodeBlockIntra(Common::BitStream *s, byte *pixels, int p
// add codebook entries to vector
for (int j = 0; j < stages; j++) {
- n3 = codebook[entries[j]] ^ 0x80808080;
+ n3 = READ_UINT32(&codebook[entries[j]]) ^ 0x80808080;
n1 += (n3 & 0xFF00FF00) >> 8;
n2 += n3 & 0x00FF00FF;
}
@@ -409,7 +424,7 @@ bool SVQ1Decoder::svq1DecodeBlockNonIntra(Common::BitStream *s, byte *pixels, in
}
int mean = _interMean->getSymbol(*s) - 256;
- const uint32 *codebook = s_svq1InterCodebooks[level];
+ const uint32 *codebook = (const uint32 *)s_svq1InterCodebooks[level];
uint32 bitCache = s->getBits(stages * 4);
// calculate codebook entries for this vector
@@ -430,7 +445,7 @@ bool SVQ1Decoder::svq1DecodeBlockNonIntra(Common::BitStream *s, byte *pixels, in
// add codebook entries to vector
for (int j = 0; j < stages; j++) {
- n3 = codebook[entries[j]] ^ 0x80808080;
+ n3 = READ_UINT32(&codebook[entries[j]]) ^ 0x80808080;
n1 += (n3 & 0xFF00FF00) >> 8;
n2 += n3 & 0x00FF00FF;
}