Пример #1
0
void FlicDecoder::FlicVideoTrack::handleFrame() {
	uint16 chunkCount = _fileStream->readUint16LE();
	// Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
	// the frame delay is the FLIC "speed", in milliseconds.
	uint16 newFrameDelay = _fileStream->readUint16LE();	// "speed", in milliseconds
	if (newFrameDelay > 0)
		_frameDelay = newFrameDelay;

	_fileStream->readUint16LE();	// reserved, always 0
	uint16 newWidth = _fileStream->readUint16LE();
	uint16 newHeight = _fileStream->readUint16LE();

	if ((newWidth != 0) || (newHeight != 0)) {
		if (newWidth == 0)
			newWidth = _surface->w;
		if (newHeight == 0)
			newHeight = _surface->h;

		_surface->free();
		delete _surface;
		_surface = new Graphics::Surface();
		_surface->create(newWidth, newHeight, Graphics::PixelFormat::createFormatCLUT8());
	}

	// Read subchunks
	for (uint32 i = 0; i < chunkCount; ++i) {
		uint32 frameSize = _fileStream->readUint32LE();
		uint16 frameType = _fileStream->readUint16LE();
		uint8 *data = new uint8[frameSize - 6];
		_fileStream->read(data, frameSize - 6);

		switch (frameType) {
		case FLI_SETPAL:
			unpackPalette(data);
			_dirtyPalette = true;
			break;
		case FLI_SS2:
			decodeDeltaFLC(data);
			break;
		case FLI_BRUN:
			decodeByteRun(data);
			break;
		case FLI_COPY:
			copyFrame(data);
			break;
		case PSTAMP:
			/* PSTAMP - skip for now */
			break;
		default:
			error("FlicDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType);
			break;
		}

		delete[] data;
	}
}
Пример #2
0
const Graphics::Surface *SmackerDecoder::decodeNextFrame() {
	uint i;
	uint32 chunkSize = 0;
	uint32 dataSizeUnpacked = 0;

	uint32 startPos = _fileStream->pos();

	_curFrame++;

	// Check if we got a frame with palette data, and
	// call back the virtual setPalette function to set
	// the current palette
	if (_frameTypes[_curFrame] & 1) {
		unpackPalette();
		_dirtyPalette = true;
	}

	// Load audio tracks
	for (i = 0; i < 7; ++i) {
		if (!(_frameTypes[_curFrame] & (2 << i)))
			continue;

		chunkSize = _fileStream->readUint32LE();
		chunkSize -= 4;    // subtract the first 4 bytes (chunk size)

		if (_header.audioInfo[i].compression == kCompressionNone) {
			dataSizeUnpacked = chunkSize;
		} else {
			dataSizeUnpacked = _fileStream->readUint32LE();
			chunkSize -= 4;    // subtract the next 4 bytes (unpacked data size)
		}

		handleAudioTrack(i, chunkSize, dataSizeUnpacked);
	}

	uint32 frameSize = _frameSizes[_curFrame] & ~3;
//	uint32 remainder =  _frameSizes[_curFrame] & 3;

	if (_fileStream->pos() - startPos > frameSize)
		error("Smacker actual frame size exceeds recorded frame size");

	uint32 frameDataSize = frameSize - (_fileStream->pos() - startPos);

	_frameData = (byte *)malloc(frameDataSize);
	_fileStream->read(_frameData, frameDataSize);

	BitStream bs(_frameData, frameDataSize);

	_MMapTree->reset();
	_MClrTree->reset();
	_FullTree->reset();
	_TypeTree->reset();

	// Height needs to be doubled if we have flags (Y-interlaced or Y-doubled)
	uint doubleY = _header.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;

	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 (_header.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;
		}
	}

	_fileStream->seek(startPos + frameSize);

	free(_frameData);

	if (_curFrame == 0)
		_startTime = g_system->getMillis();

	return _surface;
}
Пример #3
0
const Graphics::Surface *FlicDecoder::FlicVideoTrack::decodeNextFrame() {
	// Read chunk
	uint32 frameSize = _fileStream->readUint32LE();
	uint16 frameType = _fileStream->readUint16LE();
	uint16 chunkCount = 0;

	switch (frameType) {
	case FRAME_TYPE:
		{
			chunkCount = _fileStream->readUint16LE();
			// Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword)
			// the frame delay is the FLIC "speed", in milliseconds.
			uint16 newFrameDelay = _fileStream->readUint16LE();	// "speed", in milliseconds
			if (newFrameDelay > 0)
				_frameDelay = newFrameDelay;

			_fileStream->readUint16LE();	// reserved, always 0
			uint16 newWidth = _fileStream->readUint16LE();
			uint16 newHeight = _fileStream->readUint16LE();

			if ((newWidth != 0) && (newHeight != 0)) {
				if (newWidth == 0)
					newWidth = _surface->w;
				if (newHeight == 0)
					newHeight = _surface->h;

				_surface->free();
				delete _surface;
				_surface = new Graphics::Surface();
				_surface->create(newWidth, newHeight, Graphics::PixelFormat::createFormatCLUT8());
			}
		}
		break;
	default:
		error("FlicDecoder::decodeFrame(): unknown main chunk type (type = 0x%02X)", frameType);
		break;
	 }

	// Read subchunks
	if (frameType == FRAME_TYPE) {
		for (uint32 i = 0; i < chunkCount; ++i) {
			frameSize = _fileStream->readUint32LE();
			frameType = _fileStream->readUint16LE();
			uint8 *data = new uint8[frameSize - 6];
			_fileStream->read(data, frameSize - 6);

			switch (frameType) {
			case FLI_SETPAL:
				unpackPalette(data);
				_dirtyPalette = true;
				break;
			case FLI_SS2:
				decodeDeltaFLC(data);
				break;
			case FLI_BRUN:
				decodeByteRun(data);
				break;
			case FLI_COPY:
				copyFrame(data);
				break;
			case PSTAMP:
				/* PSTAMP - skip for now */
				break;
			default:
				error("FlicDecoder::decodeNextFrame(): unknown subchunk type (type = 0x%02X)", frameType);
				break;
			 }

			delete[] data;
		}
	}

	_curFrame++;
	_nextFrameStartTime += _frameDelay;

	if (_atRingFrame) {
		// If we decoded the ring frame, seek to the second frame
		_atRingFrame = false;
		_fileStream->seek(_offsetFrame2);
	}

	return _surface;
}