diff options
Diffstat (limited to 'video/avi_decoder.cpp')
-rw-r--r-- | video/avi_decoder.cpp | 84 |
1 files changed, 73 insertions, 11 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index aee2d88988..36fe83fa19 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -69,6 +69,7 @@ namespace Video { #define ID_ISFT MKTAG('I','S','F','T') #define ID_DISP MKTAG('D','I','S','P') #define ID_PRMI MKTAG('P','R','M','I') +#define ID_STRN MKTAG('s','t','r','n') // Codec tags #define ID_RLE MKTAG('R','L','E',' ') @@ -109,6 +110,7 @@ void AVIDecoder::initCommon() { _decodedHeader = false; _foundMovieList = false; _movieListStart = 0; + _movieListEnd = 0; _fileStream = 0; memset(&_header, 0, sizeof(_header)); } @@ -155,19 +157,11 @@ bool AVIDecoder::parseNextChunk() { case ID_JUNK: // Alignment bytes, should be ignored case ID_ISFT: // Metadata, safe to ignore case ID_DISP: // Metadata, should be safe to ignore + case ID_STRN: // Metadata, safe to ignore skipChunk(size); break; case ID_IDX1: - 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() + _movieListStart - 4; // Adjust to absolute - indexEntry.size = _fileStream->readUint32LE(); - _indexEntries.push_back(indexEntry); - debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags); - } + readOldIndex(size); break; default: error("Unknown tag \'%s\' found", tag2str(tag)); @@ -193,6 +187,7 @@ void AVIDecoder::handleList(uint32 listSize) { // We found the movie block _foundMovieList = true; _movieListStart = curPos; + _movieListEnd = _movieListStart + listSize + (listSize & 1); _fileStream->skip(listSize); return; case ID_HDRL: // Header List @@ -353,17 +348,27 @@ void AVIDecoder::close() { _decodedHeader = false; _foundMovieList = false; _movieListStart = 0; + _movieListEnd = 0; _indexEntries.clear(); memset(&_header, 0, sizeof(_header)); } void AVIDecoder::readNextPacket() { + if ((uint32)_fileStream->pos() >= _movieListEnd) { + // Ugh, reached the end premature. + forceVideoEnd(); + return; + } + uint32 nextTag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); - if (_fileStream->eos()) + if (_fileStream->eos()) { + // Also premature end. + forceVideoEnd(); return; + } if (nextTag == ID_LIST) { // A list of audio/video chunks @@ -621,6 +626,59 @@ byte AVIDecoder::getStreamIndex(uint32 tag) const { return strtol(string, 0, 16); } +void AVIDecoder::readOldIndex(uint32 size) { + uint32 entryCount = size / 16; + + debug(0, "Old Index: %d entries", entryCount); + + if (entryCount == 0) + return; + + // Read the first index separately + OldIndex firstEntry; + firstEntry.id = _fileStream->readUint32BE(); + firstEntry.flags = _fileStream->readUint32LE(); + firstEntry.offset = _fileStream->readUint32LE(); + firstEntry.size = _fileStream->readUint32LE(); + + // Check if the offset is already absolute + // If it's absolute, the offset will equal the start of the movie list + bool isAbsolute = firstEntry.offset == _movieListStart; + + debug(1, "Old index is %s", isAbsolute ? "absolute" : "relative"); + + if (!isAbsolute) + firstEntry.offset += _movieListStart - 4; + + debug(0, "Index 0: Tag '%s', Offset = %d, Size = %d (Flags = %d)", tag2str(firstEntry.id), firstEntry.offset, firstEntry.size, firstEntry.flags); + _indexEntries.push_back(firstEntry); + + for (uint32 i = 1; i < entryCount; i++) { + OldIndex indexEntry; + indexEntry.id = _fileStream->readUint32BE(); + indexEntry.flags = _fileStream->readUint32LE(); + indexEntry.offset = _fileStream->readUint32LE(); + indexEntry.size = _fileStream->readUint32LE(); + + // Adjust to absolute, if necessary + if (!isAbsolute) + indexEntry.offset += _movieListStart - 4; + + _indexEntries.push_back(indexEntry); + debug(0, "Index %d: Tag '%s', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags); + } +} + +void AVIDecoder::forceVideoEnd() { + // Horrible AVI video has a premature end + // Force the frame to be the last frame + debug(0, "Forcing end of AVI video"); + + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + ((AVIVideoTrack *)*it)->forceTrackEnd(); +} + AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette) : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader), _initialPalette(initialPalette) { _videoCodec = createCodec(); @@ -723,6 +781,10 @@ Codec *AVIDecoder::AVIVideoTrack::createCodec() { return 0; } +void AVIDecoder::AVIVideoTrack::forceTrackEnd() { + _curFrame = _frameCount - 1; +} + AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) : _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType) { _audStream = createAudioStream(); |