diff options
| -rw-r--r-- | video/avi_decoder.cpp | 153 | ||||
| -rw-r--r-- | video/avi_decoder.h | 30 | 
2 files changed, 99 insertions, 84 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index ff728a8437..92a60fcccf 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -67,6 +67,7 @@ namespace Video {  #define ID_STRD MKTAG('s','t','r','d')  //#define ID_INFO MKTAG('I','N','F','O')  #define ID_ISFT MKTAG('I','S','F','T') +#define ID_DISP MKTAG('D','I','S','P')  // Codec tags  #define ID_RLE  MKTAG('R','L','E',' ') @@ -78,18 +79,6 @@ namespace Video {  #define ID_DUCK MKTAG('D','U','C','K')  #define ID_MPG2 MKTAG('m','p','g','2') -static byte char2num(char c) { -	c = tolower((byte)c); -	return (c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - '0'; -} - -static byte getStreamIndex(uint32 tag) { -	return char2num((tag >> 24) & 0xFF) << 4 | char2num((tag >> 16) & 0xFF); -} - -static uint16 getStreamType(uint32 tag) { -	return tag & 0xffff; -}  AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _frameRateOverride(0), _soundType(soundType) {  	initCommon(); @@ -107,29 +96,26 @@ AVIDecoder::~AVIDecoder() {  void AVIDecoder::initCommon() {  	_decodedHeader = false;  	_foundMovieList = false; +	_movieListStart = 0;  	_fileStream = 0; -	memset(&_ixInfo, 0, sizeof(_ixInfo));  	memset(&_header, 0, sizeof(_header));  } -void AVIDecoder::runHandle(uint32 tag) { -	assert(_fileStream); +bool AVIDecoder::parseNextChunk() { +	uint32 tag = _fileStream->readUint32BE(); +	uint32 size = _fileStream->readUint32LE(); +  	if (_fileStream->eos()) -		return; +		return false;  	debug(3, "Decoding tag %s", tag2str(tag));  	switch (tag) { -	case ID_RIFF: -		/*_filesize = */_fileStream->readUint32LE(); -		if (_fileStream->readUint32BE() != ID_AVI) -			error("RIFF file is not an AVI video"); -		break;  	case ID_LIST: -		handleList(); +		handleList(size);  		break;  	case ID_AVIH: -		_header.size = _fileStream->readUint32LE(); +		_header.size = size;  		_header.microSecondsPerFrame = _fileStream->readUint32LE();  		_header.maxBytesPerSecond = _fileStream->readUint32LE();  		_header.padding = _fileStream->readUint32LE(); @@ -144,58 +130,64 @@ void AVIDecoder::runHandle(uint32 tag) {  		_fileStream->skip(16);  		break;  	case ID_STRH: -		handleStreamHeader(); +		handleStreamHeader(size);  		break;  	case ID_STRD: // Extra stream info, safe to ignore  	case ID_VEDT: // Unknown, safe to ignore  	case ID_JUNK: // Alignment bytes, should be ignored  	case ID_ISFT: // Metadata, safe to ignore -		{ -		uint32 junkSize = _fileStream->readUint32LE(); -		_fileStream->skip(junkSize + (junkSize & 1)); // Alignment -		} break; +	case ID_DISP: // Metadata, should be safe to ignore +		skipChunk(size); +		break;  	case ID_IDX1: -		_ixInfo.size = _fileStream->readUint32LE(); -		_ixInfo.indices = new OldIndex::Index[_ixInfo.size / 16]; -		debug(0, "%d Indices", (_ixInfo.size / 16)); -		for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { -			_ixInfo.indices[i].id = _fileStream->readUint32BE(); -			_ixInfo.indices[i].flags = _fileStream->readUint32LE(); -			_ixInfo.indices[i].offset = _fileStream->readUint32LE(); -			_ixInfo.indices[i].size = _fileStream->readUint32LE(); -			debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); +		debug(0, "%d Indices", size / 16); +		for (uint32 i = 0; i < size / 16; i++) { +			OldIndex indexEntry; +			indexEntry.id = _fileStream->readUint32BE(); +			indexEntry.flags = _fileStream->readUint32LE(); +			indexEntry.offset = _fileStream->readUint32LE(); +			indexEntry.size = _fileStream->readUint32LE(); +			_indexEntries.push_back(indexEntry); +			debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size);  		}  		break;  	default:  		error("Unknown tag \'%s\' found", tag2str(tag));  	} + +	return true;  } -void AVIDecoder::handleList() { -	uint32 listSize = _fileStream->readUint32LE() - 4; // Subtract away listType's 4 bytes +void AVIDecoder::skipChunk(uint32 size) { +	// Make sure we're aligned on a word boundary +	_fileStream->skip(size + (size & 1)); +} + +void AVIDecoder::handleList(uint32 listSize) {  	uint32 listType = _fileStream->readUint32BE(); +	listSize -= 4; // Subtract away listType's 4 bytes  	uint32 curPos = _fileStream->pos();  	debug(0, "Found LIST of type %s", tag2str(listType));  	if (listType == ID_MOVI) { -		// Found the 'movi' list -		// We're done parsing everything +		// If we found the movie block  		_foundMovieList = true; +		_movieListStart = curPos; +		_fileStream->skip(listSize);  		return; +	} else if (listType == ID_HDRL) { +		// Mark the header as decoded +		_decodedHeader = true;  	}  	while ((_fileStream->pos() - curPos) < listSize) -		runHandle(_fileStream->readUint32BE()); - -	// We now have all the header data -	if (listType == ID_HDRL) -		_decodedHeader = true; +		parseNextChunk();  } -void AVIDecoder::handleStreamHeader() { +void AVIDecoder::handleStreamHeader(uint32 size) {  	AVIStreamHeader sHeader; -	sHeader.size = _fileStream->readUint32LE(); +	sHeader.size = size;  	sHeader.streamType = _fileStream->readUint32BE();  	if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) @@ -286,28 +278,41 @@ void AVIDecoder::handleStreamHeader() {  bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {  	close(); -	_fileStream = stream; -	_decodedHeader = false; -	_foundMovieList = false; +	uint32 riffTag = stream->readUint32BE(); +	if (riffTag != ID_RIFF) { +		warning("Failed to find RIFF header"); +		return false; +	} -	// Read chunks until we have decoded the header -	while (!_decodedHeader && _fileStream->pos() < _fileStream->size()) -		runHandle(_fileStream->readUint32BE()); +	/* uint32 fileSize = */ stream->readUint32LE(); +	uint32 riffType = stream->readUint32BE(); -	if (_fileStream->pos() >= _fileStream->size()) { -		warning("Failed to find AVI header"); +	if (riffType != ID_AVI) { +		warning("RIFF not an AVI file");  		return false;  	} -	// Then read until we find the movie list -	while (!_foundMovieList && _fileStream->pos() < _fileStream->size()) -		runHandle(_fileStream->readUint32BE()); +	_fileStream = stream; + +	// Go through all chunks in the file +	while (parseNextChunk()) +		; -	if (_fileStream->pos() >= _fileStream->size()) { -		warning("Failed to find AVI 'movi' LIST"); +	if (!_decodedHeader) { +		warning("Failed to parse AVI header"); +		close();  		return false;  	} +	if (!_foundMovieList) { +		warning("Failed to find 'MOVI' list"); +		close(); +		return false; +	} + +	// Seek back to the start of the MOVI list +	_fileStream->seek(_movieListStart); +  	return true;  } @@ -318,33 +323,35 @@ void AVIDecoder::close() {  	_fileStream = 0;  	_decodedHeader = false;  	_foundMovieList = false; +	_movieListStart = 0; -	delete[] _ixInfo.indices; -	memset(&_ixInfo, 0, sizeof(_ixInfo)); +	_indexEntries.clear();  	memset(&_header, 0, sizeof(_header));  }  void AVIDecoder::readNextPacket() {  	uint32 nextTag = _fileStream->readUint32BE(); +	uint32 size = _fileStream->readUint32LE();  	if (_fileStream->eos())  		return;  	if (nextTag == ID_LIST) {  		// A list of audio/video chunks -		uint32 listSize = _fileStream->readUint32LE() - 4;  		int32 startPos = _fileStream->pos();  		if (_fileStream->readUint32BE() != ID_REC)  			error("Expected 'rec ' LIST"); +		size -= 4; // subtract list type +  		// Decode chunks in the list -		while (_fileStream->pos() < startPos + (int32)listSize) +		while (_fileStream->pos() < startPos + (int32)size)  			readNextPacket();  		return;  	} else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { -		runHandle(nextTag); +		skipChunk(size);  		return;  	} @@ -353,12 +360,11 @@ void AVIDecoder::readNextPacket() {  	if (!track)  		error("Cannot get track from tag '%s'", tag2str(nextTag)); -	uint32 chunkSize = _fileStream->readUint32LE();  	Common::SeekableReadStream *chunk = 0; -	if (chunkSize != 0) { -		chunk = _fileStream->readStream(chunkSize); -		_fileStream->skip(chunkSize & 1); +	if (size != 0) { +		chunk = _fileStream->readStream(size); +		_fileStream->skip(size & 1);  	}  	if (track->getTrackType() == Track::kTrackTypeAudio) { @@ -403,6 +409,13 @@ void AVIDecoder::readNextPacket() {  	}  } +byte AVIDecoder::getStreamIndex(uint32 tag) const { +	char string[3]; +	WRITE_BE_UINT16(string, tag >> 16); +	string[2] = 0; +	return strtol(string, 0, 16); +} +  AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader)  		: _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader) {  	memset(_palette, 0, sizeof(_palette)); diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 6082232464..5d52c7c797 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -20,10 +20,10 @@   *   */ -#ifndef VIDEO_AVI_PLAYER_H -#define VIDEO_AVI_PLAYER_H +#ifndef VIDEO_AVI_DECODER_H +#define VIDEO_AVI_DECODER_H -#include "common/endian.h" +#include "common/array.h"  #include "common/rational.h"  #include "common/rect.h"  #include "common/str.h" @@ -102,13 +102,10 @@ private:  	};  	struct OldIndex { +		uint32 id; +		uint32 flags; +		uint32 offset;  		uint32 size; -		struct Index { -			uint32 id; -			uint32 flags; -			uint32 offset; -			uint32 size; -		} *indices;  	};  	// Index Flags @@ -218,19 +215,24 @@ private:  		Audio::QueuingAudioStream *createAudioStream();  	}; -	OldIndex _ixInfo; +	Common::Array<OldIndex> _indexEntries;  	AVIHeader _header;  	Common::SeekableReadStream *_fileStream; -	bool _decodedHeader, _foundMovieList; +	bool _decodedHeader; +	bool _foundMovieList; +	uint32 _movieListStart;  	Audio::Mixer::SoundType _soundType;  	Common::Rational _frameRateOverride;  	void initCommon(); -	void runHandle(uint32 tag); -	void handleList(); -	void handleStreamHeader(); +	bool parseNextChunk(); +	void skipChunk(uint32 size); +	void handleList(uint32 listSize); +	void handleStreamHeader(uint32 size); +	uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; } +	byte getStreamIndex(uint32 tag) const;  };  } // End of namespace Video  | 
