diff options
-rw-r--r-- | video/avi_decoder.cpp | 102 | ||||
-rw-r--r-- | video/avi_decoder.h | 4 |
2 files changed, 64 insertions, 42 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 9f97ffd5c8..910a4092aa 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -120,6 +120,7 @@ void AVIDecoder::initCommon() { _videoTrackCounter = _audioTrackCounter = 0; _lastAddedTrack = nullptr; memset(&_header, 0, sizeof(_header)); + _transparencyTrack.track = nullptr; } bool AVIDecoder::isSeekable() const { @@ -129,10 +130,10 @@ bool AVIDecoder::isSeekable() const { } const Graphics::Surface *AVIDecoder::decodeNextTransparency() { - if (_videoTracks.size() != 2) + if (!_transparencyTrack.track) return nullptr; - AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks[1].track); + AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_transparencyTrack.track); return track->decodeNextFrame(); } @@ -392,16 +393,22 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { } else if (_videoTracks.empty()) { _videoTracks.push_back(status); } else { - // Secondary video track - assert(_videoTracks.size() == 1); + // Secondary video track. For now we assume it will always be a + // transparency information track status.chunkSearchOffset = getVideoTrackOffset(index); + assert(!_transparencyTrack.track); assert(status.chunkSearchOffset != 0); - // Add the video track to the list - _videoTracks.push_back(status); + // Copy the track status information into the transparency track field + _transparencyTrack = status; } } + // If there is a transparency track, remove it from the video decoder's track list. + // This is to stop it being included in calls like getFrameCount + if (_transparencyTrack.track) + eraseTrack(_transparencyTrack.track); + // Check if this is a special Duck Truemotion video checkTruemotion1(); @@ -423,6 +430,9 @@ void AVIDecoder::close() { _videoTracks.clear(); _audioTracks.clear(); + + delete _transparencyTrack.track; + _transparencyTrack.track = nullptr; } void AVIDecoder::readNextPacket() { @@ -434,6 +444,10 @@ void AVIDecoder::readNextPacket() { for (uint idx = 0; idx < _videoTracks.size(); ++idx) handleNextPacket(_videoTracks[idx]); + // Handle any transparency track + if (_transparencyTrack.track) + handleNextPacket(_transparencyTrack); + // Handle audio tracks next for (uint idx = 0; idx < _audioTracks.size(); ++idx) handleNextPacket(_audioTracks[idx]); @@ -715,41 +729,9 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { videoTrack->decodeFrame(chunk); } - // Update any secondary video track for transparencies - if (_videoTracks.size() == 2) { - // Find the index entry for the frame - int indexFrame = frame; - OldIndex *entry = nullptr; - do { - entry = _indexEntries.find(_videoTracks.back().index, indexFrame); - } while (!entry && indexFrame-- > 0); - assert(entry); - - // Set it's frame number - AVIVideoTrack *videoTrack2 = static_cast<AVIVideoTrack *>(_videoTracks.back().track); - videoTrack2->setCurFrame(indexFrame - 1); - - // Read in the frame - Common::SeekableReadStream *chunk = nullptr; - _fileStream->seek(entry->offset + 8); - _videoTracks.back().chunkSearchOffset = entry->offset; - - if (entry->size != 0) - chunk = _fileStream->readStream(entry->size); - videoTrack2->decodeFrame(chunk); - - if (indexFrame < (int)frame) { - TrackStatus &status = _videoTracks.back(); - while (status.chunkSearchOffset < _movieListEnd && indexFrame++ < (int)frame) { - // There was no index entry for the desired frame, so an earlier one was decoded. - // We now have to sequentially decode frames until we get to the desired frame - handleNextPacket(status); - } - } - - videoTrack2->setCurFrame((int)frame - 1); - videoTrack2->setFrameRate(videoTrack->getFrameRate()); - } + // Update any transparency track if present + if (_transparencyTrack.track) + seekTransparencyFrame(frame); // Set the video track's frame videoTrack->setCurFrame((int)frame - 1); @@ -759,6 +741,44 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { return true; } +void AVIDecoder::seekTransparencyFrame(int frame) { + TrackStatus &status = _transparencyTrack; + AVIVideoTrack *transTrack = static_cast<AVIVideoTrack *>(status.track); + + // Find the index entry for the frame + int indexFrame = frame; + OldIndex *entry = nullptr; + do { + entry = _indexEntries.find(status.index, indexFrame); + } while (!entry && indexFrame-- > 0); + assert(entry); + + // Set it's frame number + transTrack->setCurFrame(indexFrame - 1); + + // Read in the frame + Common::SeekableReadStream *chunk = nullptr; + _fileStream->seek(entry->offset + 8); + status.chunkSearchOffset = entry->offset; + + if (entry->size != 0) + chunk = _fileStream->readStream(entry->size); + transTrack->decodeFrame(chunk); + + if (indexFrame < (int)frame) { + while (status.chunkSearchOffset < _movieListEnd && indexFrame++ < (int)frame) { + // There was no index entry for the desired frame, so an earlier one was decoded. + // We now have to sequentially skip frames until we get to the desired frame + _fileStream->readUint32BE(); + uint32 size = _fileStream->readUint32LE() - 8; + _fileStream->skip(size & 1); + status.chunkSearchOffset = _fileStream->pos(); + } + } + + transTrack->setCurFrame((int)frame - 1); +} + byte AVIDecoder::getStreamIndex(uint32 tag) { char string[3]; WRITE_BE_UINT16(string, tag >> 16); diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 541c73e068..a3dbddf015 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -337,8 +337,10 @@ protected: void handleNextPacket(TrackStatus& status); bool shouldQueueAudio(TrackStatus& status); - Common::Array<TrackStatus> _videoTracks, _audioTracks; + void seekTransparencyFrame(int frame); + Common::Array<TrackStatus> _videoTracks, _audioTracks; + TrackStatus _transparencyTrack; public: virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo); |