diff options
-rw-r--r-- | engines/titanic/support/avi_surface.cpp | 101 | ||||
-rw-r--r-- | engines/titanic/support/avi_surface.h | 14 | ||||
-rw-r--r-- | video/avi_decoder.cpp | 42 | ||||
-rw-r--r-- | video/avi_decoder.h | 1 |
4 files changed, 80 insertions, 78 deletions
diff --git a/engines/titanic/support/avi_surface.cpp b/engines/titanic/support/avi_surface.cpp index 7d9c681f39..38f44271f4 100644 --- a/engines/titanic/support/avi_surface.cpp +++ b/engines/titanic/support/avi_surface.cpp @@ -30,12 +30,10 @@ namespace Titanic { -Video::AVIDecoder::AVIVideoTrack &AVIDecoder::getVideoTrack() { - for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) - if ((*it)->getTrackType() == Track::kTrackTypeVideo) - return *dynamic_cast<AVIVideoTrack *>(*it); - - error("Could not find video track"); +Video::AVIDecoder::AVIVideoTrack &AVIDecoder::getVideoTrack(uint idx) { + assert(idx < _videoTracks.size()); + AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks[idx].track); + return *track; } AVISurface::AVISurface(const CResourceKey &key) { @@ -44,29 +42,18 @@ AVISurface::AVISurface(const CResourceKey &key) { _movieFrameSurface[0] = _movieFrameSurface[1] = nullptr; _framePixels = nullptr; - // Reset current frame. We need to keep track of frames separately from the decoders, + // Reset current frame. We need to keep track of frames separately from the decoder, // since it needs to be able to go beyond the frame count or to negative to allow // correct detection of when range playbacks have finished _currentFrame = -1; _isReversed = false; // Create a decoder - _decoders[0] = new AVIDecoder(Audio::Mixer::kPlainSoundType); - if (!_decoders[0]->loadFile(key.getString())) + _decoder = new AVIDecoder(Audio::Mixer::kPlainSoundType); + if (!_decoder->loadFile(key.getString())) error("Could not open video - %s", key.getString().c_str()); - _streamCount = 1; -/* - // Create a decoder for any secondary video track - AVIDecoder *decoder2 = new AVIDecoder(Audio::Mixer::kPlainSoundType, secondaryTrackSelect); - if (decoder2->loadFile(key.getString())) { - _decoders[1] = decoder2; - ++_streamCount; - } else { - delete decoder2; - _decoders[1] = nullptr; - } - */ + _streamCount = _decoder->videoTrackCount(); } AVISurface::~AVISurface() { @@ -75,15 +62,14 @@ AVISurface::~AVISurface() { delete _framePixels; delete _movieFrameSurface[0]; delete _movieFrameSurface[1]; - delete _decoders[0]; - delete _decoders[1]; + delete _decoder; } bool AVISurface::play(uint flags, CGameObject *obj) { if (flags & MOVIE_REVERSE) - return play(_decoders[0]->getFrameCount() - 1, 0, flags, obj); + return play(_decoder->getFrameCount() - 1, 0, flags, obj); else - return play(0, _decoders[0]->getFrameCount() - 1, flags, obj); + return play(0, _decoder->getFrameCount() - 1, flags, obj); } bool AVISurface::play(int startFrame, int endFrame, uint flags, CGameObject *obj) { @@ -124,10 +110,7 @@ bool AVISurface::play(int startFrame, int endFrame, int initialFrame, uint flags } void AVISurface::stop() { - _decoders[0]->stop(); - if (_decoders[1]) - _decoders[1]->stop(); - + _decoder->stop(); _movieRangeInfo.destroyContents(); } @@ -145,19 +128,14 @@ bool AVISurface::startAtFrame(int frameNumber) { renderFrame(); // Start the playback - _decoders[0]->start(); - if (_decoders[1]) - _decoders[1]->start(); - + _decoder->start(); + return true; } void AVISurface::seekToFrame(uint frameNumber) { if ((int)frameNumber != getFrame()) { - _decoders[0]->seekToFrame(frameNumber); - if (_decoders[1]) - _decoders[1]->seekToFrame(frameNumber); - + _decoder->seekToFrame(frameNumber); _currentFrame = (int)frameNumber; } @@ -165,10 +143,7 @@ void AVISurface::seekToFrame(uint frameNumber) { } void AVISurface::setReversed(bool isReversed) { - _decoders[0]->setReverse(isReversed); - if (_decoders[1]) - _decoders[1]->setReverse(isReversed); - + _decoder->setReverse(isReversed); _isReversed = isReversed; } @@ -219,8 +194,8 @@ void AVISurface::setVideoSurface(CVideoSurface *surface) { _videoSurface = surface; // Handling for secondary video stream - if (_decoders[1]) { - const Common::String &streamName = _decoders[1]->getVideoTrack().getName(); + if (_streamCount == 2) { + const Common::String &streamName = _decoder->getVideoTrack(1).getName(); if (streamName == "mask0") { _videoSurface->_transparencyMode = TRANS_MASK0; @@ -237,18 +212,17 @@ void AVISurface::setVideoSurface(CVideoSurface *surface) { } void AVISurface::setupDecompressor() { - for (int idx = 0; idx < 2; ++idx) { - if (!_decoders[idx]) - continue; - AVIDecoder &decoder = *_decoders[idx]; + if (!_decoder) + return; + for (int idx = 0; idx < _streamCount; ++idx) { // Setup frame surface - _movieFrameSurface[idx] = new Graphics::ManagedSurface(decoder.getWidth(), decoder.getHeight(), - decoder.getVideoTrack().getPixelFormat()); + _movieFrameSurface[idx] = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(), + _decoder->getVideoTrack(idx).getPixelFormat()); bool flag = false; if (idx == 0 && _videoSurface) { - const Graphics::PixelFormat &ff = decoder.getVideoTrack().getPixelFormat(); + const Graphics::PixelFormat &ff = _decoder->getVideoTrack(0).getPixelFormat(); const int vDepth = _videoSurface->getPixelDepth(); switch (ff.bpp()) { @@ -270,8 +244,8 @@ void AVISurface::setupDecompressor() { } if (!flag) { - _framePixels = new Graphics::ManagedSurface(decoder.getWidth(), decoder.getHeight(), - decoder.getVideoTrack().getPixelFormat()); + _framePixels = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(), + _decoder->getVideoTrack(0).getPixelFormat()); } else if (idx == 0) { _videoSurface->_transBlitFlag = true; } @@ -279,11 +253,11 @@ void AVISurface::setupDecompressor() { } uint AVISurface::getWidth() const { - return _decoders[0]->getWidth(); + return _decoder->getWidth(); } uint AVISurface::getHeight() const { - return _decoders[0]->getHeight(); + return _decoder->getHeight(); } void AVISurface::setFrame(int frameNumber) { @@ -292,25 +266,26 @@ void AVISurface::setFrame(int frameNumber) { stop(); // Ensure the frame number is valid - if (frameNumber >= (int)_decoders[0]->getFrameCount()) - frameNumber = _decoders[0]->getFrameCount() - 1; + if (frameNumber >= (int)_decoder->getFrameCount()) + frameNumber = _decoder->getFrameCount() - 1; seekToFrame(frameNumber); renderFrame(); } bool AVISurface::isNextFrame() const { - return _decoders[0]->getTimeToNextFrame() == 0; + return _decoder->getTimeToNextFrame() == 0; } bool AVISurface::renderFrame() { // Check there's a frame ready for display - if (!_decoders[0]->needsUpdate()) + if (!_decoder->needsUpdate()) return false; // Make a copy of each decoder's video frame for (int idx = 0; idx < _streamCount; ++idx) { - const Graphics::Surface *frame = _decoders[idx]->decodeNextFrame(); + const Graphics::Surface *frame = (idx == 0) ? + _decoder->decodeNextFrame() : _decoder->decodeNextTransparency(); assert(_movieFrameSurface[idx]->format == frame->format); _movieFrameSurface[idx]->blitFrom(*frame); @@ -328,7 +303,7 @@ bool AVISurface::renderFrame() { } else { // Blit the primary video track's frame to the video surface Graphics::Surface *s = _movieFrameSurface[0]->rawSurface().convertTo( - g_system->getScreenFormat(), _decoders[0]->getPalette()); + g_system->getScreenFormat(), _decoder->getPalette()); _videoSurface->lock(); _videoSurface->getRawSurface()->blitFrom(*s); _videoSurface->unlock(); @@ -360,9 +335,7 @@ bool AVISurface::addEvent(int frameNumber, CGameObject *obj) { } void AVISurface::setFrameRate(double rate) { - _decoders[0]->setRate(Common::Rational((int)rate)); - if (_decoders[1]) - _decoders[1]->setRate(Common::Rational((int)rate)); + _decoder->setRate(Common::Rational((int)rate)); } Graphics::ManagedSurface *AVISurface::getSecondarySurface() { @@ -388,7 +361,7 @@ void AVISurface::playCutscene(const Rect &r, uint startFrame, uint endFrame) { while (_currentFrame < (int)endFrame && !g_vm->shouldQuit()) { if (isNextFrame()) { renderFrame(); - _currentFrame = _decoders[0]->getCurFrame(); + _currentFrame = _decoder->getCurFrame(); if (isDifferent) { // Clear the destination area, and use the transBlitFrom method, diff --git a/engines/titanic/support/avi_surface.h b/engines/titanic/support/avi_surface.h index ae9ee316c9..0bb14ceb27 100644 --- a/engines/titanic/support/avi_surface.h +++ b/engines/titanic/support/avi_surface.h @@ -45,12 +45,20 @@ public: AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType) : Video::AVIDecoder(frameRateOverride, soundType) {} - Video::AVIDecoder::AVIVideoTrack &getVideoTrack(); + /** + * Returns the number of video tracks the decoder has + */ + uint videoTrackCount() const { return _videoTracks.size(); } + + /** + * Returns the specified video track + */ + Video::AVIDecoder::AVIVideoTrack &getVideoTrack(uint idx); }; class AVISurface { private: - AVIDecoder *_decoders[2]; + AVIDecoder *_decoder; CVideoSurface *_videoSurface; CMovieRangeInfoList _movieRangeInfo; int _streamCount; @@ -114,7 +122,7 @@ public: /** * Return true if a video is currently playing */ - virtual bool isPlaying() const { return _decoders[0]->isPlaying(); } + virtual bool isPlaying() const { return _decoder->isPlaying(); } /** * Handle any movie events relevent for the frame diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 30f87a126a..e2f5bbd465 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -111,6 +111,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(); @@ -362,15 +370,26 @@ 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. Figure out the starting chunk offset, + // by iteratiing through the frames of the primary one + assert(_videoTracks.size() == 1); + stream->seek(_movieListStart); + + for (uint idx = 0; idx < _header.totalFrames; ++idx) { + _fileStream->readUint32BE(); + uint32 size = _fileStream->readUint32LE(); + _fileStream->seek(size, SEEK_CUR); + } - if (_videoTracks.size() != 1) { - close(); - return false; + status.chunkSearchOffset = _fileStream->pos(); + assert(status.chunkSearchOffset < _movieListEnd); + _videoTracks.push_back(status); + } } // Check if this is a special Duck Truemotion video @@ -401,12 +420,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) { diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 7f4431f670..3448204429 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -75,6 +75,7 @@ public: bool isRewindable() const { return true; } bool isSeekable() const; + const Graphics::Surface *decodeNextTransparency(); protected: // VideoDecoder API void readNextPacket(); |