diff options
author | Matthew Hoops | 2010-01-04 17:27:36 +0000 |
---|---|---|
committer | Matthew Hoops | 2010-01-04 17:27:36 +0000 |
commit | bf3973051beb03d331c3ce3a06aa106ad817e1a4 (patch) | |
tree | 93e46b053eb3af19b83430917f7eafb1ef2f7ada /engines/mohawk | |
parent | 01eb329be2df445f3374f8183bec5d9031450062 (diff) | |
download | scummvm-rg350-bf3973051beb03d331c3ce3a06aa106ad817e1a4.tar.gz scummvm-rg350-bf3973051beb03d331c3ce3a06aa106ad817e1a4.tar.bz2 scummvm-rg350-bf3973051beb03d331c3ce3a06aa106ad817e1a4.zip |
Merge the Mohawk Video class into QTPlayer and general cleanup.
svn-id: r46976
Diffstat (limited to 'engines/mohawk')
-rw-r--r-- | engines/mohawk/mohawk.h | 3 | ||||
-rw-r--r-- | engines/mohawk/video/qt_player.cpp | 193 | ||||
-rw-r--r-- | engines/mohawk/video/qt_player.h | 63 | ||||
-rw-r--r-- | engines/mohawk/video/video.cpp | 206 | ||||
-rw-r--r-- | engines/mohawk/video/video.h | 94 |
5 files changed, 248 insertions, 311 deletions
diff --git a/engines/mohawk/mohawk.h b/engines/mohawk/mohawk.h index 8b00777226..8e03e65cdc 100644 --- a/engines/mohawk/mohawk.h +++ b/engines/mohawk/mohawk.h @@ -56,8 +56,7 @@ enum MohawkGameFeatures { GF_DVD = (1 << 1), GF_10TH = (1 << 2), // 10th Anniversary GF_DEMO = (1 << 3), - GF_HASMIDI = (1 << 4), - GF_HASBINK = (1 << 5) + GF_HASMIDI = (1 << 4) }; struct MohawkGameDescription; diff --git a/engines/mohawk/video/qt_player.cpp b/engines/mohawk/video/qt_player.cpp index 20fc8c1aa4..8c6e9b1a95 100644 --- a/engines/mohawk/video/qt_player.cpp +++ b/engines/mohawk/video/qt_player.cpp @@ -33,6 +33,7 @@ #include "mohawk/video/qt_player.h" +#include "common/debug.h" #include "common/endian.h" #include "common/util.h" #include "common/zlib.h" @@ -41,15 +42,72 @@ #include "sound/adpcm.h" #include "mohawk/video/qdm2.h" +// Video codecs +#include "mohawk/video/cinepak.h" +#include "mohawk/video/qtrle.h" +#include "mohawk/video/rpza.h" +#include "mohawk/video/smc.h" + namespace Mohawk { -QTPlayer::QTPlayer() : Video() { +//////////////////////////////////////////// +// QueuedAudioStream +//////////////////////////////////////////// + +QueuedAudioStream::QueuedAudioStream(int rate, int channels, bool autofree) { + _rate = rate; + _channels = channels; + _autofree = autofree; + _finished = false; +} + +QueuedAudioStream::~QueuedAudioStream() { + if (_autofree) + while (!_queue.empty()) + delete _queue.pop(); + _queue.clear(); +} + +void QueuedAudioStream::queueAudioStream(Audio::AudioStream *audStream) { + if (audStream->getRate() != getRate() && audStream->isStereo() && isStereo()) + error("QueuedAudioStream::queueAudioStream: audStream has mismatched parameters"); + + _queue.push(audStream); +} + +int QueuedAudioStream::readBuffer(int16 *buffer, const int numSamples) { + int samplesDecoded = 0; + + while (samplesDecoded < numSamples && !_queue.empty()) { + samplesDecoded += _queue.front()->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded); + + if (_queue.front()->endOfData()) { + Audio::AudioStream *temp = _queue.pop(); + if (_autofree) + delete temp; + } + } + + return samplesDecoded; +} + +//////////////////////////////////////////// +// QTPlayer +//////////////////////////////////////////// + +QTPlayer::QTPlayer() { _audStream = NULL; _beginOffset = 0; + _videoCodec = NULL; + _noCodecFound = false; + _curFrame = -1; + _lastFrameStart = _nextFrameStart = 0; + _audHandle = Audio::SoundHandle(); + _numStreams = 0; } QTPlayer::~QTPlayer() { - closeFile(); + stop(); } uint16 QTPlayer::getWidth() { @@ -94,24 +152,144 @@ ScaleMode QTPlayer::getScaleMode() { return (ScaleMode)(_scaleMode * _streams[_videoStreamIndex]->scaleMode); } -uint32 QTPlayer::getFrameDuration(uint32 frame) { +uint32 QTPlayer::getFrameDuration() { if (_videoStreamIndex < 0) return 0; uint32 curFrameIndex = 0; for (int32 i = 0; i < _streams[_videoStreamIndex]->stts_count; i++) { curFrameIndex += _streams[_videoStreamIndex]->stts_data[i].count; - if (frame < curFrameIndex) { + if ((uint32)_curFrame < curFrameIndex) { // Ok, now we have what duration this frame has. Now, we have to convert the duration to 1/100 ms. return _streams[_videoStreamIndex]->stts_data[i].duration * 1000 * 100 / _streams[_videoStreamIndex]->time_scale; } } // This should never occur - error ("Cannot find duration for frame %d", frame); + error ("Cannot find duration for frame %d", _curFrame); return 0; } +void QTPlayer::stop() { + stopAudio(); + + if (!_noCodecFound) + delete _videoCodec; + + closeFile(); +} + +void QTPlayer::reset() { + delete _videoCodec; _videoCodec = NULL; + _noCodecFound = false; + _curFrame = -1; + _lastFrameStart = _nextFrameStart = 0; + + // Restart the audio too + stopAudio(); + if (_audioStreamIndex >= 0) { + _curAudioChunk = 0; + _audStream = new QueuedAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels); + } + startAudio(); +} + +Graphics::Codec *QTPlayer::createCodec(uint32 codecTag, byte bitsPerPixel) { + if (codecTag == MKID_BE('cvid')) { + // Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this. + return new CinepakDecoder(); + } else if (codecTag == MKID_BE('rpza')) { + // Apple Video ("Road Pizza"): Used by some Myst videos. + return new RPZADecoder(getWidth(), getHeight()); + } else if (codecTag == MKID_BE('rle ')) { + // QuickTime RLE: Used by some Myst ME videos. + return new QTRLEDecoder(getWidth(), getHeight(), bitsPerPixel); + } else if (codecTag == MKID_BE('smc ')) { + // Apple SMC: Used by some Myst videos. + return new SMCDecoder(getWidth(), getHeight()); + } else if (codecTag == MKID_BE('SVQ1')) { + // Sorenson Video 1: Used by some Myst ME videos. + warning ("Sorenson Video 1 not yet supported"); + } else if (codecTag == MKID_BE('SVQ3')) { + // Sorenson Video 3: Used by some Myst ME videos. + warning ("Sorenson Video 3 not yet supported"); + } else if (codecTag == MKID_BE('jpeg')) { + // Motion JPEG: Used by some Myst ME videos. + warning ("Motion JPEG not yet supported"); + } else if (codecTag == MKID_BE('QkBk')) { + // CDToons: Used by most of the Broderbund games. This is an unknown format so far. + warning ("CDToons not yet supported"); + } else { + warning ("Unsupported codec \'%s\'", tag2str(codecTag)); + } + + return NULL; +} + +void QTPlayer::startAudio() { + if (!_audStream) // No audio/audio not supported + return; + + g_system->getMixer()->playInputStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream); +} + +void QTPlayer::pauseAudio() { + g_system->getMixer()->pauseHandle(_audHandle, true); +} + +void QTPlayer::resumeAudio() { + g_system->getMixer()->pauseHandle(_audHandle, false); +} + +void QTPlayer::stopAudio() { + g_system->getMixer()->stopHandle(_audHandle); +} + +Graphics::Surface *QTPlayer::getNextFrame() { + if (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1) + return NULL; + + if (_nextFrameStart == 0) + _nextFrameStart = g_system->getMillis() * 100; + + _lastFrameStart = _nextFrameStart; + _curFrame++; + _nextFrameStart = getFrameDuration() + _lastFrameStart; + + Common::SeekableReadStream *frameData = getNextFramePacket(); + + if (!_videoCodec) { + _videoCodec = createCodec(getCodecTag(), getBitsPerPixel()); + // If we don't get it still, the codec is unsupported ;) + if (!_videoCodec) { + _noCodecFound = true; + return NULL; + } + } + + if (frameData) { + Graphics::Surface *frame = _videoCodec->decodeImage(frameData); + delete frameData; + return frame; + } + + return NULL; +} + +bool QTPlayer::endOfVideo() { + return (!_audStream || _audStream->endOfData()) && (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1); +} + +bool QTPlayer::needsUpdate() { + if (endOfVideo()) + return false; + + if (_curFrame == -1) + return true; + + return (g_system->getMillis() * 100 - _lastFrameStart) >= getFrameDuration(); +} + bool QTPlayer::loadFile(Common::SeekableReadStream *stream) { _fd = stream; _foundMOOV = _foundMDAT = false; @@ -949,10 +1127,7 @@ void QTPlayer::closeFile() { } void QTPlayer::resetInternal() { - if (_audioStreamIndex >= 0) { - _curAudioChunk = 0; - _audStream = new QueuedAudioStream(_streams[_audioStreamIndex]->sample_rate, _streams[_audioStreamIndex]->channels); - } + } Common::SeekableReadStream *QTPlayer::getNextFramePacket() { diff --git a/engines/mohawk/video/qt_player.h b/engines/mohawk/video/qt_player.h index 14aea31ded..4bdf5b869b 100644 --- a/engines/mohawk/video/qt_player.h +++ b/engines/mohawk/video/qt_player.h @@ -35,8 +35,10 @@ #define MOHAWK_QT_PLAYER_H #include "common/scummsys.h" - -#include "mohawk/video/video.h" +#include "common/queue.h" +#include "graphics/video/codecs/codec.h" +#include "sound/audiostream.h" +#include "sound/mixer.h" namespace Common { class File; @@ -44,7 +46,38 @@ namespace Common { namespace Mohawk { -class QTPlayer : public Video { +class QueuedAudioStream : public Audio::AudioStream { +public: + QueuedAudioStream(int rate, int channels, bool autofree = true); + ~QueuedAudioStream(); + + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return _channels == 2; } + int getRate() const { return _rate; } + bool endOfData() const { return _queue.empty(); } + bool endOfStream() const { return _finished; } + + void queueAudioStream(Audio::AudioStream *audStream); + void finish() { _finished = true; } + + uint32 streamsInQueue() { return _queue.size(); } + +private: + bool _autofree; + bool _finished; + int _rate; + int _channels; + + Common::Queue<Audio::AudioStream*> _queue; +}; + +enum ScaleMode { + kScaleNormal = 1, + kScaleHalf = 2, + kScaleQuarter = 4 +}; + +class QTPlayer { public: QTPlayer(); virtual ~QTPlayer(); @@ -108,6 +141,19 @@ public: * @param the beginning offset of the video */ void setChunkBeginOffset(uint32 offset) { _beginOffset = offset; } + + int32 getCurFrame() { return _curFrame; } + void addPauseTime(uint32 p) { _lastFrameStart += p; _nextFrameStart += p; } + Graphics::Surface *getNextFrame(); + void updateAudioBuffer(); + void startAudio(); + void stopAudio(); + void pauseAudio(); + void resumeAudio(); + bool needsUpdate(); + bool endOfVideo(); + void stop(); + void reset(); protected: // This is the file handle from which data is read from. It can be the actual file handle or a decompressed stream. @@ -219,19 +265,24 @@ protected: byte _palette[256 * 4]; void initParseTable(); - QueuedAudioStream *getAudioStream() { return _audStream; } Audio::AudioStream *createAudioStream(Common::SeekableReadStream *stream); bool checkAudioCodecSupport(uint32 tag); - void updateAudioBuffer(); Common::SeekableReadStream *getNextFramePacket(); void resetInternal(); - uint32 getFrameDuration(uint32 frame); + uint32 getFrameDuration(); QueuedAudioStream *_audStream; int8 _videoStreamIndex; int8 _audioStreamIndex; uint _curAudioChunk; uint32 _beginOffset; + + Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel); + Graphics::Codec *_videoCodec; + bool _noCodecFound; + int32 _curFrame; + uint32 _lastFrameStart, _nextFrameStart; // In 1/100 ms + Audio::SoundHandle _audHandle; int readDefault(MOVatom atom); int readLeaf(MOVatom atom); diff --git a/engines/mohawk/video/video.cpp b/engines/mohawk/video/video.cpp index 8bdf9d6d8c..61e2bec9a6 100644 --- a/engines/mohawk/video/video.cpp +++ b/engines/mohawk/video/video.cpp @@ -27,204 +27,11 @@ #include "mohawk/video/video.h" #include "mohawk/video/qt_player.h" -// Codecs -#include "mohawk/video/cinepak.h" -#include "mohawk/video/qtrle.h" -#include "mohawk/video/rpza.h" -#include "mohawk/video/smc.h" - #include "common/events.h" namespace Mohawk { - -//////////////////////////////////////////// -// QueuedAudioStream -//////////////////////////////////////////// - -QueuedAudioStream::QueuedAudioStream(int rate, int channels, bool autofree) { - _rate = rate; - _channels = channels; - _autofree = autofree; - _finished = false; -} - -QueuedAudioStream::~QueuedAudioStream() { - if (_autofree) - while (!_queue.empty()) - delete _queue.pop(); - _queue.clear(); -} - -void QueuedAudioStream::queueAudioStream(Audio::AudioStream *audStream) { - if (audStream->getRate() != getRate() && audStream->isStereo() && isStereo()) - error("QueuedAudioStream::queueAudioStream: audStream has mismatched parameters"); - - _queue.push(audStream); -} - -int QueuedAudioStream::readBuffer(int16 *buffer, const int numSamples) { - int samplesDecoded = 0; - - while (samplesDecoded < numSamples && !_queue.empty()) { - samplesDecoded += _queue.front()->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded); - - if (_queue.front()->endOfData()) { - Audio::AudioStream *temp = _queue.pop(); - if (_autofree) - delete temp; - } - } - - return samplesDecoded; -} - -//////////////////////////////////////////// -// Video -//////////////////////////////////////////// - -Video::Video() { - _videoCodec = NULL; - _noCodecFound = false; - _curFrame = -1; - _lastFrameStart = _nextFrameStart = 0; - _audHandle = Audio::SoundHandle(); -} - -Video::~Video() { -} - -void Video::stop() { - stopAudio(); - - if (!_noCodecFound) - delete _videoCodec; - - closeFile(); -} - -void Video::reset() { - delete _videoCodec; _videoCodec = NULL; - _noCodecFound = false; - _curFrame = -1; - _lastFrameStart = _nextFrameStart = 0; - - stopAudio(); - resetInternal(); - startAudio(); -} - -Graphics::Codec *Video::createCodec(uint32 codecTag, byte bitsPerPixel) { - if (codecTag == MKID_BE('cvid')) { - // Cinepak: As used by most Myst and all Riven videos as well as some Myst ME videos. "The Chief" videos also use this. - return new CinepakDecoder(); - } else if (codecTag == MKID_BE('rpza')) { - // Apple Video ("Road Pizza"): Used by some Myst videos. - return new RPZADecoder(getWidth(), getHeight()); - } else if (codecTag == MKID_BE('rle ')) { - // QuickTime RLE: Used by some Myst ME videos. - return new QTRLEDecoder(getWidth(), getHeight(), bitsPerPixel); - } else if (codecTag == MKID_BE('smc ')) { - // Apple SMC: Used by some Myst videos. - return new SMCDecoder(getWidth(), getHeight()); - } else if (codecTag == MKID_BE('SVQ1')) { - // Sorenson Video 1: Used by some Myst ME videos. - warning ("Sorenson Video 1 not yet supported"); - } else if (codecTag == MKID_BE('SVQ3')) { - // Sorenson Video 3: Used by some Myst ME videos. - warning ("Sorenson Video 3 not yet supported"); - } else if (codecTag == MKID_BE('jpeg')) { - // Motion JPEG: Used by some Myst ME videos. - warning ("Motion JPEG not yet supported"); - } else if (codecTag == MKID_BE('QkBk')) { - // CDToons: Used by most of the Broderbund games. This is an unknown format so far. - warning ("CDToons not yet supported"); - } else { - warning ("Unsupported codec \'%s\'", tag2str(codecTag)); - } - - return NULL; -} - -void Video::startAudio() { - Audio::AudioStream *audStream = getAudioStream(); - - if (!audStream) // No audio/audio not supported - return; - - g_system->getMixer()->playInputStream(Audio::Mixer::kPlainSoundType, &_audHandle, audStream); -} - -void Video::pauseAudio() { - g_system->getMixer()->pauseHandle(_audHandle, true); -} - -void Video::resumeAudio() { - g_system->getMixer()->pauseHandle(_audHandle, false); -} - -void Video::stopAudio() { - g_system->getMixer()->stopHandle(_audHandle); -} - -Graphics::Surface *Video::getNextFrame() { - if (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1) - return NULL; - - if (_nextFrameStart == 0) - _nextFrameStart = g_system->getMillis() * 100; - - _lastFrameStart = _nextFrameStart; - _curFrame++; - _nextFrameStart = getFrameDuration() + _lastFrameStart; - - Common::SeekableReadStream *frameData = getNextFramePacket(); - - if (!_videoCodec) { - _videoCodec = createCodec(getCodecTag(), getBitsPerPixel()); - // If we don't get it still, the codec is unsupported ;) - if (!_videoCodec) { - _noCodecFound = true; - return NULL; - } - } - - if (frameData) { - Graphics::Surface *frame = _videoCodec->decodeImage(frameData); - delete frameData; - return frame; - } - - return NULL; -} - -bool Video::endOfVideo() { - QueuedAudioStream *audStream = getAudioStream(); - - return (!audStream || audStream->endOfData()) && (_noCodecFound || _curFrame >= (int32)getFrameCount() - 1); -} - -bool Video::needsUpdate() { - if (endOfVideo()) - return false; - - if (_curFrame == -1) - return true; - - return (g_system->getMillis() * 100 - _lastFrameStart) >= getFrameDuration(); -} - -//////////////////////////////////////////// -// VideoManager -//////////////////////////////////////////// VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { - if (_vm->getFeatures() & GF_HASBINK) { - warning ("This game uses bink video. Playback is disabled."); - _videoType = kBinkVideo; - } else { - _videoType = kQuickTimeVideo; - } - _pauseStart = 0; } @@ -260,7 +67,7 @@ void VideoManager::playMovie(Common::String filename, uint16 x, uint16 y, bool c return; // Return silently for now... VideoEntry entry; - entry.video = createVideo(); + entry.video = new QTPlayer(); if (!entry.video) return; @@ -285,7 +92,7 @@ void VideoManager::playMovieCentered(Common::String filename, bool clearScreen) return; // Return silently for now... VideoEntry entry; - entry.video = createVideo(); + entry.video = new QTPlayer(); if (!entry.video) return; @@ -353,7 +160,7 @@ void VideoManager::playBackgroundMovie(Common::String filename, int16 x, int16 y return; // Return silently for now... VideoEntry entry; - entry.video = createVideo(); + entry.video = new QTPlayer(); if (!entry.video) return; @@ -579,11 +386,4 @@ void VideoManager::disableAllMovies() { _mlstRecords[i].enabled = false; } -Video *VideoManager::createVideo() { - if (_videoType == kBinkVideo || _vm->shouldQuit()) - return NULL; - - return new QTPlayer(); -} - } // End of namespace Mohawk diff --git a/engines/mohawk/video/video.h b/engines/mohawk/video/video.h index fa160069c8..66259954ae 100644 --- a/engines/mohawk/video/video.h +++ b/engines/mohawk/video/video.h @@ -26,11 +26,7 @@ #ifndef MOHAWK_VIDEO_H #define MOHAWK_VIDEO_H -#include "common/queue.h" -#include "sound/audiostream.h" -#include "sound/mixer.h" // for Audio::SoundHandle #include "graphics/pixelformat.h" -#include "graphics/video/codecs/codec.h" namespace Mohawk { @@ -50,99 +46,17 @@ struct MLSTRecord { bool enabled; }; -class QueuedAudioStream : public Audio::AudioStream { -public: - QueuedAudioStream(int rate, int channels, bool autofree = true); - ~QueuedAudioStream(); - - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return _channels == 2; } - int getRate() const { return _rate; } - bool endOfData() const { return _queue.empty(); } - bool endOfStream() const { return _finished; } - - void queueAudioStream(Audio::AudioStream *audStream); - void finish() { _finished = true; } - - uint32 streamsInQueue() { return _queue.size(); } - -private: - bool _autofree; - bool _finished; - int _rate; - int _channels; - - Common::Queue<Audio::AudioStream*> _queue; -}; - -enum ScaleMode { - kScaleNormal = 1, - kScaleHalf = 2, - kScaleQuarter = 4 -}; - -class Video { -public: - Video(); - virtual ~Video(); - - virtual bool loadFile(Common::SeekableReadStream *stream) = 0; - virtual void closeFile() = 0; - void stop(); - void reset(); - - Graphics::Surface *getNextFrame(); - virtual uint16 getWidth() = 0; - virtual uint16 getHeight() = 0; - virtual uint32 getFrameCount() = 0; - - virtual void updateAudioBuffer() {} - void startAudio(); - void stopAudio(); - void pauseAudio(); - void resumeAudio(); - - int32 getCurFrame() { return _curFrame; } - void addPauseTime(uint32 p) { _lastFrameStart += p; _nextFrameStart += p; } - bool needsUpdate(); - bool endOfVideo(); - - virtual byte getBitsPerPixel() = 0; - virtual byte *getPalette() { return NULL; } - virtual uint32 getCodecTag() = 0; - virtual ScaleMode getScaleMode() { return kScaleNormal; } - -private: - Graphics::Codec *_videoCodec; - bool _noCodecFound; - Graphics::Codec *createCodec(uint32 codecTag, byte bitsPerPixel); - int32 _curFrame; - uint32 _lastFrameStart, _nextFrameStart; // In 1/100 ms - Audio::SoundHandle _audHandle; - - uint32 getFrameDuration() { return getFrameDuration(_curFrame); } - -protected: - virtual Common::SeekableReadStream *getNextFramePacket() = 0; - virtual uint32 getFrameDuration(uint32 frame) = 0; - virtual QueuedAudioStream *getAudioStream() = 0; - virtual void resetInternal() {} -}; +class QTPlayer; struct VideoEntry { - Video *video; + QTPlayer *video; uint16 x; uint16 y; bool loop; Common::String filename; uint16 id; // Riven only - Video *operator->() const { assert(video); return video; } -}; - -enum VideoType { - kQuickTimeVideo, - kBinkVideo + QTPlayer *operator->() const { assert(video); return video; } }; class VideoManager { @@ -175,10 +89,8 @@ private: MohawkEngine *_vm; void playMovie(VideoEntry videoEntry); - Video *createVideo(); // Keep tabs on any videos playing - VideoType _videoType; Common::Array<VideoEntry> _videoStreams; uint32 _pauseStart; }; |