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

codec.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 "common/list.h"
00024 #include "common/scummsys.h"
00025 
00026 #include "image/codecs/codec.h"
00027 
00028 #include "image/jpeg.h"
00029 #include "image/codecs/bmp_raw.h"
00030 #include "image/codecs/cdtoons.h"
00031 #include "image/codecs/cinepak.h"
00032 #include "image/codecs/indeo3.h"
00033 #include "image/codecs/indeo4.h"
00034 #include "image/codecs/indeo5.h"
00035 #include "image/codecs/jyv1.h"
00036 #include "image/codecs/mjpeg.h"
00037 #include "image/codecs/mpeg.h"
00038 #include "image/codecs/msvideo1.h"
00039 #include "image/codecs/msrle.h"
00040 #include "image/codecs/msrle4.h"
00041 #include "image/codecs/qtrle.h"
00042 #include "image/codecs/rpza.h"
00043 #include "image/codecs/smc.h"
00044 #include "image/codecs/svq1.h"
00045 #include "image/codecs/truemotion1.h"
00046 
00047 #include "common/endian.h"
00048 #include "common/textconsole.h"
00049 
00050 namespace Image {
00051 
00052 namespace {
00053 
00057 inline void addColorToQueue(uint16 color, uint16 index, byte *checkBuffer, Common::List<uint16> &checkQueue) {
00058     if ((READ_UINT16(checkBuffer + color * 2) & 0xFF) == 0) {
00059         // Previously unfound color
00060         WRITE_UINT16(checkBuffer + color * 2, index);
00061         checkQueue.push_back(color);
00062     }
00063 }
00064 
00065 inline byte adjustColorRange(byte currentColor, byte correctColor, byte palColor) {
00066     return CLIP<int>(currentColor - palColor + correctColor, 0, 255);
00067 }
00068 
00069 inline uint16 makeQuickTimeDitherColor(byte r, byte g, byte b) {
00070     // RGB554
00071     return ((r & 0xF8) << 6) | ((g & 0xF8) << 1) | (b >> 4);
00072 }
00073 
00074 } // End of anonymous namespace
00075 
00076 byte *Codec::createQuickTimeDitherTable(const byte *palette, uint colorCount) {
00077     byte *buf = new byte[0x10000];
00078     memset(buf, 0, 0x10000);
00079 
00080     Common::List<uint16> checkQueue;
00081 
00082     bool foundBlack = false;
00083     bool foundWhite = false;
00084 
00085     const byte *palPtr = palette;
00086 
00087     // See what colors we have, and add them to the queue to check
00088     for (uint i = 0; i < colorCount; i++) {
00089         byte r = *palPtr++;
00090         byte g = *palPtr++;
00091         byte b = *palPtr++;
00092         uint16 n = (i << 8) | 1;
00093         uint16 col = makeQuickTimeDitherColor(r, g, b);
00094 
00095         if (col == 0) {
00096             // Special case for close-to-black
00097             // The original did more here, but it effectively discarded the value
00098             // due to a poor if-check (whole 16-bit value instead of lower 8-bits).
00099             WRITE_UINT16(buf, n);
00100             foundBlack = true;
00101         } else if (col == 0x3FFF) {
00102             // Special case for close-to-white
00103             // The original did more here, but it effectively discarded the value
00104             // due to a poor if-check (whole 16-bit value instead of lower 8-bits).
00105             WRITE_UINT16(buf + 0x7FFE, n);
00106             foundWhite = true;
00107         } else {
00108             // Previously unfound color
00109             addColorToQueue(col, n, buf, checkQueue);
00110         }
00111     }
00112 
00113     // More special handling for white
00114     if (foundWhite)
00115         checkQueue.push_front(0x3FFF);
00116 
00117     // More special handling for black
00118     if (foundBlack)
00119         checkQueue.push_front(0);
00120 
00121     // Go through the list of colors we have and match up similar colors
00122     // to fill in the table as best as we can.
00123     while (!checkQueue.empty()) {
00124         uint16 col = checkQueue.front();
00125         checkQueue.pop_front();
00126         uint16 index = READ_UINT16(buf + col * 2);
00127 
00128         uint32 x = col << 4;
00129         if ((x & 0xFF) < 0xF0)
00130             addColorToQueue((x + 0x10) >> 4, index, buf, checkQueue);
00131         if ((x & 0xFF) >= 0x10)
00132             addColorToQueue((x - 0x10) >> 4, index, buf, checkQueue);
00133 
00134         uint32 y = col << 7;
00135         if ((y & 0xFF00) < 0xF800)
00136             addColorToQueue((y + 0x800) >> 7, index, buf, checkQueue);
00137         if ((y & 0xFF00) >= 0x800)
00138             addColorToQueue((y - 0x800) >> 7, index, buf, checkQueue);
00139 
00140         uint32 z = col << 2;
00141         if ((z & 0xFF00) < 0xF800)
00142             addColorToQueue((z + 0x800) >> 2, index, buf, checkQueue);
00143         if ((z & 0xFF00) >= 0x800)
00144             addColorToQueue((z - 0x800) >> 2, index, buf, checkQueue);
00145     }
00146 
00147     // Contract the table back to just palette entries
00148     for (int i = 0; i < 0x4000; i++)
00149         buf[i] = READ_UINT16(buf + i * 2) >> 8;
00150 
00151     // Now go through and distribute the error to three more pixels
00152     byte *bufPtr = buf;
00153     for (uint realR = 0; realR < 0x100; realR += 8) {
00154         for (uint realG = 0; realG < 0x100; realG += 8) {
00155             for (uint realB = 0; realB < 0x100; realB += 16) {
00156                 byte palIndex = *bufPtr;
00157                 byte r = realR;
00158                 byte g = realG;
00159                 byte b = realB;
00160 
00161                 byte palR = palette[palIndex * 3] & 0xF8;
00162                 byte palG = palette[palIndex * 3 + 1] & 0xF8;
00163                 byte palB = palette[palIndex * 3 + 2] & 0xF0;
00164 
00165                 r = adjustColorRange(r, realR, palR);
00166                 g = adjustColorRange(g, realG, palG);
00167                 b = adjustColorRange(b, realB, palB);
00168                 palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
00169                 bufPtr[0x4000] = palIndex;
00170 
00171                 palR = palette[palIndex * 3] & 0xF8;
00172                 palG = palette[palIndex * 3 + 1] & 0xF8;
00173                 palB = palette[palIndex * 3 + 2] & 0xF0;
00174 
00175                 r = adjustColorRange(r, realR, palR);
00176                 g = adjustColorRange(g, realG, palG);
00177                 b = adjustColorRange(b, realB, palB);
00178                 palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
00179                 bufPtr[0x8000] = palIndex;
00180 
00181                 palR = palette[palIndex * 3] & 0xF8;
00182                 palG = palette[palIndex * 3 + 1] & 0xF8;
00183                 palB = palette[palIndex * 3 + 2] & 0xF0;
00184 
00185                 r = adjustColorRange(r, realR, palR);
00186                 g = adjustColorRange(g, realG, palG);
00187                 b = adjustColorRange(b, realB, palB);
00188                 palIndex = buf[makeQuickTimeDitherColor(r, g, b)];
00189                 bufPtr[0xC000] = palIndex;
00190 
00191                 bufPtr++;
00192             }
00193         }
00194     }
00195 
00196     return buf;
00197 }
00198 
00199 Codec *createBitmapCodec(uint32 tag, uint32 streamTag, int width, int height, int bitsPerPixel) {
00200     // Crusader videos are special cased here because the frame type is not in the "compression"
00201     // tag but in the "stream handler" tag for these files
00202     if (JYV1Decoder::isJYV1StreamTag(streamTag)) {
00203         assert(bitsPerPixel == 8);
00204         return new JYV1Decoder(width, height, streamTag);
00205     }
00206 
00207     switch (tag) {
00208     case SWAP_CONSTANT_32(0):
00209         return new BitmapRawDecoder(width, height, bitsPerPixel);
00210     case SWAP_CONSTANT_32(1):
00211         return new MSRLEDecoder(width, height, bitsPerPixel);
00212     case SWAP_CONSTANT_32(2):
00213         return new MSRLE4Decoder(width, height, bitsPerPixel);
00214     case MKTAG('C','R','A','M'):
00215     case MKTAG('m','s','v','c'):
00216     case MKTAG('W','H','A','M'):
00217         return new MSVideo1Decoder(width, height, bitsPerPixel);
00218     case MKTAG('c','v','i','d'):
00219         return new CinepakDecoder(bitsPerPixel);
00220     case MKTAG('I','V','3','2'):
00221         return new Indeo3Decoder(width, height, bitsPerPixel);
00222     case MKTAG('I', 'V', '4', '1'):
00223     case MKTAG('I', 'V', '4', '2'):
00224         return new Indeo4Decoder(width, height, bitsPerPixel);
00225     case MKTAG('I', 'V', '5', '0'):
00226         return new Indeo5Decoder(width, height, bitsPerPixel);
00227 #ifdef IMAGE_CODECS_TRUEMOTION1_H
00228     case MKTAG('D','U','C','K'):
00229     case MKTAG('d','u','c','k'):
00230         return new TrueMotion1Decoder();
00231 #endif
00232 #ifdef USE_MPEG2
00233     case MKTAG('m','p','g','2'):
00234         return new MPEGDecoder();
00235 #endif
00236     case MKTAG('M','J','P','G'):
00237     case MKTAG('m','j','p','g'):
00238         return new MJPEGDecoder();
00239     default:
00240         if (tag & 0x00FFFFFF)
00241             warning("Unknown BMP/AVI compression format \'%s\'", tag2str(tag));
00242         else
00243             warning("Unknown BMP/AVI compression format %d", SWAP_BYTES_32(tag));
00244     }
00245 
00246     return 0;
00247 }
00248 
00249 Codec *createQuickTimeCodec(uint32 tag, int width, int height, int bitsPerPixel) {
00250     switch (tag) {
00251     case MKTAG('c','v','i','d'):
00252         // Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this.
00253         return new CinepakDecoder(bitsPerPixel);
00254     case MKTAG('r','p','z','a'):
00255         // Apple Video ("Road Pizza"): Used by some Myst videos.
00256         return new RPZADecoder(width, height);
00257     case MKTAG('r','l','e',' '):
00258         // QuickTime RLE: Used by some Myst ME videos.
00259         return new QTRLEDecoder(width, height, bitsPerPixel);
00260     case MKTAG('s','m','c',' '):
00261         // Apple SMC: Used by some Myst videos.
00262         return new SMCDecoder(width, height);
00263     case MKTAG('S','V','Q','1'):
00264         // Sorenson Video 1: Used by some Myst ME videos.
00265         return new SVQ1Decoder(width, height);
00266     case MKTAG('S','V','Q','3'):
00267         // Sorenson Video 3: Used by some Myst ME videos.
00268         warning("Sorenson Video 3 not yet supported");
00269         break;
00270     case MKTAG('j','p','e','g'):
00271         // JPEG: Used by some Myst ME 10th Anniversary videos.
00272         return new JPEGDecoder();
00273     case MKTAG('Q','k','B','k'):
00274         // CDToons: Used by most of the Broderbund games.
00275         return new CDToonsDecoder(width, height);
00276     default:
00277         warning("Unsupported QuickTime codec \'%s\'", tag2str(tag));
00278     }
00279 
00280     return 0;
00281 }
00282 
00283 } // End of namespace Image


Generated on Sat Jul 4 2020 05:01:41 for ResidualVM by doxygen 1.7.1
curved edge   curved edge