static void readBitStream(Common::BitStream &bitStream, byte (&data)[11]) { for (size_t i = 0; i < 8; i++) data[i] = bitStream.getBit(); data[8] = bitStream.getBits(4); data[9] = bitStream.getBits(4); uint32 x = 1; bitStream.addBit(x, 1); data[10] = x; }
uint32 BigHuffmanTree::getCode(Common::BitStream &bs) { byte peek = bs.peekBits(MIN<uint32>(bs.size() - bs.pos(), 8)); uint32 *p = &_tree[_prefixtree[peek]]; bs.skip(_prefixlength[peek]); while (*p & SMK_NODE) { if (bs.getBit()) p += (*p) & ~SMK_NODE; p++; } uint32 v = *p; if (v != _tree[_last[0]]) { _tree[_last[2]] = _tree[_last[1]]; _tree[_last[1]] = _tree[_last[0]]; _tree[_last[0]] = v; } return v; }
void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStream &bs) { _MMapTree->reset(); _MClrTree->reset(); _FullTree->reset(); _TypeTree->reset(); // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled) uint doubleY = _flags ? 2 : 1; uint bw = getWidth() / 4; uint bh = getHeight() / doubleY / 4; uint stride = getWidth(); uint block = 0, blocks = bw*bh; byte *out; uint type, run, j, mode; uint32 p1, p2, clr, map; byte hi, lo; uint i; while (block < blocks) { type = _TypeTree->getCode(bs); run = getBlockRun((type >> 2) & 0x3f); switch (type & 3) { case SMK_BLOCK_MONO: while (run-- && block < blocks) { clr = _MClrTree->getCode(bs); map = _MMapTree->getCode(bs); out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; hi = clr >> 8; lo = clr & 0xff; for (i = 0; i < 4; i++) { for (j = 0; j < doubleY; j++) { out[0] = (map & 1) ? hi : lo; out[1] = (map & 2) ? hi : lo; out[2] = (map & 4) ? hi : lo; out[3] = (map & 8) ? hi : lo; out += stride; } map >>= 4; } ++block; } break; case SMK_BLOCK_FULL: // Smacker v2 has one mode, Smacker v4 has three if (_signature == MKTAG('S','M','K','2')) { mode = 0; } else { // 00 - mode 0 // 10 - mode 1 // 01 - mode 2 mode = 0; if (bs.getBit()) { mode = 1; } else if (bs.getBit()) { mode = 2; } } while (run-- && block < blocks) { out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; switch (mode) { case 0: for (i = 0; i < 4; ++i) { p1 = _FullTree->getCode(bs); p2 = _FullTree->getCode(bs); for (j = 0; j < doubleY; ++j) { out[2] = p1 & 0xff; out[3] = p1 >> 8; out[0] = p2 & 0xff; out[1] = p2 >> 8; out += stride; } } break; case 1: p1 = _FullTree->getCode(bs); out[0] = out[1] = p1 & 0xFF; out[2] = out[3] = p1 >> 8; out += stride; out[0] = out[1] = p1 & 0xFF; out[2] = out[3] = p1 >> 8; out += stride; p2 = _FullTree->getCode(bs); out[0] = out[1] = p2 & 0xFF; out[2] = out[3] = p2 >> 8; out += stride; out[0] = out[1] = p2 & 0xFF; out[2] = out[3] = p2 >> 8; out += stride; break; case 2: for (i = 0; i < 2; i++) { // We first get p2 and then p1 // Check ffmpeg thread "[PATCH] Smacker video decoder bug fix" // http://article.gmane.org/gmane.comp.video.ffmpeg.devel/78768 p2 = _FullTree->getCode(bs); p1 = _FullTree->getCode(bs); for (j = 0; j < doubleY; ++j) { out[0] = p1 & 0xff; out[1] = p1 >> 8; out[2] = p2 & 0xff; out[3] = p2 >> 8; out += stride; } for (j = 0; j < doubleY; ++j) { out[0] = p1 & 0xff; out[1] = p1 >> 8; out[2] = p2 & 0xff; out[3] = p2 >> 8; out += stride; } } break; } ++block; } break; case SMK_BLOCK_SKIP: while (run-- && block < blocks) block++; break; case SMK_BLOCK_FILL: uint32 col; mode = type >> 8; while (run-- && block < blocks) { out = (byte *)_surface->pixels + (block / bw) * (stride * 4 * doubleY) + (block % bw) * 4; col = mode * 0x01010101; for (i = 0; i < 4 * doubleY; ++i) { out[0] = out[1] = out[2] = out[3] = col; out += stride; } ++block; } break; } } }
void CodebookLibrary::copy(Common::BitStream &bis, Common::BitStreamWriter &bos) { const uint32 id = bis.getBits(24); const uint16 dimensions = bis.getBits(16); const uint32 entries = bis.getBits(24); if (id != 0x564342) throw Common::Exception("CodebookLibrary::copy(): Invalid codebook identifier"); bos.putBits(id, 24); bos.putBits(dimensions, 16); bos.putBits(entries, 24); const bool ordered = bis.getBit(); bos.putBit(ordered); if (ordered) { const uint8 initialLength = bis.getBits(5); bos.putBits(initialLength, 5); uint32 currentEntry = 0; while (currentEntry < entries) { const size_t bitCount = Common::intLog2(entries - currentEntry) + 1; const uint32 number = bis.getBits(bitCount); bos.putBits(number, bitCount); currentEntry += number; } if (currentEntry > entries) throw Common::Exception("CodebookLibrary::copy(): Current entry out of range"); } else { const bool sparse = bis.getBit(); bos.putBit(sparse); for (size_t i = 0; i < entries; i++) { bool present = true; if (sparse) { present = bis.getBit(); bos.putBit(present); } if (present) bos.putBits(bis.getBits(5), 5); } } const uint8 lookupType = bis.getBits(4); bos.putBits(lookupType, 4); if (lookupType == 0) { } else if (lookupType == 1) { const uint32 min = bis.getBits(32); const uint32 max = bis.getBits(32); const uint8 valueLength = bis.getBits(4) + 1; const bool sequenceFlag = bis.getBit(); bos.putBits(min, 32); bos.putBits(max, 32); bos.putBits(valueLength - 1, 4); bos.putBit(sequenceFlag); const size_t quantVals = bookMapType1QuantVals(entries, dimensions); for (size_t i = 0; i < quantVals; i++) bos.putBits(bis.getBits(valueLength), valueLength); } else throw Common::Exception("CodebookLibrary::copy(): Invalid lookup type %u", lookupType); }
void CodebookLibrary::rebuild(Common::BitStream &bis, size_t size, Common::BitStreamWriter &bos) { const uint32 id = 0x564342; const uint16 dimensions = bis.getBits(4); const uint32 entries = bis.getBits(14); bos.putBits(id, 24); bos.putBits(dimensions, 16); bos.putBits(entries, 24); const bool ordered = bis.getBit(); bos.putBit(ordered); if (ordered) { const uint8 initialLength = bis.getBits(5); bos.putBits(initialLength, 5); uint32 currentEntry = 0; while (currentEntry < entries) { const size_t bitCount = Common::intLog2(entries - currentEntry) + 1; const uint32 number = bis.getBits(bitCount); bos.putBits(number, bitCount); currentEntry += number; } if (currentEntry > entries) throw Common::Exception("CodebookLibrary::rebuild(): Current entry out of range"); } else { const uint8 codewordLengthLength = bis.getBits(3); const bool sparse = bis.getBit(); if ((codewordLengthLength == 0) || (codewordLengthLength > 5)) throw Common::Exception("CodebookLibrary::rebuild(): Nonsense codeword length"); bos.putBit(sparse); for (size_t i = 0; i < entries; i++) { bool present = true; if (sparse) { present = bis.getBit(); bos.putBit(present); } if (present) bos.putBits(bis.getBits(codewordLengthLength), 5); } } const uint8 lookupType = bis.getBits(1); bos.putBits(lookupType, 4); if (lookupType == 0) { } else if (lookupType == 1) { const uint32 min = bis.getBits(32); const uint32 max = bis.getBits(32); const uint8 valueLength = bis.getBits(4) + 1; const bool sequenceFlag = bis.getBit(); bos.putBits(min, 32); bos.putBits(max, 32); bos.putBits(valueLength - 1, 4); bos.putBit(sequenceFlag); const size_t quantVals = bookMapType1QuantVals(entries, dimensions); for (size_t i = 0; i < quantVals; i++) bos.putBits(bis.getBits(valueLength), valueLength); } if ((size != 0) && (((bis.pos() / 8) + 1) != size )) throw Common::Exception("CodebookLibrary::rebuild(): Size mismatch: %s != %s", Common::composeString((bis.pos() / 8) + 1).c_str(), Common::composeString(size).c_str()); }