ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

cinepak.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "image/codecs/cinepak.h"
00024 #include "image/codecs/cinepak_tables.h"
00025 
00026 #include "common/debug.h"
00027 #include "common/stream.h"
00028 #include "common/system.h"
00029 #include "common/textconsole.h"
00030 #include "common/util.h"
00031 
00032 #include "graphics/surface.h"
00033 
00034 // Code here partially based off of ffmpeg ;)
00035 
00036 namespace Image {
00037 
00038 namespace {
00039 
00040 inline void convertYUVToRGB(const byte *clipTable, byte y, int8 u, int8 v, byte &r, byte &g, byte &b) {
00041     r = clipTable[y + (v << 1)];
00042     g = clipTable[y - (u >> 1) - v];
00043     b = clipTable[y + (u << 1)];
00044 }
00045 
00046 inline uint32 convertYUVToColor(const byte *clipTable, const Graphics::PixelFormat &format, byte y, byte u, byte v) {
00047     byte r, g, b;
00048     convertYUVToRGB(clipTable, y, u, v, r, g, b);
00049     return format.RGBToColor(r, g, b);
00050 }
00051 
00052 inline uint16 createDitherTableIndex(const byte *clipTable, byte y, int8 u, int8 v) {
00053     byte r, g, b;
00054     convertYUVToRGB(clipTable, y, u, v, r, g, b);
00055     return ((r & 0xF8) << 6) |
00056            ((g & 0xF8) << 1) |
00057            ((b & 0xF0) >> 4);
00058 }
00059 
00063 template<typename PixelInt>
00064 inline void putPixelRaw(PixelInt *dst, const byte *clipTable, const Graphics::PixelFormat &format, byte y, byte u, byte v) {
00065     *dst = convertYUVToColor(clipTable, format, y, u, v);
00066 }
00067 
00071 template<>
00072 inline void putPixelRaw(byte *dst, const byte *clipTable, const Graphics::PixelFormat &format, byte y, byte u, byte v) {
00073     *dst = y;
00074 }
00075 
00079 struct CodebookConverterRaw {
00080     template<typename PixelInt>
00081     static inline void decodeBlock1(byte codebookIndex, const CinepakStrip &strip, PixelInt *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
00082         const CinepakCodebook &codebook = strip.v1_codebook[codebookIndex];
00083         putPixelRaw(rows[0] + 0, clipTable, format, codebook.y[0], codebook.u, codebook.v);
00084         putPixelRaw(rows[0] + 1, clipTable, format, codebook.y[0], codebook.u, codebook.v);
00085         putPixelRaw(rows[1] + 0, clipTable, format, codebook.y[0], codebook.u, codebook.v);
00086         putPixelRaw(rows[1] + 1, clipTable, format, codebook.y[0], codebook.u, codebook.v);
00087 
00088         putPixelRaw(rows[0] + 2, clipTable, format, codebook.y[1], codebook.u, codebook.v);
00089         putPixelRaw(rows[0] + 3, clipTable, format, codebook.y[1], codebook.u, codebook.v);
00090         putPixelRaw(rows[1] + 2, clipTable, format, codebook.y[1], codebook.u, codebook.v);
00091         putPixelRaw(rows[1] + 3, clipTable, format, codebook.y[1], codebook.u, codebook.v);
00092 
00093         putPixelRaw(rows[2] + 0, clipTable, format, codebook.y[2], codebook.u, codebook.v);
00094         putPixelRaw(rows[2] + 1, clipTable, format, codebook.y[2], codebook.u, codebook.v);
00095         putPixelRaw(rows[3] + 0, clipTable, format, codebook.y[2], codebook.u, codebook.v);
00096         putPixelRaw(rows[3] + 1, clipTable, format, codebook.y[2], codebook.u, codebook.v);
00097 
00098         putPixelRaw(rows[2] + 2, clipTable, format, codebook.y[3], codebook.u, codebook.v);
00099         putPixelRaw(rows[2] + 3, clipTable, format, codebook.y[3], codebook.u, codebook.v);
00100         putPixelRaw(rows[3] + 2, clipTable, format, codebook.y[3], codebook.u, codebook.v);
00101         putPixelRaw(rows[3] + 3, clipTable, format, codebook.y[3], codebook.u, codebook.v);
00102     }
00103 
00104     template<typename PixelInt>
00105     static inline void decodeBlock4(const byte (&codebookIndex)[4], const CinepakStrip &strip, PixelInt *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
00106         const CinepakCodebook &codebook1 = strip.v4_codebook[codebookIndex[0]];
00107         putPixelRaw(rows[0] + 0, clipTable, format, codebook1.y[0], codebook1.u, codebook1.v);
00108         putPixelRaw(rows[0] + 1, clipTable, format, codebook1.y[1], codebook1.u, codebook1.v);
00109         putPixelRaw(rows[1] + 0, clipTable, format, codebook1.y[2], codebook1.u, codebook1.v);
00110         putPixelRaw(rows[1] + 1, clipTable, format, codebook1.y[3], codebook1.u, codebook1.v);
00111 
00112         const CinepakCodebook &codebook2 = strip.v4_codebook[codebookIndex[1]];
00113         putPixelRaw(rows[0] + 2, clipTable, format, codebook2.y[0], codebook2.u, codebook2.v);
00114         putPixelRaw(rows[0] + 3, clipTable, format, codebook2.y[1], codebook2.u, codebook2.v);
00115         putPixelRaw(rows[1] + 2, clipTable, format, codebook2.y[2], codebook2.u, codebook2.v);
00116         putPixelRaw(rows[1] + 3, clipTable, format, codebook2.y[3], codebook2.u, codebook2.v);
00117 
00118         const CinepakCodebook &codebook3 = strip.v4_codebook[codebookIndex[2]];
00119         putPixelRaw(rows[2] + 0, clipTable, format, codebook3.y[0], codebook3.u, codebook3.v);
00120         putPixelRaw(rows[2] + 1, clipTable, format, codebook3.y[1], codebook3.u, codebook3.v);
00121         putPixelRaw(rows[3] + 0, clipTable, format, codebook3.y[2], codebook3.u, codebook3.v);
00122         putPixelRaw(rows[3] + 1, clipTable, format, codebook3.y[3], codebook3.u, codebook3.v);
00123 
00124         const CinepakCodebook &codebook4 = strip.v4_codebook[codebookIndex[3]];
00125         putPixelRaw(rows[2] + 2, clipTable, format, codebook4.y[0], codebook4.u, codebook4.v);
00126         putPixelRaw(rows[2] + 3, clipTable, format, codebook4.y[1], codebook4.u, codebook4.v);
00127         putPixelRaw(rows[3] + 2, clipTable, format, codebook4.y[2], codebook4.u, codebook4.v);
00128         putPixelRaw(rows[3] + 3, clipTable, format, codebook4.y[3], codebook4.u, codebook4.v);
00129     }
00130 };
00131 
00135 struct CodebookConverterDitherVFW {
00136     static inline void decodeBlock1(byte codebookIndex, const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
00137         const CinepakCodebook &codebook = strip.v1_codebook[codebookIndex];
00138         byte blockBuffer[16];
00139         ditherCodebookSmooth(codebook, blockBuffer, colorMap);
00140         rows[0][0] = blockBuffer[0];
00141         rows[0][1] = blockBuffer[1];
00142         rows[0][2] = blockBuffer[2];
00143         rows[0][3] = blockBuffer[3];
00144         rows[1][0] = blockBuffer[4];
00145         rows[1][1] = blockBuffer[5];
00146         rows[1][2] = blockBuffer[6];
00147         rows[1][3] = blockBuffer[7];
00148         rows[2][0] = blockBuffer[8];
00149         rows[2][1] = blockBuffer[9];
00150         rows[2][2] = blockBuffer[10];
00151         rows[2][3] = blockBuffer[11];
00152         rows[3][0] = blockBuffer[12];
00153         rows[3][1] = blockBuffer[13];
00154         rows[3][2] = blockBuffer[14];
00155         rows[3][3] = blockBuffer[15];
00156     }
00157 
00158     static inline void decodeBlock4(const byte (&codebookIndex)[4], const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
00159         byte blockBuffer[16];
00160         ditherCodebookDetail(strip.v4_codebook[codebookIndex[0]], blockBuffer, colorMap);
00161         rows[0][0] = blockBuffer[0];
00162         rows[0][1] = blockBuffer[1];
00163         rows[1][0] = blockBuffer[4];
00164         rows[1][1] = blockBuffer[5];
00165 
00166         ditherCodebookDetail(strip.v4_codebook[codebookIndex[1]], blockBuffer, colorMap);
00167         rows[0][2] = blockBuffer[2];
00168         rows[0][3] = blockBuffer[3];
00169         rows[1][2] = blockBuffer[6];
00170         rows[1][3] = blockBuffer[7];
00171 
00172         ditherCodebookDetail(strip.v4_codebook[codebookIndex[2]], blockBuffer, colorMap);
00173         rows[2][0] = blockBuffer[8];
00174         rows[2][1] = blockBuffer[9];
00175         rows[3][0] = blockBuffer[12];
00176         rows[3][1] = blockBuffer[13];
00177 
00178         ditherCodebookDetail(strip.v4_codebook[codebookIndex[3]], blockBuffer, colorMap);
00179         rows[2][2] = blockBuffer[10];
00180         rows[2][3] = blockBuffer[11];
00181         rows[3][2] = blockBuffer[14];
00182         rows[3][3] = blockBuffer[15];
00183     }
00184 
00185 private:
00186     static inline void ditherCodebookDetail(const CinepakCodebook &codebook, byte *dst, const byte *colorMap) {
00187         int uLookup = (byte)codebook.u * 2;
00188         int vLookup = (byte)codebook.v * 2;
00189         uint32 uv1 = s_uLookup[uLookup] | s_vLookup[vLookup];
00190         uint32 uv2 = s_uLookup[uLookup + 1] | s_vLookup[vLookup + 1];
00191 
00192         int yLookup1 = codebook.y[0] * 2;
00193         int yLookup2 = codebook.y[1] * 2;
00194         int yLookup3 = codebook.y[2] * 2;
00195         int yLookup4 = codebook.y[3] * 2;
00196 
00197         uint32 pixelGroup1 = uv2 | s_yLookup[yLookup1 + 1];
00198         uint32 pixelGroup2 = uv2 | s_yLookup[yLookup2 + 1];
00199         uint32 pixelGroup3 = uv1 | s_yLookup[yLookup3];
00200         uint32 pixelGroup4 = uv1 | s_yLookup[yLookup4];
00201         uint32 pixelGroup5 = uv1 | s_yLookup[yLookup1];
00202         uint32 pixelGroup6 = uv1 | s_yLookup[yLookup2];
00203         uint32 pixelGroup7 = uv2 | s_yLookup[yLookup3 + 1];
00204         uint32 pixelGroup8 = uv2 | s_yLookup[yLookup4 + 1];
00205 
00206         dst[0] = getRGBLookupEntry(colorMap, pixelGroup1 & 0xFFFF);
00207         dst[1] = getRGBLookupEntry(colorMap, pixelGroup2 >> 16);
00208         dst[2] = getRGBLookupEntry(colorMap, pixelGroup5 & 0xFFFF);
00209         dst[3] = getRGBLookupEntry(colorMap, pixelGroup6 >> 16);
00210         dst[4] = getRGBLookupEntry(colorMap, pixelGroup3 & 0xFFFF);
00211         dst[5] = getRGBLookupEntry(colorMap, pixelGroup4 >> 16);
00212         dst[6] = getRGBLookupEntry(colorMap, pixelGroup7 & 0xFFFF);
00213         dst[7] = getRGBLookupEntry(colorMap, pixelGroup8 >> 16);
00214         dst[8] = getRGBLookupEntry(colorMap, pixelGroup1 >> 16);
00215         dst[9] = getRGBLookupEntry(colorMap, pixelGroup6 & 0xFFFF);
00216         dst[10] = getRGBLookupEntry(colorMap, pixelGroup5 >> 16);
00217         dst[11] = getRGBLookupEntry(colorMap, pixelGroup2 & 0xFFFF);
00218         dst[12] = getRGBLookupEntry(colorMap, pixelGroup3 >> 16);
00219         dst[13] = getRGBLookupEntry(colorMap, pixelGroup8 & 0xFFFF);
00220         dst[14] = getRGBLookupEntry(colorMap, pixelGroup7 >> 16);
00221         dst[15] = getRGBLookupEntry(colorMap, pixelGroup4 & 0xFFFF);
00222     }
00223 
00224     static inline void ditherCodebookSmooth(const CinepakCodebook &codebook, byte *dst, const byte *colorMap) {
00225         int uLookup = (byte)codebook.u * 2;
00226         int vLookup = (byte)codebook.v * 2;
00227         uint32 uv1 = s_uLookup[uLookup] | s_vLookup[vLookup];
00228         uint32 uv2 = s_uLookup[uLookup + 1] | s_vLookup[vLookup + 1];
00229 
00230         int yLookup1 = codebook.y[0] * 2;
00231         int yLookup2 = codebook.y[1] * 2;
00232         int yLookup3 = codebook.y[2] * 2;
00233         int yLookup4 = codebook.y[3] * 2;
00234 
00235         uint32 pixelGroup1 = uv2 | s_yLookup[yLookup1 + 1];
00236         uint32 pixelGroup2 = uv1 | s_yLookup[yLookup2];
00237         uint32 pixelGroup3 = uv1 | s_yLookup[yLookup1];
00238         uint32 pixelGroup4 = uv2 | s_yLookup[yLookup2 + 1];
00239         uint32 pixelGroup5 = uv2 | s_yLookup[yLookup3 + 1];
00240         uint32 pixelGroup6 = uv1 | s_yLookup[yLookup3];
00241         uint32 pixelGroup7 = uv1 | s_yLookup[yLookup4];
00242         uint32 pixelGroup8 = uv2 | s_yLookup[yLookup4 + 1];
00243 
00244         dst[0] = getRGBLookupEntry(colorMap, pixelGroup1 & 0xFFFF);
00245         dst[1] = getRGBLookupEntry(colorMap, pixelGroup1 >> 16);
00246         dst[2] = getRGBLookupEntry(colorMap, pixelGroup2 & 0xFFFF);
00247         dst[3] = getRGBLookupEntry(colorMap, pixelGroup2 >> 16);
00248         dst[4] = getRGBLookupEntry(colorMap, pixelGroup3 & 0xFFFF);
00249         dst[5] = getRGBLookupEntry(colorMap, pixelGroup3 >> 16);
00250         dst[6] = getRGBLookupEntry(colorMap, pixelGroup4 & 0xFFFF);
00251         dst[7] = getRGBLookupEntry(colorMap, pixelGroup4 >> 16);
00252         dst[8] = getRGBLookupEntry(colorMap, pixelGroup5 >> 16);
00253         dst[9] = getRGBLookupEntry(colorMap, pixelGroup6 & 0xFFFF);
00254         dst[10] = getRGBLookupEntry(colorMap, pixelGroup7 >> 16);
00255         dst[11] = getRGBLookupEntry(colorMap, pixelGroup8 & 0xFFFF);
00256         dst[12] = getRGBLookupEntry(colorMap, pixelGroup6 >> 16);
00257         dst[13] = getRGBLookupEntry(colorMap, pixelGroup5 & 0xFFFF);
00258         dst[14] = getRGBLookupEntry(colorMap, pixelGroup8 >> 16);
00259         dst[15] = getRGBLookupEntry(colorMap, pixelGroup7 & 0xFFFF);
00260     }
00261 
00262     static inline byte getRGBLookupEntry(const byte *colorMap, uint16 index) {
00263         return colorMap[s_defaultPaletteLookup[CLIP<int>(index, 0, 1023)]];
00264     }
00265 };
00266 
00270 struct CodebookConverterDitherQT {
00271     static inline void decodeBlock1(byte codebookIndex, const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
00272         const byte *colorPtr = strip.v1_dither + (codebookIndex << 2);
00273         WRITE_UINT32(rows[0], READ_UINT32(colorPtr));
00274         WRITE_UINT32(rows[1], READ_UINT32(colorPtr + 1024));
00275         WRITE_UINT32(rows[2], READ_UINT32(colorPtr + 2048));
00276         WRITE_UINT32(rows[3], READ_UINT32(colorPtr + 3072));
00277     }
00278 
00279     static inline void decodeBlock4(const byte (&codebookIndex)[4], const CinepakStrip &strip, byte *(&rows)[4], const byte *clipTable, const byte *colorMap, const Graphics::PixelFormat &format) {
00280         const byte *colorPtr = strip.v4_dither + (codebookIndex[0] << 2);
00281         WRITE_UINT16(rows[0] + 0, READ_UINT16(colorPtr + 0));
00282         WRITE_UINT16(rows[1] + 0, READ_UINT16(colorPtr + 2));
00283 
00284         colorPtr = strip.v4_dither + (codebookIndex[1] << 2);
00285         WRITE_UINT16(rows[0] + 2, READ_UINT16(colorPtr + 1024));
00286         WRITE_UINT16(rows[1] + 2, READ_UINT16(colorPtr + 1026));
00287 
00288         colorPtr = strip.v4_dither + (codebookIndex[2] << 2);
00289         WRITE_UINT16(rows[2] + 0, READ_UINT16(colorPtr + 2048));
00290         WRITE_UINT16(rows[3] + 0, READ_UINT16(colorPtr + 2050));
00291 
00292         colorPtr = strip.v4_dither + (codebookIndex[3] << 2);
00293         WRITE_UINT16(rows[2] + 2, READ_UINT16(colorPtr + 3072));
00294         WRITE_UINT16(rows[3] + 2, READ_UINT16(colorPtr + 3074));
00295     }
00296 };
00297 
00298 template<typename PixelInt, typename CodebookConverter>
00299 void decodeVectorsTmpl(CinepakFrame &frame, const byte *clipTable, const byte *colorMap, Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize) {
00300     uint32 flag = 0, mask = 0;
00301     PixelInt *iy[4];
00302     int32 startPos = stream.pos();
00303 
00304     for (uint16 y = frame.strips[strip].rect.top; y < frame.strips[strip].rect.bottom; y += 4) {
00305         iy[0] = (PixelInt *)frame.surface->getBasePtr(frame.strips[strip].rect.left, + y);
00306         iy[1] = iy[0] + frame.width;
00307         iy[2] = iy[1] + frame.width;
00308         iy[3] = iy[2] + frame.width;
00309 
00310         for (uint16 x = frame.strips[strip].rect.left; x < frame.strips[strip].rect.right; x += 4) {
00311             if ((chunkID & 0x01) && !(mask >>= 1)) {
00312                 if ((stream.pos() - startPos + 4) > (int32)chunkSize)
00313                     return;
00314 
00315                 flag  = stream.readUint32BE();
00316                 mask  = 0x80000000;
00317             }
00318 
00319             if (!(chunkID & 0x01) || (flag & mask)) {
00320                 if (!(chunkID & 0x02) && !(mask >>= 1)) {
00321                     if ((stream.pos() - startPos + 4) > (int32)chunkSize)
00322                         return;
00323 
00324                     flag  = stream.readUint32BE();
00325                     mask  = 0x80000000;
00326                 }
00327 
00328                 if ((chunkID & 0x02) || (~flag & mask)) {
00329                     if ((stream.pos() - startPos + 1) > (int32)chunkSize)
00330                         return;
00331 
00332                     // Get the codebook
00333                     byte codebook = stream.readByte();
00334                     CodebookConverter::decodeBlock1(codebook, frame.strips[strip], iy, clipTable, colorMap, frame.surface->format);
00335                 } else if (flag & mask) {
00336                     if ((stream.pos() - startPos + 4) > (int32)chunkSize)
00337                         return;
00338 
00339                     byte codebook[4];
00340                     stream.read(codebook, 4);
00341                     CodebookConverter::decodeBlock4(codebook, frame.strips[strip], iy, clipTable, colorMap, frame.surface->format);
00342                 }
00343             }
00344 
00345             for (byte i = 0; i < 4; i++)
00346                 iy[i] += 4;
00347         }
00348     }
00349 }
00350 
00351 } // End of anonymous namespace
00352 
00353 CinepakDecoder::CinepakDecoder(int bitsPerPixel) : Codec(), _bitsPerPixel(bitsPerPixel) {
00354     _curFrame.surface = 0;
00355     _curFrame.strips = 0;
00356     _y = 0;
00357     _colorMap = 0;
00358     _ditherPalette = 0;
00359     _ditherType = kDitherTypeUnknown;
00360 
00361     if (bitsPerPixel == 8) {
00362         _pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
00363     } else {
00364         _pixelFormat = g_system->getScreenFormat();
00365 
00366         // Default to a 32bpp format, if in 8bpp mode
00367         if (_pixelFormat.bytesPerPixel == 1)
00368             _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0);
00369     }
00370 
00371     // Create a lookup for the clip function
00372     // This dramatically improves the performance of the color conversion
00373     _clipTableBuf = new byte[1024];
00374 
00375     for (uint i = 0; i < 1024; i++) {
00376         if (i <= 512)
00377             _clipTableBuf[i] = 0;
00378         else if (i >= 768)
00379             _clipTableBuf[i] = 255;
00380         else
00381             _clipTableBuf[i] = i - 512;
00382     }
00383 
00384     _clipTable = _clipTableBuf + 512;
00385 }
00386 
00387 CinepakDecoder::~CinepakDecoder() {
00388     if (_curFrame.surface) {
00389         _curFrame.surface->free();
00390         delete _curFrame.surface;
00391     }
00392 
00393     delete[] _curFrame.strips;
00394     delete[] _clipTableBuf;
00395 
00396     delete[] _colorMap;
00397     delete[] _ditherPalette;
00398 }
00399 
00400 const Graphics::Surface *CinepakDecoder::decodeFrame(Common::SeekableReadStream &stream) {
00401     _curFrame.flags = stream.readByte();
00402     _curFrame.length = (stream.readByte() << 16);
00403     _curFrame.length |= stream.readUint16BE();
00404     _curFrame.width = stream.readUint16BE();
00405     _curFrame.height = stream.readUint16BE();
00406     _curFrame.stripCount = stream.readUint16BE();
00407 
00408     if (!_curFrame.strips) {
00409         _curFrame.strips = new CinepakStrip[_curFrame.stripCount];
00410         for (uint16 i = 0; i < _curFrame.stripCount; i++) {
00411             initializeCodebook(i, 1);
00412             initializeCodebook(i, 4);
00413         }
00414     }
00415 
00416     debug(4, "Cinepak Frame: Width = %d, Height = %d, Strip Count = %d", _curFrame.width, _curFrame.height, _curFrame.stripCount);
00417 
00418     // Borrowed from FFMPEG. This should cut out the extra data Cinepak for Sega has (which is useless).
00419     // The theory behind this is that this is here to confuse standard Cinepak decoders. But, we won't let that happen! ;)
00420     if (_curFrame.length != (uint32)stream.size()) {
00421         if (stream.readUint16BE() == 0xFE00)
00422             stream.readUint32BE();
00423         else if ((stream.size() % _curFrame.length) == 0)
00424             stream.seek(-2, SEEK_CUR);
00425     }
00426 
00427     if (!_curFrame.surface) {
00428         _curFrame.surface = new Graphics::Surface();
00429         _curFrame.surface->create(_curFrame.width, _curFrame.height, _pixelFormat);
00430     }
00431 
00432     _y = 0;
00433 
00434     for (uint16 i = 0; i < _curFrame.stripCount; i++) {
00435         if (i > 0 && !(_curFrame.flags & 1)) { // Use codebooks from last strip
00436 
00437             for (uint16 j = 0; j < 256; j++) {
00438                 _curFrame.strips[i].v1_codebook[j] = _curFrame.strips[i - 1].v1_codebook[j];
00439                 _curFrame.strips[i].v4_codebook[j] = _curFrame.strips[i - 1].v4_codebook[j];
00440             }
00441 
00442             // Copy the QuickTime dither tables
00443             memcpy(_curFrame.strips[i].v1_dither, _curFrame.strips[i - 1].v1_dither, 256 * 4 * 4 * 4);
00444             memcpy(_curFrame.strips[i].v4_dither, _curFrame.strips[i - 1].v4_dither, 256 * 4 * 4 * 4);
00445         }
00446 
00447         _curFrame.strips[i].id = stream.readUint16BE();
00448         _curFrame.strips[i].length = stream.readUint16BE() - 12; // Subtract the 12 byte header
00449         _curFrame.strips[i].rect.top = _y; stream.readUint16BE(); // Ignore, substitute with our own.
00450         _curFrame.strips[i].rect.left = 0; stream.readUint16BE(); // Ignore, substitute with our own
00451         _curFrame.strips[i].rect.bottom = _y + stream.readUint16BE();
00452         _curFrame.strips[i].rect.right = _curFrame.width; stream.readUint16BE(); // Ignore, substitute with our own
00453 
00454         // Sanity check. Because Cinepak is based on 4x4 blocks, the width and height of each strip needs to be divisible by 4.
00455         assert(!(_curFrame.strips[i].rect.width() % 4) && !(_curFrame.strips[i].rect.height() % 4));
00456 
00457         uint32 pos = stream.pos();
00458 
00459         while ((uint32)stream.pos() < (pos + _curFrame.strips[i].length) && !stream.eos()) {
00460             byte chunkID = stream.readByte();
00461 
00462             if (stream.eos())
00463                 break;
00464 
00465             // Chunk Size is 24-bit, ignore the first 4 bytes
00466             uint32 chunkSize = stream.readByte() << 16;
00467             chunkSize += stream.readUint16BE() - 4;
00468 
00469             int32 startPos = stream.pos();
00470 
00471             switch (chunkID) {
00472             case 0x20:
00473             case 0x21:
00474             case 0x24:
00475             case 0x25:
00476                 loadCodebook(stream, i, 4, chunkID, chunkSize);
00477                 break;
00478             case 0x22:
00479             case 0x23:
00480             case 0x26:
00481             case 0x27:
00482                 loadCodebook(stream, i, 1, chunkID, chunkSize);
00483                 break;
00484             case 0x30:
00485             case 0x31:
00486             case 0x32:
00487                 if (_ditherPalette)
00488                     ditherVectors(stream, i, chunkID, chunkSize);
00489                 else
00490                     decodeVectors(stream, i, chunkID, chunkSize);
00491                 break;
00492             default:
00493                 warning("Unknown Cinepak chunk ID %02x", chunkID);
00494                 return _curFrame.surface;
00495             }
00496 
00497             if (stream.pos() != startPos + (int32)chunkSize)
00498                 stream.seek(startPos + chunkSize);
00499         }
00500 
00501         _y = _curFrame.strips[i].rect.bottom;
00502     }
00503 
00504     return _curFrame.surface;
00505 }
00506 
00507 void CinepakDecoder::initializeCodebook(uint16 strip, byte codebookType) {
00508     CinepakCodebook *codebook = (codebookType == 1) ? _curFrame.strips[strip].v1_codebook : _curFrame.strips[strip].v4_codebook;
00509 
00510     for (uint16 i = 0; i < 256; i++) {
00511         memset(codebook[i].y, 0, 4);
00512         codebook[i].u = 0;
00513         codebook[i].v = 0;
00514 
00515         if (_ditherType == kDitherTypeQT)
00516             ditherCodebookQT(strip, codebookType, i);
00517     }
00518 }
00519 
00520 void CinepakDecoder::loadCodebook(Common::SeekableReadStream &stream, uint16 strip, byte codebookType, byte chunkID, uint32 chunkSize) {
00521     CinepakCodebook *codebook = (codebookType == 1) ? _curFrame.strips[strip].v1_codebook : _curFrame.strips[strip].v4_codebook;
00522 
00523     int32 startPos = stream.pos();
00524     uint32 flag = 0, mask = 0;
00525 
00526     for (uint16 i = 0; i < 256; i++) {
00527         if ((chunkID & 0x01) && !(mask >>= 1)) {
00528             if ((stream.pos() - startPos + 4) > (int32)chunkSize)
00529                 break;
00530 
00531             flag  = stream.readUint32BE();
00532             mask  = 0x80000000;
00533         }
00534 
00535         if (!(chunkID & 0x01) || (flag & mask)) {
00536             byte n = (chunkID & 0x04) ? 4 : 6;
00537             if ((stream.pos() - startPos + n) > (int32)chunkSize)
00538                 break;
00539 
00540             stream.read(codebook[i].y, 4);
00541 
00542             if (n == 6) {
00543                 codebook[i].u = stream.readSByte();
00544                 codebook[i].v = stream.readSByte();
00545             } else {
00546                 // This codebook type indicates either greyscale or
00547                 // palettized video. For greyscale, default us to
00548                 // 0 for both u and v.
00549                 codebook[i].u = 0;
00550                 codebook[i].v = 0;
00551             }
00552 
00553             // Dither the codebook if we're dithering for QuickTime
00554             if (_ditherType == kDitherTypeQT)
00555                 ditherCodebookQT(strip, codebookType, i);
00556         }
00557     }
00558 }
00559 
00560 void CinepakDecoder::ditherCodebookQT(uint16 strip, byte codebookType, uint16 codebookIndex) {
00561     if (codebookType == 1) {
00562         const CinepakCodebook &codebook = _curFrame.strips[strip].v1_codebook[codebookIndex];
00563         byte *output = _curFrame.strips[strip].v1_dither + (codebookIndex << 2);
00564 
00565         byte *ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[0], codebook.u, codebook.v);
00566         output[0x000] = ditherEntry[0x0000];
00567         output[0x001] = ditherEntry[0x4000];
00568         output[0x400] = ditherEntry[0xC000];
00569         output[0x401] = ditherEntry[0x0000];
00570 
00571         ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[1], codebook.u, codebook.v);
00572         output[0x002] = ditherEntry[0x8000];
00573         output[0x003] = ditherEntry[0xC000];
00574         output[0x402] = ditherEntry[0x4000];
00575         output[0x403] = ditherEntry[0x8000];
00576 
00577         ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[2], codebook.u, codebook.v);
00578         output[0x800] = ditherEntry[0x4000];
00579         output[0x801] = ditherEntry[0x8000];
00580         output[0xC00] = ditherEntry[0x8000];
00581         output[0xC01] = ditherEntry[0xC000];
00582 
00583         ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[3], codebook.u, codebook.v);
00584         output[0x802] = ditherEntry[0xC000];
00585         output[0x803] = ditherEntry[0x0000];
00586         output[0xC02] = ditherEntry[0x0000];
00587         output[0xC03] = ditherEntry[0x4000];
00588     } else {
00589         const CinepakCodebook &codebook = _curFrame.strips[strip].v4_codebook[codebookIndex];
00590         byte *output = _curFrame.strips[strip].v4_dither + (codebookIndex << 2);
00591 
00592         byte *ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[0], codebook.u, codebook.v);
00593         output[0x000] = ditherEntry[0x0000];
00594         output[0x400] = ditherEntry[0x8000];
00595         output[0x800] = ditherEntry[0x4000];
00596         output[0xC00] = ditherEntry[0xC000];
00597 
00598         ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[1], codebook.u, codebook.v);
00599         output[0x001] = ditherEntry[0x4000];
00600         output[0x401] = ditherEntry[0xC000];
00601         output[0x801] = ditherEntry[0x8000];
00602         output[0xC01] = ditherEntry[0x0000];
00603 
00604         ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[2], codebook.u, codebook.v);
00605         output[0x002] = ditherEntry[0xC000];
00606         output[0x402] = ditherEntry[0x4000];
00607         output[0x802] = ditherEntry[0x8000];
00608         output[0xC02] = ditherEntry[0x0000];
00609 
00610         ditherEntry = _colorMap + createDitherTableIndex(_clipTable, codebook.y[3], codebook.u, codebook.v);
00611         output[0x003] = ditherEntry[0x0000];
00612         output[0x403] = ditherEntry[0x8000];
00613         output[0x803] = ditherEntry[0xC000];
00614         output[0xC03] = ditherEntry[0x4000];
00615     }
00616 }
00617 
00618 void CinepakDecoder::decodeVectors(Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize) {
00619     if (_curFrame.surface->format.bytesPerPixel == 1) {
00620         decodeVectorsTmpl<byte, CodebookConverterRaw>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
00621     } else if (_curFrame.surface->format.bytesPerPixel == 2) {
00622         decodeVectorsTmpl<uint16, CodebookConverterRaw>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
00623     } else if (_curFrame.surface->format.bytesPerPixel == 4) {
00624         decodeVectorsTmpl<uint32, CodebookConverterRaw>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
00625     }
00626 }
00627 
00628 bool CinepakDecoder::canDither(DitherType type) const {
00629     return (type == kDitherTypeVFW || type == kDitherTypeQT) && _bitsPerPixel == 24;
00630 }
00631 
00632 void CinepakDecoder::setDither(DitherType type, const byte *palette) {
00633     assert(canDither(type));
00634 
00635     delete[] _colorMap;
00636     delete[] _ditherPalette;
00637 
00638     _ditherPalette = new byte[256 * 3];
00639     memcpy(_ditherPalette, palette, 256 * 3);
00640 
00641     _dirtyPalette = true;
00642     _pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
00643     _ditherType = type;
00644 
00645     if (type == kDitherTypeVFW) {
00646         _colorMap = new byte[221];
00647 
00648         for (int i = 0; i < 221; i++)
00649             _colorMap[i] = findNearestRGB(i);
00650     } else {
00651         // Generate QuickTime dither table
00652         // 4 blocks of 0x4000 bytes (RGB554 lookup)
00653         _colorMap = createQuickTimeDitherTable(palette, 256);
00654     }
00655 }
00656 
00657 byte CinepakDecoder::findNearestRGB(int index) const {
00658     int r = s_defaultPalette[index * 3];
00659     int g = s_defaultPalette[index * 3 + 1];
00660     int b = s_defaultPalette[index * 3 + 2];
00661 
00662     byte result = 0;
00663     int diff = 0x7FFFFFFF;
00664 
00665     for (int i = 0; i < 256; i++) {
00666         int bDiff = b - (int)_ditherPalette[i * 3 + 2];
00667         int curDiffB = diff - (bDiff * bDiff);
00668 
00669         if (curDiffB > 0) {
00670             int gDiff = g - (int)_ditherPalette[i * 3 + 1];
00671             int curDiffG = curDiffB - (gDiff * gDiff);
00672 
00673             if (curDiffG > 0) {
00674                 int rDiff = r - (int)_ditherPalette[i * 3];
00675                 int curDiffR = curDiffG - (rDiff * rDiff);
00676 
00677                 if (curDiffR > 0) {
00678                     diff -= curDiffR;
00679                     result = i;
00680 
00681                     if (diff == 0)
00682                         break;
00683                 }
00684             }
00685         }
00686     }
00687 
00688     return result;
00689 }
00690 
00691 void CinepakDecoder::ditherVectors(Common::SeekableReadStream &stream, uint16 strip, byte chunkID, uint32 chunkSize) {
00692     if (_ditherType == kDitherTypeVFW)
00693         decodeVectorsTmpl<byte, CodebookConverterDitherVFW>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
00694     else
00695         decodeVectorsTmpl<byte, CodebookConverterDitherQT>(_curFrame, _clipTable, _colorMap, stream, strip, chunkID, chunkSize);
00696 }
00697 
00698 } // End of namespace Image


Generated on Sat Mar 23 2019 05:01:23 for ResidualVM by doxygen 1.7.1
curved edge   curved edge