aboutsummaryrefslogtreecommitdiff
path: root/video/codecs
diff options
context:
space:
mode:
authorD G Turner2012-04-05 05:08:08 +0100
committerD G Turner2012-04-08 03:29:24 +0100
commit97746e22815da0adc94bf0fbae7d564b0fb55bdd (patch)
tree5edd6dee29c1d289b6e0cab7d0669979c710fea7 /video/codecs
parentc9bbe5793cbd34138b722c3a7414c7d8c5f3d55f (diff)
downloadscummvm-rg350-97746e22815da0adc94bf0fbae7d564b0fb55bdd.tar.gz
scummvm-rg350-97746e22815da0adc94bf0fbae7d564b0fb55bdd.tar.bz2
scummvm-rg350-97746e22815da0adc94bf0fbae7d564b0fb55bdd.zip
VIDEO: Correct SVQ1 Header Decoding and Last Frame Buffering.
Header was incorrectly documnented in reference documents. Corrected with reference to FFMPEG. Also, added missing buffering of last frame for P frame decoding.
Diffstat (limited to 'video/codecs')
-rw-r--r--video/codecs/svq1.cpp333
-rw-r--r--video/codecs/svq1.h3
2 files changed, 170 insertions, 166 deletions
diff --git a/video/codecs/svq1.cpp b/video/codecs/svq1.cpp
index 0ccdc22fc9..e91e5b3cce 100644
--- a/video/codecs/svq1.cpp
+++ b/video/codecs/svq1.cpp
@@ -45,13 +45,12 @@ namespace Video {
#define SVQ1_BLOCK_INTRA 3
SVQ1Decoder::SVQ1Decoder(uint16 width, uint16 height) {
+ debug(1, "SVQ1Decoder::SVQ1Decoder(width:%d, height:%d)", width, height);
+ _width = width;
+ _height = height;
_surface = new Graphics::Surface();
_surface->create(width, height, g_system->getScreenFormat());
- _current[0] = new byte[width*height];
- _current[1] = new byte[(width/4)*(height/4)];
- _current[2] = new byte[(width/4)*(height/4)];
-
_last[0] = 0;
_last[1] = 0;
_last[2] = 0;
@@ -73,10 +72,6 @@ SVQ1Decoder::~SVQ1Decoder() {
_surface->free();
delete _surface;
- delete[] _current[0];
- delete[] _current[1];
- delete[] _current[2];
-
delete[] _last[0];
delete[] _last[1];
delete[] _last[2];
@@ -166,6 +161,89 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
//for (int i = 0; i < length; i++)
// value = checksum_table[data[i] ^ (value >> 8)] ^ ((value & 0xFF) << 8);
}
+
+ static const uint8 stringXORTable[256] = {
+ 0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
+ 0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
+ 0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
+ 0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
+ 0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
+ 0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
+ 0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
+ 0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
+ 0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
+ 0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
+ 0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
+ 0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
+ 0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
+ 0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
+ 0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
+ 0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
+ 0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
+ 0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
+ 0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
+ 0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
+ 0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
+ 0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
+ 0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
+ 0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
+ 0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
+ 0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
+ 0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
+ 0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
+ 0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
+ 0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
+ 0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
+ 0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
+ };
+
+ if ((frameCode ^ 0x10) >= 0x50) {
+ // Decode embedded string
+ Common::String str;
+ uint8 stringLen = frameData.getBits(8);
+ byte xorVal = stringXORTable[stringLen];
+
+ for (uint16 i = 0; i < stringLen-1; i++) {
+ byte data = frameData.getBits(8);
+ str += data ^ xorVal;
+ xorVal = stringXORTable[data];
+ }
+ debug(1, " Embedded String of %d Characters: \"%s\"", stringLen, str.c_str());
+ }
+
+ byte unk1 = frameData.getBits(2); // Unknown
+ debug(1, " unk1: %d", unk1);
+ byte unk2 = frameData.getBits(2); // Unknown
+ debug(1, " unk2: %d", unk2);
+ bool unk3 = frameData.getBit(); // Unknown
+ debug(1, " unk3: %d", unk3);
+
+ static const struct { uint w, h; } standardFrameSizes[7] = {
+ { 160, 120 }, // 0
+ { 128, 96 }, // 1
+ { 176, 144 }, // 2
+ { 352, 288 }, // 3
+ { 704, 576 }, // 4
+ { 240, 180 }, // 5
+ { 320, 240 } // 6
+ };
+
+ byte frameSizeCode = frameData.getBits(3);
+ debug(1, " frameSizeCode: %d", frameSizeCode);
+ uint16 frameWidth, frameHeight;
+ if (frameSizeCode == 7) {
+ frameWidth = frameData.getBits(12);
+ frameHeight = frameData.getBits(12);
+ } else {
+ frameWidth = standardFrameSizes[frameSizeCode].w;
+ frameHeight = standardFrameSizes[frameSizeCode].h;
+ }
+ debug(1, " frameWidth: %d", frameWidth);
+ debug(1, " frameHeight: %d", frameHeight);
+ if (frameWidth != _width || frameHeight != _height) { // Invalid
+ warning("Invalid Frame Size");
+ return _surface;
+ }
} else if (frameType == 2) { // B Frame
warning("B Frames not supported by SVQ1 decoder");
return _surface;
@@ -174,88 +252,6 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
return _surface;
}
- static const uint8 stringXORTable[256] = {
- 0x00, 0xD5, 0x7F, 0xAA, 0xFE, 0x2B, 0x81, 0x54,
- 0x29, 0xFC, 0x56, 0x83, 0xD7, 0x02, 0xA8, 0x7D,
- 0x52, 0x87, 0x2D, 0xF8, 0xAC, 0x79, 0xD3, 0x06,
- 0x7B, 0xAE, 0x04, 0xD1, 0x85, 0x50, 0xFA, 0x2F,
- 0xA4, 0x71, 0xDB, 0x0E, 0x5A, 0x8F, 0x25, 0xF0,
- 0x8D, 0x58, 0xF2, 0x27, 0x73, 0xA6, 0x0C, 0xD9,
- 0xF6, 0x23, 0x89, 0x5C, 0x08, 0xDD, 0x77, 0xA2,
- 0xDF, 0x0A, 0xA0, 0x75, 0x21, 0xF4, 0x5E, 0x8B,
- 0x9D, 0x48, 0xE2, 0x37, 0x63, 0xB6, 0x1C, 0xC9,
- 0xB4, 0x61, 0xCB, 0x1E, 0x4A, 0x9F, 0x35, 0xE0,
- 0xCF, 0x1A, 0xB0, 0x65, 0x31, 0xE4, 0x4E, 0x9B,
- 0xE6, 0x33, 0x99, 0x4C, 0x18, 0xCD, 0x67, 0xB2,
- 0x39, 0xEC, 0x46, 0x93, 0xC7, 0x12, 0xB8, 0x6D,
- 0x10, 0xC5, 0x6F, 0xBA, 0xEE, 0x3B, 0x91, 0x44,
- 0x6B, 0xBE, 0x14, 0xC1, 0x95, 0x40, 0xEA, 0x3F,
- 0x42, 0x97, 0x3D, 0xE8, 0xBC, 0x69, 0xC3, 0x16,
- 0xEF, 0x3A, 0x90, 0x45, 0x11, 0xC4, 0x6E, 0xBB,
- 0xC6, 0x13, 0xB9, 0x6C, 0x38, 0xED, 0x47, 0x92,
- 0xBD, 0x68, 0xC2, 0x17, 0x43, 0x96, 0x3C, 0xE9,
- 0x94, 0x41, 0xEB, 0x3E, 0x6A, 0xBF, 0x15, 0xC0,
- 0x4B, 0x9E, 0x34, 0xE1, 0xB5, 0x60, 0xCA, 0x1F,
- 0x62, 0xB7, 0x1D, 0xC8, 0x9C, 0x49, 0xE3, 0x36,
- 0x19, 0xCC, 0x66, 0xB3, 0xE7, 0x32, 0x98, 0x4D,
- 0x30, 0xE5, 0x4F, 0x9A, 0xCE, 0x1B, 0xB1, 0x64,
- 0x72, 0xA7, 0x0D, 0xD8, 0x8C, 0x59, 0xF3, 0x26,
- 0x5B, 0x8E, 0x24, 0xF1, 0xA5, 0x70, 0xDA, 0x0F,
- 0x20, 0xF5, 0x5F, 0x8A, 0xDE, 0x0B, 0xA1, 0x74,
- 0x09, 0xDC, 0x76, 0xA3, 0xF7, 0x22, 0x88, 0x5D,
- 0xD6, 0x03, 0xA9, 0x7C, 0x28, 0xFD, 0x57, 0x82,
- 0xFF, 0x2A, 0x80, 0x55, 0x01, 0xD4, 0x7E, 0xAB,
- 0x84, 0x51, 0xFB, 0x2E, 0x7A, 0xAF, 0x05, 0xD0,
- 0xAD, 0x78, 0xD2, 0x07, 0x53, 0x86, 0x2C, 0xF9
- };
-
- if ((frameCode ^ 0x10) >= 0x50) {
- // Decode embedded string
- Common::String str;
- uint8 stringLen = frameData.getBits(8);
- byte xorVal = stringXORTable[stringLen];
-
- for (uint16 i = 0; i < stringLen-1; i++) {
- byte data = frameData.getBits(8);
- str += data ^ xorVal;
- xorVal = stringXORTable[data];
- }
- debug(1, " Embedded String of %d Characters: \"%s\"", stringLen, str.c_str());
- }
-
- byte unk1 = frameData.getBits(2); // Unknown
- debug(1, " unk1: %d", unk1);
- byte unk2 = frameData.getBits(2); // Unknown
- debug(1, " unk2: %d", unk2);
- bool unk3 = frameData.getBit(); // Unknown
- debug(1, " unk3: %d", unk3);
-
- static const struct { uint w, h; } standardFrameSizes[7] = {
- { 160, 120 }, // 0
- { 128, 96 }, // 1
- { 176, 144 }, // 2
- { 352, 288 }, // 3
- { 704, 576 }, // 4
- { 240, 180 }, // 5
- { 320, 240 } // 6
- };
-
- byte frameSizeCode = frameData.getBits(3);
- debug(1, " frameSizeCode: %d", frameSizeCode);
- uint16 frameWidth, frameHeight;
- if (frameSizeCode == 7) {
- frameWidth = frameData.getBits(12);
- frameHeight = frameData.getBits(12);
- } else {
- frameWidth = standardFrameSizes[frameSizeCode].w;
- frameHeight = standardFrameSizes[frameSizeCode].h;
- }
- debug(1, " frameWidth: %d", frameWidth);
- debug(1, " frameHeight: %d", frameHeight);
- if (frameWidth == 0 || frameHeight == 0) { // Invalid
- warning("Invalid Frame Size");
- return _surface;
- }
bool checksumPresent = frameData.getBit();
debug(1, " checksumPresent: %d", checksumPresent);
if (checksumPresent) {
@@ -286,91 +282,98 @@ const Graphics::Surface *SVQ1Decoder::decodeImage(Common::SeekableReadStream *st
}
}
- if (frameWidth == _surface->w && frameHeight == _surface->h) {
- // Decode Y, U and V component planes
- for (int i = 0; i < 3; i++) {
- int linesize, width, height;
- if (i == 0) {
- // Y Size is width * height
- width = frameWidth;
- if (width % 16) {
- width /= 16;
- width++;
- width *= 16;
- }
- assert(width % 16 == 0);
- height = frameHeight;
- if (height % 16) {
- height /= 16;
- height++;
- height *= 16;
- }
- assert(height % 16 == 0);
- linesize = width;
- } else {
- // U and V size is width/4 * height/4
- width = frameWidth/4;
- if (width % 16) {
- width /= 16;
- width++;
- width *= 16;
- }
- assert(width % 16 == 0);
- height = frameHeight/4;
- if (height % 16) {
- height /= 16;
- height++;
- height *= 16;
- }
- assert(height % 16 == 0);
- linesize = width;
+ byte *current[3];
+ current[0] = new byte[_width*_height];
+ current[1] = new byte[(_width/4)*(_height/4)];
+ current[2] = new byte[(_width/4)*(_height/4)];
+
+ // Decode Y, U and V component planes
+ for (int i = 0; i < 3; i++) {
+ int linesize, width, height;
+ if (i == 0) {
+ // Y Size is width * height
+ width = _width;
+ if (width % 16) {
+ width /= 16;
+ width++;
+ width *= 16;
+ }
+ assert(width % 16 == 0);
+ height = _height;
+ if (height % 16) {
+ height /= 16;
+ height++;
+ height *= 16;
+ }
+ assert(height % 16 == 0);
+ linesize = _width;
+ } else {
+ // U and V size is width/4 * height/4
+ width = _width/4;
+ if (width % 16) {
+ width /= 16;
+ width++;
+ width *= 16;
}
+ assert(width % 16 == 0);
+ height = _height/4;
+ if (height % 16) {
+ height /= 16;
+ height++;
+ height *= 16;
+ }
+ assert(height % 16 == 0);
+ linesize = _width/4;
+ }
- if (frameType == 0) { // I Frame
- // Keyframe (I)
- byte *current = _current[i];
- for (uint16 y = 0; y < height; y += 16) {
- for (uint16 x = 0; x < width; x += 16) {
- if (int result = svq1DecodeBlockIntra(&frameData, &current[x], linesize) != 0) {
- warning("Error in svq1DecodeBlock %i (keyframe)", result);
- return _surface;
- }
+ if (frameType == 0) { // I Frame
+ // Keyframe (I)
+ byte *currentP = current[i];
+ for (uint16 y = 0; y < height; y += 16) {
+ for (uint16 x = 0; x < width; x += 16) {
+ if (int result = svq1DecodeBlockIntra(&frameData, &currentP[x], linesize) != 0) {
+ warning("Error in svq1DecodeBlock %i (keyframe)", result);
+ return _surface;
}
- current += 16 * linesize;
}
- } else {
- // Delta frame (P or B)
-
- // Prediction Motion Vector
- Common::Point *pmv = new Common::Point[(width/8) + 3];
-
- byte *previous;
- if(frameType == 2) { // B Frame
- warning("B Frame not supported currently");
- //previous = _next[i];
- } else
- previous = _last[i];
-
- byte *current = _current[i];
- for (uint16 y = 0; y < height; y += 16) {
- for (uint16 x = 0; x < width; x += 16) {
- if (int result = svq1DecodeDeltaBlock(&frameData, &current[x], previous, linesize, pmv, x, y) != 0) {
- warning("Error in svq1DecodeDeltaBlock %i", result);
- return _surface;
- }
+ currentP += 16 * linesize;
+ }
+ } else {
+ // Delta frame (P or B)
+
+ // Prediction Motion Vector
+ Common::Point *pmv = new Common::Point[(width/8) + 3];
+
+ byte *previous;
+ if(frameType == 2) { // B Frame
+ warning("B Frame not supported currently");
+ //previous = _next[i];
+ } else
+ previous = _last[i];
+
+ byte *currentP = current[i];
+ for (uint16 y = 0; y < height; y += 16) {
+ for (uint16 x = 0; x < width; x += 16) {
+ if (int result = svq1DecodeDeltaBlock(&frameData, &currentP[x], previous, linesize, pmv, x, y) != 0) {
+ warning("Error in svq1DecodeDeltaBlock %i", result);
+ return _surface;
}
+ }
- pmv[0].x = pmv[0].y = 0;
+ pmv[0].x = pmv[0].y = 0;
- current += 16*linesize;
- }
- delete[] pmv;
+ currentP += 16*linesize;
}
+ delete[] pmv;
}
+ }
- convertYUV410ToRGB(_surface, _current[0], _current[1], _current[2], frameWidth, frameHeight, frameWidth, frameWidth/2);
- } else
- warning("FrameWidth/Height Sanity Check Failed!");
+ convertYUV410ToRGB(_surface, current[0], current[1], current[2], _width, _height, _width, _width/4);
+
+ for (int i = 0; i < 3; i++) {
+ delete _last[i];
+ _last[i] = current[i];
+ }
return _surface;
}
diff --git a/video/codecs/svq1.h b/video/codecs/svq1.h
index 2271bf4d2b..ed34439329 100644
--- a/video/codecs/svq1.h
+++ b/video/codecs/svq1.h
@@ -43,8 +43,9 @@ public:
private:
Graphics::Surface *_surface;
+ uint16 _width;
+ uint16 _height;
- byte *_current[3];
byte *_last[3];
Common::Huffman *_blockType;