Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
		}
	}
}
Beispiel #4
0
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);
}
Beispiel #5
0
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());
}