From c676ecb258d9fca8a997055c5628e1cc786103de Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 2 Oct 2016 20:22:53 -0400 Subject: VIDEO: Implement seeking for AVI videos with a transparency video track --- video/avi_decoder.cpp | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ video/avi_decoder.h | 8 +++++++ video/video_decoder.h | 2 +- 3 files changed, 71 insertions(+), 1 deletion(-) (limited to 'video') diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index e2f5bbd465..7d88379007 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -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(_videoTracks.front().track); + Audio::Timestamp time = track->getFrameTime(frame); + + if (time < 0) + return false; + + return seek(time); +} + void AVIDecoder::initCommon() { _decodedHeader = false; _foundMovieList = false; @@ -386,9 +403,28 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { _fileStream->seek(size, SEEK_CUR); } + // Set the chunk offset, and force the stream num to 10, + // to avoid conflicting with any other audio track + status.index = 10; status.chunkSearchOffset = _fileStream->pos(); assert(status.chunkSearchOffset < _movieListEnd); _videoTracks.push_back(status); + + // Build up index entries for the secondary video track, so we + // can seek in at at the same time as the primary video track + for (uint idx = 0; idx < _header.totalFrames; ++idx) { + uint chunkPos = _fileStream->pos(); + _fileStream->seek(4, SEEK_CUR); + uint chunkSize = _fileStream->readUint32LE(); + _fileStream->seek(chunkSize, SEEK_CUR); + + OldIndex indexEntry; + indexEntry.flags = 0; + indexEntry.id = MKTAG('0', 'A', 'd', 'b'); + indexEntry.offset = chunkPos; + indexEntry.size = chunkSize; + _indexEntries.push_back(indexEntry); + } } } @@ -680,6 +716,32 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { videoTrack->decodeFrame(chunk); } + // Update any secondary video track for transparencies + if (_videoTracks.size() == 2) { + AVIVideoTrack *videoTrack2 = static_cast(_videoTracks.back().track); + + // Set it's frame number + videoTrack2->setCurFrame((int)frame - 1); + + // Find the index entry for the frame and move to it + for (uint i = 0, frameNum = 0; i < _indexEntries.size(); ++i) { + if (_indexEntries[i].id != ID_REC && + getStreamIndex(_indexEntries[i].id) == _videoTracks.back().index) { + if (frameNum++ == frame) { + Common::SeekableReadStream *chunk = nullptr; + _fileStream->seek(_indexEntries[i].offset + 8); + _videoTracks.back().chunkSearchOffset = _indexEntries[i].offset; + + if (_indexEntries[i].size != 0) + chunk = _fileStream->readStream(_indexEntries[i].size); + + videoTrack2->decodeFrame(chunk); + break; + } + } + } + } + // Set the video track's frame videoTrack->setCurFrame((int)frame - 1); diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 3448204429..3581b65409 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -304,6 +304,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 -- cgit v1.2.3