aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--video/avi_decoder.cpp153
-rw-r--r--video/avi_decoder.h30
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