diff options
Diffstat (limited to 'video')
-rw-r--r-- | video/avi_decoder.cpp | 115 | ||||
-rw-r--r-- | video/avi_decoder.h | 27 | ||||
-rw-r--r-- | video/video_decoder.h | 2 |
3 files changed, 111 insertions, 33 deletions
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 980ce3a3ea..7041f428ab 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -76,13 +76,13 @@ enum { }; -AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType, SelectTrackFn trackFn) : - _frameRateOverride(0), _soundType(soundType), _selectTrackFn(trackFn) { +AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : + _frameRateOverride(0), _soundType(soundType) { initCommon(); } -AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType, - SelectTrackFn trackFn) : _frameRateOverride(frameRateOverride), _soundType(soundType), _selectTrackFn(trackFn) { +AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType) : + _frameRateOverride(frameRateOverride), _soundType(soundType) { initCommon(); } @@ -94,6 +94,23 @@ AVIDecoder::AVIAudioTrack *AVIDecoder::createAudioTrack(AVIStreamHeader sHeader, return new AVIAudioTrack(sHeader, wvInfo, _soundType); } +bool AVIDecoder::seekToFrame(uint frame) { + if (!isSeekable()) + return false; + + // If we didn't find a video track, we can't seek by frame (of course) + if (_videoTracks.empty()) + return false; + + AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks.front().track); + Audio::Timestamp time = track->getFrameTime(frame); + + if (time < 0) + return false; + + return seek(time); +} + void AVIDecoder::initCommon() { _decodedHeader = false; _foundMovieList = false; @@ -111,6 +128,14 @@ bool AVIDecoder::isSeekable() const { return isVideoLoaded() && !_indexEntries.empty(); } +const Graphics::Surface *AVIDecoder::decodeNextTransparency() { + if (_videoTracks.size() != 2) + return nullptr; + + AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks[1].track); + return track->decodeNextFrame(); +} + bool AVIDecoder::parseNextChunk() { uint32 tag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); @@ -293,14 +318,8 @@ void AVIDecoder::handleStreamHeader(uint32 size) { } void AVIDecoder::addTrack(Track *track, bool isExternal) { - if (!_selectTrackFn || - (dynamic_cast<AVIVideoTrack *>(track) && _selectTrackFn(true, _videoTrackCounter++)) || - (dynamic_cast<AVIAudioTrack *>(track) && _selectTrackFn(false, _audioTrackCounter++))) { - VideoDecoder::addTrack(track, isExternal); - _lastAddedTrack = track; - } else { - _lastAddedTrack = nullptr; - } + VideoDecoder::addTrack(track, isExternal); + _lastAddedTrack = track; } void AVIDecoder::readStreamName(uint32 size) { @@ -368,15 +387,19 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { status.index = index; status.chunkSearchOffset = _movieListStart; - if ((*it)->getTrackType() == Track::kTrackTypeVideo) - _videoTracks.push_back(status); - else + if ((*it)->getTrackType() == Track::kTrackTypeAudio) { _audioTracks.push_back(status); - } + } else if (_videoTracks.empty()) { + _videoTracks.push_back(status); + } else { + // Secondary video track + assert(_videoTracks.size() == 1); + status.chunkSearchOffset = getVideoTrackOffset(index); + assert(status.chunkSearchOffset != 0); - if (_videoTracks.size() != 1) { - close(); - return false; + // Add the video track to the list + _videoTracks.push_back(status); + } } // Check if this is a special Duck Truemotion video @@ -407,12 +430,13 @@ void AVIDecoder::readNextPacket() { if (_videoTracks.empty()) return; - // Get the video frame first - handleNextPacket(_videoTracks[0]); + // Handle the video first + for (uint idx = 0; idx < _videoTracks.size(); ++idx) + handleNextPacket(_videoTracks[idx]); // Handle audio tracks next - for (uint32 i = 0; i < _audioTracks.size(); i++) - handleNextPacket(_audioTracks[i]); + for (uint idx = 0; idx < _audioTracks.size(); ++idx) + handleNextPacket(_audioTracks[idx]); } void AVIDecoder::handleNextPacket(TrackStatus &status) { @@ -524,7 +548,7 @@ bool AVIDecoder::rewind() { return false; for (uint32 i = 0; i < _videoTracks.size(); i++) - _videoTracks[i].chunkSearchOffset = _movieListStart; + _videoTracks[i].chunkSearchOffset = getVideoTrackOffset(_videoTracks[i].index); for (uint32 i = 0; i < _audioTracks.size(); i++) _audioTracks[i].chunkSearchOffset = _movieListStart; @@ -532,6 +556,15 @@ bool AVIDecoder::rewind() { return true; } +uint AVIDecoder::getVideoTrackOffset(uint trackIndex, uint frameNumber) { + if (trackIndex == _videoTracks.front().index && frameNumber == 0) + return _movieListStart; + + OldIndex *entry = _indexEntries.find(trackIndex, frameNumber); + assert(entry); + return entry->offset; +} + bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { // Can't seek beyond the end if (time > getDuration()) @@ -666,6 +699,26 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { videoTrack->decodeFrame(chunk); } + // Update any secondary video track for transparencies + if (_videoTracks.size() == 2) { + // Set it's frame number + AVIVideoTrack *videoTrack2 = static_cast<AVIVideoTrack *>(_videoTracks.back().track); + videoTrack2->setCurFrame((int)frame - 1); + + // Find the index entry for the frame and read it in + OldIndex *entry = _indexEntries.find(_videoTracks.back().index, frame); + assert(entry); + + 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); + } + // Set the video track's frame videoTrack->setCurFrame((int)frame - 1); @@ -674,7 +727,7 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { return true; } -byte AVIDecoder::getStreamIndex(uint32 tag) const { +byte AVIDecoder::getStreamIndex(uint32 tag) { char string[3]; WRITE_BE_UINT16(string, tag >> 16); string[2] = 0; @@ -975,4 +1028,16 @@ void AVIDecoder::AVIAudioTrack::createAudioStream() { AVIDecoder::TrackStatus::TrackStatus() : track(0), chunkSearchOffset(0) { } +AVIDecoder::OldIndex *AVIDecoder::IndexEntries::find(uint index, uint frameNumber) { + for (uint idx = 0, frameCtr = 0; idx < size(); ++idx) { + if ((*this)[idx].id != ID_REC && + AVIDecoder::getStreamIndex((*this)[idx].id) == index) { + if (frameCtr++ == frameNumber) + return &(*this)[idx]; + } + } + + return nullptr; +} + } // End of namespace Video diff --git a/video/avi_decoder.h b/video/avi_decoder.h index a3733b579c..4bba07e98f 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -62,10 +62,8 @@ namespace Video { */ class AVIDecoder : public VideoDecoder { public: - typedef bool(*SelectTrackFn)(bool isVideo, int trackNumber); - AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType, SelectTrackFn trackFn = nullptr); - AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType, - SelectTrackFn trackFn = nullptr); + AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); virtual ~AVIDecoder(); bool loadStream(Common::SeekableReadStream *stream); @@ -77,6 +75,7 @@ public: bool isRewindable() const { return true; } bool isSeekable() const; + const Graphics::Surface *decodeNextTransparency(); protected: // VideoDecoder API void readNextPacket(); @@ -190,6 +189,7 @@ protected: uint16 getWidth() const { return _bmInfo.width; } uint16 getHeight() const { return _bmInfo.height; } + uint16 getBitCount() const { return _bmInfo.bitCount; } Graphics::PixelFormat getPixelFormat() const; int getCurFrame() const { return _curFrame; } int getFrameCount() const { return _frameCount; } @@ -272,10 +272,15 @@ protected: uint32 chunkSearchOffset; }; + class IndexEntries : public Common::Array<OldIndex> { + public: + OldIndex *find(uint index, uint frameNumber); + }; + AVIHeader _header; void readOldIndex(uint32 size); - Common::Array<OldIndex> _indexEntries; + IndexEntries _indexEntries; Common::SeekableReadStream *_fileStream; bool _decodedHeader; @@ -287,7 +292,6 @@ protected: int _videoTrackCounter, _audioTrackCounter; Track *_lastAddedTrack; - SelectTrackFn _selectTrackFn; void initCommon(); @@ -297,8 +301,9 @@ protected: void handleStreamHeader(uint32 size); void readStreamName(uint32 size); uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; } - byte getStreamIndex(uint32 tag) const; + static byte getStreamIndex(uint32 tag); void checkTruemotion1(); + uint getVideoTrackOffset(uint trackIndex, uint frameNumber = 0); void handleNextPacket(TrackStatus& status); bool shouldQueueAudio(TrackStatus& status); @@ -306,6 +311,14 @@ protected: public: virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo); + + /** + * Seek to a given frame. + * + * This only works when the video track(s) supports getFrameTime(). + * This calls seek() internally. + */ + virtual bool seekToFrame(uint frame); }; } // End of namespace Video diff --git a/video/video_decoder.h b/video/video_decoder.h index eca15e7265..a415a70724 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -184,7 +184,7 @@ public: * This only works when one video track is present, and that track * supports getFrameTime(). This calls seek() internally. */ - bool seekToFrame(uint frame); + virtual bool seekToFrame(uint frame); /** * Pause or resume the video. This should stop/resume any audio playback |