From 62f2763bf794dfb711fd48e32d7c2162bdb5aed8 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 10 Jul 2016 14:59:11 -0400 Subject: VIDEO: Respect RIFF filesize field when decoding AVI files Starship Titanic in particular needs this, since some of the videos have extra junk at the end of the file, such as ycursors.avi, and parsing fails if we don't respect the filesize field --- video/avi_decoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'video') diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 52a55f600c..8f1bec4388 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -296,7 +296,7 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { return false; } - /* uint32 fileSize = */ stream->readUint32LE(); + uint32 fileSize = stream->readUint32LE(); uint32 riffType = stream->readUint32BE(); if (riffType != ID_AVI) { @@ -307,7 +307,7 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { _fileStream = stream; // Go through all chunks in the file - while (parseNextChunk()) + while (_fileStream->pos() < fileSize && parseNextChunk()) ; if (!_decodedHeader) { -- cgit v1.2.3 From fa6e12aaab4e19424481fc26eab281663cbf3283 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 11 Jul 2016 19:39:53 -0400 Subject: VIDEO: Add support for a track filtering callback function This is needed for Starship Titanic, where videos can have a secondary video track. It was simpler to use the callback as a means to select one video track each across two decoders than trying to make VideoDecoder and/or AVIDecoder support decoding from multiple video tracks simultaneously --- video/avi_decoder.cpp | 20 ++++++++++++-------- video/avi_decoder.h | 10 ++++++++-- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'video') diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 8f1bec4388..cb087c72fc 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -76,12 +76,13 @@ enum { }; -AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _frameRateOverride(0), _soundType(soundType) { +AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType, SelectTrackFn trackFn) : + _frameRateOverride(0), _soundType(soundType), _selectTrackFn(trackFn) { initCommon(); } -AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType) - : _frameRateOverride(frameRateOverride), _soundType(soundType) { +AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType, + SelectTrackFn trackFn) : _frameRateOverride(frameRateOverride), _soundType(soundType), _selectTrackFn(trackFn) { initCommon(); } @@ -99,6 +100,7 @@ void AVIDecoder::initCommon() { _movieListStart = 0; _movieListEnd = 0; _fileStream = 0; + _videoTrackCounter = _audioTrackCounter = 0; memset(&_header, 0, sizeof(_header)); } @@ -263,7 +265,8 @@ void AVIDecoder::handleStreamHeader(uint32 size) { } } - addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette)); + if (!_selectTrackFn || _selectTrackFn(true, _videoTrackCounter++)) + addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette)); } else if (sHeader.streamType == ID_AUDS) { PCMWaveFormat wvInfo; wvInfo.tag = _fileStream->readUint16LE(); @@ -278,9 +281,11 @@ void AVIDecoder::handleStreamHeader(uint32 size) { if (wvInfo.channels == 2) sHeader.sampleSize /= 2; - AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo); - track->createAudioStream(); - addTrack(track); + if (!_selectTrackFn || _selectTrackFn(false, _audioTrackCounter++)) { + AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo); + track->createAudioStream(); + addTrack(track); + } } // Ensure that we're at the end of the chunk @@ -337,7 +342,6 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { } if (_videoTracks.size() != 1) { - warning("Unhandled AVI video track count: %d", _videoTracks.size()); close(); return false; } diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 96d9e821ff..04e6a1847e 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -61,8 +61,10 @@ namespace Video { */ class AVIDecoder : public VideoDecoder { public: - AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); - AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + 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); virtual ~AVIDecoder(); bool loadStream(Common::SeekableReadStream *stream); @@ -268,6 +270,10 @@ protected: Audio::Mixer::SoundType _soundType; Common::Rational _frameRateOverride; + + int _videoTrackCounter, _audioTrackCounter; + SelectTrackFn _selectTrackFn; + void initCommon(); bool parseNextChunk(); -- cgit v1.2.3 From bb2d290dcaae8d29f56066ac92330c59862012a7 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Mon, 11 Jul 2016 21:49:11 -0400 Subject: VIDEO: Handle STRN chunks in AVI file streams to set stream name --- video/avi_decoder.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++--------- video/avi_decoder.h | 15 +++++++++++++++ 2 files changed, 57 insertions(+), 9 deletions(-) (limited to 'video') diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index cb087c72fc..44f8ade933 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -101,6 +101,7 @@ void AVIDecoder::initCommon() { _movieListEnd = 0; _fileStream = 0; _videoTrackCounter = _audioTrackCounter = 0; + _lastAddedTrack = nullptr; memset(&_header, 0, sizeof(_header)); } @@ -147,10 +148,12 @@ bool AVIDecoder::parseNextChunk() { case ID_JUNQ: // Same as JUNK, safe to ignore case ID_ISFT: // Metadata, safe to ignore case ID_DISP: // Metadata, should be safe to ignore - case ID_STRN: // Metadata, safe to ignore case ID_DMLH: // OpenDML extension, contains an extra total frames field, safe to ignore skipChunk(size); break; + case ID_STRN: // Metadata, safe to ignore + readStreamName(size); + break; case ID_IDX1: readOldIndex(size); break; @@ -265,8 +268,7 @@ void AVIDecoder::handleStreamHeader(uint32 size) { } } - if (!_selectTrackFn || _selectTrackFn(true, _videoTrackCounter++)) - addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette)); + addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette)); } else if (sHeader.streamType == ID_AUDS) { PCMWaveFormat wvInfo; wvInfo.tag = _fileStream->readUint16LE(); @@ -281,17 +283,48 @@ void AVIDecoder::handleStreamHeader(uint32 size) { if (wvInfo.channels == 2) sHeader.sampleSize /= 2; - if (!_selectTrackFn || _selectTrackFn(false, _audioTrackCounter++)) { - AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo); - track->createAudioStream(); - addTrack(track); - } + AVIAudioTrack *track = createAudioTrack(sHeader, wvInfo); + track->createAudioStream(); + addTrack(track); } // Ensure that we're at the end of the chunk _fileStream->seek(startPos + strfSize); } +void AVIDecoder::addTrack(Track *track, bool isExternal) { + if (!_selectTrackFn || + (dynamic_cast(track) && _selectTrackFn(true, _videoTrackCounter++)) || + (dynamic_cast(track) && _selectTrackFn(false, _audioTrackCounter++))) { + VideoDecoder::addTrack(track, isExternal); + _lastAddedTrack = track; + } else { + _lastAddedTrack = nullptr; + } +} + +void AVIDecoder::readStreamName(uint32 size) { + if (!_lastAddedTrack) { + skipChunk(size); + } else { + // Get in the name + assert(size > 0 && size < 64); + char buffer[64]; + _fileStream->read(buffer, size); + if (size & 1) + _fileStream->skip(1); + + // Apply it to the most recently read stream + assert(_lastAddedTrack); + AVIVideoTrack *vidTrack = dynamic_cast(_lastAddedTrack); + AVIAudioTrack *audTrack = dynamic_cast(_lastAddedTrack); + if (vidTrack) + vidTrack->getName() = Common::String(buffer); + else if (audTrack) + audTrack->getName() = Common::String(buffer); + } +} + bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { close(); @@ -301,7 +334,7 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { return false; } - uint32 fileSize = stream->readUint32LE(); + int32 fileSize = stream->readUint32LE(); uint32 riffType = stream->readUint32BE(); if (riffType != ID_AVI) { diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 04e6a1847e..8b9fcbd9a3 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -83,6 +83,16 @@ protected: bool supportsAudioTrackSwitching() const { return true; } AudioTrack *getAudioTrack(int index); + /** + * Define a track to be used by this class. + * + * The pointer is then owned by this base class. + * + * @param track The track to add + * @param isExternal Is this an external track not found by loadStream()? + */ + void addTrack(Track *track, bool isExternal = false); + struct BitmapInfoHeader { uint32 size; uint32 width; @@ -166,6 +176,7 @@ protected: uint32 quality; uint32 sampleSize; Common::Rect frame; + Common::String name; }; class AVIVideoTrack : public FixedRateVideoTrack { @@ -181,6 +192,7 @@ protected: Graphics::PixelFormat getPixelFormat() const; int getCurFrame() const { return _curFrame; } int getFrameCount() const { return _frameCount; } + Common::String &getName() { return _vidsHeader.name; } const Graphics::Surface *decodeNextFrame() { return _lastFrame; } const byte *getPalette() const; @@ -224,6 +236,7 @@ protected: void skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime); virtual void resetStream(); uint32 getCurChunk() const { return _curChunk; } + Common::String &getName() { return _audsHeader.name; } void setCurChunk(uint32 chunk) { _curChunk = chunk; } bool isRewindable() const { return true; } @@ -272,6 +285,7 @@ protected: Common::Rational _frameRateOverride; int _videoTrackCounter, _audioTrackCounter; + Track *_lastAddedTrack; SelectTrackFn _selectTrackFn; void initCommon(); @@ -280,6 +294,7 @@ protected: void skipChunk(uint32 size); void handleList(uint32 listSize); void handleStreamHeader(uint32 size); + void readStreamName(uint32 size); uint16 getStreamType(uint32 tag) const { return tag & 0xFFFF; } byte getStreamIndex(uint32 tag) const; void checkTruemotion1(); -- cgit v1.2.3 From 789760295df25b209e312a1d48c0ca6be74c2c81 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 17 Jul 2016 13:05:48 -0400 Subject: VIDEO: Add titanic to list of engines using AVIDecoder --- video/avi_decoder.h | 1 + 1 file changed, 1 insertion(+) (limited to 'video') diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 8b9fcbd9a3..a3733b579c 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -57,6 +57,7 @@ namespace Video { * - sci * - sword1 * - sword2 + * - titanic * - zvision */ class AVIDecoder : public VideoDecoder { -- cgit v1.2.3