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

smk_decoder.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 // Based on http://wiki.multimedia.cx/index.php?title=Smacker
00024 // and the FFmpeg Smacker decoder (libavcodec/smacker.c), revision 16143
00025 // http://git.ffmpeg.org/?p=ffmpeg;a=blob;f=libavcodec/smacker.c;hb=b8437a00a2f14d4a437346455d624241d726128e
00026 
00027 #include "video/smk_decoder.h"
00028 
00029 #include "common/endian.h"
00030 #include "common/util.h"
00031 #include "common/stream.h"
00032 #include "common/bitstream.h"
00033 #include "common/system.h"
00034 #include "common/textconsole.h"
00035 
00036 #include "audio/audiostream.h"
00037 #include "audio/mixer.h"
00038 #include "audio/decoders/raw.h"
00039 
00040 namespace Video {
00041 
00042 enum SmkBlockTypes {
00043     SMK_BLOCK_MONO = 0,
00044     SMK_BLOCK_FULL = 1,
00045     SMK_BLOCK_SKIP = 2,
00046     SMK_BLOCK_FILL = 3
00047 };
00048 
00049 /*
00050  * class SmallHuffmanTree
00051  * A Huffman-tree to hold 8-bit values.
00052  */
00053 
00054 class SmallHuffmanTree {
00055 public:
00056     SmallHuffmanTree(Common::BitStreamMemory8LSB &bs);
00057 
00058     uint16 getCode(Common::BitStreamMemory8LSB &bs);
00059 private:
00060     enum {
00061         SMK_NODE = 0x8000
00062     };
00063 
00064     uint16 decodeTree(uint32 prefix, int length);
00065 
00066     uint16 _treeSize;
00067     uint16 _tree[511];
00068 
00069     uint16 _prefixtree[256];
00070     byte _prefixlength[256];
00071 
00072     Common::BitStreamMemory8LSB &_bs;
00073 };
00074 
00075 SmallHuffmanTree::SmallHuffmanTree(Common::BitStreamMemory8LSB &bs)
00076     : _treeSize(0), _bs(bs) {
00077     uint32 bit = _bs.getBit();
00078     assert(bit);
00079 
00080     for (uint16 i = 0; i < 256; ++i)
00081         _prefixtree[i] = _prefixlength[i] = 0;
00082 
00083     decodeTree(0, 0);
00084 
00085     bit = _bs.getBit();
00086     assert(!bit);
00087 }
00088 
00089 uint16 SmallHuffmanTree::decodeTree(uint32 prefix, int length) {
00090     if (!_bs.getBit()) { // Leaf
00091         _tree[_treeSize] = _bs.getBits(8);
00092 
00093         if (length <= 8) {
00094             for (int i = 0; i < 256; i += (1 << length)) {
00095                 _prefixtree[prefix | i] = _treeSize;
00096                 _prefixlength[prefix | i] = length;
00097             }
00098         }
00099         ++_treeSize;
00100 
00101         return 1;
00102     }
00103 
00104     uint16 t = _treeSize++;
00105 
00106     if (length == 8) {
00107         _prefixtree[prefix] = t;
00108         _prefixlength[prefix] = 8;
00109     }
00110 
00111     uint16 r1 = decodeTree(prefix, length + 1);
00112 
00113     _tree[t] = (SMK_NODE | r1);
00114 
00115     uint16 r2 = decodeTree(prefix | (1 << length), length + 1);
00116 
00117     return r1+r2+1;
00118 }
00119 
00120 uint16 SmallHuffmanTree::getCode(Common::BitStreamMemory8LSB &bs) {
00121     byte peek = bs.peekBits(MIN<uint32>(bs.size() - bs.pos(), 8));
00122     uint16 *p = &_tree[_prefixtree[peek]];
00123     bs.skip(_prefixlength[peek]);
00124 
00125     while (*p & SMK_NODE) {
00126         if (bs.getBit())
00127             p += *p & ~SMK_NODE;
00128         p++;
00129     }
00130 
00131     return *p;
00132 }
00133 
00134 /*
00135  * class BigHuffmanTree
00136  * A Huffman-tree to hold 16-bit values.
00137  */
00138 
00139 class BigHuffmanTree {
00140 public:
00141     BigHuffmanTree(Common::BitStreamMemory8LSB &bs, int allocSize);
00142     ~BigHuffmanTree();
00143 
00144     void reset();
00145     uint32 getCode(Common::BitStreamMemory8LSB &bs);
00146 private:
00147     enum {
00148         SMK_NODE = 0x80000000
00149     };
00150 
00151     uint32 decodeTree(uint32 prefix, int length);
00152 
00153     uint32  _treeSize;
00154     uint32 *_tree;
00155     uint32  _last[3];
00156 
00157     uint32 _prefixtree[256];
00158     byte _prefixlength[256];
00159 
00160     /* Used during construction */
00161     Common::BitStreamMemory8LSB &_bs;
00162     uint32 _markers[3];
00163     SmallHuffmanTree *_loBytes;
00164     SmallHuffmanTree *_hiBytes;
00165 };
00166 
00167 BigHuffmanTree::BigHuffmanTree(Common::BitStreamMemory8LSB &bs, int allocSize)
00168     : _bs(bs) {
00169     uint32 bit = _bs.getBit();
00170     if (!bit) {
00171         _tree = new uint32[1];
00172         _tree[0] = 0;
00173         _last[0] = _last[1] = _last[2] = 0;
00174         return;
00175     }
00176 
00177     for (uint32 i = 0; i < 256; ++i)
00178         _prefixtree[i] = _prefixlength[i] = 0;
00179 
00180     _loBytes = new SmallHuffmanTree(_bs);
00181     _hiBytes = new SmallHuffmanTree(_bs);
00182 
00183     _markers[0] = _bs.getBits(16);
00184     _markers[1] = _bs.getBits(16);
00185     _markers[2] = _bs.getBits(16);
00186 
00187     _last[0] = _last[1] = _last[2] = 0xffffffff;
00188 
00189     _treeSize = 0;
00190     _tree = new uint32[allocSize / 4];
00191     decodeTree(0, 0);
00192     bit = _bs.getBit();
00193     assert(!bit);
00194 
00195     for (uint32 i = 0; i < 3; ++i) {
00196         if (_last[i] == 0xffffffff) {
00197             _last[i] = _treeSize;
00198             _tree[_treeSize++] = 0;
00199         }
00200     }
00201 
00202     delete _loBytes;
00203     delete _hiBytes;
00204 }
00205 
00206 BigHuffmanTree::~BigHuffmanTree() {
00207     delete[] _tree;
00208 }
00209 
00210 void BigHuffmanTree::reset() {
00211     _tree[_last[0]] = _tree[_last[1]] = _tree[_last[2]] = 0;
00212 }
00213 
00214 uint32 BigHuffmanTree::decodeTree(uint32 prefix, int length) {
00215     uint32 bit = _bs.getBit();
00216 
00217     if (!bit) { // Leaf
00218         uint32 lo = _loBytes->getCode(_bs);
00219         uint32 hi = _hiBytes->getCode(_bs);
00220 
00221         uint32 v = (hi << 8) | lo;
00222 
00223         _tree[_treeSize] = v;
00224 
00225         if (length <= 8) {
00226             for (int i = 0; i < 256; i += (1 << length)) {
00227                 _prefixtree[prefix | i] = _treeSize;
00228                 _prefixlength[prefix | i] = length;
00229             }
00230         }
00231 
00232         for (int i = 0; i < 3; ++i) {
00233             if (_markers[i] == v) {
00234                 _last[i] = _treeSize;
00235                 _tree[_treeSize] = 0;
00236             }
00237         }
00238         ++_treeSize;
00239 
00240         return 1;
00241     }
00242 
00243     uint32 t = _treeSize++;
00244 
00245     if (length == 8) {
00246         _prefixtree[prefix] = t;
00247         _prefixlength[prefix] = 8;
00248     }
00249 
00250     uint32 r1 = decodeTree(prefix, length + 1);
00251 
00252     _tree[t] = SMK_NODE | r1;
00253 
00254     uint32 r2 = decodeTree(prefix | (1 << length), length + 1);
00255     return r1+r2+1;
00256 }
00257 
00258 uint32 BigHuffmanTree::getCode(Common::BitStreamMemory8LSB &bs) {
00259     byte peek = bs.peekBits(MIN<uint32>(bs.size() - bs.pos(), 8));
00260     uint32 *p = &_tree[_prefixtree[peek]];
00261     bs.skip(_prefixlength[peek]);
00262 
00263     while (*p & SMK_NODE) {
00264         if (bs.getBit())
00265             p += (*p) & ~SMK_NODE;
00266         p++;
00267     }
00268 
00269     uint32 v = *p;
00270     if (v != _tree[_last[0]]) {
00271         _tree[_last[2]] = _tree[_last[1]];
00272         _tree[_last[1]] = _tree[_last[0]];
00273         _tree[_last[0]] = v;
00274     }
00275 
00276     return v;
00277 }
00278 
00279 SmackerDecoder::SmackerDecoder() {
00280     _fileStream = 0;
00281     _firstFrameStart = 0;
00282     _frameTypes = 0;
00283     _frameSizes = 0;
00284 }
00285 
00286 SmackerDecoder::~SmackerDecoder() {
00287     close();
00288 }
00289 
00290 bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) {
00291     close();
00292 
00293     _fileStream = stream;
00294 
00295     // Read in the Smacker header
00296     _header.signature = _fileStream->readUint32BE();
00297 
00298     if (_header.signature != MKTAG('S', 'M', 'K', '2') && _header.signature != MKTAG('S', 'M', 'K', '4'))
00299         return false;
00300 
00301     uint32 width = _fileStream->readUint32LE();
00302     uint32 height = _fileStream->readUint32LE();
00303     uint32 frameCount = _fileStream->readUint32LE();
00304     int32 frameDelay = _fileStream->readSint32LE();
00305 
00306     // frame rate contains 2 digits after the comma, so 1497 is actually 14.97 fps
00307     Common::Rational frameRate;
00308     if (frameDelay > 0)
00309         frameRate = Common::Rational(1000, frameDelay);
00310     else if (frameDelay < 0)
00311         frameRate = Common::Rational(100000, -frameDelay);
00312     else
00313         frameRate = 1000;
00314 
00315     // Flags are determined by which bit is set, which can be one of the following:
00316     // 0 - set to 1 if file contains a ring frame.
00317     // 1 - set to 1 if file is Y-interlaced
00318     // 2 - set to 1 if file is Y-doubled
00319     // If bits 1 or 2 are set, the frame should be scaled to twice its height
00320     // before it is displayed.
00321     _header.flags = _fileStream->readUint32LE();
00322 
00323     SmackerVideoTrack *videoTrack = createVideoTrack(width, height, frameCount, frameRate, _header.flags, _header.signature);
00324     addTrack(videoTrack);
00325 
00326     // TODO: should we do any extra processing for Smacker files with ring frames?
00327 
00328     // TODO: should we do any extra processing for Y-doubled videos? Are they the
00329     // same as Y-interlaced videos?
00330 
00331     uint32 i;
00332     for (i = 0; i < 7; ++i)
00333         _header.audioSize[i] = _fileStream->readUint32LE();
00334 
00335     _header.treesSize = _fileStream->readUint32LE();
00336     _header.mMapSize = _fileStream->readUint32LE();
00337     _header.mClrSize = _fileStream->readUint32LE();
00338     _header.fullSize = _fileStream->readUint32LE();
00339     _header.typeSize = _fileStream->readUint32LE();
00340 
00341     for (i = 0; i < 7; ++i) {
00342         // AudioRate - Frequency and format information for each sound track, up to 7 audio tracks.
00343         // The 32 constituent bits have the following meaning:
00344         // * bit 31 - indicates Huffman + DPCM compression
00345         // * bit 30 - indicates that audio data is present for this track
00346         // * bit 29 - 1 = 16-bit audio; 0 = 8-bit audio
00347         // * bit 28 - 1 = stereo audio; 0 = mono audio
00348         // * bit 27 - indicates Bink RDFT compression
00349         // * bit 26 - indicates Bink DCT compression
00350         // * bits 25-24 - unused
00351         // * bits 23-0 - audio sample rate
00352         uint32 audioInfo = _fileStream->readUint32LE();
00353         _header.audioInfo[i].hasAudio = audioInfo & 0x40000000;
00354         _header.audioInfo[i].is16Bits = audioInfo & 0x20000000;
00355         _header.audioInfo[i].isStereo = audioInfo & 0x10000000;
00356         _header.audioInfo[i].sampleRate = audioInfo & 0xFFFFFF;
00357 
00358         if (audioInfo & 0x8000000)
00359             _header.audioInfo[i].compression = kCompressionRDFT;
00360         else if (audioInfo & 0x4000000)
00361             _header.audioInfo[i].compression = kCompressionDCT;
00362         else if (audioInfo & 0x80000000)
00363             _header.audioInfo[i].compression = kCompressionDPCM;
00364         else
00365             _header.audioInfo[i].compression = kCompressionNone;
00366 
00367         if (_header.audioInfo[i].hasAudio) {
00368             if (_header.audioInfo[i].compression == kCompressionRDFT || _header.audioInfo[i].compression == kCompressionDCT)
00369                 warning("Unhandled Smacker v2 audio compression");
00370 
00371             addTrack(new SmackerAudioTrack(_header.audioInfo[i], getSoundType()));
00372         }
00373     }
00374 
00375     _header.dummy = _fileStream->readUint32LE();
00376 
00377     _frameSizes = new uint32[frameCount];
00378     for (i = 0; i < frameCount; ++i)
00379         _frameSizes[i] = _fileStream->readUint32LE();
00380 
00381     _frameTypes = new byte[frameCount];
00382     for (i = 0; i < frameCount; ++i)
00383         _frameTypes[i] = _fileStream->readByte();
00384 
00385     byte *huffmanTrees = (byte *) malloc(_header.treesSize);
00386     _fileStream->read(huffmanTrees, _header.treesSize);
00387 
00388     Common::BitStreamMemory8LSB bs(new Common::BitStreamMemoryStream(huffmanTrees, _header.treesSize, DisposeAfterUse::YES), DisposeAfterUse::YES);
00389     videoTrack->readTrees(bs, _header.mMapSize, _header.mClrSize, _header.fullSize, _header.typeSize);
00390 
00391     _firstFrameStart = _fileStream->pos();
00392 
00393     return true;
00394 }
00395 
00396 void SmackerDecoder::close() {
00397     VideoDecoder::close();
00398 
00399     delete _fileStream;
00400     _fileStream = 0;
00401 
00402     delete[] _frameTypes;
00403     _frameTypes = 0;
00404 
00405     delete[] _frameSizes;
00406     _frameSizes = 0;
00407 }
00408 
00409 bool SmackerDecoder::rewind() {
00410     // Call the parent method to rewind the tracks first
00411     if (!VideoDecoder::rewind())
00412         return false;
00413 
00414     // And seek back to where the first frame begins
00415     _fileStream->seek(_firstFrameStart);
00416     return true;
00417 }
00418 
00419 void SmackerDecoder::readNextPacket() {
00420     SmackerVideoTrack *videoTrack = (SmackerVideoTrack *)getTrack(0);
00421 
00422     if (videoTrack->endOfTrack())
00423         return;
00424 
00425     videoTrack->increaseCurFrame();
00426 
00427     uint i;
00428     uint32 chunkSize = 0;
00429     uint32 dataSizeUnpacked = 0;
00430 
00431     uint32 startPos = _fileStream->pos();
00432 
00433     // Check if we got a frame with palette data, and
00434     // call back the virtual setPalette function to set
00435     // the current palette
00436     if (_frameTypes[videoTrack->getCurFrame()] & 1)
00437         videoTrack->unpackPalette(_fileStream);
00438 
00439     // Load audio tracks
00440     for (i = 0; i < 7; ++i) {
00441         if (!(_frameTypes[videoTrack->getCurFrame()] & (2 << i)))
00442             continue;
00443 
00444         chunkSize = _fileStream->readUint32LE();
00445         chunkSize -= 4;    // subtract the first 4 bytes (chunk size)
00446 
00447         if (_header.audioInfo[i].compression == kCompressionNone) {
00448             dataSizeUnpacked = chunkSize;
00449         } else {
00450             dataSizeUnpacked = _fileStream->readUint32LE();
00451             chunkSize -= 4;    // subtract the next 4 bytes (unpacked data size)
00452         }
00453 
00454         handleAudioTrack(i, chunkSize, dataSizeUnpacked);
00455     }
00456 
00457     uint32 frameSize = _frameSizes[videoTrack->getCurFrame()] & ~3;
00458 //  uint32 remainder =  _frameSizes[videoTrack->getCurFrame()] & 3;
00459 
00460     if (_fileStream->pos() - startPos > frameSize)
00461         error("Smacker actual frame size exceeds recorded frame size");
00462 
00463     uint32 frameDataSize = frameSize - (_fileStream->pos() - startPos);
00464 
00465     byte *frameData = (byte *)malloc(frameDataSize + 1);
00466     // Padding to keep the BigHuffmanTrees from reading past the data end
00467     frameData[frameDataSize] = 0x00;
00468 
00469     _fileStream->read(frameData, frameDataSize);
00470 
00471     Common::BitStreamMemory8LSB bs(new Common::BitStreamMemoryStream(frameData, frameDataSize + 1, DisposeAfterUse::YES), DisposeAfterUse::YES);
00472     videoTrack->decodeFrame(bs);
00473 
00474     _fileStream->seek(startPos + frameSize);
00475 }
00476 
00477 void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) {
00478     if (chunkSize == 0)
00479         return;
00480 
00481     if (_header.audioInfo[track].hasAudio) {
00482         // Get the audio track, which start at offset 1 (first track is video)
00483         SmackerAudioTrack *audioTrack = (SmackerAudioTrack *)getTrack(track + 1);
00484 
00485         // If it's track 0, play the audio data
00486         byte *soundBuffer = (byte *)malloc(chunkSize + 1);
00487         // Padding to keep the SmallHuffmanTrees from reading past the data end
00488         soundBuffer[chunkSize] = 0x00;
00489 
00490         _fileStream->read(soundBuffer, chunkSize);
00491 
00492         if (_header.audioInfo[track].compression == kCompressionRDFT || _header.audioInfo[track].compression == kCompressionDCT) {
00493             // TODO: Compressed audio (Bink RDFT/DCT encoded)
00494             free(soundBuffer);
00495             return;
00496         } else if (_header.audioInfo[track].compression == kCompressionDPCM) {
00497             // Compressed audio (Huffman DPCM encoded)
00498             audioTrack->queueCompressedBuffer(soundBuffer, chunkSize + 1, unpackedSize);
00499             free(soundBuffer);
00500         } else {
00501             // Uncompressed audio (PCM)
00502             audioTrack->queuePCM(soundBuffer, chunkSize);
00503         }
00504     } else {
00505         // Ignore possibly unused data
00506         _fileStream->skip(chunkSize);
00507     }
00508 }
00509 
00510 VideoDecoder::AudioTrack *SmackerDecoder::getAudioTrack(int index) {
00511     // Smacker audio track indexes are relative to the first audio track
00512     Track *track = getTrack(index + 1);
00513 
00514     if (!track || track->getTrackType() != Track::kTrackTypeAudio)
00515         return 0;
00516 
00517     return (AudioTrack *)track;
00518 }
00519 
00520 SmackerDecoder::SmackerVideoTrack::SmackerVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) {
00521     _surface = new Graphics::Surface();
00522     _surface->create(width, height * (flags ? 2 : 1), Graphics::PixelFormat::createFormatCLUT8());
00523     _frameCount = frameCount;
00524     _frameRate = frameRate;
00525     _flags = flags;
00526     _signature = signature;
00527     _curFrame = -1;
00528     _dirtyPalette = false;
00529     _MMapTree = _MClrTree = _FullTree = _TypeTree = 0;
00530     memset(_palette, 0, 3 * 256);
00531 }
00532 
00533 SmackerDecoder::SmackerVideoTrack::~SmackerVideoTrack() {
00534     _surface->free();
00535     delete _surface;
00536 
00537     delete _MMapTree;
00538     delete _MClrTree;
00539     delete _FullTree;
00540     delete _TypeTree;
00541 }
00542 
00543 uint16 SmackerDecoder::SmackerVideoTrack::getWidth() const {
00544     return _surface->w;
00545 }
00546 
00547 uint16 SmackerDecoder::SmackerVideoTrack::getHeight() const {
00548     return _surface->h;
00549 }
00550 
00551 Graphics::PixelFormat SmackerDecoder::SmackerVideoTrack::getPixelFormat() const {
00552     return _surface->format;
00553 }
00554 
00555 void SmackerDecoder::SmackerVideoTrack::readTrees(Common::BitStreamMemory8LSB &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize) {
00556     _MMapTree = new BigHuffmanTree(bs, mMapSize);
00557     _MClrTree = new BigHuffmanTree(bs, mClrSize);
00558     _FullTree = new BigHuffmanTree(bs, fullSize);
00559     _TypeTree = new BigHuffmanTree(bs, typeSize);
00560 }
00561 
00562 void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStreamMemory8LSB &bs) {
00563     _MMapTree->reset();
00564     _MClrTree->reset();
00565     _FullTree->reset();
00566     _TypeTree->reset();
00567 
00568     // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled)
00569     uint doubleY = _flags ? 2 : 1;
00570 
00571     uint bw = getWidth() / 4;
00572     uint bh = getHeight() / doubleY / 4;
00573     uint stride = getWidth();
00574     uint block = 0, blocks = bw*bh;
00575 
00576     byte *out;
00577     uint type, run, j, mode;
00578     uint32 p1, p2, clr, map;
00579     byte hi, lo;
00580     uint i;
00581 
00582     while (block < blocks) {
00583         type = _TypeTree->getCode(bs);
00584         run = getBlockRun((type >> 2) & 0x3f);
00585 
00586         switch (type & 3) {
00587         case SMK_BLOCK_MONO:
00588             while (run-- && block < blocks) {
00589                 clr = _MClrTree->getCode(bs);
00590                 map = _MMapTree->getCode(bs);
00591                 out = (byte *)_surface->getPixels() + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
00592                 hi = clr >> 8;
00593                 lo = clr & 0xff;
00594                 for (i = 0; i < 4; i++) {
00595                     for (j = 0; j < doubleY; j++) {
00596                         out[0] = (map & 1) ? hi : lo;
00597                         out[1] = (map & 2) ? hi : lo;
00598                         out[2] = (map & 4) ? hi : lo;
00599                         out[3] = (map & 8) ? hi : lo;
00600                         out += stride;
00601                     }
00602                     map >>= 4;
00603                 }
00604                 ++block;
00605             }
00606             break;
00607         case SMK_BLOCK_FULL:
00608             // Smacker v2 has one mode, Smacker v4 has three
00609             if (_signature == MKTAG('S','M','K','2')) {
00610                 mode = 0;
00611             } else {
00612                 // 00 - mode 0
00613                 // 10 - mode 1
00614                 // 01 - mode 2
00615                 mode = 0;
00616                 if (bs.getBit()) {
00617                     mode = 1;
00618                 } else if (bs.getBit()) {
00619                     mode = 2;
00620                 }
00621             }
00622 
00623             while (run-- && block < blocks) {
00624                 out = (byte *)_surface->getPixels() + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
00625                 switch (mode) {
00626                     case 0:
00627                         for (i = 0; i < 4; ++i) {
00628                             p1 = _FullTree->getCode(bs);
00629                             p2 = _FullTree->getCode(bs);
00630                             for (j = 0; j < doubleY; ++j) {
00631                                 out[2] = p1 & 0xff;
00632                                 out[3] = p1 >> 8;
00633                                 out[0] = p2 & 0xff;
00634                                 out[1] = p2 >> 8;
00635                                 out += stride;
00636                             }
00637                         }
00638                         break;
00639                     case 1:
00640                         p1 = _FullTree->getCode(bs);
00641                         out[0] = out[1] = p1 & 0xFF;
00642                         out[2] = out[3] = p1 >> 8;
00643                         out += stride;
00644                         out[0] = out[1] = p1 & 0xFF;
00645                         out[2] = out[3] = p1 >> 8;
00646                         out += stride;
00647                         p2 = _FullTree->getCode(bs);
00648                         out[0] = out[1] = p2 & 0xFF;
00649                         out[2] = out[3] = p2 >> 8;
00650                         out += stride;
00651                         out[0] = out[1] = p2 & 0xFF;
00652                         out[2] = out[3] = p2 >> 8;
00653                         out += stride;
00654                         break;
00655                     case 2:
00656                         for (i = 0; i < 2; i++) {
00657                             // We first get p2 and then p1
00658                             // Check ffmpeg thread "[PATCH] Smacker video decoder bug fix"
00659                             // http://article.gmane.org/gmane.comp.video.ffmpeg.devel/78768
00660                             p2 = _FullTree->getCode(bs);
00661                             p1 = _FullTree->getCode(bs);
00662                             for (j = 0; j < doubleY; ++j) {
00663                                 out[0] = p1 & 0xff;
00664                                 out[1] = p1 >> 8;
00665                                 out[2] = p2 & 0xff;
00666                                 out[3] = p2 >> 8;
00667                                 out += stride;
00668                             }
00669                             for (j = 0; j < doubleY; ++j) {
00670                                 out[0] = p1 & 0xff;
00671                                 out[1] = p1 >> 8;
00672                                 out[2] = p2 & 0xff;
00673                                 out[3] = p2 >> 8;
00674                                 out += stride;
00675                             }
00676                         }
00677                         break;
00678                 }
00679                 ++block;
00680             }
00681             break;
00682         case SMK_BLOCK_SKIP:
00683             while (run-- && block < blocks)
00684                 block++;
00685             break;
00686         case SMK_BLOCK_FILL:
00687             uint32 col;
00688             mode = type >> 8;
00689             while (run-- && block < blocks) {
00690                 out = (byte *)_surface->getPixels() + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4;
00691                 col = mode * 0x01010101;
00692                 for (i = 0; i < 4 * doubleY; ++i) {
00693                     out[0] = out[1] = out[2] = out[3] = col;
00694                     out += stride;
00695                 }
00696                 ++block;
00697             }
00698             break;
00699         }
00700     }
00701 }
00702 
00703 void SmackerDecoder::SmackerVideoTrack::unpackPalette(Common::SeekableReadStream *stream) {
00704     uint startPos = stream->pos();
00705     uint32 len = 4 * stream->readByte();
00706 
00707     byte *chunk = (byte *)malloc(len);
00708     stream->read(chunk, len);
00709     byte *p = chunk;
00710 
00711     byte oldPalette[3 * 256];
00712     memcpy(oldPalette, _palette, 3 * 256);
00713 
00714     byte *pal = _palette;
00715 
00716     int sz = 0;
00717     byte b0;
00718     while (sz < 256) {
00719         b0 = *p++;
00720         if (b0 & 0x80) {               // if top bit is 1 (0x80 = 10000000)
00721             sz += (b0 & 0x7f) + 1;     // get lower 7 bits + 1 (0x7f = 01111111)
00722             pal += 3 * ((b0 & 0x7f) + 1);
00723         } else if (b0 & 0x40) {        // if top 2 bits are 01 (0x40 = 01000000)
00724             byte c = (b0 & 0x3f) + 1;  // get lower 6 bits + 1 (0x3f = 00111111)
00725             uint s = 3 * *p++;
00726             sz += c;
00727 
00728             while (c--) {
00729                 *pal++ = oldPalette[s + 0];
00730                 *pal++ = oldPalette[s + 1];
00731                 *pal++ = oldPalette[s + 2];
00732                 s += 3;
00733             }
00734         } else {                       // top 2 bits are 00
00735             sz++;
00736             // get the lower 6 bits for each component (0x3f = 00111111)
00737             byte r = b0 & 0x3f;
00738             byte g = (*p++) & 0x3f;
00739             byte b = (*p++) & 0x3f;
00740 
00741             // upscale to full 8-bit color values. The Multimedia Wiki suggests
00742             // a lookup table for this, but this should produce the same result.
00743             *pal++ = (r * 4 + r / 16);
00744             *pal++ = (g * 4 + g / 16);
00745             *pal++ = (b * 4 + b / 16);
00746         }
00747     }
00748 
00749     stream->seek(startPos + len);
00750     free(chunk);
00751 
00752     _dirtyPalette = true;
00753 }
00754 
00755 SmackerDecoder::SmackerAudioTrack::SmackerAudioTrack(const AudioInfo &audioInfo, Audio::Mixer::SoundType soundType) :
00756         AudioTrack(soundType),
00757         _audioInfo(audioInfo) {
00758     _audioStream = Audio::makeQueuingAudioStream(_audioInfo.sampleRate, _audioInfo.isStereo);
00759 }
00760 
00761 SmackerDecoder::SmackerAudioTrack::~SmackerAudioTrack() {
00762     delete _audioStream;
00763 }
00764 
00765 bool SmackerDecoder::SmackerAudioTrack::rewind() {
00766     delete _audioStream;
00767     _audioStream = Audio::makeQueuingAudioStream(_audioInfo.sampleRate, _audioInfo.isStereo);
00768     return true;
00769 }
00770 
00771 Audio::AudioStream *SmackerDecoder::SmackerAudioTrack::getAudioStream() const {
00772     return _audioStream;
00773 }
00774 
00775 void SmackerDecoder::SmackerAudioTrack::queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize) {
00776     Common::BitStreamMemory8LSB audioBS(new Common::BitStreamMemoryStream(buffer, bufferSize), DisposeAfterUse::YES);
00777     bool dataPresent = audioBS.getBit();
00778 
00779     if (!dataPresent)
00780         return;
00781 
00782     bool isStereo = audioBS.getBit();
00783     assert(isStereo == _audioInfo.isStereo);
00784     bool is16Bits = audioBS.getBit();
00785     assert(is16Bits == _audioInfo.is16Bits);
00786 
00787     int numBytes = 1 * (isStereo ? 2 : 1) * (is16Bits ? 2 : 1);
00788 
00789     byte *unpackedBuffer = (byte *)malloc(unpackedSize);
00790     byte *curPointer = unpackedBuffer;
00791     uint32 curPos = 0;
00792 
00793     SmallHuffmanTree *audioTrees[4];
00794     for (int k = 0; k < numBytes; k++)
00795         audioTrees[k] = new SmallHuffmanTree(audioBS);
00796 
00797     // Base values, stored as big endian
00798 
00799     int32 bases[2];
00800 
00801     if (isStereo) {
00802         if (is16Bits) {
00803             bases[1] = SWAP_BYTES_16(audioBS.getBits(16));
00804         } else {
00805             bases[1] = audioBS.getBits(8);
00806         }
00807     }
00808 
00809     if (is16Bits) {
00810         bases[0] = SWAP_BYTES_16(audioBS.getBits(16));
00811     } else {
00812         bases[0] = audioBS.getBits(8);
00813     }
00814 
00815     // The bases are the first samples, too
00816     for (int i = 0; i < (isStereo ? 2 : 1); i++, curPointer += (is16Bits ? 2 : 1), curPos += (is16Bits ? 2 : 1)) {
00817         if (is16Bits)
00818             WRITE_BE_UINT16(curPointer, bases[i]);
00819         else
00820             *curPointer = (bases[i] & 0xFF) ^ 0x80;
00821     }
00822 
00823     // Next follow the deltas, which are added to the corresponding base values and
00824     // are stored as little endian
00825     // We store the unpacked bytes in big endian format
00826 
00827     while (curPos < unpackedSize) {
00828         // If the sample is stereo, the data is stored for the left and right channel, respectively
00829         // (the exact opposite to the base values)
00830         if (!is16Bits) {
00831             for (int k = 0; k < (isStereo ? 2 : 1); k++) {
00832                 int8 delta = (int8) ((int16) audioTrees[k]->getCode(audioBS));
00833                 bases[k] = (bases[k] + delta) & 0xFF;
00834                 *curPointer++ = bases[k] ^ 0x80;
00835                 curPos++;
00836             }
00837         } else {
00838             for (int k = 0; k < (isStereo ? 2 : 1); k++) {
00839                 byte lo = audioTrees[k * 2]->getCode(audioBS);
00840                 byte hi = audioTrees[k * 2 + 1]->getCode(audioBS);
00841                 bases[k] += (int16) (lo | (hi << 8));
00842 
00843                 WRITE_BE_UINT16(curPointer, bases[k]);
00844                 curPointer += 2;
00845                 curPos += 2;
00846             }
00847         }
00848 
00849     }
00850 
00851     for (int k = 0; k < numBytes; k++)
00852         delete audioTrees[k];
00853 
00854     queuePCM(unpackedBuffer, unpackedSize);
00855 }
00856 
00857 void SmackerDecoder::SmackerAudioTrack::queuePCM(byte *buffer, uint32 bufferSize) {
00858     byte flags = 0;
00859     if (_audioInfo.is16Bits)
00860         flags |= Audio::FLAG_16BITS;
00861     if (_audioInfo.isStereo)
00862         flags |= Audio::FLAG_STEREO;
00863 
00864     _audioStream->queueBuffer(buffer, bufferSize, DisposeAfterUse::YES, flags);
00865 }
00866 
00867 SmackerDecoder::SmackerVideoTrack *SmackerDecoder::createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const {
00868     return new SmackerVideoTrack(width, height, frameCount, frameRate, flags, signature);
00869 }
00870 
00871 // ResidualVM-specific function
00872 Common::Rational SmackerDecoder::getFrameRate() const {
00873     const SmackerVideoTrack *videoTrack = (const SmackerVideoTrack *)getTrack(0);
00874 
00875     return videoTrack->getFrameRate();
00876 }
00877 
00878 } // End of namespace Video


Generated on Sat Sep 14 2019 05:01:37 for ResidualVM by doxygen 1.7.1
curved edge   curved edge