Ejemplo n.º 1
0
void SmackerDecoder::readNextPacket() {
	SmackerVideoTrack *videoTrack = (SmackerVideoTrack *)getTrack(0);

	if (videoTrack->endOfTrack())
		return;

	videoTrack->increaseCurFrame();

	uint i;
	uint32 chunkSize = 0;
	uint32 dataSizeUnpacked = 0;

	uint32 startPos = _fileStream->pos();

	// Check if we got a frame with palette data, and
	// call back the virtual setPalette function to set
	// the current palette
	if (_frameTypes[videoTrack->getCurFrame()] & 1)
		videoTrack->unpackPalette(_fileStream);

	// Load audio tracks
	for (i = 0; i < 7; ++i) {
		if (!(_frameTypes[videoTrack->getCurFrame()] & (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[videoTrack->getCurFrame()] & ~3;
//	uint32 remainder =  _frameSizes[videoTrack->getCurFrame()] & 3;

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

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

	byte *frameData = (byte *)malloc(frameDataSize + 1);
	// Padding to keep the BigHuffmanTrees from reading past the data end
	frameData[frameDataSize] = 0x00;

	_fileStream->read(frameData, frameDataSize);

	Common::BitStream8LSB bs(new Common::MemoryReadStream(frameData, frameDataSize + 1, DisposeAfterUse::YES), true);
	videoTrack->decodeFrame(bs);

	_fileStream->seek(startPos + frameSize);
}
Ejemplo n.º 2
0
void NeverhoodSmackerDecoder::forceSeekToFrame(uint frame) {
	if (!isVideoLoaded())
		return;

	if (frame >= getFrameCount())
		error("Can't force Smacker seek to invalid frame %d", frame);

	if (_header.audioInfo[0].hasAudio)
		error("Can't force Smacker frame seek with audio");
	if (!rewind())
		error("Failed to rewind");

	SmackerVideoTrack *videoTrack = (SmackerVideoTrack *)getTrack(0);
	uint32 offset = 0;
	for (uint32 i = 0; i < frame; i++) {
		videoTrack->increaseCurFrame();
		offset += _frameSizes[i] & ~3;
	}

	_fileStream->seek(offset, SEEK_CUR);
}
Ejemplo n.º 3
0
bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) {
	close();

	_fileStream = stream;

	// Read in the Smacker header
	_header.signature = _fileStream->readUint32BE();

	if (_header.signature != MKTAG('S', 'M', 'K', '2') && _header.signature != MKTAG('S', 'M', 'K', '4'))
		return false;

	uint32 width = _fileStream->readUint32LE();
	uint32 height = _fileStream->readUint32LE();
	uint32 frameCount = _fileStream->readUint32LE();
	int32 frameDelay = _fileStream->readSint32LE();

	// frame rate contains 2 digits after the comma, so 1497 is actually 14.97 fps
	Common::Rational frameRate;
	if (frameDelay > 0)
		frameRate = Common::Rational(1000, frameDelay);
	else if (frameDelay < 0)
		frameRate = Common::Rational(100000, -frameDelay);
	else
		frameRate = 1000;

	// Flags are determined by which bit is set, which can be one of the following:
	// 0 - set to 1 if file contains a ring frame.
	// 1 - set to 1 if file is Y-interlaced
	// 2 - set to 1 if file is Y-doubled
	// If bits 1 or 2 are set, the frame should be scaled to twice its height
	// before it is displayed.
	_header.flags = _fileStream->readUint32LE();

	SmackerVideoTrack *videoTrack = createVideoTrack(width, height, frameCount, frameRate, _header.flags, _header.signature);
	addTrack(videoTrack);

	// TODO: should we do any extra processing for Smacker files with ring frames?

	// TODO: should we do any extra processing for Y-doubled videos? Are they the
	// same as Y-interlaced videos?

	uint32 i;
	for (i = 0; i < 7; ++i)
		_header.audioSize[i] = _fileStream->readUint32LE();

	_header.treesSize = _fileStream->readUint32LE();
	_header.mMapSize = _fileStream->readUint32LE();
	_header.mClrSize = _fileStream->readUint32LE();
	_header.fullSize = _fileStream->readUint32LE();
	_header.typeSize = _fileStream->readUint32LE();

	for (i = 0; i < 7; ++i) {
		// AudioRate - Frequency and format information for each sound track, up to 7 audio tracks.
		// The 32 constituent bits have the following meaning:
		// * bit 31 - indicates Huffman + DPCM compression
		// * bit 30 - indicates that audio data is present for this track
		// * bit 29 - 1 = 16-bit audio; 0 = 8-bit audio
		// * bit 28 - 1 = stereo audio; 0 = mono audio
		// * bit 27 - indicates Bink RDFT compression
		// * bit 26 - indicates Bink DCT compression
		// * bits 25-24 - unused
		// * bits 23-0 - audio sample rate
		uint32 audioInfo = _fileStream->readUint32LE();
		_header.audioInfo[i].hasAudio = audioInfo & 0x40000000;
		_header.audioInfo[i].is16Bits = audioInfo & 0x20000000;
		_header.audioInfo[i].isStereo = audioInfo & 0x10000000;
		_header.audioInfo[i].sampleRate = audioInfo & 0xFFFFFF;

		if (audioInfo & 0x8000000)
			_header.audioInfo[i].compression = kCompressionRDFT;
		else if (audioInfo & 0x4000000)
			_header.audioInfo[i].compression = kCompressionDCT;
		else if (audioInfo & 0x80000000)
			_header.audioInfo[i].compression = kCompressionDPCM;
		else
			_header.audioInfo[i].compression = kCompressionNone;

		if (_header.audioInfo[i].hasAudio) {
			if (_header.audioInfo[i].compression == kCompressionRDFT || _header.audioInfo[i].compression == kCompressionDCT)
				warning("Unhandled Smacker v2 audio compression");

			if (i == 0)
				addTrack(new SmackerAudioTrack(_header.audioInfo[i], _soundType));
		}
	}

	_header.dummy = _fileStream->readUint32LE();

	_frameSizes = new uint32[frameCount];
	for (i = 0; i < frameCount; ++i)
		_frameSizes[i] = _fileStream->readUint32LE();

	_frameTypes = new byte[frameCount];
	for (i = 0; i < frameCount; ++i)
		_frameTypes[i] = _fileStream->readByte();

	byte *huffmanTrees = (byte *) malloc(_header.treesSize);
	_fileStream->read(huffmanTrees, _header.treesSize);

	Common::BitStream8LSB bs(new Common::MemoryReadStream(huffmanTrees, _header.treesSize, DisposeAfterUse::YES), true);
	videoTrack->readTrees(bs, _header.mMapSize, _header.mClrSize, _header.fullSize, _header.typeSize);

	_firstFrameStart = _fileStream->pos();

	return true;
}