From 818c16bdd09f4aa92c4a46de5256f28331c35cbb Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 20 Jul 2012 20:51:42 -0400 Subject: VIDEO: Add first draft of the new VideoDecoder API It is currently named "AdvancedVideoDecoder" until all current VideoDecoders are converted to the new API. --- video/video_decoder.cpp | 405 ++++++++++++++++++++++++++++++++++++++++++++++-- video/video_decoder.h | 358 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 744 insertions(+), 19 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 44d7917652..ef2aeae94f 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -22,6 +22,7 @@ #include "video/video_decoder.h" +#include "audio/audiostream.h" #include "audio/mixer.h" // for kMaxChannelVolume #include "common/rational.h" @@ -51,26 +52,10 @@ uint32 VideoDecoder::getTime() const { return g_system->getMillis() - _startTime; } -void VideoDecoder::setSystemPalette() { - g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); -} - bool VideoDecoder::needsUpdate() const { return !endOfVideo() && getTimeToNextFrame() == 0; } -void VideoDecoder::reset() { - _curFrame = -1; - _startTime = 0; - _pauseLevel = 0; - _audioVolume = Audio::Mixer::kMaxChannelVolume; - _audioBalance = 0; -} - -bool VideoDecoder::endOfVideo() const { - return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1); -} - void VideoDecoder::pauseVideo(bool pause) { if (pause) { _pauseLevel++; @@ -108,6 +93,394 @@ void VideoDecoder::setBalance(int8 balance) { updateBalance(); } +AdvancedVideoDecoder::AdvancedVideoDecoder() { + _needsRewind = false; + _dirtyPalette = false; + _palette = 0; + _isPlaying = false; +} + +void AdvancedVideoDecoder::close() { + if (_isPlaying) + stop(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + delete *it; + + _tracks.clear(); + _needsRewind = false; + _dirtyPalette = false; + _palette = 0; + _startTime = 0; + reset(); +} + +bool AdvancedVideoDecoder::isVideoLoaded() const { + return !_tracks.empty(); +} + +const Graphics::Surface *AdvancedVideoDecoder::decodeNextFrame() { + readNextPacket(); + VideoTrack *track = findNextVideoTrack(); + + if (!track) + return 0; + + const Graphics::Surface *frame = track->decodeNextFrame(); + + if (track->hasDirtyPalette()) { + _palette = track->getPalette(); + _dirtyPalette = true; + } + + return frame; +} + +const byte *AdvancedVideoDecoder::getPalette() { + _dirtyPalette = false; + return _palette; +} + +int AdvancedVideoDecoder::getCurFrame() const { + int32 frame = -1; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + frame += ((VideoTrack *)*it)->getCurFrame() + 1; + + return frame; +} + +uint32 AdvancedVideoDecoder::getFrameCount() const { + int count = 0; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + count += ((VideoTrack *)*it)->getFrameCount(); + + return count; +} + +uint32 AdvancedVideoDecoder::getTime() const { + if (isPaused()) + return _pauseStartTime - _startTime; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeAudio) { + uint32 time = ((const AudioTrack *)*it)->getRunningTime(); + + if (time != 0) + return time + _audioStartOffset.msecs(); + } + } + + return g_system->getMillis() - _startTime; +} + +uint32 AdvancedVideoDecoder::getTimeToNextFrame() const { + if (endOfVideo()) + return 0; + + const VideoTrack *track = findNextVideoTrack(); + + if (!track) + return 0; + + uint32 elapsedTime = getTime(); + uint32 nextFrameStartTime = track->getNextFrameStartTime(); + + if (nextFrameStartTime <= elapsedTime) + return 0; + + return nextFrameStartTime - elapsedTime; +} + +bool AdvancedVideoDecoder::endOfVideo() const { + // TODO: Bring _isPlaying into account? + + if (!isVideoLoaded()) + return true; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->endOfTrack()) + return false; + + return true; +} + +bool AdvancedVideoDecoder::isRewindable() const { + if (_tracks.empty()) + return false; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->isRewindable()) + return false; + + return true; +} + +bool AdvancedVideoDecoder::rewind() { + if (!isRewindable()) + return false; + + _needsRewind = false; + + // TODO: Pause status + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->rewind()) + return false; + + _audioStartOffset = 0; + return true; +} + +bool AdvancedVideoDecoder::isSeekable() const { + if (_tracks.empty()) + return false; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->isSeekable()) + return false; + + return true; +} + +bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { + if (!isSeekable()) + return false; + + _needsRewind = false; + + // TODO: Pause status + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->seek(time)) + return false; + + _audioStartOffset = time; + return true; +} + +void AdvancedVideoDecoder::start() { + if (_isPlaying || !isVideoLoaded()) + return; + + _isPlaying = true; + _startTime = g_system->getMillis(); + _audioStartOffset = 0; + + // If someone previously called stop(), we'll rewind it. + if (_needsRewind) + rewind(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->start(); +} + +void AdvancedVideoDecoder::stop() { + if (!_isPlaying) + return; + + _isPlaying = false; + _startTime = 0; + _audioStartOffset = 0; + _palette = 0; + _dirtyPalette = false; + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->stop(); + + // Also reset the pause state. + _pauseLevel = 0; + + // If this is a rewindable video, don't close it too. We'll just rewind() the video + // the next time someone calls start(). Otherwise, since it can't be rewound, we + // just close it. + if (isRewindable()) + _needsRewind = true; + else + close(); +} + +Audio::Timestamp AdvancedVideoDecoder::getDuration() const { + return Audio::Timestamp(0, 1000); +} + +void AdvancedVideoDecoder::pauseVideoIntern(bool pause) { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->pause(pause); +} + +void AdvancedVideoDecoder::updateVolume() { + // For API compatibility only + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->setVolume(_audioVolume); +} + +void AdvancedVideoDecoder::updateBalance() { + // For API compatibility only + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->setBalance(_audioBalance); +} + +AdvancedVideoDecoder::Track::Track() { + _paused = false; +} + +bool AdvancedVideoDecoder::Track::isRewindable() const { + return isSeekable(); +} + +bool AdvancedVideoDecoder::Track::rewind() { + return seek(Audio::Timestamp(0, 1000)); +} + +uint32 AdvancedVideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { + if (endOfTrack() || getCurFrame() < 0) + return 0; + + Common::Rational time = (getCurFrame() + 1) * 1000; + time /= getFrameRate(); + return time.toInt(); +} + +bool AdvancedVideoDecoder::FixedLengthVideoTrack::endOfTrack() const { + return getCurFrame() >= (getFrameCount() - 1); +} + +bool AdvancedVideoDecoder::AudioTrack::endOfTrack() const { + Audio::AudioStream *stream = getAudioStream(); + return !stream || (!g_system->getMixer()->isSoundHandleActive(_handle) && stream->endOfData()); +} + +void AdvancedVideoDecoder::AudioTrack::setVolume(byte volume) { + _volume = volume; + + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->setChannelVolume(_handle, _volume); +} + +void AdvancedVideoDecoder::AudioTrack::setBalance(int8 balance) { + _balance = balance; + + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->setChannelBalance(_handle, _balance); +} + +void AdvancedVideoDecoder::AudioTrack::start() { + stop(); + + Audio::AudioStream *stream = getAudioStream(); + assert(stream); + + g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::NO); + + // Pause the audio again if we're still paused + if (isPaused()) + g_system->getMixer()->pauseHandle(_handle, true); +} + +void AdvancedVideoDecoder::AudioTrack::stop() { + g_system->getMixer()->stopHandle(_handle); +} + +uint32 AdvancedVideoDecoder::AudioTrack::getRunningTime() const { + if (g_system->getMixer()->isSoundHandleActive(_handle)) + return g_system->getMixer()->getSoundElapsedTime(_handle); + + return 0; +} + +void AdvancedVideoDecoder::AudioTrack::pauseIntern(bool shouldPause) { + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->pauseHandle(_handle, shouldPause); +} + +Audio::AudioStream *AdvancedVideoDecoder::RewindableAudioTrack::getAudioStream() const { + return getRewindableAudioStream(); +} + +bool AdvancedVideoDecoder::RewindableAudioTrack::rewind() { + Audio::RewindableAudioStream *stream = getRewindableAudioStream(); + assert(stream); + return stream->rewind(); +} + +Audio::AudioStream *AdvancedVideoDecoder::SeekableAudioTrack::getAudioStream() const { + return getSeekableAudioStream(); +} + +bool AdvancedVideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time) { + Audio::SeekableAudioStream *stream = getSeekableAudioStream(); + assert(stream); + return stream->seek(time); +} + +void AdvancedVideoDecoder::addTrack(Track *track) { + _tracks.push_back(track); +} + +AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() { + VideoTrack *bestTrack = 0; + uint32 bestTime = 0xFFFFFFFF; + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo) { + VideoTrack *track = (VideoTrack *)*it; + uint32 time = track->getNextFrameStartTime(); + + if (time < bestTime) { + bestTime = time; + bestTrack = track; + } + } + } + + return bestTrack; +} + +const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() const { + const VideoTrack *bestTrack = 0; + uint32 bestTime = 0xFFFFFFFF; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo) { + const VideoTrack *track = (const VideoTrack *)*it; + uint32 time = track->getNextFrameStartTime(); + + if (time < bestTime) { + bestTime = time; + bestTrack = track; + } + } + } + + return bestTrack; +} + +////////////////////////////////////////////// +///////////////// DEPRECATED ///////////////// +////////////////////////////////////////////// + +void VideoDecoder::reset() { + _curFrame = -1; + _startTime = 0; + _pauseLevel = 0; + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; +} + +bool VideoDecoder::endOfVideo() const { + return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1); +} + +void VideoDecoder::setSystemPalette() { + g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); +} + uint32 FixedRateVideoDecoder::getTimeToNextFrame() const { if (endOfVideo() || _curFrame < 0) return 0; diff --git a/video/video_decoder.h b/video/video_decoder.h index 3bb75ade09..1c359591b3 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -23,10 +23,16 @@ #ifndef VIDEO_DECODER_H #define VIDEO_DECODER_H -#include "common/str.h" - +#include "audio/mixer.h" #include "audio/timestamp.h" // TODO: Move this to common/ ? +#include "common/list.h" +#include "common/str.h" +namespace Audio { +class AudioStream; +class RewindableAudioStream; +class SeekableAudioStream; +} namespace Common { class Rational; @@ -42,6 +48,7 @@ namespace Video { /** * Generic interface for video decoder classes. + * @note This class is now deprecated in favor of AdvancedVideoDecoder. */ class VideoDecoder { public: @@ -109,6 +116,7 @@ public: /** * Set the system palette to the palette returned by getPalette. * @see getPalette + * @note This function is now deprecated. There is no replacement. */ void setSystemPalette(); @@ -222,47 +230,389 @@ public: protected: /** * Resets _curFrame and _startTime. Should be called from every close() function. + * @note This function is now deprecated. There is no replacement. */ void reset(); /** * Actual implementation of pause by subclasses. See pause() * for details. + * @note This function is now deprecated. There is no replacement. */ virtual void pauseVideoIntern(bool pause) {} /** * Add the time the video has been paused to maintain sync + * @note This function is now deprecated. There is no replacement. */ virtual void addPauseTime(uint32 ms) { _startTime += ms; } /** * Reset the pause start time (which should be called when seeking) + * @note This function is now deprecated. There is no replacement. */ void resetPauseStartTime(); /** * Update currently playing audio tracks with the new volume setting + * @note This function is now deprecated. There is no replacement. */ virtual void updateVolume() {} /** * Update currently playing audio tracks with the new balance setting + * @note This function is now deprecated. There is no replacement. */ virtual void updateBalance() {} int32 _curFrame; int32 _startTime; -private: +// FIXME: These are protected until the new API takes over this one +//private: uint32 _pauseLevel; uint32 _pauseStartTime; byte _audioVolume; int8 _audioBalance; }; +/** + * Improved interface for video decoder classes. + */ +class AdvancedVideoDecoder : public VideoDecoder { +public: + AdvancedVideoDecoder(); + virtual ~AdvancedVideoDecoder() {} + + // Old API Non-changing + // loadFile() + // loadStream() + // getWidth() + // getHeight() + // needsUpdate() + + // Old API Changing + virtual void close(); + bool isVideoLoaded() const; + virtual const Graphics::Surface *decodeNextFrame(); + const byte *getPalette(); + bool hasDirtyPalette() const { return _dirtyPalette; } + int getCurFrame() const; + uint32 getFrameCount() const; + uint32 getTime() const; + uint32 getTimeToNextFrame() const; + bool endOfVideo() const; + + // New API + /** + * Returns if a video is rewindable or not. + */ + bool isRewindable() const; + + /** + * Rewind a video to its beginning. + * + * If the video is playing, it will continue to play. + * + * @return true on success, false otherwise + */ + bool rewind(); + + /** + * Returns if a video is seekable or not. + */ + bool isSeekable() const; + + /** + * Seek to a given time in the video. + * + * If the video is playing, it will continue to play. + * + * @param time The time to seek to + * @return true on success, false otherwise + */ + bool seek(const Audio::Timestamp &time); + + /** + * Begin playback of the video. + * + * @note This has no effect is the video is already playing. + */ + void start(); + + /** + * Stop playback of the video. + * + * @note This will close() the video if it is not rewindable. + */ + void stop(); + + /** + * Returns if the video is currently playing or not. + * @todo Differentiate this function from endOfVideo() + */ + bool isPlaying() const { return _isPlaying; } + + /** + * Get the duration of the video. + * + * If the duration is unknown, this will return 0. + */ + virtual Audio::Timestamp getDuration() const; + + // Future API + //void setRate(const Common::Rational &rate); + //Common::Rational getRate() const; + //void setStartTime(const Audio::Timestamp &startTime); + //Audio::Timestamp getStartTime() const; + //void setStopTime(const Audio::Timestamp &stopTime); + //Audio::Timestamp getStopTime() const; + //void setSegment(const Audio::Timestamp &startTime, const Audio::Timestamp &stopTime); + +protected: + // Old API + void pauseVideoIntern(bool pause); + void updateVolume(); + void updateBalance(); + + // New API + + /** + * An abstract representation of a track in a movie. + */ + class Track { + public: + Track(); + virtual ~Track() {} + + /** + * The types of tracks this class can be. + */ + enum TrackType { + kTrackTypeNone, + kTrackTypeVideo, + kTrackTypeAudio + }; + + /** + * Get the type of track. + */ + virtual TrackType getTrackType() const = 0; + + /** + * Return if the track has finished. + */ + virtual bool endOfTrack() const = 0; + + /** + * Return if the track is rewindable. + */ + virtual bool isRewindable() const; + + /** + * Rewind the video to the beginning. + * @return true on success, false otherwise. + */ + virtual bool rewind(); + + /** + * Return if the track is seekable. + */ + virtual bool isSeekable() const { return false; } + + /** + * Seek to the given time. + * @param time The time to seek to. + * @return true on success, false otherwise. + */ + virtual bool seek(const Audio::Timestamp &time) { return false; } + + /** + * Start playback of the track. + */ + virtual void start() {} + + /** + * Stop playback of the track. + */ + virtual void stop() {} + + /** + * Set the pause status of the track. + */ + void pause(bool shouldPause) {} + + /** + * Return if the track is paused. + */ + bool isPaused() const { return _paused; } + + protected: + /** + * Function called by pause() for subclasses to implement. + */ + void pauseIntern(bool pause); + + private: + bool _paused; + }; + + /** + * An abstract representation of a video track. + */ + class VideoTrack : public Track { + public: + VideoTrack() {} + virtual ~VideoTrack() {} + + TrackType getTrackType() const { return kTrackTypeVideo; } + + // TODO: Document + virtual int getCurFrame() const = 0; + virtual int getFrameCount() const { return 0; } + virtual uint32 getNextFrameStartTime() const = 0; + virtual const Graphics::Surface *decodeNextFrame() = 0; + virtual const byte *getPalette() const { return 0; } + virtual bool hasDirtyPalette() const { return false; } + }; + + /** + * A VideoTrack that is played at a constant rate. + */ + class FixedRateVideoTrack : public virtual VideoTrack { + public: + FixedRateVideoTrack() {} + virtual ~FixedRateVideoTrack() {} + + uint32 getNextFrameStartTime() const; + + protected: + /** + * Get the rate at which this track is played. + */ + virtual Common::Rational getFrameRate() const = 0; + }; + + /** + * A VideoTrack with a known frame count that can be reliably + * used to figure out if the track has finished. + */ + class FixedLengthVideoTrack : public virtual VideoTrack { + public: + FixedLengthVideoTrack() {} + virtual ~FixedLengthVideoTrack() {} + + bool endOfTrack() const; + }; + + /** + * An abstract representation of an audio track. + */ + class AudioTrack : public Track { + public: + AudioTrack() {} + virtual ~AudioTrack() {} + + TrackType getTrackType() const { return kTrackTypeAudio; } + + virtual bool endOfTrack() const; + void start(); + void stop(); + + // TODO: Document + byte getVolume() const { return _volume; } + void setVolume(byte volume); + int8 getBalance() const { return _balance; } + void setBalance(int8 balance); + uint32 getRunningTime() const; + + virtual Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kPlainSoundType; } + + protected: + void pauseIntern(bool pause); + + // TODO: Document + virtual Audio::AudioStream *getAudioStream() const = 0; + + private: + Audio::SoundHandle _handle; + byte _volume; + int8 _balance; + }; + + /** + * An AudioTrack that implements isRewindable() and rewind() using + * the RewindableAudioStream API. + */ + class RewindableAudioTrack : public AudioTrack { + public: + RewindableAudioTrack() {} + virtual ~RewindableAudioTrack() {} + + bool isRewindable() const { return true; } + bool rewind(); + + protected: + Audio::AudioStream *getAudioStream() const; + + // TODO: Document + virtual Audio::RewindableAudioStream *getRewindableAudioStream() const = 0; + }; + + /** + * An AudioTrack that implements isSeekable() and seek() using + * the SeekableAudioStream API. + */ + class SeekableAudioTrack : public AudioTrack { + public: + SeekableAudioTrack() {} + virtual ~SeekableAudioTrack() {} + + bool isSeekable() const { return true; } + bool seek(const Audio::Timestamp &time); + + protected: + Audio::AudioStream *getAudioStream() const; + + // TODO: Document + virtual Audio::SeekableAudioStream *getSeekableAudioStream() const = 0; + }; + + /** + * Decode enough data for the next frame and enough audio to last that long. + * + * This function is used by the default decodeNextFrame() function. A subclass + * of a Track may decide to just have its decodeNextFrame() function read + * and decode the frame. + */ + virtual void readNextPacket() {} + + /** + * Define a track to be used by this class. + * + * The pointer is then owned by this base class. + */ + void addTrack(Track *track); + +private: + // Tracks owned by this AdvancedVideoDecoder + typedef Common::List TrackList; + TrackList _tracks; + VideoTrack *findNextVideoTrack(); + const VideoTrack *findNextVideoTrack() const; + + // Current playback status + bool _isPlaying, _needsRewind; + Audio::Timestamp _audioStartOffset; + + // Palette settings from individual tracks + mutable bool _dirtyPalette; + const byte *_palette; +}; + /** * A VideoDecoder wrapper that implements getTimeToNextFrame() based on getFrameRate(). + * @note This class is now deprecated. Use AdvancedVideoDecoder instead. */ class FixedRateVideoDecoder : public virtual VideoDecoder { public: @@ -282,6 +632,7 @@ private: /** * A VideoDecoder that can be rewound back to the beginning. + * @note This class is now deprecated. Use AdvancedVideoDecoder instead. */ class RewindableVideoDecoder : public virtual VideoDecoder { public: @@ -293,6 +644,7 @@ public: /** * A VideoDecoder that can seek to a frame or point in time. + * @note This class is now deprecated. Use AdvancedVideoDecoder instead. */ class SeekableVideoDecoder : public virtual RewindableVideoDecoder { public: -- cgit v1.2.3 From a12b3ea2dde9db348424f401a35fca3167120011 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 20 Jul 2012 20:52:58 -0400 Subject: SCI: Move the SEQ code to the new VideoDecoder API --- engines/sci/console.cpp | 5 ++-- engines/sci/engine/kvideo.cpp | 7 +++-- engines/sci/video/seq_decoder.cpp | 61 +++++++++++++++++++-------------------- engines/sci/video/seq_decoder.h | 52 ++++++++++++++++++--------------- 4 files changed, 64 insertions(+), 61 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 564bbbbd79..2a4ad1743d 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -250,9 +250,8 @@ void Console::postEnter() { #endif if (_videoFile.hasSuffix(".seq")) { - SeqDecoder *seqDecoder = new SeqDecoder(); - seqDecoder->setFrameDelay(_videoFrameDelay); - videoDecoder = seqDecoder; + videoDecoder = new SEQDecoder(_videoFrameDelay); + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { videoDecoder = new Video::VMDDecoder(g_system->getMixer()); diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index cb2a763da9..bfe32a8d82 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -162,15 +162,16 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { } else { // DOS SEQ // SEQ's are called with no subops, just the string and delay - SeqDecoder *seqDecoder = new SeqDecoder(); - seqDecoder->setFrameDelay(argv[1].toUint16()); // Time between frames in ticks - videoDecoder = seqDecoder; + // Time is specified as ticks + videoDecoder = new SEQDecoder(argv[1].toUint16()); if (!videoDecoder->loadFile(filename)) { warning("Failed to open movie file %s", filename.c_str()); delete videoDecoder; videoDecoder = 0; } + + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete } } else { // Windows AVI diff --git a/engines/sci/video/seq_decoder.cpp b/engines/sci/video/seq_decoder.cpp index abd64911a7..a7b6346eca 100644 --- a/engines/sci/video/seq_decoder.cpp +++ b/engines/sci/video/seq_decoder.cpp @@ -41,33 +41,44 @@ enum seqFrameTypes { kSeqFrameDiff = 1 }; -SeqDecoder::SeqDecoder() { - _fileStream = 0; - _surface = 0; - _dirtyPalette = false; +SEQDecoder::SEQDecoder(uint frameDelay) : _frameDelay(frameDelay) { } -SeqDecoder::~SeqDecoder() { +SEQDecoder::~SEQDecoder() { close(); } -bool SeqDecoder::loadStream(Common::SeekableReadStream *stream) { +bool SEQDecoder::loadStream(Common::SeekableReadStream *stream) { close(); + addTrack(new SEQVideoTrack(stream, _frameDelay)); + + return true; +} + +SEQDecoder::SEQVideoTrack::SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay) { + assert(stream); + assert(frameDelay != 0); _fileStream = stream; + _frameDelay = frameDelay; + _curFrame = -1; + _surface = new Graphics::Surface(); _surface->create(SEQ_SCREEN_WIDTH, SEQ_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); _frameCount = _fileStream->readUint16LE(); - // Set palette - int paletteChunkSize = _fileStream->readUint32LE(); - readPaletteChunk(paletteChunkSize); + // Set initial palette + readPaletteChunk(_fileStream->readUint32LE()); +} - return true; +SEQDecoder::SEQVideoTrack::~SEQVideoTrack() { + delete _fileStream; + _surface->free(); + delete _surface; } -void SeqDecoder::readPaletteChunk(uint16 chunkSize) { +void SEQDecoder::SEQVideoTrack::readPaletteChunk(uint16 chunkSize) { byte *paletteData = new byte[chunkSize]; _fileStream->read(paletteData, chunkSize); @@ -91,23 +102,7 @@ void SeqDecoder::readPaletteChunk(uint16 chunkSize) { delete[] paletteData; } -void SeqDecoder::close() { - if (!_fileStream) - return; - - _frameDelay = 0; - - delete _fileStream; - _fileStream = 0; - - _surface->free(); - delete _surface; - _surface = 0; - - reset(); -} - -const Graphics::Surface *SeqDecoder::decodeNextFrame() { +const Graphics::Surface *SEQDecoder::SEQVideoTrack::decodeNextFrame() { int16 frameWidth = _fileStream->readUint16LE(); int16 frameHeight = _fileStream->readUint16LE(); int16 frameLeft = _fileStream->readUint16LE(); @@ -142,9 +137,6 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() { delete[] buf; } - if (_curFrame == -1) - _startTime = g_system->getMillis(); - _curFrame++; return _surface; } @@ -159,7 +151,7 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() { } \ memcpy(dest + writeRow * SEQ_SCREEN_WIDTH + writeCol, litData + litPos, n); -bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) { +bool SEQDecoder::SEQVideoTrack::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) { int writeRow = 0; int writeCol = left; int litPos = 0; @@ -237,4 +229,9 @@ bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litS return true; } +const byte *SEQDecoder::SEQVideoTrack::getPalette() const { + _dirtyPalette = false; + return _palette; +} + } // End of namespace Sci diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h index 800a3c9024..c07bcd748b 100644 --- a/engines/sci/video/seq_decoder.h +++ b/engines/sci/video/seq_decoder.h @@ -40,27 +40,16 @@ namespace Sci { /** * Implementation of the Sierra SEQ decoder, used in KQ6 DOS floppy/CD and GK1 DOS */ -class SeqDecoder : public Video::FixedRateVideoDecoder { +class SEQDecoder : public Video::AdvancedVideoDecoder { public: - SeqDecoder(); - virtual ~SeqDecoder(); + SEQDecoder(uint frameDelay); + virtual ~SEQDecoder(); bool loadStream(Common::SeekableReadStream *stream); - void close(); - void setFrameDelay(int frameDelay) { _frameDelay = frameDelay; } - - bool isVideoLoaded() const { return _fileStream != 0; } uint16 getWidth() const { return SEQ_SCREEN_WIDTH; } uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; } - uint32 getFrameCount() const { return _frameCount; } - const Graphics::Surface *decodeNextFrame(); Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } - -protected: - Common::Rational getFrameRate() const { assert(_frameDelay); return Common::Rational(60, _frameDelay); } private: enum { @@ -68,16 +57,33 @@ private: SEQ_SCREEN_HEIGHT = 200 }; - void readPaletteChunk(uint16 chunkSize); - bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey); + class SEQVideoTrack : public FixedRateVideoTrack, public FixedLengthVideoTrack { + public: + SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay); + ~SEQVideoTrack(); + + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const; + bool hasDirtyPalette() const { return _dirtyPalette; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(60, _frameDelay); } + + private: + void readPaletteChunk(uint16 chunkSize); + bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey); + + Common::SeekableReadStream *_fileStream; + int _curFrame, _frameCount; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + Graphics::Surface *_surface; + uint _frameDelay; + }; - uint16 _width, _height; - uint16 _frameDelay; - Common::SeekableReadStream *_fileStream; - byte _palette[256 * 3]; - bool _dirtyPalette; - uint32 _frameCount; - Graphics::Surface *_surface; + uint _frameDelay; }; } // End of namespace Sci -- cgit v1.2.3 From fb1edcd4fef7fd750b4af18745ca7b3151b56aae Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 12:40:16 -0400 Subject: VIDEO: Add getWidth()/getHeight()/getPixelFormat() functions to VideoTrack The default implementations of those functions in AdvancedVideoDecoder now call into them. --- engines/sci/video/seq_decoder.h | 17 ++++++++--------- video/video_decoder.cpp | 24 ++++++++++++++++++++++++ video/video_decoder.h | 8 ++++++-- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h index c07bcd748b..ac801d3f19 100644 --- a/engines/sci/video/seq_decoder.h +++ b/engines/sci/video/seq_decoder.h @@ -47,21 +47,15 @@ public: bool loadStream(Common::SeekableReadStream *stream); - uint16 getWidth() const { return SEQ_SCREEN_WIDTH; } - uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; } - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - private: - enum { - SEQ_SCREEN_WIDTH = 320, - SEQ_SCREEN_HEIGHT = 200 - }; - class SEQVideoTrack : public FixedRateVideoTrack, public FixedLengthVideoTrack { public: SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay); ~SEQVideoTrack(); + uint16 getWidth() const { return SEQ_SCREEN_WIDTH; } + uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; } + Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } int getCurFrame() const { return _curFrame; } int getFrameCount() const { return _frameCount; } const Graphics::Surface *decodeNextFrame(); @@ -72,6 +66,11 @@ private: Common::Rational getFrameRate() const { return Common::Rational(60, _frameDelay); } private: + enum { + SEQ_SCREEN_WIDTH = 320, + SEQ_SCREEN_HEIGHT = 200 + }; + void readPaletteChunk(uint16 chunkSize); bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey); diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index ef2aeae94f..a8cf32575a 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -119,6 +119,30 @@ bool AdvancedVideoDecoder::isVideoLoaded() const { return !_tracks.empty(); } +uint16 AdvancedVideoDecoder::getWidth() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + return ((VideoTrack *)*it)->getWidth(); + + return 0; +} + +uint16 AdvancedVideoDecoder::getHeight() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + return ((VideoTrack *)*it)->getHeight(); + + return 0; +} + +Graphics::PixelFormat AdvancedVideoDecoder::getPixelFormat() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + return ((VideoTrack *)*it)->getPixelFormat(); + + return Graphics::PixelFormat(); +} + const Graphics::Surface *AdvancedVideoDecoder::decodeNextFrame() { readNextPacket(); VideoTrack *track = findNextVideoTrack(); diff --git a/video/video_decoder.h b/video/video_decoder.h index 1c359591b3..ede2872c6a 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -287,13 +287,14 @@ public: // Old API Non-changing // loadFile() // loadStream() - // getWidth() - // getHeight() // needsUpdate() // Old API Changing virtual void close(); bool isVideoLoaded() const; + virtual uint16 getWidth() const; + virtual uint16 getHeight() const; + virtual Graphics::PixelFormat getPixelFormat() const; virtual const Graphics::Surface *decodeNextFrame(); const byte *getPalette(); bool hasDirtyPalette() const { return _dirtyPalette; } @@ -468,6 +469,9 @@ protected: TrackType getTrackType() const { return kTrackTypeVideo; } // TODO: Document + virtual uint16 getWidth() const = 0; + virtual uint16 getHeight() const = 0; + virtual Graphics::PixelFormat getPixelFormat() const = 0; virtual int getCurFrame() const = 0; virtual int getFrameCount() const { return 0; } virtual uint32 getNextFrameStartTime() const = 0; -- cgit v1.2.3 From 10341d2b5722fb39cba39356c8596d857319a1ba Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 14:39:03 -0400 Subject: VIDEO: Add getDuration() and getStartTime() functions to Track The AdvancedVideoDecoder::getDuration() function now attempts to calculate duration based on the longest track. --- video/video_decoder.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- video/video_decoder.h | 29 ++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index a8cf32575a..285290da6e 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -328,7 +328,21 @@ void AdvancedVideoDecoder::stop() { } Audio::Timestamp AdvancedVideoDecoder::getDuration() const { - return Audio::Timestamp(0, 1000); + Audio::Timestamp maxDuration(0, 1000); + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { + Audio::Timestamp startTime = (*it)->getStartTime(); + Audio::Timestamp duration = (*it)->getDuration(); + + if (duration.totalNumberOfFrames() != 0) { + // HACK: Timestamp's + operator doesn't do framerate conversion :( + duration = duration + startTime.convertToFramerate(duration.framerate()); + if (duration > maxDuration) + maxDuration = duration; + } + } + + return maxDuration; } void AdvancedVideoDecoder::pauseVideoIntern(bool pause) { @@ -359,7 +373,15 @@ bool AdvancedVideoDecoder::Track::isRewindable() const { } bool AdvancedVideoDecoder::Track::rewind() { - return seek(Audio::Timestamp(0, 1000)); + return seek(getStartTime()); +} + +Audio::Timestamp AdvancedVideoDecoder::Track::getStartTime() const { + return Audio::Timestamp(0, 1000); +} + +Audio::Timestamp AdvancedVideoDecoder::Track::getDuration() const { + return Audio::Timestamp(0, 1000); } uint32 AdvancedVideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { @@ -375,6 +397,14 @@ bool AdvancedVideoDecoder::FixedLengthVideoTrack::endOfTrack() const { return getCurFrame() >= (getFrameCount() - 1); } +Audio::Timestamp AdvancedVideoDecoder::FixedDurationVideoTrack::getDuration() const { + // Since Audio::Timestamp doesn't support a fractional frame rate, we're currently + // just converting to milliseconds. + Common::Rational time = getFrameCount() * 1000; + time /= getFrameRate(); + return time.toInt(); +} + bool AdvancedVideoDecoder::AudioTrack::endOfTrack() const { Audio::AudioStream *stream = getAudioStream(); return !stream || (!g_system->getMixer()->isSoundHandleActive(_handle) && stream->endOfData()); @@ -433,6 +463,12 @@ bool AdvancedVideoDecoder::RewindableAudioTrack::rewind() { return stream->rewind(); } +Audio::Timestamp AdvancedVideoDecoder::SeekableAudioTrack::getDuration() const { + Audio::SeekableAudioStream *stream = getSeekableAudioStream(); + assert(stream); + return stream->getLength(); +} + Audio::AudioStream *AdvancedVideoDecoder::SeekableAudioTrack::getAudioStream() const { return getSeekableAudioStream(); } diff --git a/video/video_decoder.h b/video/video_decoder.h index ede2872c6a..87d832eeb9 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -423,7 +423,7 @@ protected: /** * Seek to the given time. - * @param time The time to seek to. + * @param time The time to seek to, from the beginning of the video. * @return true on success, false otherwise. */ virtual bool seek(const Audio::Timestamp &time) { return false; } @@ -448,6 +448,19 @@ protected: */ bool isPaused() const { return _paused; } + /** + * Get the start time of the track (starting from the beginning of the + * movie). + */ + virtual Audio::Timestamp getStartTime() const; + + /** + * Get the duration of the track (starting from this track's start time). + * + * By default, this returns 0 for unknown. + */ + virtual Audio::Timestamp getDuration() const; + protected: /** * Function called by pause() for subclasses to implement. @@ -509,6 +522,18 @@ protected: bool endOfTrack() const; }; + /** + * A FixedRateVideoTrack and FixedLengthVideoTrack that implements the getDuration() + * function. + */ + class FixedDurationVideoTrack : public FixedRateVideoTrack, public FixedLengthVideoTrack { + public: + FixedDurationVideoTrack() {} + virtual ~FixedDurationVideoTrack() {} + + virtual Audio::Timestamp getDuration() const; + }; + /** * An abstract representation of an audio track. */ @@ -575,6 +600,8 @@ protected: bool isSeekable() const { return true; } bool seek(const Audio::Timestamp &time); + Audio::Timestamp getDuration() const; + protected: Audio::AudioStream *getAudioStream() const; -- cgit v1.2.3 From e74c306a7f3847128eb786c2d56f04d559e5a822 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 14:43:08 -0400 Subject: SCI: Switch SEQDecoder to using the new FixedDurationVideoTrack subclass --- engines/sci/video/seq_decoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h index ac801d3f19..75d7ce6c3d 100644 --- a/engines/sci/video/seq_decoder.h +++ b/engines/sci/video/seq_decoder.h @@ -48,7 +48,7 @@ public: bool loadStream(Common::SeekableReadStream *stream); private: - class SEQVideoTrack : public FixedRateVideoTrack, public FixedLengthVideoTrack { + class SEQVideoTrack : public FixedDurationVideoTrack { public: SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay); ~SEQVideoTrack(); -- cgit v1.2.3 From c3cc3620c0d66a2ea7eac9738ead934f3b6381b0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 14:50:10 -0400 Subject: VIDEO: When adding tracks, keep them in sync with the main video status --- video/video_decoder.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 285290da6e..67e53c6b47 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -481,6 +481,12 @@ bool AdvancedVideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time void AdvancedVideoDecoder::addTrack(Track *track) { _tracks.push_back(track); + + if (isPaused()) + track->pause(true); + + if (isPlaying()) + track->start(); } AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() { -- cgit v1.2.3 From 1d565a26610a174c16b58b569fe413f3acf9bd75 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 17:11:09 -0400 Subject: VIDEO: Fix volume/balance settings in AdvancedVideoDecoder --- video/video_decoder.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 67e53c6b47..07fd225dcf 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -98,6 +98,9 @@ AdvancedVideoDecoder::AdvancedVideoDecoder() { _dirtyPalette = false; _palette = 0; _isPlaying = false; + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; + _pauseLevel = 0; } void AdvancedVideoDecoder::close() { @@ -112,7 +115,9 @@ void AdvancedVideoDecoder::close() { _dirtyPalette = false; _palette = 0; _startTime = 0; - reset(); + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; + _pauseLevel = 0; } bool AdvancedVideoDecoder::isVideoLoaded() const { @@ -482,9 +487,17 @@ bool AdvancedVideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time void AdvancedVideoDecoder::addTrack(Track *track) { _tracks.push_back(track); + // Update volume settings if it's an audio track + if (track->getTrackType() == Track::kTrackTypeAudio) { + ((AudioTrack *)track)->setVolume(_audioVolume); + ((AudioTrack *)track)->setBalance(_audioBalance); + } + + // Keep the track paused if we're paused if (isPaused()) track->pause(true); + // Start the track if we're playing if (isPlaying()) track->start(); } -- cgit v1.2.3 From fc1163ac28aae1c7bc9f8f9d3877c6f368b4b19c Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 17:30:06 -0400 Subject: VIDEO: Allow for disabling of automatic audio sync in AdvancedVideoDecoder --- video/video_decoder.cpp | 12 +++++++----- video/video_decoder.h | 7 +++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 07fd225dcf..3312b2530d 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -194,12 +194,14 @@ uint32 AdvancedVideoDecoder::getTime() const { if (isPaused()) return _pauseStartTime - _startTime; - for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { - if ((*it)->getTrackType() == Track::kTrackTypeAudio) { - uint32 time = ((const AudioTrack *)*it)->getRunningTime(); + if (useAudioSync()) { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeAudio) { + uint32 time = ((const AudioTrack *)*it)->getRunningTime(); - if (time != 0) - return time + _audioStartOffset.msecs(); + if (time != 0) + return time + _audioStartOffset.msecs(); + } } } diff --git a/video/video_decoder.h b/video/video_decoder.h index 87d832eeb9..9496148de6 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -625,6 +625,13 @@ protected: */ void addTrack(Track *track); + /** + * Whether or not getTime() will sync with a playing audio track. + * + * A subclass should override this to disable this feature. + */ + virtual bool useAudioSync() const { return true; } + private: // Tracks owned by this AdvancedVideoDecoder typedef Common::List TrackList; -- cgit v1.2.3 From 5cdb0f71a499250d36d79d0f8ba85ff2d370f9aa Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 17:30:43 -0400 Subject: VIDEO: Fix AudioTrack::endOfTrack() --- video/video_decoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 3312b2530d..82cba7e6e2 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -414,7 +414,7 @@ Audio::Timestamp AdvancedVideoDecoder::FixedDurationVideoTrack::getDuration() co bool AdvancedVideoDecoder::AudioTrack::endOfTrack() const { Audio::AudioStream *stream = getAudioStream(); - return !stream || (!g_system->getMixer()->isSoundHandleActive(_handle) && stream->endOfData()); + return !stream || !g_system->getMixer()->isSoundHandleActive(_handle) || stream->endOfData(); } void AdvancedVideoDecoder::AudioTrack::setVolume(byte volume) { -- cgit v1.2.3 From 24c97b89138190d211b1f19d5575c9029c0329b2 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 17:31:00 -0400 Subject: VIDEO: Move PSXStreamDecoder to the new VideoDecoder API --- engines/sword1/animation.cpp | 1 + engines/sword2/animation.cpp | 1 + video/psx_decoder.cpp | 256 +++++++++++++++++++++---------------------- video/psx_decoder.h | 112 +++++++++++-------- 4 files changed, 195 insertions(+), 175 deletions(-) diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index ddafd964eb..49c5ef7312 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -189,6 +189,7 @@ bool MoviePlayer::load(uint32 id) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { + ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete return true; } else { initGraphics(g_system->getWidth(), g_system->getHeight(), true); diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 5e3f8929e9..c1cf33ff09 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -99,6 +99,7 @@ bool MoviePlayer::load(const char *name) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { + ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete return true; } else { initGraphics(640, 480, true); diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp index df91a2badd..93bf711c25 100644 --- a/video/psx_decoder.cpp +++ b/video/psx_decoder.cpp @@ -149,22 +149,12 @@ static const uint32 s_huffmanACSymbols[AC_CODE_COUNT] = { END_OF_BLOCK }; -PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) : _nextFrameStartTime(0, speed), _frameCount(frameCount) { +PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) : _speed(speed), _frameCount(frameCount) { _stream = 0; - _audStream = 0; - _surface = new Graphics::Surface(); - _yBuffer = _cbBuffer = _crBuffer = 0; - _acHuffman = new Common::Huffman(0, AC_CODE_COUNT, s_huffmanACCodes, s_huffmanACLengths, s_huffmanACSymbols); - _dcHuffmanChroma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCChromaCodes, s_huffmanDCChromaLengths, s_huffmanDCSymbols); - _dcHuffmanLuma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCLumaCodes, s_huffmanDCLumaLengths, s_huffmanDCSymbols); } PSXStreamDecoder::~PSXStreamDecoder() { close(); - delete _surface; - delete _acHuffman; - delete _dcHuffmanLuma; - delete _dcHuffmanChroma; } #define RAW_CD_SECTOR_SIZE 2352 @@ -178,95 +168,30 @@ bool PSXStreamDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _stream = stream; - - Common::SeekableReadStream *sector = readSector(); - - if (!sector) { - close(); - return false; - } - - // Rip out video info from the first frame - sector->seek(18); - byte sectorType = sector->readByte() & CDXA_TYPE_MASK; - - if (sectorType != CDXA_TYPE_VIDEO && sectorType != CDXA_TYPE_DATA) { - close(); - return false; - } - - sector->seek(40); - - uint16 width = sector->readUint16LE(); - uint16 height = sector->readUint16LE(); - _surface->create(width, height, g_system->getScreenFormat()); - - _macroBlocksW = (width + 15) / 16; - _macroBlocksH = (height + 15) / 16; - _yBuffer = new byte[_macroBlocksW * _macroBlocksH * 16 * 16]; - _cbBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; - _crBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; - - delete sector; - _stream->seek(0); + readNextPacket(); return true; } void PSXStreamDecoder::close() { - if (!_stream) - return; + AdvancedVideoDecoder::close(); + _audioTrack = 0; + _videoTrack = 0; + _frameCount = 0; delete _stream; _stream = 0; - - // Deinitialize sound - g_system->getMixer()->stopHandle(_audHandle); - _audStream = 0; - - _surface->free(); - - memset(&_adpcmStatus, 0, sizeof(_adpcmStatus)); - - _macroBlocksW = _macroBlocksH = 0; - delete[] _yBuffer; _yBuffer = 0; - delete[] _cbBuffer; _cbBuffer = 0; - delete[] _crBuffer; _crBuffer = 0; - - reset(); -} - -uint32 PSXStreamDecoder::getTime() const { - // TODO: Currently, the audio is always after the video so using this - // can often lead to gaps in the audio... - //if (_audStream) - // return _mixer->getSoundElapsedTime(_audHandle); - - return VideoDecoder::getTime(); -} - -uint32 PSXStreamDecoder::getTimeToNextFrame() const { - if (!isVideoLoaded() || endOfVideo()) - return 0; - - uint32 nextTimeMillis = _nextFrameStartTime.msecs(); - uint32 elapsedTime = getTime(); - - if (elapsedTime > nextTimeMillis) - return 0; - - return nextTimeMillis - elapsedTime; } #define VIDEO_DATA_CHUNK_SIZE 2016 #define VIDEO_DATA_HEADER_SIZE 56 -const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { +void PSXStreamDecoder::readNextPacket() { Common::SeekableReadStream *sector = 0; byte *partialFrame = 0; int sectorsRead = 0; - while (!endOfVideo()) { + while (_stream->pos() < _stream->size()) { sector = readSector(); sectorsRead++; @@ -284,6 +209,11 @@ const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { case CDXA_TYPE_DATA: case CDXA_TYPE_VIDEO: if (track == 1) { + if (!_videoTrack) { + _videoTrack = new PSXVideoTrack(sector, _speed, _frameCount); + addTrack(_videoTrack); + } + sector->seek(28); uint16 curSector = sector->readUint16LE(); uint16 sectorCount = sector->readUint16LE(); @@ -303,35 +233,27 @@ const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { // Done assembling the frame Common::SeekableReadStream *frame = new Common::MemoryReadStream(partialFrame, frameSize, DisposeAfterUse::YES); - decodeFrame(frame); + _videoTrack->decodeFrame(frame, sectorsRead); delete frame; delete sector; - - _curFrame++; - if (_curFrame == 0) - _startTime = g_system->getMillis(); - - // Increase the time by the amount of sectors we read - // One may notice that this is still not the most precise - // method since a frame takes up the time its sectors took - // up instead of the amount of time it takes the next frame - // to be read from the sectors. The actual frame rate should - // be constant instead of variable, so the slight difference - // in a frame's showing time is negligible (1/150 of a second). - _nextFrameStartTime = _nextFrameStartTime.addFrames(sectorsRead); - - return _surface; + return; } } else error("Unhandled multi-track video"); break; case CDXA_TYPE_AUDIO: // We only handle one audio channel so far - if (track == 1) - queueAudioFromSector(sector); - else + if (track == 1) { + if (!_audioTrack) { + _audioTrack = new PSXAudioTrack(sector); + addTrack(_audioTrack); + } + + _audioTrack->queueAudioFromSector(sector); + } else { warning("Unhandled multi-track audio"); + } break; default: // This shows up way too often, but the other sectors @@ -343,7 +265,19 @@ const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { delete sector; } - return 0; + if (_stream->pos() >= _stream->size()) { + if (_videoTrack) + _videoTrack->setEndOfTrack(); + + if (_audioTrack) + _audioTrack->setEndOfTrack(); + } +} + +bool PSXStreamDecoder::useAudioSync() const { + // Audio sync is disabled since most audio data comes after video + // data. + return false; } static const byte s_syncHeader[12] = { 0x00, 0xff ,0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; @@ -373,20 +307,29 @@ static const int s_xaTable[5][2] = { { 122, -60 } }; -void PSXStreamDecoder::queueAudioFromSector(Common::SeekableReadStream *sector) { +PSXStreamDecoder::PSXAudioTrack::PSXAudioTrack(Common::SeekableReadStream *sector) { assert(sector); + _endOfTrack = false; - if (!_audStream) { - // Initialize audio stream - sector->seek(19); - byte format = sector->readByte(); + sector->seek(19); + byte format = sector->readByte(); + bool stereo = (format & (1 << 0)) != 0; + uint rate = (format & (1 << 2)) ? 18900 : 37800; + _audStream = Audio::makeQueuingAudioStream(rate, stereo); - bool stereo = (format & (1 << 0)) != 0; - uint rate = (format & (1 << 2)) ? 18900 : 37800; + memset(&_adpcmStatus, 0, sizeof(_adpcmStatus)); +} - _audStream = Audio::makeQueuingAudioStream(rate, stereo); - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream, -1, getVolume(), getBalance()); - } +PSXStreamDecoder::PSXAudioTrack::~PSXAudioTrack() { + delete _audStream; +} + +bool PSXStreamDecoder::PSXAudioTrack::endOfTrack() const { + return AudioTrack::endOfTrack() && _endOfTrack; +} + +void PSXStreamDecoder::PSXAudioTrack::queueAudioFromSector(Common::SeekableReadStream *sector) { + assert(sector); sector->seek(24); @@ -472,7 +415,54 @@ void PSXStreamDecoder::queueAudioFromSector(Common::SeekableReadStream *sector) delete[] buf; } -void PSXStreamDecoder::decodeFrame(Common::SeekableReadStream *frame) { +Audio::AudioStream *PSXStreamDecoder::PSXAudioTrack::getAudioStream() const { + return _audStream; +} + + +PSXStreamDecoder::PSXVideoTrack::PSXVideoTrack(Common::SeekableReadStream *firstSector, CDSpeed speed, int frameCount) : _nextFrameStartTime(0, speed), _frameCount(frameCount) { + assert(firstSector); + + firstSector->seek(40); + uint16 width = firstSector->readUint16LE(); + uint16 height = firstSector->readUint16LE(); + _surface = new Graphics::Surface(); + _surface->create(width, height, g_system->getScreenFormat()); + + _macroBlocksW = (width + 15) / 16; + _macroBlocksH = (height + 15) / 16; + _yBuffer = new byte[_macroBlocksW * _macroBlocksH * 16 * 16]; + _cbBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; + _crBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; + + _endOfTrack = false; + _curFrame = -1; + _acHuffman = new Common::Huffman(0, AC_CODE_COUNT, s_huffmanACCodes, s_huffmanACLengths, s_huffmanACSymbols); + _dcHuffmanChroma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCChromaCodes, s_huffmanDCChromaLengths, s_huffmanDCSymbols); + _dcHuffmanLuma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCLumaCodes, s_huffmanDCLumaLengths, s_huffmanDCSymbols); +} + +PSXStreamDecoder::PSXVideoTrack::~PSXVideoTrack() { + _surface->free(); + delete _surface; + + delete[] _yBuffer; + delete[] _cbBuffer; + delete[] _crBuffer; + delete _acHuffman; + delete _dcHuffmanChroma; + delete _dcHuffmanLuma; +} + +uint32 PSXStreamDecoder::PSXVideoTrack::getNextFrameStartTime() const { + return _nextFrameStartTime.msecs(); +} + +const Graphics::Surface *PSXStreamDecoder::PSXVideoTrack::decodeNextFrame() { + return _surface; +} + +void PSXStreamDecoder::PSXVideoTrack::decodeFrame(Common::SeekableReadStream *frame, uint sectorCount) { // A frame is essentially an MPEG-1 intra frame Common::BitStream16LEMSB bits(frame); @@ -494,9 +484,20 @@ void PSXStreamDecoder::decodeFrame(Common::SeekableReadStream *frame) { // Output data onto the frame Graphics::convertYUV420ToRGB(_surface, _yBuffer, _cbBuffer, _crBuffer, _surface->w, _surface->h, _macroBlocksW * 16, _macroBlocksW * 8); + + _curFrame++; + + // Increase the time by the amount of sectors we read + // One may notice that this is still not the most precise + // method since a frame takes up the time its sectors took + // up instead of the amount of time it takes the next frame + // to be read from the sectors. The actual frame rate should + // be constant instead of variable, so the slight difference + // in a frame's showing time is negligible (1/150 of a second). + _nextFrameStartTime = _nextFrameStartTime.addFrames(sectorCount); } -void PSXStreamDecoder::decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version) { +void PSXStreamDecoder::PSXVideoTrack::decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version) { int pitchY = _macroBlocksW * 16; int pitchC = _macroBlocksW * 8; @@ -533,7 +534,7 @@ static const byte s_quantizationTable[8 * 8] = { 27, 29, 35, 38, 46, 56, 69, 83 }; -void PSXStreamDecoder::dequantizeBlock(int *coefficients, float *block, uint16 scale) { +void PSXStreamDecoder::PSXVideoTrack::dequantizeBlock(int *coefficients, float *block, uint16 scale) { // Dequantize the data, un-zig-zagging as we go along for (int i = 0; i < 8 * 8; i++) { if (i == 0) // Special case for the DC coefficient @@ -543,7 +544,7 @@ void PSXStreamDecoder::dequantizeBlock(int *coefficients, float *block, uint16 s } } -int PSXStreamDecoder::readDC(Common::BitStream *bits, uint16 version, PlaneType plane) { +int PSXStreamDecoder::PSXVideoTrack::readDC(Common::BitStream *bits, uint16 version, PlaneType plane) { // Version 2 just has its coefficient as 10-bits if (version == 2) return readSignedCoefficient(bits); @@ -573,7 +574,7 @@ int PSXStreamDecoder::readDC(Common::BitStream *bits, uint16 version, PlaneType if (count > 63) \ error("PSXStreamDecoder::readAC(): Too many coefficients") -void PSXStreamDecoder::readAC(Common::BitStream *bits, int *block) { +void PSXStreamDecoder::PSXVideoTrack::readAC(Common::BitStream *bits, int *block) { // Clear the block first for (int i = 0; i < 63; i++) block[i] = 0; @@ -608,7 +609,7 @@ void PSXStreamDecoder::readAC(Common::BitStream *bits, int *block) { } } -int PSXStreamDecoder::readSignedCoefficient(Common::BitStream *bits) { +int PSXStreamDecoder::PSXVideoTrack::readSignedCoefficient(Common::BitStream *bits) { uint val = bits->getBits(10); // extend the sign @@ -630,7 +631,7 @@ static const double s_idct8x8[8][8] = { { 0.353553390593274, -0.490392640201615, 0.461939766255643, -0.415734806151273, 0.353553390593273, -0.277785116509801, 0.191341716182545, -0.097545161008064 } }; -void PSXStreamDecoder::idct(float *dequantData, float *result) { +void PSXStreamDecoder::PSXVideoTrack::idct(float *dequantData, float *result) { // IDCT code based on JPEG's IDCT code // TODO: Switch to the integer-based one mentioned in the docs // This is by far the costliest operation here @@ -669,7 +670,7 @@ void PSXStreamDecoder::idct(float *dequantData, float *result) { } } -void PSXStreamDecoder::decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane) { +void PSXStreamDecoder::PSXVideoTrack::decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane) { // Version 2 just has signed 10 bits for DC // Version 3 has them huffman coded int coefficients[8 * 8]; @@ -686,22 +687,13 @@ void PSXStreamDecoder::decodeBlock(Common::BitStream *bits, byte *block, int pit // Now output the data for (int y = 0; y < 8; y++) { - byte *start = block + pitch * y; + byte *dst = block + pitch * y; // Convert the result to be in the range [0, 255] for (int x = 0; x < 8; x++) - *start++ = (int)CLIP(idctData[y * 8 + x], -128.0f, 127.0f) + 128; + *dst++ = (int)CLIP(idctData[y * 8 + x], -128.0f, 127.0f) + 128; } } -void PSXStreamDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audHandle)) - g_system->getMixer()->setChannelVolume(_audHandle, getVolume()); -} - -void PSXStreamDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audHandle)) - g_system->getMixer()->setChannelBalance(_audHandle, getBalance()); -} } // End of namespace Video diff --git a/video/psx_decoder.h b/video/psx_decoder.h index 4364ec4bbb..2a9dedf77f 100644 --- a/video/psx_decoder.h +++ b/video/psx_decoder.h @@ -56,7 +56,7 @@ namespace Video { * - sword1 (psx) * - sword2 (psx) */ -class PSXStreamDecoder : public VideoDecoder { +class PSXStreamDecoder : public AdvancedVideoDecoder { public: // CD speed in sectors/second // Calling code should use these enum values instead of the constants @@ -71,59 +71,85 @@ public: bool loadStream(Common::SeekableReadStream *stream); void close(); - bool isVideoLoaded() const { return _stream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _frameCount; } - uint32 getTime() const; - uint32 getTimeToNextFrame() const; - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return _surface->format; } - bool endOfVideo() const { return _stream->pos() >= _stream->size(); } - protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void readNextPacket(); + bool useAudioSync() const; private: - void initCommon(); - Common::SeekableReadStream *_stream; - Graphics::Surface *_surface; + class PSXVideoTrack : public VideoTrack { + public: + PSXVideoTrack(Common::SeekableReadStream *firstSector, CDSpeed speed, int frameCount); + ~PSXVideoTrack(); + + uint16 getWidth() const { return _surface->w; } + uint16 getHeight() const { return _surface->h; } + Graphics::PixelFormat getPixelFormat() const { return _surface->format; } + bool endOfTrack() const { return _endOfTrack; } + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + uint32 getNextFrameStartTime() const; + const Graphics::Surface *decodeNextFrame(); + + void setEndOfTrack() { _endOfTrack = true; } + void decodeFrame(Common::SeekableReadStream *frame, uint sectorCount); + + private: + Graphics::Surface *_surface; + uint32 _frameCount; + Audio::Timestamp _nextFrameStartTime; + bool _endOfTrack; + int _curFrame; + + enum PlaneType { + kPlaneY = 0, + kPlaneU = 1, + kPlaneV = 2 + }; + + uint16 _macroBlocksW, _macroBlocksH; + byte *_yBuffer, *_cbBuffer, *_crBuffer; + void decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version); + void decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane); + + void readAC(Common::BitStream *bits, int *block); + Common::Huffman *_acHuffman; + + int readDC(Common::BitStream *bits, uint16 version, PlaneType plane); + Common::Huffman *_dcHuffmanLuma, *_dcHuffmanChroma; + int _lastDC[3]; + + void dequantizeBlock(int *coefficients, float *block, uint16 scale); + void idct(float *dequantData, float *result); + int readSignedCoefficient(Common::BitStream *bits); + }; - uint32 _frameCount; - Audio::Timestamp _nextFrameStartTime; + class PSXAudioTrack : public AudioTrack { + public: + PSXAudioTrack(Common::SeekableReadStream *sector); + ~PSXAudioTrack(); - Audio::SoundHandle _audHandle; - Audio::QueuingAudioStream *_audStream; - void queueAudioFromSector(Common::SeekableReadStream *sector); + bool endOfTrack() const; - enum PlaneType { - kPlaneY = 0, - kPlaneU = 1, - kPlaneV = 2 - }; + void setEndOfTrack() { _endOfTrack = true; } + void queueAudioFromSector(Common::SeekableReadStream *sector); - uint16 _macroBlocksW, _macroBlocksH; - byte *_yBuffer, *_cbBuffer, *_crBuffer; - void decodeFrame(Common::SeekableReadStream *frame); - void decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version); - void decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane); + private: + Audio::AudioStream *getAudioStream() const; - void readAC(Common::BitStream *bits, int *block); - Common::Huffman *_acHuffman; + Audio::QueuingAudioStream *_audStream; - int readDC(Common::BitStream *bits, uint16 version, PlaneType plane); - Common::Huffman *_dcHuffmanLuma, *_dcHuffmanChroma; - int _lastDC[3]; + struct ADPCMStatus { + int16 sample[2]; + } _adpcmStatus[2]; - void dequantizeBlock(int *coefficients, float *block, uint16 scale); - void idct(float *dequantData, float *result); - int readSignedCoefficient(Common::BitStream *bits); + bool _endOfTrack; + }; - struct ADPCMStatus { - int16 sample[2]; - } _adpcmStatus[2]; + CDSpeed _speed; + uint32 _frameCount; + Common::SeekableReadStream *_stream; + PSXVideoTrack *_videoTrack; + PSXAudioTrack *_audioTrack; Common::SeekableReadStream *readSector(); }; -- cgit v1.2.3 From 144b9ce9189260973994ca83b6e2b29126ef269a Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 17:38:24 -0400 Subject: VIDEO: Don't try to sync video off of finished audio tracks --- video/video_decoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 82cba7e6e2..3cce2dea02 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -196,7 +196,7 @@ uint32 AdvancedVideoDecoder::getTime() const { if (useAudioSync()) { for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { - if ((*it)->getTrackType() == Track::kTrackTypeAudio) { + if ((*it)->getTrackType() == Track::kTrackTypeAudio && !(*it)->endOfTrack()) { uint32 time = ((const AudioTrack *)*it)->getRunningTime(); if (time != 0) -- cgit v1.2.3 From 067e02e90b7fbe3406cbc7b5b08d63ae281b360c Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 21 Jul 2012 17:52:16 -0400 Subject: VIDEO: Add StreamFileAudioTrack wrapper --- video/video_decoder.cpp | 15 +++++++++++++++ video/video_decoder.h | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 3cce2dea02..4ac914927e 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -486,6 +486,21 @@ bool AdvancedVideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time return stream->seek(time); } +AdvancedVideoDecoder::StreamFileAudioTrack::StreamFileAudioTrack() { + _stream = 0; +} + +AdvancedVideoDecoder::StreamFileAudioTrack::~StreamFileAudioTrack() { + delete _stream; +} + +bool AdvancedVideoDecoder::StreamFileAudioTrack::loadFromFile(const Common::String &baseName) { + // TODO: Make sure the stream isn't being played + delete _stream; + _stream = Audio::SeekableAudioStream::openStreamFile(baseName); + return _stream != 0; +} + void AdvancedVideoDecoder::addTrack(Track *track) { _tracks.push_back(track); diff --git a/video/video_decoder.h b/video/video_decoder.h index 9496148de6..3e991ade66 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -609,6 +609,27 @@ protected: virtual Audio::SeekableAudioStream *getSeekableAudioStream() const = 0; }; + /** + * A SeekableAudioTrack that constructs its SeekableAudioStream using + * SeekableAudioStream::openStreamFile() + */ + class StreamFileAudioTrack : public SeekableAudioTrack { + public: + StreamFileAudioTrack(); + ~StreamFileAudioTrack(); + + /** + * Load the track from a file with the given base name. + * + * @return true on success, false otherwise + */ + bool loadFromFile(const Common::String &baseName); + + protected: + Audio::SeekableAudioStream *_stream; + Audio::SeekableAudioStream *getSeekableAudioStream() const { return _stream; } + }; + /** * Decode enough data for the next frame and enough audio to last that long. * -- cgit v1.2.3 From 4c9c22b374569e9f93b30137b57eaa2912beffc4 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 22 Jul 2012 00:39:10 -0400 Subject: VIDEO: Make seek/rewind functions in AdvancedVideoDecoder virtual This is to allow for seeking in videos where not everything is indexed --- video/video_decoder.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/video/video_decoder.h b/video/video_decoder.h index 3e991ade66..3d8b09f26e 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -306,33 +306,37 @@ public: // New API /** - * Returns if a video is rewindable or not. + * Returns if a video is rewindable or not. The default implementation + * polls each track for rewindability. */ - bool isRewindable() const; + virtual bool isRewindable() const; /** * Rewind a video to its beginning. * - * If the video is playing, it will continue to play. + * If the video is playing, it will continue to play. The default + * implementation will rewind each track. * * @return true on success, false otherwise */ - bool rewind(); + virtual bool rewind(); /** - * Returns if a video is seekable or not. + * Returns if a video is seekable or not. The default implementation + * polls each track for seekability. */ - bool isSeekable() const; + virtual bool isSeekable() const; /** * Seek to a given time in the video. * - * If the video is playing, it will continue to play. + * If the video is playing, it will continue to play. The default + * implementation will seek each track. * * @param time The time to seek to * @return true on success, false otherwise */ - bool seek(const Audio::Timestamp &time); + virtual bool seek(const Audio::Timestamp &time); /** * Begin playback of the video. -- cgit v1.2.3 From 9bf17934d3fb6ab30c64dd87dfed1e5f154bca51 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 22 Jul 2012 00:58:38 -0400 Subject: VIDEO: Take audio start time into account when syncing to audio --- video/video_decoder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 4ac914927e..5946a7d79c 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -200,7 +200,7 @@ uint32 AdvancedVideoDecoder::getTime() const { uint32 time = ((const AudioTrack *)*it)->getRunningTime(); if (time != 0) - return time + _audioStartOffset.msecs(); + return time + (*it)->getStartTime().msecs() + _audioStartOffset.msecs(); } } } -- cgit v1.2.3 From 29541dc5f4dd492f7443463f709a5c6396dab9d8 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 22 Jul 2012 12:17:54 -0400 Subject: VIDEO: Hold tracks in an Array instead of a List Decoders such as AVI will need to access them by index --- video/video_decoder.cpp | 14 ++++++++++++++ video/video_decoder.h | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 5946a7d79c..b2fcdda04c 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -519,6 +519,20 @@ void AdvancedVideoDecoder::addTrack(Track *track) { track->start(); } +AdvancedVideoDecoder::Track *AdvancedVideoDecoder::getTrack(uint track) { + if (track > _tracks.size()) + return 0; + + return _tracks[track]; +} + +const AdvancedVideoDecoder::Track *AdvancedVideoDecoder::getTrack(uint track) const { + if (track > _tracks.size()) + return 0; + + return _tracks[track]; +} + AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() { VideoTrack *bestTrack = 0; uint32 bestTime = 0xFFFFFFFF; diff --git a/video/video_decoder.h b/video/video_decoder.h index 3d8b09f26e..2a5eebfc60 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -25,7 +25,7 @@ #include "audio/mixer.h" #include "audio/timestamp.h" // TODO: Move this to common/ ? -#include "common/list.h" +#include "common/array.h" #include "common/str.h" namespace Audio { @@ -657,9 +657,23 @@ protected: */ virtual bool useAudioSync() const { return true; } + /** + * Get the given track based on its index. + * + * @return A valid track pointer on success, 0 otherwise + */ + Track *getTrack(uint track); + + /** + * Get the given track based on its index + * + * @return A valid track pointer on success, 0 otherwise + */ + const Track *getTrack(uint track) const; + private: // Tracks owned by this AdvancedVideoDecoder - typedef Common::List TrackList; + typedef Common::Array TrackList; TrackList _tracks; VideoTrack *findNextVideoTrack(); const VideoTrack *findNextVideoTrack() const; -- cgit v1.2.3 From 7654b2036268bb56f3b08b88858f2a9e4862b056 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 22 Jul 2012 14:11:11 -0400 Subject: VIDEO: Merge the three Fixed* VideoTrack classes Avoids diamond inheritance, which makes it impossible to downcast without rtti --- engines/sci/video/seq_decoder.h | 2 +- video/video_decoder.cpp | 4 ++-- video/video_decoder.h | 30 +++++------------------------- 3 files changed, 8 insertions(+), 28 deletions(-) diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h index 75d7ce6c3d..82254990d6 100644 --- a/engines/sci/video/seq_decoder.h +++ b/engines/sci/video/seq_decoder.h @@ -48,7 +48,7 @@ public: bool loadStream(Common::SeekableReadStream *stream); private: - class SEQVideoTrack : public FixedDurationVideoTrack { + class SEQVideoTrack : public FixedRateVideoTrack { public: SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay); ~SEQVideoTrack(); diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index b2fcdda04c..ad176da73b 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -400,11 +400,11 @@ uint32 AdvancedVideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const return time.toInt(); } -bool AdvancedVideoDecoder::FixedLengthVideoTrack::endOfTrack() const { +bool AdvancedVideoDecoder::FixedRateVideoTrack::endOfTrack() const { return getCurFrame() >= (getFrameCount() - 1); } -Audio::Timestamp AdvancedVideoDecoder::FixedDurationVideoTrack::getDuration() const { +Audio::Timestamp AdvancedVideoDecoder::FixedRateVideoTrack::getDuration() const { // Since Audio::Timestamp doesn't support a fractional frame rate, we're currently // just converting to milliseconds. Common::Rational time = getFrameCount() * 1000; diff --git a/video/video_decoder.h b/video/video_decoder.h index 2a5eebfc60..efc8f7a37d 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -499,13 +499,17 @@ protected: /** * A VideoTrack that is played at a constant rate. + * + * If the frame count is unknown, you must override endOfTrack(). */ - class FixedRateVideoTrack : public virtual VideoTrack { + class FixedRateVideoTrack : public VideoTrack { public: FixedRateVideoTrack() {} virtual ~FixedRateVideoTrack() {} + virtual bool endOfTrack() const; uint32 getNextFrameStartTime() const; + virtual Audio::Timestamp getDuration() const; protected: /** @@ -514,30 +518,6 @@ protected: virtual Common::Rational getFrameRate() const = 0; }; - /** - * A VideoTrack with a known frame count that can be reliably - * used to figure out if the track has finished. - */ - class FixedLengthVideoTrack : public virtual VideoTrack { - public: - FixedLengthVideoTrack() {} - virtual ~FixedLengthVideoTrack() {} - - bool endOfTrack() const; - }; - - /** - * A FixedRateVideoTrack and FixedLengthVideoTrack that implements the getDuration() - * function. - */ - class FixedDurationVideoTrack : public FixedRateVideoTrack, public FixedLengthVideoTrack { - public: - FixedDurationVideoTrack() {} - virtual ~FixedDurationVideoTrack() {} - - virtual Audio::Timestamp getDuration() const; - }; - /** * An abstract representation of an audio track. */ -- cgit v1.2.3 From 0f0c6f935443212d76422959d040b87fc78d02c7 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 22 Jul 2012 14:13:20 -0400 Subject: VIDEO: Rewrite the AVI code to use AdvancedVideoDecoder In addition to using the new API, it should theoretically support multiple audio and video tracks now but that has not been tested. --- engines/sci/console.cpp | 6 +- engines/sci/engine/kvideo.cpp | 7 +- video/avi_decoder.cpp | 554 +++++++++++++++++++++--------------------- video/avi_decoder.h | 317 ++++++++++++------------ 4 files changed, 441 insertions(+), 443 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 2a4ad1743d..a6a6d4496f 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -259,10 +259,12 @@ void Console::postEnter() { videoDecoder = new RobotDecoder(g_system->getMixer(), _engine->getPlatform() == Common::kPlatformMacintosh); } else if (_videoFile.hasSuffix(".duk")) { duckMode = true; - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); #endif } else if (_videoFile.hasSuffix(".avi")) { - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); } else { warning("Unrecognized video type"); } diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index bfe32a8d82..2c1532cc46 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -191,7 +191,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case 0: { Common::String filename = s->_segMan->getString(argv[1]); - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); if (filename.equalsIgnoreCase("gk2a.avi")) { // HACK: Switch to 16bpp graphics for Indeo3. @@ -212,6 +212,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { videoDecoder = 0; } else { s->_videoState.fileName = filename; + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); } break; } @@ -407,13 +408,15 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) { s->_videoState.reset(); s->_videoState.fileName = Common::String::format("%d.duk", argv[1].toUint16()); - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); if (!videoDecoder->loadFile(s->_videoState.fileName)) { warning("Could not open Duck %s", s->_videoState.fileName.c_str()); break; } + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); + if (reshowCursor) g_sci->_gfxCursor->kernelHide(); diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 2ea7e8d90e..375cc6f0f3 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -42,106 +42,128 @@ namespace Video { -/* +#define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a)) + +// IDs used throughout the AVI files +// that will be handled by this player +#define ID_RIFF MKTAG('R','I','F','F') +#define ID_AVI MKTAG('A','V','I',' ') +#define ID_LIST MKTAG('L','I','S','T') +#define ID_HDRL MKTAG('h','d','r','l') +#define ID_AVIH MKTAG('a','v','i','h') +#define ID_STRL MKTAG('s','t','r','l') +#define ID_STRH MKTAG('s','t','r','h') +#define ID_VIDS MKTAG('v','i','d','s') +#define ID_AUDS MKTAG('a','u','d','s') +#define ID_MIDS MKTAG('m','i','d','s') +#define ID_TXTS MKTAG('t','x','t','s') +#define ID_JUNK MKTAG('J','U','N','K') +#define ID_STRF MKTAG('s','t','r','f') +#define ID_MOVI MKTAG('m','o','v','i') +#define ID_REC MKTAG('r','e','c',' ') +#define ID_VEDT MKTAG('v','e','d','t') +#define ID_IDX1 MKTAG('i','d','x','1') +#define ID_STRD MKTAG('s','t','r','d') +#define ID_00AM MKTAG('0','0','A','M') +//#define ID_INFO MKTAG('I','N','F','O') + +// Codec tags +#define ID_RLE MKTAG('R','L','E',' ') +#define ID_CRAM MKTAG('C','R','A','M') +#define ID_MSVC MKTAG('m','s','v','c') +#define ID_WHAM MKTAG('W','H','A','M') +#define ID_CVID MKTAG('c','v','i','d') +#define ID_IV32 MKTAG('i','v','3','2') +#define ID_DUCK MKTAG('D','U','C','K') + static byte char2num(char c) { - return (c >= 48 && c <= 57) ? c - 48 : 0; + c = tolower((byte)c); + return (c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - '0'; } -static byte getStreamNum(uint32 tag) { - return char2num((char)(tag >> 24)) * 16 + char2num((char)(tag >> 16)); +static byte getStreamIndex(uint32 tag) { + return char2num((tag >> 24) & 0xFF) << 4 | char2num((tag >> 16) & 0xFF); } -*/ static uint16 getStreamType(uint32 tag) { return tag & 0xffff; } -AviDecoder::AviDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) { - _soundType = soundType; - - _videoCodec = NULL; +AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { _decodedHeader = false; - _audStream = NULL; - _fileStream = NULL; - _audHandle = new Audio::SoundHandle(); - _dirtyPalette = false; - memset(_palette, 0, sizeof(_palette)); - memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT)); - memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER)); - memset(&_vidsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_audsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_ixInfo, 0, sizeof(AVIOLDINDEX)); + _fileStream = 0; + memset(&_ixInfo, 0, sizeof(_ixInfo)); + memset(&_header, 0, sizeof(_header)); } -AviDecoder::~AviDecoder() { +AVIDecoder::~AVIDecoder() { close(); - delete _audHandle; } -void AviDecoder::runHandle(uint32 tag) { - assert (_fileStream); +void AVIDecoder::runHandle(uint32 tag) { + assert(_fileStream); if (_fileStream->eos()) return; - debug (3, "Decoding tag %s", tag2str(tag)); + debug(3, "Decoding tag %s", tag2str(tag)); switch (tag) { - case ID_RIFF: - /*_filesize = */_fileStream->readUint32LE(); - if (_fileStream->readUint32BE() != ID_AVI) - error("RIFF file is not an AVI video"); - break; - case ID_LIST: - handleList(); - break; - case ID_AVIH: - _header.size = _fileStream->readUint32LE(); - _header.microSecondsPerFrame = _fileStream->readUint32LE(); - _header.maxBytesPerSecond = _fileStream->readUint32LE(); - _header.padding = _fileStream->readUint32LE(); - _header.flags = _fileStream->readUint32LE(); - _header.totalFrames = _fileStream->readUint32LE(); - _header.initialFrames = _fileStream->readUint32LE(); - _header.streams = _fileStream->readUint32LE(); - _header.bufferSize = _fileStream->readUint32LE(); - _header.width = _fileStream->readUint32LE(); - _header.height = _fileStream->readUint32LE(); - //Ignore 16 bytes of reserved data - _fileStream->skip(16); - break; - case ID_STRH: - handleStreamHeader(); - break; - case ID_STRD: // Extra stream info, safe to ignore - case ID_VEDT: // Unknown, safe to ignore - case ID_JUNK: // Alignment bytes, should be ignored - { - uint32 junkSize = _fileStream->readUint32LE(); - _fileStream->skip(junkSize + (junkSize & 1)); // Alignment - } break; - case ID_IDX1: - _ixInfo.size = _fileStream->readUint32LE(); - _ixInfo.indices = new AVIOLDINDEX::Index[_ixInfo.size / 16]; - debug (0, "%d Indices", (_ixInfo.size / 16)); - for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { - _ixInfo.indices[i].id = _fileStream->readUint32BE(); - _ixInfo.indices[i].flags = _fileStream->readUint32LE(); - _ixInfo.indices[i].offset = _fileStream->readUint32LE(); - _ixInfo.indices[i].size = _fileStream->readUint32LE(); - debug (0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); - } - break; - default: - error ("Unknown tag \'%s\' found", tag2str(tag)); + case ID_RIFF: + /*_filesize = */_fileStream->readUint32LE(); + if (_fileStream->readUint32BE() != ID_AVI) + error("RIFF file is not an AVI video"); + break; + case ID_LIST: + handleList(); + break; + case ID_AVIH: + _header.size = _fileStream->readUint32LE(); + _header.microSecondsPerFrame = _fileStream->readUint32LE(); + _header.maxBytesPerSecond = _fileStream->readUint32LE(); + _header.padding = _fileStream->readUint32LE(); + _header.flags = _fileStream->readUint32LE(); + _header.totalFrames = _fileStream->readUint32LE(); + _header.initialFrames = _fileStream->readUint32LE(); + _header.streams = _fileStream->readUint32LE(); + _header.bufferSize = _fileStream->readUint32LE(); + _header.width = _fileStream->readUint32LE(); + _header.height = _fileStream->readUint32LE(); + // Ignore 16 bytes of reserved data + _fileStream->skip(16); + break; + case ID_STRH: + handleStreamHeader(); + break; + case ID_STRD: // Extra stream info, safe to ignore + case ID_VEDT: // Unknown, safe to ignore + case ID_JUNK: // Alignment bytes, should be ignored + { + uint32 junkSize = _fileStream->readUint32LE(); + _fileStream->skip(junkSize + (junkSize & 1)); // Alignment + } break; + case ID_IDX1: + _ixInfo.size = _fileStream->readUint32LE(); + _ixInfo.indices = new OldIndex::Index[_ixInfo.size / 16]; + debug(0, "%d Indices", (_ixInfo.size / 16)); + for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { + _ixInfo.indices[i].id = _fileStream->readUint32BE(); + _ixInfo.indices[i].flags = _fileStream->readUint32LE(); + _ixInfo.indices[i].offset = _fileStream->readUint32LE(); + _ixInfo.indices[i].size = _fileStream->readUint32LE(); + debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); + } + break; + default: + error("Unknown tag \'%s\' found", tag2str(tag)); } } -void AviDecoder::handleList() { +void AVIDecoder::handleList() { uint32 listSize = _fileStream->readUint32LE() - 4; // Subtract away listType's 4 bytes uint32 listType = _fileStream->readUint32BE(); uint32 curPos = _fileStream->pos(); - debug (0, "Found LIST of type %s", tag2str(listType)); + debug(0, "Found LIST of type %s", tag2str(listType)); while ((_fileStream->pos() - curPos) < listSize) runHandle(_fileStream->readUint32BE()); @@ -151,12 +173,14 @@ void AviDecoder::handleList() { _decodedHeader = true; } -void AviDecoder::handleStreamHeader() { +void AVIDecoder::handleStreamHeader() { AVIStreamHeader sHeader; sHeader.size = _fileStream->readUint32LE(); sHeader.streamType = _fileStream->readUint32BE(); + if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) - error ("Unhandled MIDI/Text stream"); + error("Unhandled MIDI/Text stream"); + sHeader.streamHandler = _fileStream->readUint32BE(); sHeader.flags = _fileStream->readUint32LE(); sHeader.priority = _fileStream->readUint16LE(); @@ -174,63 +198,67 @@ void AviDecoder::handleStreamHeader() { if (_fileStream->readUint32BE() != ID_STRF) error("Could not find STRF tag"); + uint32 strfSize = _fileStream->readUint32LE(); uint32 startPos = _fileStream->pos(); if (sHeader.streamType == ID_VIDS) { - _vidsHeader = sHeader; - - _bmInfo.size = _fileStream->readUint32LE(); - _bmInfo.width = _fileStream->readUint32LE(); - assert (_header.width == _bmInfo.width); - _bmInfo.height = _fileStream->readUint32LE(); - assert (_header.height == _bmInfo.height); - _bmInfo.planes = _fileStream->readUint16LE(); - _bmInfo.bitCount = _fileStream->readUint16LE(); - _bmInfo.compression = _fileStream->readUint32BE(); - _bmInfo.sizeImage = _fileStream->readUint32LE(); - _bmInfo.xPelsPerMeter = _fileStream->readUint32LE(); - _bmInfo.yPelsPerMeter = _fileStream->readUint32LE(); - _bmInfo.clrUsed = _fileStream->readUint32LE(); - _bmInfo.clrImportant = _fileStream->readUint32LE(); - - if (_bmInfo.bitCount == 8) { - if (_bmInfo.clrUsed == 0) - _bmInfo.clrUsed = 256; - - for (uint32 i = 0; i < _bmInfo.clrUsed; i++) { - _palette[i * 3 + 2] = _fileStream->readByte(); - _palette[i * 3 + 1] = _fileStream->readByte(); - _palette[i * 3] = _fileStream->readByte(); + BitmapInfoHeader bmInfo; + bmInfo.size = _fileStream->readUint32LE(); + bmInfo.width = _fileStream->readUint32LE(); + bmInfo.height = _fileStream->readUint32LE(); + bmInfo.planes = _fileStream->readUint16LE(); + bmInfo.bitCount = _fileStream->readUint16LE(); + bmInfo.compression = _fileStream->readUint32BE(); + bmInfo.sizeImage = _fileStream->readUint32LE(); + bmInfo.xPelsPerMeter = _fileStream->readUint32LE(); + bmInfo.yPelsPerMeter = _fileStream->readUint32LE(); + bmInfo.clrUsed = _fileStream->readUint32LE(); + bmInfo.clrImportant = _fileStream->readUint32LE(); + + if (bmInfo.clrUsed == 0) + bmInfo.clrUsed = 256; + + if (sHeader.streamHandler == 0) + sHeader.streamHandler = bmInfo.compression; + + AVIVideoTrack *track = new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo); + + if (bmInfo.bitCount == 8) { + byte *palette = const_cast(track->getPalette()); + for (uint32 i = 0; i < bmInfo.clrUsed; i++) { + palette[i * 3 + 2] = _fileStream->readByte(); + palette[i * 3 + 1] = _fileStream->readByte(); + palette[i * 3] = _fileStream->readByte(); _fileStream->readByte(); } - _dirtyPalette = true; + track->markPaletteDirty(); } - if (!_vidsHeader.streamHandler) - _vidsHeader.streamHandler = _bmInfo.compression; + addTrack(track); } else if (sHeader.streamType == ID_AUDS) { - _audsHeader = sHeader; - - _wvInfo.tag = _fileStream->readUint16LE(); - _wvInfo.channels = _fileStream->readUint16LE(); - _wvInfo.samplesPerSec = _fileStream->readUint32LE(); - _wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); - _wvInfo.blockAlign = _fileStream->readUint16LE(); - _wvInfo.size = _fileStream->readUint16LE(); + PCMWaveFormat wvInfo; + wvInfo.tag = _fileStream->readUint16LE(); + wvInfo.channels = _fileStream->readUint16LE(); + wvInfo.samplesPerSec = _fileStream->readUint32LE(); + wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); + wvInfo.blockAlign = _fileStream->readUint16LE(); + wvInfo.size = _fileStream->readUint16LE(); // AVI seems to treat the sampleSize as including the second // channel as well, so divide for our sake. - if (_wvInfo.channels == 2) - _audsHeader.sampleSize /= 2; + if (wvInfo.channels == 2) + sHeader.sampleSize /= 2; + + addTrack(new AVIAudioTrack(sHeader, wvInfo, _soundType)); } // Ensure that we're at the end of the chunk _fileStream->seek(startPos + strfSize); } -bool AviDecoder::loadStream(Common::SeekableReadStream *stream) { +bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _fileStream = stream; @@ -252,74 +280,31 @@ bool AviDecoder::loadStream(Common::SeekableReadStream *stream) { if (nextTag == ID_LIST) { _fileStream->readUint32BE(); // Skip size if (_fileStream->readUint32BE() != ID_MOVI) - error ("Expected 'movi' LIST"); - } else - error ("Expected 'movi' LIST"); - - // Now, create the codec - _videoCodec = createCodec(); - - // Initialize the video stuff too - _audStream = createAudioStream(); - if (_audStream) - _mixer->playStream(_soundType, _audHandle, _audStream, -1, getVolume(), getBalance()); - - debug (0, "Frames = %d, Dimensions = %d x %d", _header.totalFrames, _header.width, _header.height); - debug (0, "Frame Rate = %d", _vidsHeader.rate / _vidsHeader.scale); - if (_wvInfo.samplesPerSec != 0) - debug (0, "Sound Rate = %d", _wvInfo.samplesPerSec); - debug (0, "Video Codec = \'%s\'", tag2str(_vidsHeader.streamHandler)); - - if (!_videoCodec) - return false; + error("Expected 'movi' LIST"); + } else { + error("Expected 'movi' LIST"); + } return true; } -void AviDecoder::close() { - if (!_fileStream) - return; +void AVIDecoder::close() { + AdvancedVideoDecoder::close(); delete _fileStream; _fileStream = 0; - - // Deinitialize sound - _mixer->stopHandle(*_audHandle); - _audStream = 0; - _decodedHeader = false; - delete _videoCodec; - _videoCodec = 0; - delete[] _ixInfo.indices; - _ixInfo.indices = 0; - - memset(_palette, 0, sizeof(_palette)); - memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT)); - memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER)); - memset(&_vidsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_audsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_ixInfo, 0, sizeof(AVIOLDINDEX)); - - reset(); -} - -uint32 AviDecoder::getTime() const { - if (_audStream) - return _mixer->getSoundElapsedTime(*_audHandle); - - return FixedRateVideoDecoder::getTime(); + memset(&_ixInfo, 0, sizeof(_ixInfo)); + memset(&_header, 0, sizeof(_header)); } -const Graphics::Surface *AviDecoder::decodeNextFrame() { +void AVIDecoder::readNextPacket() { uint32 nextTag = _fileStream->readUint32BE(); if (_fileStream->eos()) - return NULL; - - if (_curFrame == -1) - _startTime = g_system->getMillis(); + return; if (nextTag == ID_LIST) { // A list of audio/video chunks @@ -327,138 +312,159 @@ const Graphics::Surface *AviDecoder::decodeNextFrame() { int32 startPos = _fileStream->pos(); if (_fileStream->readUint32BE() != ID_REC) - error ("Expected 'rec ' LIST"); - - // Decode chunks in the list and see if we get a frame - const Graphics::Surface *frame = NULL; - while (_fileStream->pos() < startPos + (int32)listSize) { - const Graphics::Surface *temp = decodeNextFrame(); - if (temp) - frame = temp; - } + error("Expected 'rec ' LIST"); - return frame; - } else if (getStreamType(nextTag) == 'wb') { - // Audio Chunk - uint32 chunkSize = _fileStream->readUint32LE(); - queueAudioBuffer(chunkSize); - _fileStream->skip(chunkSize & 1); // Alignment - } else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id' || - getStreamType(nextTag) == 'AM' || getStreamType(nextTag) == '32' || - getStreamType(nextTag) == 'iv') { - // Compressed Frame - _curFrame++; - uint32 chunkSize = _fileStream->readUint32LE(); - - if (chunkSize == 0) // Keep last frame on screen - return NULL; - - Common::SeekableReadStream *frameData = _fileStream->readStream(chunkSize); - const Graphics::Surface *surface = _videoCodec->decodeImage(frameData); - delete frameData; - _fileStream->skip(chunkSize & 1); // Alignment - return surface; - } else if (getStreamType(nextTag) == 'pc') { - // Palette Change - _fileStream->readUint32LE(); // Chunk size, not needed here - byte firstEntry = _fileStream->readByte(); - uint16 numEntries = _fileStream->readByte(); - _fileStream->readUint16LE(); // Reserved - - // 0 entries means all colors are going to be changed - if (numEntries == 0) - numEntries = 256; - - for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { - _palette[i * 3] = _fileStream->readByte(); - _palette[i * 3 + 1] = _fileStream->readByte(); - _palette[i * 3 + 2] = _fileStream->readByte(); - _fileStream->readByte(); // Flags that don't serve us any purpose - } + // Decode chunks in the list + while (_fileStream->pos() < startPos + (int32)listSize) + readNextPacket(); - _dirtyPalette = true; + return; + } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { + runHandle(nextTag); + return; + } - // No alignment necessary. It's always even. - } else if (nextTag == ID_JUNK) { - runHandle(ID_JUNK); - } else if (nextTag == ID_IDX1) { - runHandle(ID_IDX1); - } else - error("Tag = \'%s\', %d", tag2str(nextTag), _fileStream->pos()); + Track *track = getTrack(getStreamIndex(nextTag)); - return NULL; -} + if (!track) + error("Cannot get track from tag '%s'", tag2str(nextTag)); -Codec *AviDecoder::createCodec() { - switch (_vidsHeader.streamHandler) { - case ID_CRAM: - case ID_MSVC: - case ID_WHAM: - return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); - case ID_RLE: - return new MSRLEDecoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); - case ID_CVID: - return new CinepakDecoder(_bmInfo.bitCount); - case ID_IV32: - return new Indeo3Decoder(_bmInfo.width, _bmInfo.height); -#ifdef VIDEO_CODECS_TRUEMOTION1_H - case ID_DUCK: - return new TrueMotion1Decoder(_bmInfo.width, _bmInfo.height); -#endif - default: - warning ("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); + uint32 chunkSize = _fileStream->readUint32LE(); + Common::SeekableReadStream *chunk = _fileStream->readStream(chunkSize); + _fileStream->skip(chunkSize & 1); + + if (track->getTrackType() == Track::kTrackTypeAudio) { + if (getStreamType(nextTag) != 'wb') + error("Invalid audio track tag '%s'", tag2str(nextTag)); + + ((AVIAudioTrack *)track)->queueSound(chunk); + } else { + AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; + + if (getStreamType(nextTag) == 'pc') { + // Palette Change + byte firstEntry = chunk->readByte(); + uint16 numEntries = chunk->readByte(); + chunk->readUint16LE(); // Reserved + + // 0 entries means all colors are going to be changed + if (numEntries == 0) + numEntries = 256; + + byte *palette = const_cast(videoTrack->getPalette()); + + for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { + palette[i * 3] = chunk->readByte(); + palette[i * 3 + 1] = chunk->readByte(); + palette[i * 3 + 2] = chunk->readByte(); + chunk->readByte(); // Flags that don't serve us any purpose + } + + delete chunk; + videoTrack->markPaletteDirty(); + } else if (getStreamType(nextTag) == 'db') { + // TODO: Check if this really is uncompressed. Many videos + // falsely put compressed data in here. + error("Uncompressed AVI frame found"); + } else { + // Otherwise, assume it's a compressed frame + videoTrack->decodeFrame(chunk); + } } +} - return NULL; +AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader) + : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader) { + memset(_palette, 0, sizeof(_palette)); + _videoCodec = createCodec(); + _dirtyPalette = false; + _lastFrame = 0; + _curFrame = -1; } -Graphics::PixelFormat AviDecoder::getPixelFormat() const { - assert(_videoCodec); - return _videoCodec->getPixelFormat(); +AVIDecoder::AVIVideoTrack::~AVIVideoTrack() { + delete _videoCodec; } -Audio::QueuingAudioStream *AviDecoder::createAudioStream() { - if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatDK3) - return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2); - else if (_wvInfo.tag != kWaveFormatNone) // No sound - warning("Unsupported AVI audio format %d", _wvInfo.tag); +void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) { + if (_videoCodec) + _lastFrame = _videoCodec->decodeImage(stream); - return NULL; + delete stream; + _curFrame++; } -void AviDecoder::queueAudioBuffer(uint32 chunkSize) { - // Return if we haven't created the queue (unsupported audio format) - if (!_audStream) { - _fileStream->skip(chunkSize); - return; +Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const { + if (_videoCodec) + return _videoCodec->getPixelFormat(); + + return Graphics::PixelFormat(); +} + +Codec *AVIDecoder::AVIVideoTrack::createCodec() { + switch (_vidsHeader.streamHandler) { + case ID_CRAM: + case ID_MSVC: + case ID_WHAM: + return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); + case ID_RLE: + return new MSRLEDecoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); + case ID_CVID: + return new CinepakDecoder(_bmInfo.bitCount); + case ID_IV32: + return new Indeo3Decoder(_bmInfo.width, _bmInfo.height); +#ifdef VIDEO_CODECS_TRUEMOTION1_H + case ID_DUCK: + return new TrueMotion1Decoder(_bmInfo.width, _bmInfo.height); +#endif + default: + warning("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); } - Common::SeekableReadStream *stream = _fileStream->readStream(chunkSize); + return 0; +} - if (_wvInfo.tag == kWaveFormatPCM) { - byte flags = 0; - if (_audsHeader.sampleSize == 2) - flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN; - else - flags |= Audio::FLAG_UNSIGNED; +AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) + : _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType) { + _audStream = createAudioStream(); +} - if (_wvInfo.channels == 2) - flags |= Audio::FLAG_STEREO; +AVIDecoder::AVIAudioTrack::~AVIAudioTrack() { + delete _audStream; +} - _audStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES); - } else if (_wvInfo.tag == kWaveFormatDK3) { - _audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, chunkSize, Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES); +void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) { + if (_audStream) { + if (_wvInfo.tag == kWaveFormatPCM) { + byte flags = 0; + if (_audsHeader.sampleSize == 2) + flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN; + else + flags |= Audio::FLAG_UNSIGNED; + + if (_wvInfo.channels == 2) + flags |= Audio::FLAG_STEREO; + + _audStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES); + } else if (_wvInfo.tag == kWaveFormatDK3) { + _audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES); + } + } else { + delete stream; } } -void AviDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelVolume(*_audHandle, getVolume()); +Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const { + return _audStream; } -void AviDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelBalance(*_audHandle, getBalance()); +Audio::QueuingAudioStream *AVIDecoder::AVIAudioTrack::createAudioStream() { + if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatDK3) + return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2); + else if (_wvInfo.tag != kWaveFormatNone) // No sound + warning("Unsupported AVI audio format %d", _wvInfo.tag); + + return 0; } } // End of namespace Video diff --git a/video/avi_decoder.h b/video/avi_decoder.h index fb4dae6711..010702cce3 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -47,196 +47,183 @@ namespace Video { class Codec; -#define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a)) - -// IDs used throughout the AVI files -// that will be handled by this player -#define ID_RIFF MKTAG('R','I','F','F') -#define ID_AVI MKTAG('A','V','I',' ') -#define ID_LIST MKTAG('L','I','S','T') -#define ID_HDRL MKTAG('h','d','r','l') -#define ID_AVIH MKTAG('a','v','i','h') -#define ID_STRL MKTAG('s','t','r','l') -#define ID_STRH MKTAG('s','t','r','h') -#define ID_VIDS MKTAG('v','i','d','s') -#define ID_AUDS MKTAG('a','u','d','s') -#define ID_MIDS MKTAG('m','i','d','s') -#define ID_TXTS MKTAG('t','x','t','s') -#define ID_JUNK MKTAG('J','U','N','K') -#define ID_STRF MKTAG('s','t','r','f') -#define ID_MOVI MKTAG('m','o','v','i') -#define ID_REC MKTAG('r','e','c',' ') -#define ID_VEDT MKTAG('v','e','d','t') -#define ID_IDX1 MKTAG('i','d','x','1') -#define ID_STRD MKTAG('s','t','r','d') -#define ID_00AM MKTAG('0','0','A','M') -//#define ID_INFO MKTAG('I','N','F','O') - -// Codec tags -#define ID_RLE MKTAG('R','L','E',' ') -#define ID_CRAM MKTAG('C','R','A','M') -#define ID_MSVC MKTAG('m','s','v','c') -#define ID_WHAM MKTAG('W','H','A','M') -#define ID_CVID MKTAG('c','v','i','d') -#define ID_IV32 MKTAG('i','v','3','2') -#define ID_DUCK MKTAG('D','U','C','K') - -struct BITMAPINFOHEADER { - uint32 size; - uint32 width; - uint32 height; - uint16 planes; - uint16 bitCount; - uint32 compression; - uint32 sizeImage; - uint32 xPelsPerMeter; - uint32 yPelsPerMeter; - uint32 clrUsed; - uint32 clrImportant; -}; - -struct WAVEFORMAT { - uint16 tag; - uint16 channels; - uint32 samplesPerSec; - uint32 avgBytesPerSec; - uint16 blockAlign; -}; - -struct PCMWAVEFORMAT : public WAVEFORMAT { - uint16 size; -}; - -struct WAVEFORMATEX : public WAVEFORMAT { - uint16 bitsPerSample; - uint16 size; -}; - -struct AVIOLDINDEX { - uint32 size; - struct Index { - uint32 id; - uint32 flags; - uint32 offset; - uint32 size; - } *indices; -}; - -// Index Flags -enum IndexFlags { - AVIIF_INDEX = 0x10 -}; - -// Audio Codecs -enum { - kWaveFormatNone = 0, - kWaveFormatPCM = 1, - kWaveFormatDK3 = 98 -}; - -struct AVIHeader { - uint32 size; - uint32 microSecondsPerFrame; - uint32 maxBytesPerSecond; - uint32 padding; - uint32 flags; - uint32 totalFrames; - uint32 initialFrames; - uint32 streams; - uint32 bufferSize; - uint32 width; - uint32 height; -}; - -// Flags from the AVIHeader -enum AviFlags { - AVIF_HASINDEX = 0x00000010, - AVIF_MUSTUSEINDEX = 0x00000020, - AVIF_ISINTERLEAVED = 0x00000100, - AVIF_TRUSTCKTYPE = 0x00000800, - AVIF_WASCAPTUREFILE = 0x00010000, - AVIF_WASCOPYRIGHTED = 0x00020000 -}; - -struct AVIStreamHeader { - uint32 size; - uint32 streamType; - uint32 streamHandler; - uint32 flags; - uint16 priority; - uint16 language; - uint32 initialFrames; - uint32 scale; - uint32 rate; - uint32 start; - uint32 length; - uint32 bufferSize; - uint32 quality; - uint32 sampleSize; - Common::Rect frame; -}; - /** * Decoder for AVI videos. * * Video decoder used in engines: * - sci */ -class AviDecoder : public FixedRateVideoDecoder { +class AVIDecoder : public AdvancedVideoDecoder { public: - AviDecoder(Audio::Mixer *mixer, - Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); - virtual ~AviDecoder(); + AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + virtual ~AVIDecoder(); bool loadStream(Common::SeekableReadStream *stream); void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } uint16 getWidth() const { return _header.width; } uint16 getHeight() const { return _header.height; } - uint32 getFrameCount() const { return _header.totalFrames; } - uint32 getTime() const; - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const; - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - - // FixedRateVideoDecoder API - Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); } + void readNextPacket(); private: - Audio::Mixer *_mixer; - BITMAPINFOHEADER _bmInfo; - PCMWAVEFORMAT _wvInfo; - AVIOLDINDEX _ixInfo; - AVIHeader _header; - AVIStreamHeader _vidsHeader; - AVIStreamHeader _audsHeader; - byte _palette[3 * 256]; - bool _dirtyPalette; + struct BitmapInfoHeader { + uint32 size; + uint32 width; + uint32 height; + uint16 planes; + uint16 bitCount; + uint32 compression; + uint32 sizeImage; + uint32 xPelsPerMeter; + uint32 yPelsPerMeter; + uint32 clrUsed; + uint32 clrImportant; + }; + + struct WaveFormat { + uint16 tag; + uint16 channels; + uint32 samplesPerSec; + uint32 avgBytesPerSec; + uint16 blockAlign; + }; + + struct PCMWaveFormat : public WaveFormat { + uint16 size; + }; + + struct WaveFormatEX : public WaveFormat { + uint16 bitsPerSample; + uint16 size; + }; + + struct OldIndex { + uint32 size; + struct Index { + uint32 id; + uint32 flags; + uint32 offset; + uint32 size; + } *indices; + }; + + // Index Flags + enum IndexFlags { + AVIIF_INDEX = 0x10 + }; + + struct AVIHeader { + uint32 size; + uint32 microSecondsPerFrame; + uint32 maxBytesPerSecond; + uint32 padding; + uint32 flags; + uint32 totalFrames; + uint32 initialFrames; + uint32 streams; + uint32 bufferSize; + uint32 width; + uint32 height; + }; + + // Flags from the AVIHeader + enum AVIFlags { + AVIF_HASINDEX = 0x00000010, + AVIF_MUSTUSEINDEX = 0x00000020, + AVIF_ISINTERLEAVED = 0x00000100, + AVIF_TRUSTCKTYPE = 0x00000800, + AVIF_WASCAPTUREFILE = 0x00010000, + AVIF_WASCOPYRIGHTED = 0x00020000 + }; + + struct AVIStreamHeader { + uint32 size; + uint32 streamType; + uint32 streamHandler; + uint32 flags; + uint16 priority; + uint16 language; + uint32 initialFrames; + uint32 scale; + uint32 rate; + uint32 start; + uint32 length; + uint32 bufferSize; + uint32 quality; + uint32 sampleSize; + Common::Rect frame; + }; + + class AVIVideoTrack : public FixedRateVideoTrack { + public: + AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader); + ~AVIVideoTrack(); + + void decodeFrame(Common::SeekableReadStream *stream); + + uint16 getWidth() const { return _bmInfo.width; } + uint16 getHeight() const { return _bmInfo.height; } + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return _lastFrame; } + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + void markPaletteDirty() { _dirtyPalette = true; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); } + + private: + AVIStreamHeader _vidsHeader; + BitmapInfoHeader _bmInfo; + byte _palette[3 * 256]; + mutable bool _dirtyPalette; + int _frameCount, _curFrame; + + Codec *_videoCodec; + const Graphics::Surface *_lastFrame; + Codec *createCodec(); + }; + + class AVIAudioTrack : public AudioTrack { + public: + AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType); + ~AVIAudioTrack(); + + void queueSound(Common::SeekableReadStream *stream); + Audio::Mixer::SoundType getSoundType() const { return _soundType; } + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + // Audio Codecs + enum { + kWaveFormatNone = 0, + kWaveFormatPCM = 1, + kWaveFormatDK3 = 98 + }; + + AVIStreamHeader _audsHeader; + PCMWaveFormat _wvInfo; + Audio::Mixer::SoundType _soundType; + Audio::QueuingAudioStream *_audStream; + Audio::QueuingAudioStream *createAudioStream(); + }; + + OldIndex _ixInfo; + AVIHeader _header; Common::SeekableReadStream *_fileStream; bool _decodedHeader; - Codec *_videoCodec; - Codec *createCodec(); - Audio::Mixer::SoundType _soundType; void runHandle(uint32 tag); void handleList(); void handleStreamHeader(); - void handlePalChange(); - - Audio::SoundHandle *_audHandle; - Audio::QueuingAudioStream *_audStream; - Audio::QueuingAudioStream *createAudioStream(); - void queueAudioBuffer(uint32 chunkSize); }; } // End of namespace Video -- cgit v1.2.3 From d4231fda1cb2399e123054ddaaeca2b4c2749966 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 22 Jul 2012 23:17:36 -0400 Subject: SCI: Rewrite RobotDecoder to use the AdvancedVideoDecoder API --- engines/sci/console.cpp | 8 +- engines/sci/engine/kvideo.cpp | 9 +- engines/sci/sci.cpp | 2 +- engines/sci/video/robot_decoder.cpp | 377 +++++++++++++++++++----------------- engines/sci/video/robot_decoder.h | 129 ++++++------ 5 files changed, 282 insertions(+), 243 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index a6a6d4496f..9b5ef35e92 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -251,25 +251,25 @@ void Console::postEnter() { if (_videoFile.hasSuffix(".seq")) { videoDecoder = new SEQDecoder(_videoFrameDelay); - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { videoDecoder = new Video::VMDDecoder(g_system->getMixer()); } else if (_videoFile.hasSuffix(".rbt")) { - videoDecoder = new RobotDecoder(g_system->getMixer(), _engine->getPlatform() == Common::kPlatformMacintosh); + videoDecoder = new RobotDecoder(_engine->getPlatform() == Common::kPlatformMacintosh); } else if (_videoFile.hasSuffix(".duk")) { duckMode = true; videoDecoder = new Video::AVIDecoder(); - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); #endif } else if (_videoFile.hasSuffix(".avi")) { videoDecoder = new Video::AVIDecoder(); - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); } else { warning("Unrecognized video type"); } if (videoDecoder && videoDecoder->loadFile(_videoFile)) { + if (!_videoFile.hasSuffix(".vmd")) // TODO: Remove after new API is complete + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); + _engine->_gfxCursor->kernelHide(); #ifdef ENABLE_SCI32 diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 2c1532cc46..456f860493 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -254,6 +254,7 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { int16 y = argv[5].toUint16(); warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); g_sci->_robotDecoder->load(id); + g_sci->_robotDecoder->start(); g_sci->_robotDecoder->setPos(x, y); } break; @@ -269,13 +270,13 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { warning("kRobot(%d)", subop); break; case 8: // sync - //if (false) { // debug: automatically skip all robot videos - if ((uint32)g_sci->_robotDecoder->getCurFrame() != g_sci->_robotDecoder->getFrameCount() - 1) { - writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); - } else { + //if (true) { // debug: automatically skip all robot videos + if (g_sci->_robotDecoder->endOfVideo()) { g_sci->_robotDecoder->close(); // Signal the engine scripts that the video is done writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); + } else { + writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); } break; default: diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index d43a9d06fc..42ae00b525 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -632,7 +632,7 @@ void SciEngine::initGraphics() { _gfxPaint = _gfxPaint32; _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxText32); - _robotDecoder = new RobotDecoder(g_system->getMixer(), getPlatform() == Common::kPlatformMacintosh); + _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32); } else { #endif diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp index ebcfac6054..6fe4c645f4 100644 --- a/engines/sci/video/robot_decoder.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -22,11 +22,13 @@ #include "common/archive.h" #include "common/stream.h" +#include "common/substream.h" #include "common/system.h" #include "common/textconsole.h" #include "common/util.h" #include "graphics/surface.h" +#include "audio/audiostream.h" #include "audio/decoders/raw.h" #include "sci/resource.h" @@ -63,57 +65,26 @@ namespace Sci { // our graphics engine, it looks just like a part of the room. A RBT can move // around the screen and go behind other objects. (...) -#ifdef ENABLE_SCI32 - -enum robotPalTypes { +enum RobotPalTypes { kRobotPalVariable = 0, kRobotPalConstant = 1 }; -RobotDecoder::RobotDecoder(Audio::Mixer *mixer, bool isBigEndian) { - _surface = 0; - _width = 0; - _height = 0; +RobotDecoder::RobotDecoder(bool isBigEndian) { _fileStream = 0; - _audioStream = 0; - _dirtyPalette = false; _pos = Common::Point(0, 0); - _mixer = mixer; _isBigEndian = isBigEndian; + _frameTotalSize = 0; } RobotDecoder::~RobotDecoder() { close(); } -bool RobotDecoder::load(GuiResourceId id) { - // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) - - // its drawn at odd coordinates. SV can't play it either (along with some - // others), so it must be some new functionality added in RAMA's robot - // videos. Skip it for now. - if (g_sci->getGameId() == GID_RAMA && id == 1003) - return false; - - // TODO: The robot video in the Lighthouse demo gets stuck - if (g_sci->getGameId() == GID_LIGHTHOUSE && id == 16) - return false; - - Common::String fileName = Common::String::format("%d.rbt", id); - Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName); - - if (!stream) { - warning("Unable to open robot file %s", fileName.c_str()); - return false; - } - - return loadStream(stream); -} - bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _fileStream = new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), _isBigEndian, DisposeAfterUse::YES); - _surface = new Graphics::Surface(); readHeaderChunk(); @@ -125,131 +96,60 @@ bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) { if (_header.version < 4 || _header.version > 6) error("Unknown robot version: %d", _header.version); - if (_header.hasSound) { - _audioStream = Audio::makeQueuingAudioStream(11025, false); - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance()); - } + RobotVideoTrack *videoTrack = new RobotVideoTrack(_header.frameCount); + addTrack(videoTrack); - readPaletteChunk(_header.paletteDataSize); - readFrameSizesChunk(); - calculateVideoDimensions(); - _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8()); + if (_header.hasSound) + addTrack(new RobotAudioTrack()); + videoTrack->readPaletteChunk(_fileStream, _header.paletteDataSize); + readFrameSizesChunk(); + videoTrack->calculateVideoDimensions(_fileStream, _frameTotalSize); return true; } -void RobotDecoder::readHeaderChunk() { - // Header (60 bytes) - _fileStream->skip(6); - _header.version = _fileStream->readUint16(); - _header.audioChunkSize = _fileStream->readUint16(); - _header.audioSilenceSize = _fileStream->readUint16(); - _fileStream->skip(2); - _header.frameCount = _fileStream->readUint16(); - _header.paletteDataSize = _fileStream->readUint16(); - _header.unkChunkDataSize = _fileStream->readUint16(); - _fileStream->skip(5); - _header.hasSound = _fileStream->readByte(); - _fileStream->skip(34); - - // Some videos (e.g. robot 1305 in Phantasmagoria and - // robot 184 in Lighthouse) have an unknown chunk before - // the palette chunk (probably used for sound preloading). - // Skip it here. - if (_header.unkChunkDataSize) - _fileStream->skip(_header.unkChunkDataSize); -} - -void RobotDecoder::readPaletteChunk(uint16 chunkSize) { - byte *paletteData = new byte[chunkSize]; - _fileStream->read(paletteData, chunkSize); - - // SCI1.1 palette - byte palFormat = paletteData[32]; - uint16 palColorStart = paletteData[25]; - uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29); +bool RobotDecoder::load(GuiResourceId id) { + // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) - + // its drawn at odd coordinates. SV can't play it either (along with some + // others), so it must be some new functionality added in RAMA's robot + // videos. Skip it for now. + if (g_sci->getGameId() == GID_RAMA && id == 1003) + return false; + + // TODO: The robot video in the Lighthouse demo gets stuck + if (g_sci->getGameId() == GID_LIGHTHOUSE && id == 16) + return false; - int palOffset = 37; - memset(_palette, 0, 256 * 3); + Common::String fileName = Common::String::format("%d.rbt", id); + Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName); - for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { - if (palFormat == kRobotPalVariable) - palOffset++; - _palette[colorNo * 3 + 0] = paletteData[palOffset++]; - _palette[colorNo * 3 + 1] = paletteData[palOffset++]; - _palette[colorNo * 3 + 2] = paletteData[palOffset++]; + if (!stream) { + warning("Unable to open robot file %s", fileName.c_str()); + return false; } - _dirtyPalette = true; - delete[] paletteData; + return loadStream(stream); } +void RobotDecoder::close() { + AdvancedVideoDecoder::close(); -void RobotDecoder::readFrameSizesChunk() { - // The robot video file contains 2 tables, with one entry for each frame: - // - A table containing the size of the image in each video frame - // - A table containing the total size of each video frame. - // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots, - // they contain 32-bit integers. - - _frameTotalSize = new uint32[_header.frameCount]; - - // TODO: The table reading code can probably be removed once the - // audio chunk size is figured out (check the TODO inside processNextFrame()) -#if 0 - // We don't need any of the two tables to play the video, so we ignore - // both of them. - uint16 wordSize = _header.version == 6 ? 4 : 2; - _fileStream->skip(_header.frameCount * wordSize * 2); -#else - switch (_header.version) { - case 4: - case 5: // sizes are 16-bit integers - // Skip table with frame image sizes, as we don't need it - _fileStream->skip(_header.frameCount * 2); - for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _fileStream->readUint16(); - break; - case 6: // sizes are 32-bit integers - // Skip table with frame image sizes, as we don't need it - _fileStream->skip(_header.frameCount * 4); - for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _fileStream->readUint32(); - break; - default: - error("Can't yet handle index table for robot version %d", _header.version); - } -#endif - - // 2 more unknown tables - _fileStream->skip(1024 + 512); + delete _fileStream; + _fileStream = 0; - // Pad to nearest 2 kilobytes - uint32 curPos = _fileStream->pos(); - if (curPos & 0x7ff) - _fileStream->seek((curPos & ~0x7ff) + 2048); + delete[] _frameTotalSize; + _frameTotalSize = 0; } -void RobotDecoder::calculateVideoDimensions() { - // This is an O(n) operation, as each frame has a different size. - // We need to know the actual frame size to have a constant video size. - uint32 pos = _fileStream->pos(); - - for (uint32 curFrame = 0; curFrame < _header.frameCount; curFrame++) { - _fileStream->skip(4); - uint16 frameWidth = _fileStream->readUint16(); - uint16 frameHeight = _fileStream->readUint16(); - if (frameWidth > _width) - _width = frameWidth; - if (frameHeight > _height) - _height = frameHeight; - _fileStream->skip(_frameTotalSize[curFrame] - 8); - } +void RobotDecoder::readNextPacket() { + // Get our track + RobotVideoTrack *videoTrack = (RobotVideoTrack *)getTrack(0); + videoTrack->increaseCurFrame(); + Graphics::Surface *surface = videoTrack->getSurface(); - _fileStream->seek(pos); -} + if (videoTrack->endOfTrack()) + return; -const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Read frame image header (24 bytes) _fileStream->skip(3); byte frameScale = _fileStream->readByte(); @@ -258,23 +158,28 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { _fileStream->skip(4); // unknown, almost always 0 uint16 frameX = _fileStream->readUint16(); uint16 frameY = _fileStream->readUint16(); + // TODO: In v4 robot files, frameX and frameY have a different meaning. // Set them both to 0 for v4 for now, so that robots in PQ:SWAT show up // correctly. if (_header.version == 4) frameX = frameY = 0; + uint16 compressedSize = _fileStream->readUint16(); uint16 frameFragments = _fileStream->readUint16(); _fileStream->skip(4); // unknown uint32 decompressedSize = frameWidth * frameHeight * frameScale / 100; + // FIXME: A frame's height + position can go off limits... why? With the // following, we cut the contents to fit the frame - uint16 scaledHeight = CLIP(decompressedSize / frameWidth, 0, _height - frameY); + uint16 scaledHeight = CLIP(decompressedSize / frameWidth, 0, surface->h - frameY); + // FIXME: Same goes for the frame's width + position. In this case, we // modify the position to fit the contents on screen. - if (frameWidth + frameX > _width) - frameX = _width - frameWidth; - assert (frameWidth + frameX <= _width && scaledHeight + frameY <= _height); + if (frameWidth + frameX > surface->w) + frameX = surface->w - frameWidth; + + assert(frameWidth + frameX <= surface->w && scaledHeight + frameY <= surface->h); DecompressorLZS lzs; byte *decompressedFrame = new byte[decompressedSize]; @@ -305,24 +210,23 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Copy over the decompressed frame byte *inFrame = decompressedFrame; - byte *outFrame = (byte *)_surface->pixels; + byte *outFrame = (byte *)surface->pixels; // Black out the surface - memset(outFrame, 0, _width * _height); + memset(outFrame, 0, surface->w * surface->h); // Move to the correct y coordinate - outFrame += _width * frameY; + outFrame += surface->w * frameY; for (uint16 y = 0; y < scaledHeight; y++) { memcpy(outFrame + frameX, inFrame, frameWidth); inFrame += frameWidth; - outFrame += _width; + outFrame += surface->w; } delete[] decompressedFrame; - // +1 because we start with frame number -1 - uint32 audioChunkSize = _frameTotalSize[_curFrame + 1] - (24 + compressedSize); + uint32 audioChunkSize = _frameTotalSize[videoTrack->getCurFrame()] - (24 + compressedSize); // TODO: The audio chunk size below is usually correct, but there are some // exceptions (e.g. robot 4902 in Phantasmagoria, towards its end) @@ -337,51 +241,166 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Queue the next audio frame // FIXME: For some reason, there are audio hiccups/gaps if (_header.hasSound) { - _fileStream->skip(8); // header - _audioStream->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize - 8), - (audioChunkSize - 8) * 2, DisposeAfterUse::NO, - Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); + RobotAudioTrack *audioTrack = (RobotAudioTrack *)getTrack(1); + _fileStream->skip(8); // header + audioChunkSize -= 8; + audioTrack->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize), audioChunkSize * 2); } else { _fileStream->skip(audioChunkSize); - } - - if (_curFrame == -1) - _startTime = g_system->getMillis(); + } +} - _curFrame++; +void RobotDecoder::readHeaderChunk() { + // Header (60 bytes) + _fileStream->skip(6); + _header.version = _fileStream->readUint16(); + _header.audioChunkSize = _fileStream->readUint16(); + _header.audioSilenceSize = _fileStream->readUint16(); + _fileStream->skip(2); + _header.frameCount = _fileStream->readUint16(); + _header.paletteDataSize = _fileStream->readUint16(); + _header.unkChunkDataSize = _fileStream->readUint16(); + _fileStream->skip(5); + _header.hasSound = _fileStream->readByte(); + _fileStream->skip(34); - return _surface; + // Some videos (e.g. robot 1305 in Phantasmagoria and + // robot 184 in Lighthouse) have an unknown chunk before + // the palette chunk (probably used for sound preloading). + // Skip it here. + if (_header.unkChunkDataSize) + _fileStream->skip(_header.unkChunkDataSize); } -void RobotDecoder::close() { - if (!_fileStream) - return; +void RobotDecoder::readFrameSizesChunk() { + // The robot video file contains 2 tables, with one entry for each frame: + // - A table containing the size of the image in each video frame + // - A table containing the total size of each video frame. + // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots, + // they contain 32-bit integers. - delete _fileStream; - _fileStream = 0; + _frameTotalSize = new uint32[_header.frameCount]; + // TODO: The table reading code can probably be removed once the + // audio chunk size is figured out (check the TODO inside processNextFrame()) +#if 0 + // We don't need any of the two tables to play the video, so we ignore + // both of them. + uint16 wordSize = _header.version == 6 ? 4 : 2; + _fileStream->skip(_header.frameCount * wordSize * 2); +#else + switch (_header.version) { + case 4: + case 5: // sizes are 16-bit integers + // Skip table with frame image sizes, as we don't need it + _fileStream->skip(_header.frameCount * 2); + for (int i = 0; i < _header.frameCount; ++i) + _frameTotalSize[i] = _fileStream->readUint16(); + break; + case 6: // sizes are 32-bit integers + // Skip table with frame image sizes, as we don't need it + _fileStream->skip(_header.frameCount * 4); + for (int i = 0; i < _header.frameCount; ++i) + _frameTotalSize[i] = _fileStream->readUint32(); + break; + default: + error("Can't yet handle index table for robot version %d", _header.version); + } +#endif + + // 2 more unknown tables + _fileStream->skip(1024 + 512); + + // Pad to nearest 2 kilobytes + uint32 curPos = _fileStream->pos(); + if (curPos & 0x7ff) + _fileStream->seek((curPos & ~0x7ff) + 2048); +} + +RobotDecoder::RobotVideoTrack::RobotVideoTrack(int frameCount) : _frameCount(frameCount) { + _surface = new Graphics::Surface(); + _curFrame = -1; + _dirtyPalette = false; +} + +RobotDecoder::RobotVideoTrack::~RobotVideoTrack() { _surface->free(); delete _surface; - _surface = 0; +} - if (_header.hasSound) { - _mixer->stopHandle(_audioHandle); - //delete _audioStream; _audioStream = 0; +uint16 RobotDecoder::RobotVideoTrack::getWidth() const { + return _surface->w; +} + +uint16 RobotDecoder::RobotVideoTrack::getHeight() const { + return _surface->h; +} + +Graphics::PixelFormat RobotDecoder::RobotVideoTrack::getPixelFormat() const { + return _surface->format; +} + +void RobotDecoder::RobotVideoTrack::readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize) { + byte *paletteData = new byte[chunkSize]; + stream->read(paletteData, chunkSize); + + // SCI1.1 palette + byte palFormat = paletteData[32]; + uint16 palColorStart = paletteData[25]; + uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29); + + int palOffset = 37; + memset(_palette, 0, 256 * 3); + + for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + if (palFormat == kRobotPalVariable) + palOffset++; + _palette[colorNo * 3 + 0] = paletteData[palOffset++]; + _palette[colorNo * 3 + 1] = paletteData[palOffset++]; + _palette[colorNo * 3 + 2] = paletteData[palOffset++]; } - reset(); + _dirtyPalette = true; + delete[] paletteData; } -void RobotDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); +void RobotDecoder::RobotVideoTrack::calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes) { + // This is an O(n) operation, as each frame has a different size. + // We need to know the actual frame size to have a constant video size. + uint32 pos = stream->pos(); + + uint16 width = 0, height = 0; + + for (int curFrame = 0; curFrame < _frameCount; curFrame++) { + stream->skip(4); + uint16 frameWidth = stream->readUint16(); + uint16 frameHeight = stream->readUint16(); + if (frameWidth > width) + width = frameWidth; + if (frameHeight > height) + height = frameHeight; + stream->skip(frameSizes[curFrame] - 8); + } + + stream->seek(pos); + + _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); } -void RobotDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); +RobotDecoder::RobotAudioTrack::RobotAudioTrack() { + _audioStream = Audio::makeQueuingAudioStream(11025, false); } -#endif +RobotDecoder::RobotAudioTrack::~RobotAudioTrack() { + delete _audioStream; +} + +void RobotDecoder::RobotAudioTrack::queueBuffer(byte *buffer, int size) { + _audioStream->queueBuffer(buffer, size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); +} + +Audio::AudioStream *RobotDecoder::RobotAudioTrack::getAudioStream() const { + return _audioStream; +} } // End of namespace Sci diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h index e9cefe7d91..de5b669ab8 100644 --- a/engines/sci/video/robot_decoder.h +++ b/engines/sci/video/robot_decoder.h @@ -25,84 +25,103 @@ #include "common/rational.h" #include "common/rect.h" -#include "common/stream.h" -#include "common/substream.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "graphics/pixelformat.h" #include "video/video_decoder.h" -namespace Sci { +namespace Audio { +class QueuingAudioStream; +} -#ifdef ENABLE_SCI32 - -struct RobotHeader { - // 6 bytes, identifier bytes - uint16 version; - uint16 audioChunkSize; - uint16 audioSilenceSize; - // 2 bytes, unknown - uint16 frameCount; - uint16 paletteDataSize; - uint16 unkChunkDataSize; - // 5 bytes, unknown - byte hasSound; - // 34 bytes, unknown -}; +namespace Common { +class SeekableSubReadStreamEndian; +} + +namespace Sci { -class RobotDecoder : public Video::FixedRateVideoDecoder { +class RobotDecoder : public Video::AdvancedVideoDecoder { public: - RobotDecoder(Audio::Mixer *mixer, bool isBigEndian); + RobotDecoder(bool isBigEndian); virtual ~RobotDecoder(); bool loadStream(Common::SeekableReadStream *stream); bool load(GuiResourceId id); void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _width; } - uint16 getHeight() const { return _height; } - uint32 getFrameCount() const { return _header.frameCount; } - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } + void setPos(uint16 x, uint16 y) { _pos = Common::Point(x, y); } Common::Point getPos() const { return _pos; } protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - - // FixedRateVideoDecoder API - Common::Rational getFrameRate() const { return Common::Rational(60, 10); } - + void readNextPacket(); + private: + class RobotVideoTrack : public FixedRateVideoTrack { + public: + RobotVideoTrack(int frameCount); + ~RobotVideoTrack(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return _surface; } + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + void readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize); + void calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes); + Graphics::Surface *getSurface() { return _surface; } + void increaseCurFrame() { _curFrame++; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(60, 10); } + + private: + int _frameCount; + int _curFrame; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + Graphics::Surface *_surface; + }; + + class RobotAudioTrack : public AudioTrack { + public: + RobotAudioTrack(); + ~RobotAudioTrack(); + + Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kMusicSoundType; } + + void queueBuffer(byte *buffer, int size); + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + Audio::QueuingAudioStream *_audioStream; + }; + + struct RobotHeader { + // 6 bytes, identifier bytes + uint16 version; + uint16 audioChunkSize; + uint16 audioSilenceSize; + // 2 bytes, unknown + uint16 frameCount; + uint16 paletteDataSize; + uint16 unkChunkDataSize; + // 5 bytes, unknown + byte hasSound; + // 34 bytes, unknown + } _header; + void readHeaderChunk(); - void readPaletteChunk(uint16 chunkSize); void readFrameSizesChunk(); - void calculateVideoDimensions(); - - void freeData(); - RobotHeader _header; Common::Point _pos; bool _isBigEndian; + uint32 *_frameTotalSize; Common::SeekableSubReadStreamEndian *_fileStream; - - uint16 _width; - uint16 _height; - uint32 *_frameTotalSize; - byte _palette[256 * 3]; - bool _dirtyPalette; - Graphics::Surface *_surface; - Audio::QueuingAudioStream *_audioStream; - Audio::SoundHandle _audioHandle; - Audio::Mixer *_mixer; }; -#endif } // End of namespace Sci -- cgit v1.2.3 From 3a780a63db79c2a1b2527e6510182a74f6fcfe12 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 23 Jul 2012 21:03:49 -0400 Subject: VIDEO: Set _startTime when rewinding and seeking --- video/video_decoder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index ad176da73b..97f8eec7bb 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -263,6 +263,7 @@ bool AdvancedVideoDecoder::rewind() { return false; _audioStartOffset = 0; + _startTime = g_system->getMillis(); return true; } @@ -290,6 +291,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { return false; _audioStartOffset = time; + _startTime = g_system->getMillis() - time.msecs(); return true; } -- cgit v1.2.3 From a652f6669e2e9225aee17431784b433397b41ae3 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 23 Jul 2012 21:04:51 -0400 Subject: VIDEO: Rewrite SmackerDecoder to use the new API --- engines/agos/animation.cpp | 12 +- engines/agos/animation.h | 4 +- engines/saga/introproc_saga2.cpp | 4 +- engines/scumm/he/animation_he.cpp | 5 +- engines/sword1/animation.cpp | 9 +- engines/sword2/animation.cpp | 9 +- engines/toon/movie.cpp | 35 ++-- engines/toon/movie.h | 14 +- engines/toon/toon.cpp | 2 +- video/smk_decoder.cpp | 391 ++++++++++++++++++++------------------ video/smk_decoder.h | 117 ++++++++---- 11 files changed, 338 insertions(+), 264 deletions(-) diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 10c01741ae..3e8488d7d5 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -415,7 +415,7 @@ void MoviePlayerDXA::updateBalance() { MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name) - : MoviePlayer(vm), SmackerDecoder(vm->_mixer) { + : MoviePlayer(vm), SmackerDecoder() { debug(0, "Creating SMK cutscene player"); memset(baseName, 0, sizeof(baseName)); @@ -431,12 +431,12 @@ bool MoviePlayerSMK::load() { if (!loadStream(videoStream)) error("Failed to load video stream from file %s", videoName.c_str()); + start(); + debug(0, "Playing video %s", videoName.c_str()); CursorMan.showMouse(false); - _firstFrameOffset = _fileStream->pos(); - return true; } @@ -477,10 +477,8 @@ void MoviePlayerSMK::handleNextFrame() { } void MoviePlayerSMK::nextFrame() { - if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) { - _fileStream->seek(_firstFrameOffset); - _curFrame = -1; - } + if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) + rewind(); if (!endOfVideo()) { decodeNextFrame(); diff --git a/engines/agos/animation.h b/engines/agos/animation.h index d1ff074b03..37a666b201 100644 --- a/engines/agos/animation.h +++ b/engines/agos/animation.h @@ -67,9 +67,6 @@ protected: virtual void handleNextFrame(); virtual bool processFrame() = 0; virtual void startSound() {} - -protected: - uint32 _firstFrameOffset; }; class MoviePlayerDXA : public MoviePlayer, Video::DXADecoder { @@ -93,6 +90,7 @@ private: bool processFrame(); void startSound(); void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch); + uint32 _firstFrameOffset; }; class MoviePlayerSMK : public MoviePlayer, Video::SmackerDecoder { diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp index b6470370af..15f7f4dc15 100644 --- a/engines/saga/introproc_saga2.cpp +++ b/engines/saga/introproc_saga2.cpp @@ -92,7 +92,7 @@ int Scene::FTA2EndProc(FTA2Endings whichEnding) { } void Scene::playMovie(const char *filename) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(_vm->_mixer); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); if (!smkDecoder->loadFile(filename)) return; @@ -101,6 +101,8 @@ void Scene::playMovie(const char *filename) { uint16 y = (g_system->getHeight() - smkDecoder->getHeight()) / 2; bool skipVideo = false; + smkDecoder->start(); + while (!_vm->shouldQuit() && !smkDecoder->endOfVideo() && !skipVideo) { if (smkDecoder->needsUpdate()) { const Graphics::Surface *frame = smkDecoder->decodeNextFrame(); diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 40e99c26a8..b37a565aab 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -40,7 +40,10 @@ MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) : _vm(vm) { _video = new Video::BinkDecoder(); else #endif - _video = new Video::SmackerDecoder(mixer); + { + _video = new Video::SmackerDecoder(); + ((Video::AdvancedVideoDecoder *)_video)->start(); + } _flags = 0; _wizResNum = 0; diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 49c5ef7312..8f863d1e09 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -179,6 +179,13 @@ bool MoviePlayer::load(uint32 id) { break; case kVideoDecoderSMK: filename = Common::String::format("%s.smk", sequenceList[id]); + + if (_decoder->loadFile(filename)) { + ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + return true; + } else { + return false; + } break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", (_vm->_systemVars.isDemo) ? sequenceList[id] : sequenceListPSX[id]); @@ -547,7 +554,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * filename = Common::String::format("%s.smk", sequenceList[id]); if (Common::File::exists(filename)) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); } diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index c1cf33ff09..e257ec9029 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -89,6 +89,13 @@ bool MoviePlayer::load(const char *name) { break; case kVideoDecoderSMK: filename = Common::String::format("%s.smk", name); + + if (_decoder->loadFile(filename)) { + ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + return true; + } else { + return false; + } break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", name); @@ -442,7 +449,7 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *s filename = Common::String::format("%s.smk", name); if (Common::File::exists(filename)) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); return new MoviePlayer(vm, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); } diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index 93e41adf57..d988a3ed60 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -33,6 +33,10 @@ namespace Toon { +ToonstruckSmackerDecoder::ToonstruckSmackerDecoder() : Video::SmackerDecoder() { + _lowRes = false; +} + void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { debugC(6, kDebugMovie, "handleAudioTrack(%d, %d, %d)", track, chunkSize, unpackedSize); @@ -40,33 +44,21 @@ void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, ui /* uint16 width = */ _fileStream->readUint16LE(); uint16 height = _fileStream->readUint16LE(); _lowRes = (height == getHeight() / 2); - } else + } else { Video::SmackerDecoder::handleAudioTrack(track, chunkSize, unpackedSize); + } } -bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename) { - debugC(1, kDebugMovie, "loadFile(%s)", filename.c_str()); +bool ToonstruckSmackerDecoder::loadStream(Common::SeekableReadStream *stream) { + if (!Video::SmackerDecoder::loadStream(stream)) + return false; _lowRes = false; - - if (Video::SmackerDecoder::loadFile(filename)) { - if (_surface->h == 200) { - if (_surface) { - _surface->free(); - delete _surface; - } - _surface = new Graphics::Surface(); - _surface->create(640, 400, Graphics::PixelFormat::createFormatCLUT8()); - _header.flags = 4; - } - - return true; - } - return false; + return true; } -ToonstruckSmackerDecoder::ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : Video::SmackerDecoder(mixer, soundType) { - _lowRes = false; +Video::SmackerDecoder::SmackerVideoTrack *ToonstruckSmackerDecoder::createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const { + return Video::SmackerDecoder::createVideoTrack(width, height, frameCount, frameRate, (height == 200) ? 4 : flags, signature); } // decoder is deallocated with Movie destruction i.e. new ToonstruckSmackerDecoder is needed @@ -103,6 +95,9 @@ void Movie::play(const Common::String &video, int32 flags) { bool Movie::playVideo(bool isFirstIntroVideo) { debugC(1, kDebugMovie, "playVideo(isFirstIntroVideo: %d)", isFirstIntroVideo); + + _decoder->start(); + while (!_vm->shouldQuit() && !_decoder->endOfVideo()) { if (_decoder->needsUpdate()) { const Graphics::Surface *frame = _decoder->decodeNextFrame(); diff --git a/engines/toon/movie.h b/engines/toon/movie.h index 2cd33302f2..e795182cba 100644 --- a/engines/toon/movie.h +++ b/engines/toon/movie.h @@ -30,13 +30,17 @@ namespace Toon { class ToonstruckSmackerDecoder : public Video::SmackerDecoder { public: - ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); - virtual ~ToonstruckSmackerDecoder() {} - void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); - bool loadFile(const Common::String &filename); + ToonstruckSmackerDecoder(); + + bool loadStream(Common::SeekableReadStream *stream); bool isLowRes() { return _lowRes; } + protected: - bool _lowRes; + void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); + SmackerVideoTrack *createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const; + +private: + bool _lowRes; }; class Movie { diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index ee427652d8..9fd8415676 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -51,7 +51,7 @@ void ToonEngine::init() { _currentScriptRegion = 0; _resources = new Resources(this); _animationManager = new AnimationManager(this); - _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder(_mixer)); + _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder()); _hotspots = new Hotspots(this); _mainSurface = new Graphics::Surface(); diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp index 359f4cb9bd..d707ad519f 100644 --- a/video/smk_decoder.cpp +++ b/video/smk_decoder.cpp @@ -204,8 +204,7 @@ BigHuffmanTree::BigHuffmanTree(Common::BitStream &bs, int allocSize) delete _hiBytes; } -BigHuffmanTree::~BigHuffmanTree() -{ +BigHuffmanTree::~BigHuffmanTree() { delete[] _tree; } @@ -278,24 +277,17 @@ uint32 BigHuffmanTree::getCode(Common::BitStream &bs) { return v; } -SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) - : _audioStarted(false), _audioStream(0), _mixer(mixer), _soundType(soundType) { - _surface = 0; +SmackerDecoder::SmackerDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { _fileStream = 0; - _dirtyPalette = false; + _firstFrameStart = 0; + _frameTypes = 0; + _frameSizes = 0; } SmackerDecoder::~SmackerDecoder() { close(); } -uint32 SmackerDecoder::getTime() const { - if (_audioStream && _audioStarted) - return _mixer->getSoundElapsedTime(_audioHandle); - - return FixedRateVideoDecoder::getTime(); -} - bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { close(); @@ -309,16 +301,17 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { uint32 width = _fileStream->readUint32LE(); uint32 height = _fileStream->readUint32LE(); - _frameCount = _fileStream->readUint32LE(); - int32 frameRate = _fileStream->readSint32LE(); - - // framerate contains 2 digits after the comma, so 1497 is actually 14.97 fps - if (frameRate > 0) - _frameRate = Common::Rational(1000, frameRate); - else if (frameRate < 0) - _frameRate = Common::Rational(100000, -frameRate); + uint32 frameCount = _fileStream->readUint32LE(); + int32 frameDelay = _fileStream->readSint32LE(); + + // frame rate contains 2 digits after the comma, so 1497 is actually 14.97 fps + Common::Rational frameRate; + if (frameDelay > 0) + frameRate = Common::Rational(1000, frameDelay); + else if (frameDelay < 0) + frameRate = Common::Rational(100000, -frameDelay); else - _frameRate = 1000; + frameRate = 1000; // Flags are determined by which bit is set, which can be one of the following: // 0 - set to 1 if file contains a ring frame. @@ -328,6 +321,9 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { // before it is displayed. _header.flags = _fileStream->readUint32LE(); + SmackerVideoTrack *videoTrack = createVideoTrack(width, height, frameCount, frameRate, _header.flags, _header.signature); + addTrack(videoTrack); + // TODO: should we do any extra processing for Smacker files with ring frames? // TODO: should we do any extra processing for Y-doubled videos? Are they the @@ -374,92 +370,78 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { warning("Unhandled Smacker v2 audio compression"); if (i == 0) - _audioStream = Audio::makeQueuingAudioStream(_header.audioInfo[0].sampleRate, _header.audioInfo[0].isStereo); + addTrack(new SmackerAudioTrack(_header.audioInfo[i], _soundType)); } } _header.dummy = _fileStream->readUint32LE(); - _frameSizes = new uint32[_frameCount]; - for (i = 0; i < _frameCount; ++i) + _frameSizes = new uint32[frameCount]; + for (i = 0; i < frameCount; ++i) _frameSizes[i] = _fileStream->readUint32LE(); - _frameTypes = new byte[_frameCount]; - for (i = 0; i < _frameCount; ++i) + _frameTypes = new byte[frameCount]; + for (i = 0; i < frameCount; ++i) _frameTypes[i] = _fileStream->readByte(); byte *huffmanTrees = (byte *) malloc(_header.treesSize); _fileStream->read(huffmanTrees, _header.treesSize); Common::BitStream8LSB bs(new Common::MemoryReadStream(huffmanTrees, _header.treesSize, DisposeAfterUse::YES), true); + videoTrack->readTrees(bs, _header.mMapSize, _header.mClrSize, _header.fullSize, _header.typeSize); - _MMapTree = new BigHuffmanTree(bs, _header.mMapSize); - _MClrTree = new BigHuffmanTree(bs, _header.mClrSize); - _FullTree = new BigHuffmanTree(bs, _header.fullSize); - _TypeTree = new BigHuffmanTree(bs, _header.typeSize); - - _surface = new Graphics::Surface(); + _firstFrameStart = _fileStream->pos(); - // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled) - _surface->create(width, height * (_header.flags ? 2 : 1), Graphics::PixelFormat::createFormatCLUT8()); - - memset(_palette, 0, 3 * 256); return true; } void SmackerDecoder::close() { - if (!_fileStream) - return; - - if (_audioStream) { - if (_audioStarted) { - // The mixer will delete the stream. - _mixer->stopHandle(_audioHandle); - _audioStarted = false; - } else { - delete _audioStream; - } - _audioStream = 0; - } + AdvancedVideoDecoder::close(); delete _fileStream; _fileStream = 0; - _surface->free(); - delete _surface; - _surface = 0; - - delete _MMapTree; - delete _MClrTree; - delete _FullTree; - delete _TypeTree; + delete[] _frameTypes; + _frameTypes = 0; delete[] _frameSizes; - delete[] _frameTypes; + _frameSizes = 0; +} - reset(); +bool SmackerDecoder::rewind() { + // Call the parent method to rewind the tracks first + // In particular, only videos without sound can be rewound + if (!AdvancedVideoDecoder::rewind()) + return false; + + // And seek back to where the first frame begins + _fileStream->seek(_firstFrameStart); + return true; } -const Graphics::Surface *SmackerDecoder::decodeNextFrame() { +void SmackerDecoder::readNextPacket() { + SmackerVideoTrack *videoTrack = (SmackerVideoTrack *)getTrack(0); + + if (videoTrack->endOfTrack()) + return; + + videoTrack->increaseCurFrame(); + uint i; uint32 chunkSize = 0; uint32 dataSizeUnpacked = 0; uint32 startPos = _fileStream->pos(); - _curFrame++; - // Check if we got a frame with palette data, and // call back the virtual setPalette function to set // the current palette - if (_frameTypes[_curFrame] & 1) { - unpackPalette(); - _dirtyPalette = true; - } + if (_frameTypes[videoTrack->getCurFrame()] & 1) + videoTrack->unpackPalette(_fileStream); // Load audio tracks for (i = 0; i < 7; ++i) { - if (!(_frameTypes[_curFrame] & (2 << i))) + if (!(_frameTypes[videoTrack->getCurFrame()] & (2 << i))) continue; chunkSize = _fileStream->readUint32LE(); @@ -475,29 +457,109 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { handleAudioTrack(i, chunkSize, dataSizeUnpacked); } - uint32 frameSize = _frameSizes[_curFrame] & ~3; -// uint32 remainder = _frameSizes[_curFrame] & 3; + uint32 frameSize = _frameSizes[videoTrack->getCurFrame()] & ~3; +// uint32 remainder = _frameSizes[videoTrack->getCurFrame()] & 3; if (_fileStream->pos() - startPos > frameSize) error("Smacker actual frame size exceeds recorded frame size"); uint32 frameDataSize = frameSize - (_fileStream->pos() - startPos); - _frameData = (byte *)malloc(frameDataSize + 1); + byte *frameData = (byte *)malloc(frameDataSize + 1); // Padding to keep the BigHuffmanTrees from reading past the data end - _frameData[frameDataSize] = 0x00; + frameData[frameDataSize] = 0x00; + + _fileStream->read(frameData, frameDataSize); - _fileStream->read(_frameData, frameDataSize); + Common::BitStream8LSB bs(new Common::MemoryReadStream(frameData, frameDataSize + 1, DisposeAfterUse::YES), true); + videoTrack->decodeFrame(bs); - Common::BitStream8LSB bs(new Common::MemoryReadStream(_frameData, frameDataSize + 1, DisposeAfterUse::YES), true); + _fileStream->seek(startPos + frameSize); +} +void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { + if (_header.audioInfo[track].hasAudio && chunkSize > 0 && track == 0) { + // Get the audio track, which start at offset 1 (first track is video) + SmackerAudioTrack *audioTrack = (SmackerAudioTrack *)getTrack(track + 1); + + // If it's track 0, play the audio data + byte *soundBuffer = (byte *)malloc(chunkSize + 1); + // Padding to keep the SmallHuffmanTrees from reading past the data end + soundBuffer[chunkSize] = 0x00; + + _fileStream->read(soundBuffer, chunkSize); + + if (_header.audioInfo[track].compression == kCompressionRDFT || _header.audioInfo[track].compression == kCompressionDCT) { + // TODO: Compressed audio (Bink RDFT/DCT encoded) + free(soundBuffer); + return; + } else if (_header.audioInfo[track].compression == kCompressionDPCM) { + // Compressed audio (Huffman DPCM encoded) + audioTrack->queueCompressedBuffer(soundBuffer, chunkSize + 1, unpackedSize); + free(soundBuffer); + } else { + // Uncompressed audio (PCM) + audioTrack->queuePCM(soundBuffer, chunkSize); + } + } else { + // Ignore the rest of the audio tracks, if they exist + // TODO: Are there any Smacker videos with more than one audio stream? + // If yes, we should play the rest of the audio streams as well + if (chunkSize > 0) + _fileStream->skip(chunkSize); + } +} + +SmackerDecoder::SmackerVideoTrack::SmackerVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) { + _surface = new Graphics::Surface(); + _surface->create(width, height * (flags ? 2 : 1), Graphics::PixelFormat::createFormatCLUT8()); + _frameCount = frameCount; + _frameRate = frameRate; + _flags = flags; + _signature = signature; + _curFrame = -1; + _dirtyPalette = false; + _MMapTree = _MClrTree = _FullTree = _TypeTree = 0; + memset(_palette, 0, 3 * 256); +} + +SmackerDecoder::SmackerVideoTrack::~SmackerVideoTrack() { + _surface->free(); + delete _surface; + + delete _MMapTree; + delete _MClrTree; + delete _FullTree; + delete _TypeTree; +} + +uint16 SmackerDecoder::SmackerVideoTrack::getWidth() const { + return _surface->w; +} + +uint16 SmackerDecoder::SmackerVideoTrack::getHeight() const { + return _surface->h; +} + +Graphics::PixelFormat SmackerDecoder::SmackerVideoTrack::getPixelFormat() const { + return _surface->format; +} + +void SmackerDecoder::SmackerVideoTrack::readTrees(Common::BitStream &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize) { + _MMapTree = new BigHuffmanTree(bs, mMapSize); + _MClrTree = new BigHuffmanTree(bs, mClrSize); + _FullTree = new BigHuffmanTree(bs, fullSize); + _TypeTree = new BigHuffmanTree(bs, typeSize); +} + +void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStream &bs) { _MMapTree->reset(); _MClrTree->reset(); _FullTree->reset(); _TypeTree->reset(); // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled) - uint doubleY = _header.flags ? 2 : 1; + uint doubleY = _flags ? 2 : 1; uint bw = getWidth() / 4; uint bh = getHeight() / doubleY / 4; @@ -508,6 +570,7 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { uint type, run, j, mode; uint32 p1, p2, clr, map; byte hi, lo; + uint i; while (block < blocks) { type = _TypeTree->getCode(bs); @@ -536,7 +599,7 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { break; case SMK_BLOCK_FULL: // Smacker v2 has one mode, Smacker v4 has three - if (_header.signature == MKTAG('S','M','K','2')) { + if (_signature == MKTAG('S','M','K','2')) { mode = 0; } else { // 00 - mode 0 @@ -628,60 +691,75 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { break; } } +} - _fileStream->seek(startPos + frameSize); +void SmackerDecoder::SmackerVideoTrack::unpackPalette(Common::SeekableReadStream *stream) { + uint startPos = stream->pos(); + uint32 len = 4 * stream->readByte(); - if (_curFrame == 0) - _startTime = g_system->getMillis(); + byte *chunk = (byte *)malloc(len); + stream->read(chunk, len); + byte *p = chunk; - return _surface; -} + byte oldPalette[3 * 256]; + memcpy(oldPalette, _palette, 3 * 256); -void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { - if (_header.audioInfo[track].hasAudio && chunkSize > 0 && track == 0) { - // If it's track 0, play the audio data - byte *soundBuffer = (byte *)malloc(chunkSize + 1); - // Padding to keep the SmallHuffmanTrees from reading past the data end - soundBuffer[chunkSize] = 0x00; + byte *pal = _palette; - _fileStream->read(soundBuffer, chunkSize); + int sz = 0; + byte b0; + while (sz < 256) { + b0 = *p++; + if (b0 & 0x80) { // if top bit is 1 (0x80 = 10000000) + sz += (b0 & 0x7f) + 1; // get lower 7 bits + 1 (0x7f = 01111111) + pal += 3 * ((b0 & 0x7f) + 1); + } else if (b0 & 0x40) { // if top 2 bits are 01 (0x40 = 01000000) + byte c = (b0 & 0x3f) + 1; // get lower 6 bits + 1 (0x3f = 00111111) + uint s = 3 * *p++; + sz += c; - if (_header.audioInfo[track].compression == kCompressionRDFT || _header.audioInfo[track].compression == kCompressionDCT) { - // TODO: Compressed audio (Bink RDFT/DCT encoded) - free(soundBuffer); - return; - } else if (_header.audioInfo[track].compression == kCompressionDPCM) { - // Compressed audio (Huffman DPCM encoded) - queueCompressedBuffer(soundBuffer, chunkSize + 1, unpackedSize, track); - free(soundBuffer); - } else { - // Uncompressed audio (PCM) - byte flags = 0; - if (_header.audioInfo[track].is16Bits) - flags = flags | Audio::FLAG_16BITS; - if (_header.audioInfo[track].isStereo) - flags = flags | Audio::FLAG_STEREO; - - _audioStream->queueBuffer(soundBuffer, chunkSize, DisposeAfterUse::YES, flags); - // The sound buffer will be deleted by QueuingAudioStream - } + while (c--) { + *pal++ = oldPalette[s + 0]; + *pal++ = oldPalette[s + 1]; + *pal++ = oldPalette[s + 2]; + s += 3; + } + } else { // top 2 bits are 00 + sz++; + // get the lower 6 bits for each component (0x3f = 00111111) + byte b = b0 & 0x3f; + byte g = (*p++) & 0x3f; + byte r = (*p++) & 0x3f; + + assert(g < 0xc0 && b < 0xc0); - if (!_audioStarted) { - _mixer->playStream(_soundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance()); - _audioStarted = true; + // upscale to full 8-bit color values by multiplying by 4 + *pal++ = b * 4; + *pal++ = g * 4; + *pal++ = r * 4; } - } else { - // Ignore the rest of the audio tracks, if they exist - // TODO: Are there any Smacker videos with more than one audio stream? - // If yes, we should play the rest of the audio streams as well - if (chunkSize > 0) - _fileStream->skip(chunkSize); } + + stream->seek(startPos + len); + free(chunk); + + _dirtyPalette = true; } -void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, - uint32 unpackedSize, int streamNum) { +SmackerDecoder::SmackerAudioTrack::SmackerAudioTrack(const AudioInfo &audioInfo, Audio::Mixer::SoundType soundType) : + _audioInfo(audioInfo), _soundType(soundType) { + _audioStream = Audio::makeQueuingAudioStream(_audioInfo.sampleRate, _audioInfo.isStereo); +} +SmackerDecoder::SmackerAudioTrack::~SmackerAudioTrack() { + delete _audioStream; +} + +Audio::AudioStream *SmackerDecoder::SmackerAudioTrack::getAudioStream() const { + return _audioStream; +} + +void SmackerDecoder::SmackerAudioTrack::queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize) { Common::BitStream8LSB audioBS(new Common::MemoryReadStream(buffer, bufferSize), true); bool dataPresent = audioBS.getBit(); @@ -689,9 +767,9 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, return; bool isStereo = audioBS.getBit(); - assert(isStereo == _header.audioInfo[streamNum].isStereo); + assert(isStereo == _audioInfo.isStereo); bool is16Bits = audioBS.getBit(); - assert(is16Bits == _header.audioInfo[streamNum].is16Bits); + assert(is16Bits == _audioInfo.is16Bits); int numBytes = 1 * (isStereo ? 2 : 1) * (is16Bits ? 2 : 1); @@ -759,74 +837,21 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, for (int k = 0; k < numBytes; k++) delete audioTrees[k]; - byte flags = 0; - if (_header.audioInfo[0].is16Bits) - flags = flags | Audio::FLAG_16BITS; - if (_header.audioInfo[0].isStereo) - flags = flags | Audio::FLAG_STEREO; - _audioStream->queueBuffer(unpackedBuffer, unpackedSize, DisposeAfterUse::YES, flags); - // unpackedBuffer will be deleted by QueuingAudioStream + queuePCM(unpackedBuffer, unpackedSize); } -void SmackerDecoder::unpackPalette() { - uint startPos = _fileStream->pos(); - uint32 len = 4 * _fileStream->readByte(); - - byte *chunk = (byte *)malloc(len); - _fileStream->read(chunk, len); - byte *p = chunk; - - byte oldPalette[3*256]; - memcpy(oldPalette, _palette, 3 * 256); - - byte *pal = _palette; - - int sz = 0; - byte b0; - while (sz < 256) { - b0 = *p++; - if (b0 & 0x80) { // if top bit is 1 (0x80 = 10000000) - sz += (b0 & 0x7f) + 1; // get lower 7 bits + 1 (0x7f = 01111111) - pal += 3 * ((b0 & 0x7f) + 1); - } else if (b0 & 0x40) { // if top 2 bits are 01 (0x40 = 01000000) - byte c = (b0 & 0x3f) + 1; // get lower 6 bits + 1 (0x3f = 00111111) - uint s = 3 * *p++; - sz += c; - - while (c--) { - *pal++ = oldPalette[s + 0]; - *pal++ = oldPalette[s + 1]; - *pal++ = oldPalette[s + 2]; - s += 3; - } - } else { // top 2 bits are 00 - sz++; - // get the lower 6 bits for each component (0x3f = 00111111) - byte b = b0 & 0x3f; - byte g = (*p++) & 0x3f; - byte r = (*p++) & 0x3f; - - assert(g < 0xc0 && b < 0xc0); - - // upscale to full 8-bit color values by multiplying by 4 - *pal++ = b * 4; - *pal++ = g * 4; - *pal++ = r * 4; - } - } - - _fileStream->seek(startPos + len); - free(chunk); -} +void SmackerDecoder::SmackerAudioTrack::queuePCM(byte *buffer, uint32 bufferSize) { + byte flags = 0; + if (_audioInfo.is16Bits) + flags |= Audio::FLAG_16BITS; + if (_audioInfo.isStereo) + flags |= Audio::FLAG_STEREO; -void SmackerDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); + _audioStream->queueBuffer(buffer, bufferSize, DisposeAfterUse::YES, flags); } -void SmackerDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); +SmackerDecoder::SmackerVideoTrack *SmackerDecoder::createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const { + return new SmackerVideoTrack(width, height, frameCount, frameRate, flags, signature); } } // End of namespace Video diff --git a/video/smk_decoder.h b/video/smk_decoder.h index 516882e7c8..78a4ded0fc 100644 --- a/video/smk_decoder.h +++ b/video/smk_decoder.h @@ -34,6 +34,7 @@ class QueuingAudioStream; } namespace Common { +class BitStream; class SeekableReadStream; } @@ -56,42 +57,72 @@ class BigHuffmanTree; * - sword2 * - toon */ -class SmackerDecoder : public FixedRateVideoDecoder { +class SmackerDecoder : public AdvancedVideoDecoder { public: - SmackerDecoder(Audio::Mixer *mixer, - Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); + SmackerDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); virtual ~SmackerDecoder(); - bool loadStream(Common::SeekableReadStream *stream); + virtual bool loadStream(Common::SeekableReadStream *stream); void close(); - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _frameCount; } - uint32 getTime() const; - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } - virtual void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); + bool rewind(); protected: - Common::SeekableReadStream *_fileStream; + void readNextPacket(); + + virtual void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); - // VideoDecoder API - void updateVolume(); - void updateBalance(); + class SmackerVideoTrack : public FixedRateVideoTrack { + public: + SmackerVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature); + ~SmackerVideoTrack(); - // FixedRateVideoDecoder API - Common::Rational getFrameRate() const { return _frameRate; } + bool isRewindable() const { return true; } + bool rewind() { _curFrame = -1; return true; } -protected: - void unpackPalette(); - // Possible runs of blocks - uint getBlockRun(int index) { return (index <= 58) ? index + 1 : 128 << (index - 59); } - void queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize, int streamNum); + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return _surface; } + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + void readTrees(Common::BitStream &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize); + void increaseCurFrame() { _curFrame++; } + void decodeFrame(Common::BitStream &bs); + void unpackPalette(Common::SeekableReadStream *stream); + + protected: + Common::Rational getFrameRate() const { return _frameRate; } + + Graphics::Surface *_surface; + + private: + Common::Rational _frameRate; + uint32 _flags, _signature; + + byte _palette[3 * 256]; + mutable bool _dirtyPalette; + + int _curFrame; + uint32 _frameCount; + + BigHuffmanTree *_MMapTree; + BigHuffmanTree *_MClrTree; + BigHuffmanTree *_FullTree; + BigHuffmanTree *_TypeTree; + // Possible runs of blocks + static uint getBlockRun(int index) { return (index <= 58) ? index + 1 : 128 << (index - 59); } + }; + + virtual SmackerVideoTrack *createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const; + + Common::SeekableReadStream *_fileStream; + +private: enum AudioCompression { kCompressionNone, kCompressionDPCM, @@ -120,6 +151,25 @@ protected: uint32 dummy; } _header; + class SmackerAudioTrack : public AudioTrack { + public: + SmackerAudioTrack(const AudioInfo &audioInfo, Audio::Mixer::SoundType soundType); + ~SmackerAudioTrack(); + + Audio::Mixer::SoundType getSoundType() const { return _soundType; } + + void queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize); + void queuePCM(byte *buffer, uint32 bufferSize); + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + Audio::Mixer::SoundType _soundType; + Audio::QueuingAudioStream *_audioStream; + AudioInfo _audioInfo; + }; + uint32 *_frameSizes; // The FrameTypes section of a Smacker file contains an array of bytes, where // the 8 bits of each byte describe the contents of the corresponding frame. @@ -127,25 +177,10 @@ protected: // and so on), so there can be up to 7 different audio tracks. When the lowest bit // (bit 0) is set, it denotes a frame that contains a palette record byte *_frameTypes; - byte *_frameData; - // The RGB palette - byte _palette[3 * 256]; - bool _dirtyPalette; - Common::Rational _frameRate; - uint32 _frameCount; - Graphics::Surface *_surface; + uint32 _firstFrameStart; Audio::Mixer::SoundType _soundType; - Audio::Mixer *_mixer; - bool _audioStarted; - Audio::QueuingAudioStream *_audioStream; - Audio::SoundHandle _audioHandle; - - BigHuffmanTree *_MMapTree; - BigHuffmanTree *_MClrTree; - BigHuffmanTree *_FullTree; - BigHuffmanTree *_TypeTree; }; } // End of namespace Video -- cgit v1.2.3 From 84e0b3a167fb282fb7e29614a9806f665af844c2 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 24 Jul 2012 13:23:45 -0400 Subject: VIDEO: Add helper functions to easily add an external audio track --- video/video_decoder.cpp | 11 +++++++++++ video/video_decoder.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 97f8eec7bb..1461f5dc3d 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -521,6 +521,17 @@ void AdvancedVideoDecoder::addTrack(Track *track) { track->start(); } +bool AdvancedVideoDecoder::addStreamFileTrack(const Common::String &baseName) { + StreamFileAudioTrack *track = new StreamFileAudioTrack(); + + bool result = track->loadFromFile(baseName); + + if (result) + addTrack(track); + + return result; +} + AdvancedVideoDecoder::Track *AdvancedVideoDecoder::getTrack(uint track) { if (track > _tracks.size()) return 0; diff --git a/video/video_decoder.h b/video/video_decoder.h index efc8f7a37d..616d6c4f96 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -365,6 +365,11 @@ public: */ virtual Audio::Timestamp getDuration() const; + /** + * Add an audio track from a stream file. + */ + bool addStreamFileTrack(const Common::String &baseName); + // Future API //void setRate(const Common::Rational &rate); //Common::Rational getRate() const; -- cgit v1.2.3 From 3117e4a8ff12c3a2ba4f2d4c69e8539040d49eb0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 24 Jul 2012 13:24:01 -0400 Subject: VIDEO: Convert DXADecoder to the AdvancedVideoDecoder API --- engines/agos/animation.cpp | 80 ++++++++++++-------------- engines/agos/animation.h | 5 +- engines/sword1/animation.cpp | 74 ++++++++---------------- engines/sword1/animation.h | 32 ++++------- engines/sword1/logic.cpp | 2 +- engines/sword2/animation.cpp | 62 ++++++--------------- engines/sword2/animation.h | 30 ++++------ engines/sword2/function.cpp | 2 +- video/dxa_decoder.cpp | 130 ++++++++++++++++++++----------------------- video/dxa_decoder.h | 102 ++++++++++++++++++--------------- 10 files changed, 215 insertions(+), 304 deletions(-) diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 3e8488d7d5..ec8293c91f 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -260,9 +260,6 @@ bool MoviePlayerDXA::load() { debug(0, "Playing video %s", videoName.c_str()); CursorMan.showMouse(false); - - _firstFrameOffset = _fileStream->pos(); - return true; } @@ -302,35 +299,6 @@ void MoviePlayerDXA::stopVideo() { } void MoviePlayerDXA::startSound() { - uint32 offset, size; - - if (getSoundTag() == MKTAG('W','A','V','E')) { - size = _fileStream->readUint32BE(); - - if (_sequenceNum) { - Common::File in; - - _fileStream->seek(size, SEEK_CUR); - - in.open("audio.wav"); - if (!in.isOpen()) { - error("Can't read offset file 'audio.wav'"); - } - - in.seek(_sequenceNum * 8, SEEK_SET); - offset = in.readUint32LE(); - size = in.readUint32LE(); - - in.seek(offset, SEEK_SET); - _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES); - in.close(); - } else { - _bgSoundStream = Audio::makeWAVStream(_fileStream->readStream(size), DisposeAfterUse::YES); - } - } else { - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName); - } - if (_bgSoundStream != NULL) { _vm->_mixer->stopHandle(_bgSound); _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_bgSound, _bgSoundStream, -1, getVolume(), getBalance()); @@ -344,8 +312,7 @@ void MoviePlayerDXA::nextFrame() { } if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) { - _fileStream->seek(_firstFrameOffset); - _curFrame = -1; + rewind(); startSound(); } @@ -374,13 +341,15 @@ bool MoviePlayerDXA::processFrame() { copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch); _vm->_system->unlockScreen(); - Common::Rational soundTime(_mixer->getSoundElapsedTime(_bgSound), 1000); - if ((_bgSoundStream == NULL) || ((soundTime * getFrameRate()).toInt() / 1000 < getCurFrame() + 1)) { + uint32 soundTime = _mixer->getSoundElapsedTime(_bgSound); + uint32 nextFrameStartTime = ((Video::AdvancedVideoDecoder::VideoTrack *)getTrack(0))->getNextFrameStartTime(); + + if ((_bgSoundStream == NULL) || soundTime < nextFrameStartTime) { if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) { - while (_mixer->isSoundHandleActive(_bgSound) && (soundTime * getFrameRate()).toInt() < getCurFrame()) { + while (_mixer->isSoundHandleActive(_bgSound) && soundTime < nextFrameStartTime) { _vm->_system->delayMillis(10); - soundTime = Common::Rational(_mixer->getSoundElapsedTime(_bgSound), 1000); + soundTime = _mixer->getSoundElapsedTime(_bgSound); } // In case the background sound ends prematurely, update // _ticks so that we can still fall back on the no-sound @@ -399,14 +368,35 @@ bool MoviePlayerDXA::processFrame() { return false; } -void MoviePlayerDXA::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_bgSound)) - g_system->getMixer()->setChannelVolume(_bgSound, getVolume()); -} +void MoviePlayerDXA::readSoundData(Common::SeekableReadStream *stream) { + uint32 tag = stream->readUint32BE(); + + if (tag == MKTAG('W','A','V','E')) { + uint32 size = stream->readUint32BE(); + + if (_sequenceNum) { + Common::File in; + + stream->skip(size); + + in.open("audio.wav"); + if (!in.isOpen()) { + error("Can't read offset file 'audio.wav'"); + } + + in.seek(_sequenceNum * 8, SEEK_SET); + uint32 offset = in.readUint32LE(); + size = in.readUint32LE(); -void MoviePlayerDXA::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_bgSound)) - g_system->getMixer()->setChannelBalance(_bgSound, getBalance()); + in.seek(offset, SEEK_SET); + _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES); + in.close(); + } else { + _bgSoundStream = Audio::makeWAVStream(stream->readStream(size), DisposeAfterUse::YES); + } + } else { + _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName); + } } /////////////////////////////////////////////////////////////////////////////// diff --git a/engines/agos/animation.h b/engines/agos/animation.h index 37a666b201..9e31fced6d 100644 --- a/engines/agos/animation.h +++ b/engines/agos/animation.h @@ -81,16 +81,13 @@ public: virtual void stopVideo(); protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void readSoundData(Common::SeekableReadStream *stream); private: void handleNextFrame(); bool processFrame(); void startSound(); void copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch); - uint32 _firstFrameOffset; }; class MoviePlayerSMK : public MoviePlayer, Video::SmackerDecoder { diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 8f863d1e09..70f1e5dc03 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -37,6 +37,7 @@ #include "gui/message.h" +#include "video/dxa_decoder.h" #include "video/psx_decoder.h" #include "video/smk_decoder.h" @@ -96,9 +97,8 @@ static const char *const sequenceListPSX[20] = { // Basic movie player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType) - : _vm(vm), _textMan(textMan), _resMan(resMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) { - _bgSoundStream = NULL; +MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType) + : _vm(vm), _textMan(textMan), _resMan(resMan), _system(system) { _decoderType = decoderType; _decoder = decoder; @@ -107,7 +107,6 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio:: } MoviePlayer::~MoviePlayer() { - delete _bgSoundHandle; delete _decoder; } @@ -116,16 +115,12 @@ MoviePlayer::~MoviePlayer() { * @param id the id of the file */ bool MoviePlayer::load(uint32 id) { - Common::File f; Common::String filename; - if (_decoderType == kVideoDecoderDXA) - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(sequenceList[id]); - else - _bgSoundStream = NULL; - if (SwordEngine::_systemVars.showText) { + Common::File f; filename = Common::String::format("%s.txt", sequenceList[id]); + if (f.open(filename)) { Common::String line; int lineNo = 0; @@ -169,7 +164,6 @@ bool MoviePlayer::load(uint32 id) { _movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color)); lastEnd = endFrame; } - f.close(); } } @@ -179,13 +173,6 @@ bool MoviePlayer::load(uint32 id) { break; case kVideoDecoderSMK: filename = Common::String::format("%s.smk", sequenceList[id]); - - if (_decoder->loadFile(filename)) { - ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete - return true; - } else { - return false; - } break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", (_vm->_systemVars.isDemo) ? sequenceList[id] : sequenceListPSX[id]); @@ -205,30 +192,27 @@ bool MoviePlayer::load(uint32 id) { break; } - return _decoder->loadFile(filename.c_str()); -} + if (!_decoder->loadFile(filename)) + return false; -void MoviePlayer::play() { - if (_bgSoundStream) - _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); + // For DXA, also add the external sound file + if (_decoderType == kVideoDecoderDXA) + ((Video::AdvancedVideoDecoder *)_decoder)->addStreamFileTrack(sequenceList[id]); - bool terminated = false; + ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + return true; +} +void MoviePlayer::play() { _textX = 0; _textY = 0; - terminated = !playVideo(); - - if (terminated) - _snd->stopHandle(*_bgSoundHandle); + playVideo(); _textMan->releaseText(2, false); _movieTexts.clear(); - while (_snd->isSoundHandleActive(*_bgSoundHandle)) - _system->delayMillis(100); - // It's tempting to call _screen->fullRefresh() here to restore the old // palette. However, that causes glitches with DXA movies, where the // previous location would be momentarily drawn, before switching to @@ -514,24 +498,12 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { scaledFrame.free(); } -DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) - : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { -} - -uint32 DXADecoderWithSound::getTime() const { - if (_mixer->isSoundHandleActive(*_bgSoundHandle)) - return _mixer->getSoundElapsedTime(*_bgSoundHandle); - - return DXADecoder::getTime(); -} - /////////////////////////////////////////////////////////////////////////////// // Factory function for creating the appropriate cutscene player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system) { +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system) { Common::String filename; - Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle; // For the PSX version, we'll try the PlayStation stream files if (vm->isPsx()) { @@ -542,7 +514,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * #ifdef USE_RGB_COLOR // All BS1 PSX videos run the videos at 2x speed Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX); + return new MoviePlayer(vm, textMan, resMan, system, psxDecoder, kVideoDecoderPSX); #else GUI::MessageDialog dialog(Common::String::format(_("PSX stream cutscene '%s' cannot be played in paletted mode"), filename.c_str()), _("OK")); dialog.runModal(); @@ -555,19 +527,19 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * if (Common::File::exists(filename)) { Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); + return new MoviePlayer(vm, textMan, resMan, system, smkDecoder, kVideoDecoderSMK); } filename = Common::String::format("%s.dxa", sequenceList[id]); if (Common::File::exists(filename)) { #ifdef USE_ZLIB - DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA); + Video::VideoDecoder *dxaDecoder = new Video::DXADecoder(); + return new MoviePlayer(vm, textMan, resMan, system, dxaDecoder, kVideoDecoderDXA); #else GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); dialog.runModal(); - return NULL; + return 0; #endif } @@ -577,7 +549,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * if (Common::File::exists(filename)) { GUI::MessageDialog dialog(_("MPEG2 cutscenes are no longer supported"), _("OK")); dialog.runModal(); - return NULL; + return 0; } if (!vm->isPsx() || scumm_stricmp(sequenceList[id], "enddemo") != 0) { @@ -586,7 +558,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * dialog.runModal(); } - return NULL; + return 0; } } // End of namespace Sword1 diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h index c2ed86a1a3..d0c61f5eb3 100644 --- a/engines/sword1/animation.h +++ b/engines/sword1/animation.h @@ -23,16 +23,19 @@ #ifndef SWORD1_ANIMATION_H #define SWORD1_ANIMATION_H -#include "video/dxa_decoder.h" -#include "video/video_decoder.h" - #include "common/list.h" -#include "audio/audiostream.h" - #include "sword1/screen.h" #include "sword1/sound.h" +namespace Graphics { +struct Surface; +} + +namespace Video { +class VideoDecoder; +} + namespace Sword1 { enum DecoderType { @@ -55,21 +58,9 @@ public: } }; -class DXADecoderWithSound : public Video::DXADecoder { -public: - DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); - ~DXADecoderWithSound() {} - - uint32 getTime() const; - -private: - Audio::Mixer *_mixer; - Audio::SoundHandle *_bgSoundHandle; -}; - class MoviePlayer { public: - MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType); + MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType); virtual ~MoviePlayer(); bool load(uint32 id); void play(); @@ -78,7 +69,6 @@ protected: SwordEngine *_vm; Text *_textMan; ResMan *_resMan; - Audio::Mixer *_snd; OSystem *_system; Common::List _movieTexts; int _textX, _textY, _textWidth, _textHeight; @@ -88,8 +78,6 @@ protected: DecoderType _decoderType; Video::VideoDecoder *_decoder; - Audio::SoundHandle *_bgSoundHandle; - Audio::AudioStream *_bgSoundStream; bool playVideo(); void performPostProcessing(byte *screen); @@ -100,7 +88,7 @@ protected: void convertColor(byte r, byte g, byte b, float &h, float &s, float &v); }; -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system); +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system); } // End of namespace Sword1 diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index 8e04861edf..757d768780 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -959,7 +959,7 @@ int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int3 // meantime, we don't want any looping sound effects still playing. _sound->quitScreen(); - MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _mixer, _system); + MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _system); if (player) { _screen->clearScreen(); if (player->load(sequenceId)) diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index e257ec9029..e603925e73 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -40,6 +40,7 @@ #include "gui/message.h" +#include "video/dxa_decoder.h" #include "video/smk_decoder.h" #include "video/psx_decoder.h" @@ -51,9 +52,8 @@ namespace Sword2 { // Basic movie player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType) - : _vm(vm), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) { - _bgSoundStream = NULL; +MoviePlayer::MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType) + : _vm(vm), _system(system) { _decoderType = decoderType; _decoder = decoder; @@ -62,7 +62,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A } MoviePlayer::~MoviePlayer() { - delete _bgSoundHandle; delete _decoder; } @@ -75,11 +74,6 @@ bool MoviePlayer::load(const char *name) { if (_vm->shouldQuit()) return false; - if (_decoderType == kVideoDecoderDXA) - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(name); - else - _bgSoundStream = NULL; - _textSurface = NULL; Common::String filename; @@ -89,13 +83,6 @@ bool MoviePlayer::load(const char *name) { break; case kVideoDecoderSMK: filename = Common::String::format("%s.smk", name); - - if (_decoder->loadFile(filename)) { - ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete - return true; - } else { - return false; - } break; case kVideoDecoderPSX: filename = Common::String::format("%s.str", name); @@ -114,7 +101,15 @@ bool MoviePlayer::load(const char *name) { } } - return _decoder->loadFile(filename.c_str()); + if (!_decoder->loadFile(filename)) + return false; + + // For DXA, also add the external sound file + if (_decoderType == kVideoDecoderDXA) + ((Video::AdvancedVideoDecoder *)_decoder)->addStreamFileTrack(name); + + ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + return true; } void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) { @@ -130,24 +125,15 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI if (leadIn) _vm->_sound->playMovieSound(leadIn, kLeadInSound); - if (_bgSoundStream) - _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); - - bool terminated = false; - - terminated = !playVideo(); + bool terminated = !playVideo(); closeTextObject(_currentMovieText, NULL, 0); if (terminated) { - _snd->stopHandle(*_bgSoundHandle); _vm->_sound->stopMovieSounds(); _vm->_sound->stopSpeech(); } - while (_snd->isSoundHandleActive(*_bgSoundHandle)) - _system->delayMillis(100); - if (_decoderType == kVideoDecoderPSX) { // Need to jump back to paletted color initGraphics(640, 480, true); @@ -414,31 +400,19 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { scaledFrame.free(); } -DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) - : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { -} - -uint32 DXADecoderWithSound::getTime() const { - if (_mixer->isSoundHandleActive(*_bgSoundHandle)) - return _mixer->getSoundElapsedTime(*_bgSoundHandle); - - return DXADecoder::getTime(); -} - /////////////////////////////////////////////////////////////////////////////// // Factory function for creating the appropriate cutscene player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount) { +MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount) { Common::String filename; - Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle; filename = Common::String::format("%s.str", name); if (Common::File::exists(filename)) { #ifdef USE_RGB_COLOR Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x, frameCount); - return new MoviePlayer(vm, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX); + return new MoviePlayer(vm, system, psxDecoder, kVideoDecoderPSX); #else GUI::MessageDialog dialog(_("PSX cutscenes found but ScummVM has been built without RGB color support"), _("OK")); dialog.runModal(); @@ -450,15 +424,15 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *s if (Common::File::exists(filename)) { Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); - return new MoviePlayer(vm, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); + return new MoviePlayer(vm, system, smkDecoder, kVideoDecoderSMK); } filename = Common::String::format("%s.dxa", name); if (Common::File::exists(filename)) { #ifdef USE_ZLIB - DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle); - return new MoviePlayer(vm, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA); + Video::DXADecoder *dxaDecoder = new Video::DXADecoder(); + return new MoviePlayer(vm, system, dxaDecoder, kVideoDecoderDXA); #else GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); dialog.runModal(); diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index 3d5c42b7f7..b2a243b2ca 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -25,12 +25,16 @@ #ifndef SWORD2_ANIMATION_H #define SWORD2_ANIMATION_H -#include "video/dxa_decoder.h" -#include "video/video_decoder.h" -#include "audio/mixer.h" - #include "sword2/screen.h" +namespace Graphics { +struct Surface; +} + +namespace Video { +class VideoDecoder; +} + namespace Sword2 { enum DecoderType { @@ -55,20 +59,9 @@ struct MovieText { } }; -class DXADecoderWithSound : public Video::DXADecoder { -public: - DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); - ~DXADecoderWithSound() {} - - uint32 getTime() const; -private: - Audio::Mixer *_mixer; - Audio::SoundHandle *_bgSoundHandle; -}; - class MoviePlayer { public: - MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType); + MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType); virtual ~MoviePlayer(); bool load(const char *name); @@ -76,7 +69,6 @@ public: protected: Sword2Engine *_vm; - Audio::Mixer *_snd; OSystem *_system; MovieText *_movieTexts; uint32 _numMovieTexts; @@ -87,8 +79,6 @@ protected: DecoderType _decoderType; Video::VideoDecoder *_decoder; - Audio::SoundHandle *_bgSoundHandle; - Audio::AudioStream *_bgSoundStream; uint32 _leadOut; int _leadOutFrame; @@ -105,7 +95,7 @@ protected: uint32 getWhiteColor(); }; -MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount); +MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount); } // End of namespace Sword2 diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp index 836b252d6c..07fcaa094b 100644 --- a/engines/sword2/function.cpp +++ b/engines/sword2/function.cpp @@ -2139,7 +2139,7 @@ int32 Logic::fnPlaySequence(int32 *params) { uint32 frameCount = Sword2Engine::isPsx() ? params[1] : 0; - _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system, frameCount); + _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_system, frameCount); if (_moviePlayer && _moviePlayer->load(filename)) { _moviePlayer->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut); diff --git a/video/dxa_decoder.cpp b/video/dxa_decoder.cpp index 7d1112a59c..5ac9bd2088 100644 --- a/video/dxa_decoder.cpp +++ b/video/dxa_decoder.cpp @@ -37,41 +37,43 @@ namespace Video { DXADecoder::DXADecoder() { - _fileStream = 0; - _surface = 0; - _dirtyPalette = false; +} - _frameBuffer1 = 0; - _frameBuffer2 = 0; - _scaledBuffer = 0; +DXADecoder::~DXADecoder() { + close(); +} - _inBuffer = 0; - _inBufferSize = 0; +bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { + close(); - _decompBuffer = 0; - _decompBufferSize = 0; + uint32 tag = stream->readUint32BE(); - _width = 0; - _height = 0; + if (tag != MKTAG('D','E','X','A')) { + close(); + return false; + } - _frameSize = 0; - _frameCount = 0; - _frameRate = 0; + DXAVideoTrack *track = new DXAVideoTrack(stream); + addTrack(track); - _scaleMode = S_NONE; -} + readSoundData(stream); -DXADecoder::~DXADecoder() { - close(); + track->setFrameStartPos(); + return true; } -bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { - close(); +void DXADecoder::readSoundData(Common::SeekableReadStream *stream) { + // Skip over the tag by default + stream->readUint32BE(); +} +DXADecoder::DXAVideoTrack::DXAVideoTrack(Common::SeekableReadStream *stream) { _fileStream = stream; - - uint32 tag = _fileStream->readUint32BE(); - assert(tag == MKTAG('D','E','X','A')); + _curFrame = -1; + _frameStartOffset = 0; + _decompBuffer = 0; + _inBuffer = 0; + memset(_palette, 0, 256 * 3); uint8 flags = _fileStream->readByte(); _frameCount = _fileStream->readUint16BE(); @@ -105,18 +107,14 @@ bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { _frameSize = _width * _height; _decompBufferSize = _frameSize; - _frameBuffer1 = (uint8 *)malloc(_frameSize); + _frameBuffer1 = new byte[_frameSize]; memset(_frameBuffer1, 0, _frameSize); - _frameBuffer2 = (uint8 *)malloc(_frameSize); + _frameBuffer2 = new byte[_frameSize]; memset(_frameBuffer2, 0, _frameSize); - if (!_frameBuffer1 || !_frameBuffer2) - error("DXADecoder: Error allocating frame buffers (size %u)", _frameSize); _scaledBuffer = 0; if (_scaleMode != S_NONE) { - _scaledBuffer = (uint8 *)malloc(_frameSize); - if (!_scaledBuffer) - error("Error allocating scale buffer (size %u)", _frameSize); + _scaledBuffer = new byte[_frameSize]; memset(_scaledBuffer, 0, _frameSize); } @@ -148,36 +146,33 @@ bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { } while (tag != 0); } #endif - - // Read the sound header - _soundTag = _fileStream->readUint32BE(); - - return true; } -void DXADecoder::close() { - if (!_fileStream) - return; - +DXADecoder::DXAVideoTrack::~DXAVideoTrack() { delete _fileStream; - _fileStream = 0; - delete _surface; - _surface = 0; + delete[] _frameBuffer1; + delete[] _frameBuffer2; + delete[] _scaledBuffer; + delete[] _inBuffer; + delete[] _decompBuffer; +} - free(_frameBuffer1); - free(_frameBuffer2); - free(_scaledBuffer); - free(_inBuffer); - free(_decompBuffer); +bool DXADecoder::DXAVideoTrack::rewind() { + _curFrame = -1; + _fileStream->seek(_frameStartOffset); + return true; +} - _inBuffer = 0; - _decompBuffer = 0; +Graphics::PixelFormat DXADecoder::DXAVideoTrack::getPixelFormat() const { + return _surface->format; +} - reset(); +void DXADecoder::DXAVideoTrack::setFrameStartPos() { + _frameStartOffset = _fileStream->pos(); } -void DXADecoder::decodeZlib(byte *data, int size, int totalSize) { +void DXADecoder::DXAVideoTrack::decodeZlib(byte *data, int size, int totalSize) { #ifdef USE_ZLIB unsigned long dstLen = totalSize; Common::uncompress(data, &dstLen, _inBuffer, size); @@ -187,14 +182,13 @@ void DXADecoder::decodeZlib(byte *data, int size, int totalSize) { #define BLOCKW 4 #define BLOCKH 4 -void DXADecoder::decode12(int size) { +void DXADecoder::DXAVideoTrack::decode12(int size) { #ifdef USE_ZLIB - if (_decompBuffer == NULL) { - _decompBuffer = (byte *)malloc(_decompBufferSize); + if (!_decompBuffer) { + _decompBuffer = new byte[_decompBufferSize]; memset(_decompBuffer, 0, _decompBufferSize); - if (_decompBuffer == NULL) - error("Error allocating decomp buffer (size %u)", _decompBufferSize); } + /* decompress the input data */ decodeZlib(_decompBuffer, size, _decompBufferSize); @@ -287,15 +281,13 @@ void DXADecoder::decode12(int size) { #endif } -void DXADecoder::decode13(int size) { +void DXADecoder::DXAVideoTrack::decode13(int size) { #ifdef USE_ZLIB uint8 *codeBuf, *dataBuf, *motBuf, *maskBuf; - if (_decompBuffer == NULL) { - _decompBuffer = (byte *)malloc(_decompBufferSize); + if (!_decompBuffer) { + _decompBuffer = new byte[_decompBufferSize]; memset(_decompBuffer, 0, _decompBufferSize); - if (_decompBuffer == NULL) - error("Error allocating decomp buffer (size %u)", _decompBufferSize); } /* decompress the input data */ @@ -475,7 +467,7 @@ void DXADecoder::decode13(int size) { #endif } -const Graphics::Surface *DXADecoder::decodeNextFrame() { +const Graphics::Surface *DXADecoder::DXAVideoTrack::decodeNextFrame() { uint32 tag = _fileStream->readUint32BE(); if (tag == MKTAG('C','M','A','P')) { _fileStream->read(_palette, 256 * 3); @@ -486,11 +478,10 @@ const Graphics::Surface *DXADecoder::decodeNextFrame() { if (tag == MKTAG('F','R','A','M')) { byte type = _fileStream->readByte(); uint32 size = _fileStream->readUint32BE(); - if ((_inBuffer == NULL) || (_inBufferSize < size)) { - free(_inBuffer); - _inBuffer = (byte *)malloc(size); - if (_inBuffer == NULL) - error("Error allocating input buffer (size %u)", size); + + if (!_inBuffer || _inBufferSize < size) { + delete[] _inBuffer; + _inBuffer = new byte[size]; memset(_inBuffer, 0, size); _inBufferSize = size; } @@ -551,9 +542,6 @@ const Graphics::Surface *DXADecoder::decodeNextFrame() { _curFrame++; - if (_curFrame == 0) - _startTime = g_system->getMillis(); - return _surface; } diff --git a/video/dxa_decoder.h b/video/dxa_decoder.h index d13cd3076c..a0caca4b95 100644 --- a/video/dxa_decoder.h +++ b/video/dxa_decoder.h @@ -41,62 +41,74 @@ namespace Video { * - sword1 * - sword2 */ -class DXADecoder : public FixedRateVideoDecoder { +class DXADecoder : public AdvancedVideoDecoder { public: DXADecoder(); virtual ~DXADecoder(); bool loadStream(Common::SeekableReadStream *stream); - void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _width; } - uint16 getHeight() const { return _height; } - uint32 getFrameCount() const { return _frameCount; } - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } +protected: /** - * Get the sound chunk tag of the loaded DXA file + * Read the sound data out of the given DXA stream */ - uint32 getSoundTag() { return _soundTag; } - -protected: - Common::Rational getFrameRate() const { return _frameRate; } - - Common::SeekableReadStream *_fileStream; + virtual void readSoundData(Common::SeekableReadStream *stream); private: - void decodeZlib(byte *data, int size, int totalSize); - void decode12(int size); - void decode13(int size); - - enum ScaleMode { - S_NONE, - S_INTERLACED, - S_DOUBLE + class DXAVideoTrack : public FixedRateVideoTrack { + public: + DXAVideoTrack(Common::SeekableReadStream *stream); + ~DXAVideoTrack(); + + bool isRewindable() const { return true; } + bool rewind(); + + uint16 getWidth() const { return _width; } + uint16 getHeight() const { return _height; } + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + void setFrameStartPos(); + + protected: + Common::Rational getFrameRate() const { return _frameRate; } + + private: + void decodeZlib(byte *data, int size, int totalSize); + void decode12(int size); + void decode13(int size); + + enum ScaleMode { + S_NONE, + S_INTERLACED, + S_DOUBLE + }; + + Common::SeekableReadStream *_fileStream; + Graphics::Surface *_surface; + + byte *_frameBuffer1; + byte *_frameBuffer2; + byte *_scaledBuffer; + byte *_inBuffer; + uint32 _inBufferSize; + byte *_decompBuffer; + uint32 _decompBufferSize; + uint16 _curHeight; + uint32 _frameSize; + ScaleMode _scaleMode; + uint16 _width, _height; + uint32 _frameRate; + uint32 _frameCount; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + int _curFrame; + uint32 _frameStartOffset; }; - - Graphics::Surface *_surface; - byte _palette[256 * 3]; - bool _dirtyPalette; - - byte *_frameBuffer1; - byte *_frameBuffer2; - byte *_scaledBuffer; - byte *_inBuffer; - uint32 _inBufferSize; - byte *_decompBuffer; - uint32 _decompBufferSize; - uint16 _curHeight; - uint32 _frameSize; - ScaleMode _scaleMode; - uint32 _soundTag; - uint16 _width, _height; - uint32 _frameRate; - uint32 _frameCount; }; } // End of namespace Video -- cgit v1.2.3 From 09f1519d6d369e7e59102b53cfb56a731bff99fb Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 25 Jul 2012 00:39:21 -0400 Subject: VIDEO: Stop and restart tracks when seeking/rewinding --- video/video_decoder.cpp | 32 ++++++++++++++++++++++++++------ video/video_decoder.h | 4 ++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 1461f5dc3d..355c94abb1 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -256,12 +256,18 @@ bool AdvancedVideoDecoder::rewind() { _needsRewind = false; - // TODO: Pause status + // Stop all tracks so they can be rewound + if (_isPlaying) + stopAllTracks(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if (!(*it)->rewind()) return false; + // Now that we've rewound, start all tracks again + if (_isPlaying) + startAllTracks(); + _audioStartOffset = 0; _startTime = g_system->getMillis(); return true; @@ -284,12 +290,18 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { _needsRewind = false; - // TODO: Pause status + // Stop all tracks so they can be seeked + if (_isPlaying) + stopAllTracks(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if (!(*it)->seek(time)) return false; + // Now that we've seeked, start all tracks again + if (_isPlaying) + startAllTracks(); + _audioStartOffset = time; _startTime = g_system->getMillis() - time.msecs(); return true; @@ -307,8 +319,7 @@ void AdvancedVideoDecoder::start() { if (_needsRewind) rewind(); - for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - (*it)->start(); + startAllTracks(); } void AdvancedVideoDecoder::stop() { @@ -321,8 +332,7 @@ void AdvancedVideoDecoder::stop() { _palette = 0; _dirtyPalette = false; - for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - (*it)->stop(); + stopAllTracks(); // Also reset the pause state. _pauseLevel = 0; @@ -584,6 +594,16 @@ const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack return bestTrack; } +void AdvancedVideoDecoder::startAllTracks() { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->start(); +} + +void AdvancedVideoDecoder::stopAllTracks() { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->stop(); +} + ////////////////////////////////////////////// ///////////////// DEPRECATED ///////////////// ////////////////////////////////////////////// diff --git a/video/video_decoder.h b/video/video_decoder.h index 616d6c4f96..c77fb44dfe 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -670,6 +670,10 @@ private: // Palette settings from individual tracks mutable bool _dirtyPalette; const byte *_palette; + + // Internal helper functions + void stopAllTracks(); + void startAllTracks(); }; /** -- cgit v1.2.3 From 714c6ae1195ac372998c3d5b6f3739725554bf85 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 25 Jul 2012 00:44:22 -0400 Subject: VIDEO: Add internal helper function for checking on video track end status --- video/video_decoder.cpp | 8 ++++++++ video/video_decoder.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 355c94abb1..80a208fda3 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -556,6 +556,14 @@ const AdvancedVideoDecoder::Track *AdvancedVideoDecoder::getTrack(uint track) co return _tracks[track]; } +bool AdvancedVideoDecoder::endOfVideoTracks() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) + return false; + + return true; +} + AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() { VideoTrack *bestTrack = 0; uint32 bestTime = 0xFFFFFFFF; diff --git a/video/video_decoder.h b/video/video_decoder.h index c77fb44dfe..0848ad09c7 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -656,6 +656,14 @@ protected: */ const Track *getTrack(uint track) const; + /** + * Find out if all video tracks have finished + * + * This is useful if one wants to figure out if they need to buffer all + * remaining audio in a file. + */ + bool endOfVideoTracks() const; + private: // Tracks owned by this AdvancedVideoDecoder typedef Common::Array TrackList; -- cgit v1.2.3 From c0cece8d1335a3397ea980d9a2abc4075656068c Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 25 Jul 2012 11:19:36 -0400 Subject: VIDEO: Add functions for default high color PixelFormat To be used by video that converts from YUV to RGB --- video/video_decoder.cpp | 6 ++++++ video/video_decoder.h | 20 +++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 80a208fda3..8b9a009b98 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -101,6 +101,12 @@ AdvancedVideoDecoder::AdvancedVideoDecoder() { _audioVolume = Audio::Mixer::kMaxChannelVolume; _audioBalance = 0; _pauseLevel = 0; + + // Find the best format for output + _defaultHighColorFormat = g_system->getScreenFormat(); + + if (_defaultHighColorFormat.bytesPerPixel == 1) + _defaultHighColorFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); } void AdvancedVideoDecoder::close() { diff --git a/video/video_decoder.h b/video/video_decoder.h index 0848ad09c7..a6dbed8fc5 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -27,6 +27,7 @@ #include "audio/timestamp.h" // TODO: Move this to common/ ? #include "common/array.h" #include "common/str.h" +#include "graphics/pixelformat.h" namespace Audio { class AudioStream; @@ -40,7 +41,6 @@ class SeekableReadStream; } namespace Graphics { -struct PixelFormat; struct Surface; } @@ -370,6 +370,16 @@ public: */ bool addStreamFileTrack(const Common::String &baseName); + /** + * Set the default high color format for videos that convert from YUV. + * + * By default, AdvancedVideoDecoder will attempt to use the screen format + * if it's >8bpp and use a 32bpp format when not. + * + * This must be set before calling loadStream(). + */ + void setDefaultHighColorFormat(const Graphics::PixelFormat &format) { _defaultHighColorFormat = format; } + // Future API //void setRate(const Common::Rational &rate); //Common::Rational getRate() const; @@ -664,6 +674,11 @@ protected: */ bool endOfVideoTracks() const; + /** + * Get the default high color format + */ + Graphics::PixelFormat getDefaultHighColorFormat() const { return _defaultHighColorFormat; } + private: // Tracks owned by this AdvancedVideoDecoder typedef Common::Array TrackList; @@ -679,6 +694,9 @@ private: mutable bool _dirtyPalette; const byte *_palette; + // Default PixelFormat settings + Graphics::PixelFormat _defaultHighColorFormat; + // Internal helper functions void stopAllTracks(); void startAllTracks(); -- cgit v1.2.3 From 57a06e383b7c3c950653a99c81c1c7fd7dcd5b1d Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Wed, 25 Jul 2012 11:22:28 -0400 Subject: VIDEO: Convert Bink to the new AdvancedVideoDecoder API --- engines/scumm/he/animation_he.cpp | 8 +- video/bink_decoder.cpp | 1056 +++++++++++++++++-------------------- video/bink_decoder.h | 420 ++++++++------- 3 files changed, 707 insertions(+), 777 deletions(-) diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index b37a565aab..8329511c14 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -40,10 +40,7 @@ MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) : _vm(vm) { _video = new Video::BinkDecoder(); else #endif - { _video = new Video::SmackerDecoder(); - ((Video::AdvancedVideoDecoder *)_video)->start(); - } _flags = 0; _wizResNum = 0; @@ -64,11 +61,16 @@ int MoviePlayer::load(const char *filename, int flags, int image) { if (_video->isVideoLoaded()) _video->close(); + // Ensure that Bink will use our PixelFormat + ((Video::AdvancedVideoDecoder *)_video)->setDefaultHighColorFormat(g_system->getScreenFormat()); + if (!_video->loadFile(filename)) { warning("Failed to load video file %s", filename); return -1; } + ((Video::AdvancedVideoDecoder *)_video)->start(); + debug(1, "Playing video %s", filename); if (flags & 2) diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index 538487f067..cac0b356c5 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -24,6 +24,7 @@ // based quite heavily on the Bink decoder found in FFmpeg. // Many thanks to Kostya Shishkov for doing the hard work. +#include "audio/audiostream.h" #include "audio/decoders/raw.h" #include "common/util.h" @@ -60,139 +61,108 @@ static const uint32 kDCStartBits = 11; namespace Video { -BinkDecoder::VideoFrame::VideoFrame() : bits(0) { -} - -BinkDecoder::VideoFrame::~VideoFrame() { - delete bits; +BinkDecoder::BinkDecoder() { + _bink = 0; } - -BinkDecoder::AudioTrack::AudioTrack() : bits(0), bands(0), rdft(0), dct(0) { +BinkDecoder::~BinkDecoder() { + close(); } -BinkDecoder::AudioTrack::~AudioTrack() { - delete bits; - - delete[] bands; - - delete rdft; - delete dct; -} +bool BinkDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + uint32 id = stream->readUint32BE(); + if ((id != kBIKfID) && (id != kBIKgID) && (id != kBIKhID) && (id != kBIKiID)) + return false; -BinkDecoder::BinkDecoder() { - _bink = 0; - _audioTrack = 0; + uint32 fileSize = stream->readUint32LE() + 8; + uint32 frameCount = stream->readUint32LE(); + uint32 largestFrameSize = stream->readUint32LE(); - for (int i = 0; i < 16; i++) - _huffman[i] = 0; + if (largestFrameSize > fileSize) { + warning("Largest frame size greater than file size"); + return false; + } - for (int i = 0; i < kSourceMAX; i++) { - _bundles[i].countLength = 0; + stream->skip(4); - _bundles[i].huffman.index = 0; - for (int j = 0; j < 16; j++) - _bundles[i].huffman.symbols[j] = j; + uint32 width = stream->readUint32LE(); + uint32 height = stream->readUint32LE(); - _bundles[i].data = 0; - _bundles[i].dataEnd = 0; - _bundles[i].curDec = 0; - _bundles[i].curPtr = 0; + uint32 frameRateNum = stream->readUint32LE(); + uint32 frameRateDen = stream->readUint32LE(); + if (frameRateNum == 0 || frameRateDen == 0) { + warning("Invalid frame rate (%d/%d)", frameRateNum, frameRateDen); + return false; } - for (int i = 0; i < 16; i++) { - _colHighHuffman[i].index = 0; - for (int j = 0; j < 16; j++) - _colHighHuffman[i].symbols[j] = j; - } + _bink = stream; - for (int i = 0; i < 4; i++) { - _curPlanes[i] = 0; - _oldPlanes[i] = 0; - } + uint32 videoFlags = _bink->readUint32LE(); - _audioStream = 0; -} + // BIKh and BIKi swap the chroma planes + addTrack(new BinkVideoTrack(width, height, getDefaultHighColorFormat(), frameCount, + Common::Rational(frameRateNum, frameRateDen), (id == kBIKhID || id == kBIKiID), videoFlags & kVideoFlagAlpha, id)); -void BinkDecoder::startAudio() { - if (_audioTrack < _audioTracks.size()) { - const AudioTrack &audio = _audioTracks[_audioTrack]; + uint32 audioTrackCount = _bink->readUint32LE(); - _audioStream = Audio::makeQueuingAudioStream(audio.outSampleRate, audio.outChannels == 2); - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance()); - } // else no audio -} + if (audioTrackCount > 0) { + _audioTracks.reserve(audioTrackCount); -void BinkDecoder::stopAudio() { - if (_audioStream) { - g_system->getMixer()->stopHandle(_audioHandle); - _audioStream = 0; - } -} + _bink->skip(4 * audioTrackCount); -BinkDecoder::~BinkDecoder() { - close(); -} + // Reading audio track properties + for (uint32 i = 0; i < audioTrackCount; i++) { + AudioInfo track; -void BinkDecoder::close() { - reset(); + track.sampleRate = _bink->readUint16LE(); + track.flags = _bink->readUint16LE(); - // Stop audio - stopAudio(); + _audioTracks.push_back(track); - for (int i = 0; i < 4; i++) { - delete[] _curPlanes[i]; _curPlanes[i] = 0; - delete[] _oldPlanes[i]; _oldPlanes[i] = 0; + initAudioTrack(_audioTracks[i]); + } + + _bink->skip(4 * audioTrackCount); } - deinitBundles(); + // Reading video frame properties + _frames.resize(frameCount); + for (uint32 i = 0; i < frameCount; i++) { + _frames[i].offset = _bink->readUint32LE(); + _frames[i].keyFrame = _frames[i].offset & 1; - for (int i = 0; i < 16; i++) { - delete _huffman[i]; - _huffman[i] = 0; - } + _frames[i].offset &= ~1; - delete _bink; _bink = 0; - _surface.free(); + if (i != 0) + _frames[i - 1].size = _frames[i].offset - _frames[i - 1].offset; - _audioTrack = 0; + _frames[i].bits = 0; + } - for (int i = 0; i < kSourceMAX; i++) { - _bundles[i].countLength = 0; + _frames[frameCount - 1].size = _bink->size() - _frames[frameCount - 1].offset; - _bundles[i].huffman.index = 0; - for (int j = 0; j < 16; j++) - _bundles[i].huffman.symbols[j] = j; + return true; +} - _bundles[i].data = 0; - _bundles[i].dataEnd = 0; - _bundles[i].curDec = 0; - _bundles[i].curPtr = 0; - } +void BinkDecoder::close() { + AdvancedVideoDecoder::close(); - for (int i = 0; i < 16; i++) { - _colHighHuffman[i].index = 0; - for (int j = 0; j < 16; j++) - _colHighHuffman[i].symbols[j] = j; - } + delete _bink; + _bink = 0; _audioTracks.clear(); _frames.clear(); } -uint32 BinkDecoder::getTime() const { - if (_audioStream && g_system->getMixer()->isSoundHandleActive(_audioHandle)) - return g_system->getMixer()->getSoundElapsedTime(_audioHandle) + _audioStartOffset; - - return g_system->getMillis() - _startTime; -} +void BinkDecoder::readNextPacket() { + BinkVideoTrack *videoTrack = (BinkVideoTrack *)getTrack(0); -const Graphics::Surface *BinkDecoder::decodeNextFrame() { - if (endOfVideo()) - return 0; + if (videoTrack->endOfTrack()) + return; - VideoFrame &frame = _frames[_curFrame + 1]; + VideoFrame &frame = _frames[videoTrack->getCurFrame() + 1]; if (!_bink->seek(frame.offset)) error("Bad bink seek"); @@ -200,7 +170,7 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { uint32 frameSize = frame.size; for (uint32 i = 0; i < _audioTracks.size(); i++) { - AudioTrack &audio = _audioTracks[i]; + AudioInfo &audio = _audioTracks[i]; uint32 audioPacketLength = _bink->readUint32LE(); @@ -210,24 +180,21 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { error("Audio packet too big for the frame"); if (audioPacketLength >= 4) { + // Get our track - audio index plus one as the first track is video + BinkAudioTrack *audioTrack = (BinkAudioTrack *)getTrack(i + 1); uint32 audioPacketStart = _bink->pos(); uint32 audioPacketEnd = _bink->pos() + audioPacketLength; - if (i == _audioTrack) { - // Only play one audio track + // Number of samples in bytes + audio.sampleCount = _bink->readUint32LE() / (2 * audio.channels); - // Number of samples in bytes - audio.sampleCount = _bink->readUint32LE() / (2 * audio.channels); + audio.bits = new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + audioPacketStart + 4, audioPacketEnd), true); - audio.bits = - new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, - audioPacketStart + 4, audioPacketEnd), true); + audioTrack->decodePacket(); - audioPacket(audio); - - delete audio.bits; - audio.bits = 0; - } + delete audio.bits; + audio.bits = 0; _bink->seek(audioPacketEnd); @@ -238,67 +205,125 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { uint32 videoPacketStart = _bink->pos(); uint32 videoPacketEnd = _bink->pos() + frameSize; - frame.bits = - new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, - videoPacketStart, videoPacketEnd), true); + frame.bits = new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + videoPacketStart, videoPacketEnd), true); - videoPacket(frame); + videoTrack->decodePacket(frame); delete frame.bits; frame.bits = 0; +} - _curFrame++; - if (_curFrame == 0) - _startTime = g_system->getMillis(); +BinkDecoder::VideoFrame::VideoFrame() : bits(0) { +} - return &_surface; +BinkDecoder::VideoFrame::~VideoFrame() { + delete bits; } -void BinkDecoder::audioPacket(AudioTrack &audio) { - if (!_audioStream) - return; - int outSize = audio.frameLen * audio.channels; - while (audio.bits->pos() < audio.bits->size()) { - int16 *out = (int16 *)malloc(outSize * 2); - memset(out, 0, outSize * 2); +BinkDecoder::AudioInfo::AudioInfo() : bits(0), bands(0), rdft(0), dct(0) { +} - audioBlock(audio, out); +BinkDecoder::AudioInfo::~AudioInfo() { + delete bits; - byte flags = Audio::FLAG_16BITS; - if (audio.outChannels == 2) - flags |= Audio::FLAG_STEREO; + delete[] bands; -#ifdef SCUMM_LITTLE_ENDIAN - flags |= Audio::FLAG_LITTLE_ENDIAN; -#endif + delete rdft; + delete dct; +} + +BinkDecoder::BinkVideoTrack::BinkVideoTrack(uint32 width, uint32 height, const Graphics::PixelFormat &format, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id) : + _frameCount(frameCount), _frameRate(frameRate), _swapPlanes(swapPlanes), _hasAlpha(hasAlpha), _id(id) { + _curFrame = -1; + + for (int i = 0; i < 16; i++) + _huffman[i] = 0; - _audioStream->queueBuffer((byte *)out, audio.blockSize * 2, DisposeAfterUse::YES, flags); + for (int i = 0; i < kSourceMAX; i++) { + _bundles[i].countLength = 0; + + _bundles[i].huffman.index = 0; + for (int j = 0; j < 16; j++) + _bundles[i].huffman.symbols[j] = j; - if (audio.bits->pos() & 0x1F) // next data block starts at a 32-byte boundary - audio.bits->skip(32 - (audio.bits->pos() & 0x1F)); + _bundles[i].data = 0; + _bundles[i].dataEnd = 0; + _bundles[i].curDec = 0; + _bundles[i].curPtr = 0; + } + + for (int i = 0; i < 16; i++) { + _colHighHuffman[i].index = 0; + for (int j = 0; j < 16; j++) + _colHighHuffman[i].symbols[j] = j; + } + + _surface.create(width, height, format); + + // Give the planes a bit extra space + width = _surface.w + 32; + height = _surface.h + 32; + + _curPlanes[0] = new byte[ width * height ]; // Y + _curPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution + _curPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution + _curPlanes[3] = new byte[ width * height ]; // A + _oldPlanes[0] = new byte[ width * height ]; // Y + _oldPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution + _oldPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution + _oldPlanes[3] = new byte[ width * height ]; // A + + // Initialize the video with solid black + memset(_curPlanes[0], 0, width * height ); + memset(_curPlanes[1], 0, (width >> 1) * (height >> 1)); + memset(_curPlanes[2], 0, (width >> 1) * (height >> 1)); + memset(_curPlanes[3], 255, width * height ); + memset(_oldPlanes[0], 0, width * height ); + memset(_oldPlanes[1], 0, (width >> 1) * (height >> 1)); + memset(_oldPlanes[2], 0, (width >> 1) * (height >> 1)); + memset(_oldPlanes[3], 255, width * height ); + + initBundles(); + initHuffman(); +} + +BinkDecoder::BinkVideoTrack::~BinkVideoTrack() { + for (int i = 0; i < 4; i++) { + delete[] _curPlanes[i]; _curPlanes[i] = 0; + delete[] _oldPlanes[i]; _oldPlanes[i] = 0; + } + + deinitBundles(); + + for (int i = 0; i < 16; i++) { + delete _huffman[i]; + _huffman[i] = 0; } + + _surface.free(); } -void BinkDecoder::videoPacket(VideoFrame &video) { - assert(video.bits); +void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) { + assert(frame.bits); if (_hasAlpha) { if (_id == kBIKiID) - video.bits->skip(32); + frame.bits->skip(32); - decodePlane(video, 3, false); + decodePlane(frame, 3, false); } if (_id == kBIKiID) - video.bits->skip(32); + frame.bits->skip(32); for (int i = 0; i < 3; i++) { int planeIdx = ((i == 0) || !_swapPlanes) ? i : (i ^ 3); - decodePlane(video, planeIdx, i != 0); + decodePlane(frame, planeIdx, i != 0); - if (video.bits->pos() >= video.bits->size()) + if (frame.bits->pos() >= frame.bits->size()) break; } @@ -311,10 +336,11 @@ void BinkDecoder::videoPacket(VideoFrame &video) { // And swap the planes with the reference planes for (int i = 0; i < 4; i++) SWAP(_curPlanes[i], _oldPlanes[i]); -} -void BinkDecoder::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { + _curFrame++; +} +void BinkDecoder::BinkVideoTrack::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { uint32 blockWidth = isChroma ? ((_surface.w + 15) >> 4) : ((_surface.w + 7) >> 3); uint32 blockHeight = isChroma ? ((_surface.h + 15) >> 4) : ((_surface.h + 7) >> 3); uint32 width = isChroma ? (_surface.w >> 1) : _surface.w; @@ -371,48 +397,38 @@ void BinkDecoder::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { } switch (blockType) { - case kBlockSkip: - blockSkip(ctx); - break; - - case kBlockScaled: - blockScaled(ctx); - break; - - case kBlockMotion: - blockMotion(ctx); - break; - - case kBlockRun: - blockRun(ctx); - break; - - case kBlockResidue: - blockResidue(ctx); - break; - - case kBlockIntra: - blockIntra(ctx); - break; - - case kBlockFill: - blockFill(ctx); - break; - - case kBlockInter: - blockInter(ctx); - break; - - case kBlockPattern: - blockPattern(ctx); - break; - - case kBlockRaw: - blockRaw(ctx); - break; - - default: - error("Unknown block type: %d", blockType); + case kBlockSkip: + blockSkip(ctx); + break; + case kBlockScaled: + blockScaled(ctx); + break; + case kBlockMotion: + blockMotion(ctx); + break; + case kBlockRun: + blockRun(ctx); + break; + case kBlockResidue: + blockResidue(ctx); + break; + case kBlockIntra: + blockIntra(ctx); + break; + case kBlockFill: + blockFill(ctx); + break; + case kBlockInter: + blockInter(ctx); + break; + case kBlockPattern: + blockPattern(ctx); + break; + case kBlockRaw: + blockRaw(ctx); + break; + default: + error("Unknown block type: %d", blockType); } } @@ -424,7 +440,7 @@ void BinkDecoder::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { } -void BinkDecoder::readBundle(VideoFrame &video, Source source) { +void BinkDecoder::BinkVideoTrack::readBundle(VideoFrame &video, Source source) { if (source == kSourceColors) { for (int i = 0; i < 16; i++) readHuffman(video, _colHighHuffman[i]); @@ -439,12 +455,11 @@ void BinkDecoder::readBundle(VideoFrame &video, Source source) { _bundles[source].curPtr = _bundles[source].data; } -void BinkDecoder::readHuffman(VideoFrame &video, Huffman &huffman) { +void BinkDecoder::BinkVideoTrack::readHuffman(VideoFrame &video, Huffman &huffman) { huffman.index = video.bits->getBits(4); if (huffman.index == 0) { // The first tree always gives raw nibbles - for (int i = 0; i < 16; i++) huffman.symbols[i] = i; @@ -455,7 +470,6 @@ void BinkDecoder::readHuffman(VideoFrame &video, Huffman &huffman) { if (video.bits->getBit()) { // Symbol selection - memset(hasSymbol, 0, 16); uint8 length = video.bits->getBits(3); @@ -493,214 +507,29 @@ void BinkDecoder::readHuffman(VideoFrame &video, Huffman &huffman) { memcpy(huffman.symbols, in, 16); } -void BinkDecoder::mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size) { - const byte *src2 = src + size; - int size2 = size; - - do { - if (!video.bits->getBit()) { - *dst++ = *src++; - size--; - } else { - *dst++ = *src2++; - size2--; - } - - } while (size && size2); - - while (size--) - *dst++ = *src++; - while (size2--) - *dst++ = *src2++; -} - -bool BinkDecoder::loadStream(Common::SeekableReadStream *stream) { - Graphics::PixelFormat format = g_system->getScreenFormat(); - return loadStream(stream, format); -} - -bool BinkDecoder::loadStream(Common::SeekableReadStream *stream, const Graphics::PixelFormat &format) { - close(); - - _id = stream->readUint32BE(); - if ((_id != kBIKfID) && (_id != kBIKgID) && (_id != kBIKhID) && (_id != kBIKiID)) - return false; - - uint32 fileSize = stream->readUint32LE() + 8; - uint32 frameCount = stream->readUint32LE(); - uint32 largestFrameSize = stream->readUint32LE(); - - if (largestFrameSize > fileSize) { - warning("Largest frame size greater than file size"); - return false; - } - - stream->skip(4); - - uint32 width = stream->readUint32LE(); - uint32 height = stream->readUint32LE(); - - uint32 frameRateNum = stream->readUint32LE(); - uint32 frameRateDen = stream->readUint32LE(); - if (frameRateNum == 0 || frameRateDen == 0) { - warning("Invalid frame rate (%d/%d)", frameRateNum, frameRateDen); - return false; - } - - _frameRate = Common::Rational(frameRateNum, frameRateDen); - _bink = stream; - - _videoFlags = _bink->readUint32LE(); - - uint32 audioTrackCount = _bink->readUint32LE(); - - if (audioTrackCount > 1) { - warning("More than one audio track found. Using the first one"); - - _audioTrack = 0; - } - - if (audioTrackCount > 0) { - _audioTracks.reserve(audioTrackCount); - - _bink->skip(4 * audioTrackCount); - - // Reading audio track properties - for (uint32 i = 0; i < audioTrackCount; i++) { - AudioTrack track; - - track.sampleRate = _bink->readUint16LE(); - track.flags = _bink->readUint16LE(); - - _audioTracks.push_back(track); - - initAudioTrack(_audioTracks[i]); - } - - _bink->skip(4 * audioTrackCount); - } - - // Reading video frame properties - _frames.resize(frameCount); - for (uint32 i = 0; i < frameCount; i++) { - _frames[i].offset = _bink->readUint32LE(); - _frames[i].keyFrame = _frames[i].offset & 1; - - _frames[i].offset &= ~1; - - if (i != 0) - _frames[i - 1].size = _frames[i].offset - _frames[i - 1].offset; - - _frames[i].bits = 0; - } - - _frames[frameCount - 1].size = _bink->size() - _frames[frameCount - 1].offset; - - _hasAlpha = _videoFlags & kVideoFlagAlpha; - _swapPlanes = (_id == kBIKhID) || (_id == kBIKiID); // BIKh and BIKi swap the chroma planes - - _surface.create(width, height, format); - - // Give the planes a bit extra space - width = _surface.w + 32; - height = _surface.h + 32; - - _curPlanes[0] = new byte[ width * height ]; // Y - _curPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution - _curPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution - _curPlanes[3] = new byte[ width * height ]; // A - _oldPlanes[0] = new byte[ width * height ]; // Y - _oldPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution - _oldPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution - _oldPlanes[3] = new byte[ width * height ]; // A - - // Initialize the video with solid black - memset(_curPlanes[0], 0, width * height ); - memset(_curPlanes[1], 0, (width >> 1) * (height >> 1)); - memset(_curPlanes[2], 0, (width >> 1) * (height >> 1)); - memset(_curPlanes[3], 255, width * height ); - memset(_oldPlanes[0], 0, width * height ); - memset(_oldPlanes[1], 0, (width >> 1) * (height >> 1)); - memset(_oldPlanes[2], 0, (width >> 1) * (height >> 1)); - memset(_oldPlanes[3], 255, width * height ); - - initBundles(); - initHuffman(); - - startAudio(); - _audioStartOffset = 0; - - return true; -} - -void BinkDecoder::initAudioTrack(AudioTrack &audio) { - audio.sampleCount = 0; - audio.bits = 0; - - audio.channels = ((audio.flags & kAudioFlagStereo) != 0) ? 2 : 1; - audio.codec = ((audio.flags & kAudioFlagDCT ) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; - - if (audio.channels > kAudioChannelsMax) - error("Too many audio channels: %d", audio.channels); - - uint32 frameLenBits; - // Calculate frame length - if (audio.sampleRate < 22050) - frameLenBits = 9; - else if(audio.sampleRate < 44100) - frameLenBits = 10; - else - frameLenBits = 11; - - audio.frameLen = 1 << frameLenBits; - - audio.outSampleRate = audio.sampleRate; - audio.outChannels = audio.channels; - - if (audio.codec == kAudioCodecRDFT) { - // RDFT audio already interleaves the samples correctly - - if (audio.channels == 2) - frameLenBits++; - - audio.sampleRate *= audio.channels; - audio.frameLen *= audio.channels; - audio.channels = 1; - } - - audio.overlapLen = audio.frameLen / 16; - audio.blockSize = (audio.frameLen - audio.overlapLen) * audio.channels; - audio.root = 2.0 / sqrt((double)audio.frameLen); - - uint32 sampleRateHalf = (audio.sampleRate + 1) / 2; - - // Calculate number of bands - for (audio.bandCount = 1; audio.bandCount < 25; audio.bandCount++) - if (sampleRateHalf <= binkCriticalFreqs[audio.bandCount - 1]) - break; - - audio.bands = new uint32[audio.bandCount + 1]; - - // Populate bands - audio.bands[0] = 1; - for (uint32 i = 1; i < audio.bandCount; i++) - audio.bands[i] = binkCriticalFreqs[i - 1] * (audio.frameLen / 2) / sampleRateHalf; - audio.bands[audio.bandCount] = audio.frameLen / 2; - - audio.first = true; +void BinkDecoder::BinkVideoTrack::mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size) { + const byte *src2 = src + size; + int size2 = size; - for (uint8 i = 0; i < audio.channels; i++) - audio.coeffsPtr[i] = audio.coeffs + i * audio.frameLen; + do { + if (!video.bits->getBit()) { + *dst++ = *src++; + size--; + } else { + *dst++ = *src2++; + size2--; + } - audio.codec = ((audio.flags & kAudioFlagDCT) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; + } while (size && size2); - if (audio.codec == kAudioCodecRDFT) - audio.rdft = new Common::RDFT(frameLenBits, Common::RDFT::DFT_C2R); - else if (audio.codec == kAudioCodecDCT) - audio.dct = new Common::DCT(frameLenBits, Common::DCT::DCT_III); + while (size--) + *dst++ = *src++; + + while (size2--) + *dst++ = *src2++; } -void BinkDecoder::initBundles() { +void BinkDecoder::BinkVideoTrack::initBundles() { uint32 bw = (_surface.w + 7) >> 3; uint32 bh = (_surface.h + 7) >> 3; uint32 blocks = bw * bh; @@ -729,21 +558,21 @@ void BinkDecoder::initBundles() { } } -void BinkDecoder::deinitBundles() { +void BinkDecoder::BinkVideoTrack::deinitBundles() { for (int i = 0; i < kSourceMAX; i++) delete[] _bundles[i].data; } -void BinkDecoder::initHuffman() { +void BinkDecoder::BinkVideoTrack::initHuffman() { for (int i = 0; i < 16; i++) _huffman[i] = new Common::Huffman(binkHuffmanLengths[i][15], 16, binkHuffmanCodes[i], binkHuffmanLengths[i]); } -byte BinkDecoder::getHuffmanSymbol(VideoFrame &video, Huffman &huffman) { +byte BinkDecoder::BinkVideoTrack::getHuffmanSymbol(VideoFrame &video, Huffman &huffman) { return huffman.symbols[_huffman[huffman.index]->getSymbol(*video.bits)]; } -int32 BinkDecoder::getBundleValue(Source source) { +int32 BinkDecoder::BinkVideoTrack::getBundleValue(Source source) { if ((source < kSourceXOff) || (source == kSourceRun)) return *_bundles[source].curPtr++; @@ -757,7 +586,7 @@ int32 BinkDecoder::getBundleValue(Source source) { return ret; } -uint32 BinkDecoder::readBundleCount(VideoFrame &video, Bundle &bundle) { +uint32 BinkDecoder::BinkVideoTrack::readBundleCount(VideoFrame &video, Bundle &bundle) { if (!bundle.curDec || (bundle.curDec > bundle.curPtr)) return 0; @@ -768,7 +597,7 @@ uint32 BinkDecoder::readBundleCount(VideoFrame &video, Bundle &bundle) { return n; } -void BinkDecoder::blockSkip(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockSkip(DecodeContext &ctx) { byte *dest = ctx.dest; byte *prev = ctx.prev; @@ -776,7 +605,7 @@ void BinkDecoder::blockSkip(DecodeContext &ctx) { memcpy(dest, prev, 8); } -void BinkDecoder::blockScaledSkip(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledSkip(DecodeContext &ctx) { byte *dest = ctx.dest; byte *prev = ctx.prev; @@ -784,7 +613,7 @@ void BinkDecoder::blockScaledSkip(DecodeContext &ctx) { memcpy(dest, prev, 16); } -void BinkDecoder::blockScaledRun(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledRun(DecodeContext &ctx) { const uint8 *scan = binkPatterns[ctx.video->bits->getBits(4)]; int i = 0; @@ -820,7 +649,7 @@ void BinkDecoder::blockScaledRun(DecodeContext &ctx) { ctx.dest[ctx.coordScaledMap4[*scan]] = getBundleValue(kSourceColors); } -void BinkDecoder::blockScaledIntra(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledIntra(DecodeContext &ctx) { int16 block[64]; memset(block, 0, 64 * sizeof(int16)); @@ -841,7 +670,7 @@ void BinkDecoder::blockScaledIntra(DecodeContext &ctx) { } } -void BinkDecoder::blockScaledFill(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledFill(DecodeContext &ctx) { byte v = getBundleValue(kSourceColors); byte *dest = ctx.dest; @@ -849,7 +678,7 @@ void BinkDecoder::blockScaledFill(DecodeContext &ctx) { memset(dest, v, 16); } -void BinkDecoder::blockScaledPattern(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledPattern(DecodeContext &ctx) { byte col[2]; for (int i = 0; i < 2; i++) @@ -865,7 +694,7 @@ void BinkDecoder::blockScaledPattern(DecodeContext &ctx) { } } -void BinkDecoder::blockScaledRaw(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledRaw(DecodeContext &ctx) { byte row[8]; byte *dest1 = ctx.dest; @@ -880,32 +709,27 @@ void BinkDecoder::blockScaledRaw(DecodeContext &ctx) { } } -void BinkDecoder::blockScaled(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaled(DecodeContext &ctx) { BlockType blockType = (BlockType) getBundleValue(kSourceSubBlockTypes); switch (blockType) { - case kBlockRun: - blockScaledRun(ctx); - break; - - case kBlockIntra: - blockScaledIntra(ctx); - break; - - case kBlockFill: - blockScaledFill(ctx); - break; - - case kBlockPattern: - blockScaledPattern(ctx); - break; - - case kBlockRaw: - blockScaledRaw(ctx); - break; - - default: - error("Invalid 16x16 block type: %d", blockType); + case kBlockRun: + blockScaledRun(ctx); + break; + case kBlockIntra: + blockScaledIntra(ctx); + break; + case kBlockFill: + blockScaledFill(ctx); + break; + case kBlockPattern: + blockScaledPattern(ctx); + break; + case kBlockRaw: + blockScaledRaw(ctx); + break; + default: + error("Invalid 16x16 block type: %d", blockType); } ctx.blockX += 1; @@ -913,7 +737,7 @@ void BinkDecoder::blockScaled(DecodeContext &ctx) { ctx.prev += 8; } -void BinkDecoder::blockMotion(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockMotion(DecodeContext &ctx) { int8 xOff = getBundleValue(kSourceXOff); int8 yOff = getBundleValue(kSourceYOff); @@ -926,7 +750,7 @@ void BinkDecoder::blockMotion(DecodeContext &ctx) { memcpy(dest, prev, 8); } -void BinkDecoder::blockRun(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockRun(DecodeContext &ctx) { const uint8 *scan = binkPatterns[ctx.video->bits->getBits(4)]; int i = 0; @@ -953,7 +777,7 @@ void BinkDecoder::blockRun(DecodeContext &ctx) { ctx.dest[ctx.coordMap[*scan++]] = getBundleValue(kSourceColors); } -void BinkDecoder::blockResidue(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockResidue(DecodeContext &ctx) { blockMotion(ctx); byte v = ctx.video->bits->getBits(7); @@ -970,7 +794,7 @@ void BinkDecoder::blockResidue(DecodeContext &ctx) { dst[j] += src[j]; } -void BinkDecoder::blockIntra(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockIntra(DecodeContext &ctx) { int16 block[64]; memset(block, 0, 64 * sizeof(int16)); @@ -981,7 +805,7 @@ void BinkDecoder::blockIntra(DecodeContext &ctx) { IDCTPut(ctx, block); } -void BinkDecoder::blockFill(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockFill(DecodeContext &ctx) { byte v = getBundleValue(kSourceColors); byte *dest = ctx.dest; @@ -989,7 +813,7 @@ void BinkDecoder::blockFill(DecodeContext &ctx) { memset(dest, v, 8); } -void BinkDecoder::blockInter(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockInter(DecodeContext &ctx) { blockMotion(ctx); int16 block[64]; @@ -1002,7 +826,7 @@ void BinkDecoder::blockInter(DecodeContext &ctx) { IDCTAdd(ctx, block); } -void BinkDecoder::blockPattern(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockPattern(DecodeContext &ctx) { byte col[2]; for (int i = 0; i < 2; i++) @@ -1017,7 +841,7 @@ void BinkDecoder::blockPattern(DecodeContext &ctx) { } } -void BinkDecoder::blockRaw(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockRaw(DecodeContext &ctx) { byte *dest = ctx.dest; byte *data = _bundles[kSourceColors].curPtr; for (int i = 0; i < 8; i++, dest += ctx.pitch, data += 8) @@ -1026,7 +850,7 @@ void BinkDecoder::blockRaw(DecodeContext &ctx) { _bundles[kSourceColors].curPtr += 64; } -void BinkDecoder::readRuns(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readRuns(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1046,7 +870,7 @@ void BinkDecoder::readRuns(VideoFrame &video, Bundle &bundle) { *bundle.curDec++ = getHuffmanSymbol(video, bundle.huffman); } -void BinkDecoder::readMotionValues(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readMotionValues(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1083,7 +907,7 @@ void BinkDecoder::readMotionValues(VideoFrame &video, Bundle &bundle) { } const uint8 rleLens[4] = { 4, 8, 12, 32 }; -void BinkDecoder::readBlockTypes(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readBlockTypes(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1120,7 +944,7 @@ void BinkDecoder::readBlockTypes(VideoFrame &video, Bundle &bundle) { } while (bundle.curDec < decEnd); } -void BinkDecoder::readPatterns(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readPatterns(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1138,7 +962,7 @@ void BinkDecoder::readPatterns(VideoFrame &video, Bundle &bundle) { } -void BinkDecoder::readColors(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readColors(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1182,7 +1006,7 @@ void BinkDecoder::readColors(VideoFrame &video, Bundle &bundle) { } } -void BinkDecoder::readDCS(VideoFrame &video, Bundle &bundle, int startBits, bool hasSign) { +void BinkDecoder::BinkVideoTrack::readDCS(VideoFrame &video, Bundle &bundle, int startBits, bool hasSign) { uint32 length = readBundleCount(video, bundle); if (length == 0) return; @@ -1228,7 +1052,7 @@ void BinkDecoder::readDCS(VideoFrame &video, Bundle &bundle, int startBits, bool } /** Reads 8x8 block of DCT coefficients. */ -void BinkDecoder::readDCTCoeffs(VideoFrame &video, int16 *block, bool isIntra) { +void BinkDecoder::BinkVideoTrack::readDCTCoeffs(VideoFrame &video, int16 *block, bool isIntra) { int coefCount = 0; int coefIdx[64]; @@ -1326,7 +1150,7 @@ void BinkDecoder::readDCTCoeffs(VideoFrame &video, int16 *block, bool isIntra) { } /** Reads 8x8 block with residue after motion compensation. */ -void BinkDecoder::readResidue(VideoFrame &video, int16 *block, int masksCount) { +void BinkDecoder::BinkVideoTrack::readResidue(VideoFrame &video, int16 *block, int masksCount) { int nzCoeff[64]; int nzCoeffCount = 0; @@ -1417,63 +1241,170 @@ void BinkDecoder::readResidue(VideoFrame &video, int16 *block, int masksCount) { } } -float BinkDecoder::getFloat(AudioTrack &audio) { - int power = audio.bits->getBits(5); +#define A1 2896 /* (1/sqrt(2))<<12 */ +#define A2 2217 +#define A3 3784 +#define A4 -5352 - float f = ldexp((float)audio.bits->getBits(23), power - 23); +#define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\ + const int a0 = (src)[s0] + (src)[s4]; \ + const int a1 = (src)[s0] - (src)[s4]; \ + const int a2 = (src)[s2] + (src)[s6]; \ + const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \ + const int a4 = (src)[s5] + (src)[s3]; \ + const int a5 = (src)[s5] - (src)[s3]; \ + const int a6 = (src)[s1] + (src)[s7]; \ + const int a7 = (src)[s1] - (src)[s7]; \ + const int b0 = a4 + a6; \ + const int b1 = (A3*(a5 + a7)) >> 11; \ + const int b2 = ((A4*a5) >> 11) - b0 + b1; \ + const int b3 = (A1*(a6 - a4) >> 11) - b2; \ + const int b4 = ((A2*a7) >> 11) + b3 - b1; \ + (dest)[d0] = munge(a0+a2 +b0); \ + (dest)[d1] = munge(a1+a3-a2+b2); \ + (dest)[d2] = munge(a1-a3+a2+b3); \ + (dest)[d3] = munge(a0-a2 -b4); \ + (dest)[d4] = munge(a0-a2 +b4); \ + (dest)[d5] = munge(a1-a3+a2-b3); \ + (dest)[d6] = munge(a1+a3-a2-b2); \ + (dest)[d7] = munge(a0+a2 -b0); \ +} +/* end IDCT_TRANSFORM macro */ - if (audio.bits->getBit()) - f = -f; +#define MUNGE_NONE(x) (x) +#define IDCT_COL(dest,src) IDCT_TRANSFORM(dest,0,8,16,24,32,40,48,56,0,8,16,24,32,40,48,56,MUNGE_NONE,src) - return f; +#define MUNGE_ROW(x) (((x) + 0x7F)>>8) +#define IDCT_ROW(dest,src) IDCT_TRANSFORM(dest,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,MUNGE_ROW,src) + +static inline void IDCTCol(int16 *dest, const int16 *src) { + if ((src[8] | src[16] | src[24] | src[32] | src[40] | src[48] | src[56]) == 0) { + dest[ 0] = + dest[ 8] = + dest[16] = + dest[24] = + dest[32] = + dest[40] = + dest[48] = + dest[56] = src[0]; + } else { + IDCT_COL(dest, src); + } +} + +void BinkDecoder::BinkVideoTrack::IDCT(int16 *block) { + int i; + int16 temp[64]; + + for (i = 0; i < 8; i++) + IDCTCol(&temp[i], &block[i]); + for (i = 0; i < 8; i++) { + IDCT_ROW( (&block[8*i]), (&temp[8*i]) ); + } +} + +void BinkDecoder::BinkVideoTrack::IDCTAdd(DecodeContext &ctx, int16 *block) { + int i, j; + + IDCT(block); + byte *dest = ctx.dest; + for (i = 0; i < 8; i++, dest += ctx.pitch, block += 8) + for (j = 0; j < 8; j++) + dest[j] += block[j]; +} + +void BinkDecoder::BinkVideoTrack::IDCTPut(DecodeContext &ctx, int16 *block) { + int i; + int16 temp[64]; + for (i = 0; i < 8; i++) + IDCTCol(&temp[i], &block[i]); + for (i = 0; i < 8; i++) { + IDCT_ROW( (&ctx.dest[i*ctx.pitch]), (&temp[8*i]) ); + } +} + +BinkDecoder::BinkAudioTrack::BinkAudioTrack(BinkDecoder::AudioInfo &audio) : _audioInfo(&audio) { + _audioStream = Audio::makeQueuingAudioStream(_audioInfo->outSampleRate, _audioInfo->outChannels == 2); +} + +BinkDecoder::BinkAudioTrack::~BinkAudioTrack() { + delete _audioStream; +} + +Audio::AudioStream *BinkDecoder::BinkAudioTrack::getAudioStream() const { + return _audioStream; +} + +void BinkDecoder::BinkAudioTrack::decodePacket() { + int outSize = _audioInfo->frameLen * _audioInfo->channels; + + while (_audioInfo->bits->pos() < _audioInfo->bits->size()) { + int16 *out = (int16 *)malloc(outSize * 2); + memset(out, 0, outSize * 2); + + audioBlock(out); + + byte flags = Audio::FLAG_16BITS; + if (_audioInfo->outChannels == 2) + flags |= Audio::FLAG_STEREO; + +#ifdef SCUMM_LITTLE_ENDIAN + flags |= Audio::FLAG_LITTLE_ENDIAN; +#endif + + _audioStream->queueBuffer((byte *)out, _audioInfo->blockSize * 2, DisposeAfterUse::YES, flags); + + if (_audioInfo->bits->pos() & 0x1F) // next data block starts at a 32-byte boundary + _audioInfo->bits->skip(32 - (_audioInfo->bits->pos() & 0x1F)); + } } -void BinkDecoder::audioBlock(AudioTrack &audio, int16 *out) { - if (audio.codec == kAudioCodecDCT) - audioBlockDCT (audio); - else if (audio.codec == kAudioCodecRDFT) - audioBlockRDFT(audio); +void BinkDecoder::BinkAudioTrack::audioBlock(int16 *out) { + if (_audioInfo->codec == kAudioCodecDCT) + audioBlockDCT (); + else if (_audioInfo->codec == kAudioCodecRDFT) + audioBlockRDFT(); - floatToInt16Interleave(out, const_cast(audio.coeffsPtr), audio.frameLen, audio.channels); + floatToInt16Interleave(out, const_cast(_audioInfo->coeffsPtr), _audioInfo->frameLen, _audioInfo->channels); - if (!audio.first) { - int count = audio.overlapLen * audio.channels; + if (!_audioInfo->first) { + int count = _audioInfo->overlapLen * _audioInfo->channels; int shift = Common::intLog2(count); for (int i = 0; i < count; i++) { - out[i] = (audio.prevCoeffs[i] * (count - i) + out[i] * i) >> shift; + out[i] = (_audioInfo->prevCoeffs[i] * (count - i) + out[i] * i) >> shift; } } - memcpy(audio.prevCoeffs, out + audio.blockSize, audio.overlapLen * audio.channels * sizeof(*out)); + memcpy(_audioInfo->prevCoeffs, out + _audioInfo->blockSize, _audioInfo->overlapLen * _audioInfo->channels * sizeof(*out)); - audio.first = false; + _audioInfo->first = false; } -void BinkDecoder::audioBlockDCT(AudioTrack &audio) { - audio.bits->skip(2); +void BinkDecoder::BinkAudioTrack::audioBlockDCT() { + _audioInfo->bits->skip(2); - for (uint8 i = 0; i < audio.channels; i++) { - float *coeffs = audio.coeffsPtr[i]; + for (uint8 i = 0; i < _audioInfo->channels; i++) { + float *coeffs = _audioInfo->coeffsPtr[i]; - readAudioCoeffs(audio, coeffs); + readAudioCoeffs(coeffs); coeffs[0] /= 0.5; - audio.dct->calc(coeffs); + _audioInfo->dct->calc(coeffs); - for (uint32 j = 0; j < audio.frameLen; j++) - coeffs[j] *= (audio.frameLen / 2.0); + for (uint32 j = 0; j < _audioInfo->frameLen; j++) + coeffs[j] *= (_audioInfo->frameLen / 2.0); } } -void BinkDecoder::audioBlockRDFT(AudioTrack &audio) { - for (uint8 i = 0; i < audio.channels; i++) { - float *coeffs = audio.coeffsPtr[i]; +void BinkDecoder::BinkAudioTrack::audioBlockRDFT() { + for (uint8 i = 0; i < _audioInfo->channels; i++) { + float *coeffs = _audioInfo->coeffsPtr[i]; - readAudioCoeffs(audio, coeffs); + readAudioCoeffs(coeffs); - audio.rdft->calc(coeffs); + _audioInfo->rdft->calc(coeffs); } } @@ -1481,56 +1412,56 @@ static const uint8 rleLengthTab[16] = { 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32, 64 }; -void BinkDecoder::readAudioCoeffs(AudioTrack &audio, float *coeffs) { - coeffs[0] = getFloat(audio) * audio.root; - coeffs[1] = getFloat(audio) * audio.root; +void BinkDecoder::BinkAudioTrack::readAudioCoeffs(float *coeffs) { + coeffs[0] = getFloat() * _audioInfo->root; + coeffs[1] = getFloat() * _audioInfo->root; float quant[25]; - for (uint32 i = 0; i < audio.bandCount; i++) { - int value = audio.bits->getBits(8); + for (uint32 i = 0; i < _audioInfo->bandCount; i++) { + int value = _audioInfo->bits->getBits(8); // 0.066399999 / log10(M_E) - quant[i] = exp(MIN(value, 95) * 0.15289164787221953823f) * audio.root; + quant[i] = exp(MIN(value, 95) * 0.15289164787221953823f) * _audioInfo->root; } float q = 0.0; // Find band (k) int k; - for (k = 0; audio.bands[k] < 1; k++) + for (k = 0; _audioInfo->bands[k] < 1; k++) q = quant[k]; // Parse coefficients uint32 i = 2; - while (i < audio.frameLen) { + while (i < _audioInfo->frameLen) { uint32 j = 0; - if (audio.bits->getBit()) - j = i + rleLengthTab[audio.bits->getBits(4)] * 8; + if (_audioInfo->bits->getBit()) + j = i + rleLengthTab[_audioInfo->bits->getBits(4)] * 8; else j = i + 8; - j = MIN(j, audio.frameLen); + j = MIN(j, _audioInfo->frameLen); - int width = audio.bits->getBits(4); + int width = _audioInfo->bits->getBits(4); if (width == 0) { memset(coeffs + i, 0, (j - i) * sizeof(*coeffs)); i = j; - while (audio.bands[k] * 2 < i) + while (_audioInfo->bands[k] * 2 < i) q = quant[k++]; } else { while (i < j) { - if (audio.bands[k] * 2 == i) + if (_audioInfo->bands[k] * 2 == i) q = quant[k++]; - int coeff = audio.bits->getBits(width); + int coeff = _audioInfo->bits->getBits(width); if (coeff) { - if (audio.bits->getBit()) + if (_audioInfo->bits->getBit()) coeffs[i] = -q * coeff; else coeffs[i] = q * coeff; @@ -1548,10 +1479,10 @@ void BinkDecoder::readAudioCoeffs(AudioTrack &audio, float *coeffs) { } static inline int floatToInt16One(float src) { - return (int16) CLIP((int) floor(src + 0.5), -32768, 32767); + return (int16)CLIP((int)floor(src + 0.5), -32768, 32767); } -void BinkDecoder::floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels) { +void BinkDecoder::BinkAudioTrack::floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels) { if (channels == 2) { for (uint32 i = 0; i < length; i++) { dst[2 * i ] = floatToInt16One(src[0][i]); @@ -1564,97 +1495,84 @@ void BinkDecoder::floatToInt16Interleave(int16 *dst, const float **src, uint32 l } } -#define A1 2896 /* (1/sqrt(2))<<12 */ -#define A2 2217 -#define A3 3784 -#define A4 -5352 +float BinkDecoder::BinkAudioTrack::getFloat() { + int power = _audioInfo->bits->getBits(5); -#define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\ - const int a0 = (src)[s0] + (src)[s4]; \ - const int a1 = (src)[s0] - (src)[s4]; \ - const int a2 = (src)[s2] + (src)[s6]; \ - const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \ - const int a4 = (src)[s5] + (src)[s3]; \ - const int a5 = (src)[s5] - (src)[s3]; \ - const int a6 = (src)[s1] + (src)[s7]; \ - const int a7 = (src)[s1] - (src)[s7]; \ - const int b0 = a4 + a6; \ - const int b1 = (A3*(a5 + a7)) >> 11; \ - const int b2 = ((A4*a5) >> 11) - b0 + b1; \ - const int b3 = (A1*(a6 - a4) >> 11) - b2; \ - const int b4 = ((A2*a7) >> 11) + b3 - b1; \ - (dest)[d0] = munge(a0+a2 +b0); \ - (dest)[d1] = munge(a1+a3-a2+b2); \ - (dest)[d2] = munge(a1-a3+a2+b3); \ - (dest)[d3] = munge(a0-a2 -b4); \ - (dest)[d4] = munge(a0-a2 +b4); \ - (dest)[d5] = munge(a1-a3+a2-b3); \ - (dest)[d6] = munge(a1+a3-a2-b2); \ - (dest)[d7] = munge(a0+a2 -b0); \ + float f = ldexp((float)_audioInfo->bits->getBits(23), power - 23); + + if (_audioInfo->bits->getBit()) + f = -f; + + return f; } -/* end IDCT_TRANSFORM macro */ -#define MUNGE_NONE(x) (x) -#define IDCT_COL(dest,src) IDCT_TRANSFORM(dest,0,8,16,24,32,40,48,56,0,8,16,24,32,40,48,56,MUNGE_NONE,src) +void BinkDecoder::initAudioTrack(AudioInfo &audio) { + audio.sampleCount = 0; + audio.bits = 0; -#define MUNGE_ROW(x) (((x) + 0x7F)>>8) -#define IDCT_ROW(dest,src) IDCT_TRANSFORM(dest,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,MUNGE_ROW,src) + audio.channels = ((audio.flags & kAudioFlagStereo) != 0) ? 2 : 1; + audio.codec = ((audio.flags & kAudioFlagDCT ) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; -static inline void IDCTCol(int16 *dest, const int16 *src) -{ - if ((src[8] | src[16] | src[24] | src[32] | src[40] | src[48] | src[56]) == 0) { - dest[ 0] = - dest[ 8] = - dest[16] = - dest[24] = - dest[32] = - dest[40] = - dest[48] = - dest[56] = src[0]; - } else { - IDCT_COL(dest, src); - } -} + if (audio.channels > kAudioChannelsMax) + error("Too many audio channels: %d", audio.channels); -void BinkDecoder::IDCT(int16 *block) { - int i; - int16 temp[64]; + uint32 frameLenBits; + // Calculate frame length + if (audio.sampleRate < 22050) + frameLenBits = 9; + else if(audio.sampleRate < 44100) + frameLenBits = 10; + else + frameLenBits = 11; - for (i = 0; i < 8; i++) - IDCTCol(&temp[i], &block[i]); - for (i = 0; i < 8; i++) { - IDCT_ROW( (&block[8*i]), (&temp[8*i]) ); - } -} + audio.frameLen = 1 << frameLenBits; -void BinkDecoder::IDCTAdd(DecodeContext &ctx, int16 *block) { - int i, j; + audio.outSampleRate = audio.sampleRate; + audio.outChannels = audio.channels; - IDCT(block); - byte *dest = ctx.dest; - for (i = 0; i < 8; i++, dest += ctx.pitch, block += 8) - for (j = 0; j < 8; j++) - dest[j] += block[j]; -} + if (audio.codec == kAudioCodecRDFT) { + // RDFT audio already interleaves the samples correctly -void BinkDecoder::IDCTPut(DecodeContext &ctx, int16 *block) { - int i; - int16 temp[64]; - for (i = 0; i < 8; i++) - IDCTCol(&temp[i], &block[i]); - for (i = 0; i < 8; i++) { - IDCT_ROW( (&ctx.dest[i*ctx.pitch]), (&temp[8*i]) ); + if (audio.channels == 2) + frameLenBits++; + + audio.sampleRate *= audio.channels; + audio.frameLen *= audio.channels; + audio.channels = 1; } -} -void BinkDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); -} + audio.overlapLen = audio.frameLen / 16; + audio.blockSize = (audio.frameLen - audio.overlapLen) * audio.channels; + audio.root = 2.0 / sqrt((double)audio.frameLen); + + uint32 sampleRateHalf = (audio.sampleRate + 1) / 2; + + // Calculate number of bands + for (audio.bandCount = 1; audio.bandCount < 25; audio.bandCount++) + if (sampleRateHalf <= binkCriticalFreqs[audio.bandCount - 1]) + break; + + audio.bands = new uint32[audio.bandCount + 1]; + + // Populate bands + audio.bands[0] = 1; + for (uint32 i = 1; i < audio.bandCount; i++) + audio.bands[i] = binkCriticalFreqs[i - 1] * (audio.frameLen / 2) / sampleRateHalf; + audio.bands[audio.bandCount] = audio.frameLen / 2; + + audio.first = true; + + for (uint8 i = 0; i < audio.channels; i++) + audio.coeffsPtr[i] = audio.coeffs + i * audio.frameLen; + + audio.codec = ((audio.flags & kAudioFlagDCT) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; + + if (audio.codec == kAudioCodecRDFT) + audio.rdft = new Common::RDFT(frameLenBits, Common::RDFT::DFT_C2R); + else if (audio.codec == kAudioCodecDCT) + audio.dct = new Common::DCT(frameLenBits, Common::DCT::DCT_III); -void BinkDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); + addTrack(new BinkAudioTrack(audio)); } } // End of namespace Video diff --git a/video/bink_decoder.h b/video/bink_decoder.h index a5e1b10270..836238ce99 100644 --- a/video/bink_decoder.h +++ b/video/bink_decoder.h @@ -31,22 +31,27 @@ #ifndef VIDEO_BINK_DECODER_H #define VIDEO_BINK_DECODER_H -#include "audio/audiostream.h" -#include "audio/mixer.h" #include "common/array.h" #include "common/rational.h" -#include "graphics/surface.h" - #include "video/video_decoder.h" +namespace Audio { +class AudioStream; +class QueuingAudioStream; +} + namespace Common { - class SeekableReadStream; - class BitStream; - class Huffman; +class SeekableReadStream; +class BitStream; +class Huffman; - class RDFT; - class DCT; +class RDFT; +class DCT; +} + +namespace Graphics { +struct Surface; } namespace Video { @@ -57,92 +62,28 @@ namespace Video { * Video decoder used in engines: * - scumm (he) */ -class BinkDecoder : public FixedRateVideoDecoder { +class BinkDecoder : public AdvancedVideoDecoder { public: BinkDecoder(); ~BinkDecoder(); - // VideoDecoder API bool loadStream(Common::SeekableReadStream *stream); void close(); - bool isVideoLoaded() const { return _bink != 0; } - uint16 getWidth() const { return _surface.w; } - uint16 getHeight() const { return _surface.h; } - Graphics::PixelFormat getPixelFormat() const { return _surface.format; } - uint32 getFrameCount() const { return _frames.size(); } - uint32 getTime() const; - const Graphics::Surface *decodeNextFrame(); - - // FixedRateVideoDecoder - Common::Rational getFrameRate() const { return _frameRate; } - - // Bink specific - bool loadStream(Common::SeekableReadStream *stream, const Graphics::PixelFormat &format); protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void readNextPacket(); +private: static const int kAudioChannelsMax = 2; static const int kAudioBlockSizeMax = (kAudioChannelsMax << 11); - /** IDs for different data types used in Bink video codec. */ - enum Source { - kSourceBlockTypes = 0, ///< 8x8 block types. - kSourceSubBlockTypes , ///< 16x16 block types (a subset of 8x8 block types). - kSourceColors , ///< Pixel values used for different block types. - kSourcePattern , ///< 8-bit values for 2-color pattern fill. - kSourceXOff , ///< X components of motion value. - kSourceYOff , ///< Y components of motion value. - kSourceIntraDC , ///< DC values for intrablocks with DCT. - kSourceInterDC , ///< DC values for interblocks with DCT. - kSourceRun , ///< Run lengths for special fill block. - - kSourceMAX - }; - - /** Bink video block types. */ - enum BlockType { - kBlockSkip = 0, ///< Skipped block. - kBlockScaled , ///< Block has size 16x16. - kBlockMotion , ///< Block is copied from previous frame with some offset. - kBlockRun , ///< Block is composed from runs of colors with custom scan order. - kBlockResidue , ///< Motion block with some difference added. - kBlockIntra , ///< Intra DCT block. - kBlockFill , ///< Block is filled with single color. - kBlockInter , ///< Motion block with DCT applied to the difference. - kBlockPattern , ///< Block is filled with two colors following custom pattern. - kBlockRaw ///< Uncoded 8x8 block. - }; - - /** Data structure for decoding and tranlating Huffman'd data. */ - struct Huffman { - int index; ///< Index of the Huffman codebook to use. - byte symbols[16]; ///< Huffman symbol => Bink symbol tranlation list. - }; - - /** Data structure used for decoding a single Bink data type. */ - struct Bundle { - int countLengths[2]; ///< Lengths of number of entries to decode (in bits). - int countLength; ///< Length of number of entries to decode (in bits) for the current plane. - - Huffman huffman; ///< Huffman codebook. - - byte *data; ///< Buffer for decoded symbols. - byte *dataEnd; ///< Buffer end. - - byte *curDec; ///< Pointer to the data that wasn't yet decoded. - byte *curPtr; ///< Pointer to the data that wasn't yet read. - }; - enum AudioCodec { kAudioCodecDCT, kAudioCodecRDFT }; /** An audio track. */ - struct AudioTrack { + struct AudioInfo { uint16 flags; uint32 sampleRate; @@ -177,8 +118,8 @@ protected: Common::RDFT *rdft; Common::DCT *dct; - AudioTrack(); - ~AudioTrack(); + AudioInfo(); + ~AudioInfo(); }; /** A video frame. */ @@ -194,149 +135,218 @@ protected: ~VideoFrame(); }; - /** A decoder state. */ - struct DecodeContext { - VideoFrame *video; + class BinkVideoTrack : public FixedRateVideoTrack { + public: + BinkVideoTrack(uint32 width, uint32 height, const Graphics::PixelFormat &format, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id); + ~BinkVideoTrack(); + + uint16 getWidth() const { return _surface.w; } + uint16 getHeight() const { return _surface.h; } + Graphics::PixelFormat getPixelFormat() const { return _surface.format; } + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return &_surface; } + + /** Decode a video packet. */ + void decodePacket(VideoFrame &frame); + + protected: + Common::Rational getFrameRate() const { return _frameRate; } - uint32 planeIdx; + private: + /** A decoder state. */ + struct DecodeContext { + VideoFrame *video; + + uint32 planeIdx; - uint32 blockX; - uint32 blockY; + uint32 blockX; + uint32 blockY; - byte *dest; - byte *prev; + byte *dest; + byte *prev; - byte *destStart, *destEnd; - byte *prevStart, *prevEnd; + byte *destStart, *destEnd; + byte *prevStart, *prevEnd; - uint32 pitch; + uint32 pitch; - int coordMap[64]; - int coordScaledMap1[64]; - int coordScaledMap2[64]; - int coordScaledMap3[64]; - int coordScaledMap4[64]; + int coordMap[64]; + int coordScaledMap1[64]; + int coordScaledMap2[64]; + int coordScaledMap3[64]; + int coordScaledMap4[64]; + }; + + /** IDs for different data types used in Bink video codec. */ + enum Source { + kSourceBlockTypes = 0, ///< 8x8 block types. + kSourceSubBlockTypes , ///< 16x16 block types (a subset of 8x8 block types). + kSourceColors , ///< Pixel values used for different block types. + kSourcePattern , ///< 8-bit values for 2-color pattern fill. + kSourceXOff , ///< X components of motion value. + kSourceYOff , ///< Y components of motion value. + kSourceIntraDC , ///< DC values for intrablocks with DCT. + kSourceInterDC , ///< DC values for interblocks with DCT. + kSourceRun , ///< Run lengths for special fill block. + + kSourceMAX + }; + + /** Bink video block types. */ + enum BlockType { + kBlockSkip = 0, ///< Skipped block. + kBlockScaled , ///< Block has size 16x16. + kBlockMotion , ///< Block is copied from previous frame with some offset. + kBlockRun , ///< Block is composed from runs of colors with custom scan order. + kBlockResidue , ///< Motion block with some difference added. + kBlockIntra , ///< Intra DCT block. + kBlockFill , ///< Block is filled with single color. + kBlockInter , ///< Motion block with DCT applied to the difference. + kBlockPattern , ///< Block is filled with two colors following custom pattern. + kBlockRaw ///< Uncoded 8x8 block. + }; + + /** Data structure for decoding and tranlating Huffman'd data. */ + struct Huffman { + int index; ///< Index of the Huffman codebook to use. + byte symbols[16]; ///< Huffman symbol => Bink symbol tranlation list. + }; + + /** Data structure used for decoding a single Bink data type. */ + struct Bundle { + int countLengths[2]; ///< Lengths of number of entries to decode (in bits). + int countLength; ///< Length of number of entries to decode (in bits) for the current plane. + + Huffman huffman; ///< Huffman codebook. + + byte *data; ///< Buffer for decoded symbols. + byte *dataEnd; ///< Buffer end. + + byte *curDec; ///< Pointer to the data that wasn't yet decoded. + byte *curPtr; ///< Pointer to the data that wasn't yet read. + }; + + int _curFrame; + int _frameCount; + + Graphics::Surface _surface; + + uint32 _id; ///< The BIK FourCC. + + bool _hasAlpha; ///< Do video frames have alpha? + bool _swapPlanes; ///< Are the planes ordered (A)YVU instead of (A)YUV? + + Common::Rational _frameRate; + + Bundle _bundles[kSourceMAX]; ///< Bundles for decoding all data types. + + Common::Huffman *_huffman[16]; ///< The 16 Huffman codebooks used in Bink decoding. + + /** Huffman codebooks to use for decoding high nibbles in color data types. */ + Huffman _colHighHuffman[16]; + /** Value of the last decoded high nibble in color data types. */ + int _colLastVal; + + byte *_curPlanes[4]; ///< The 4 color planes, YUVA, current frame. + byte *_oldPlanes[4]; ///< The 4 color planes, YUVA, last frame. + + /** Initialize the bundles. */ + void initBundles(); + /** Deinitialize the bundles. */ + void deinitBundles(); + + /** Initialize the Huffman decoders. */ + void initHuffman(); + + /** Decode a plane. */ + void decodePlane(VideoFrame &video, int planeIdx, bool isChroma); + + /** Read/Initialize a bundle for decoding a plane. */ + void readBundle(VideoFrame &video, Source source); + + /** Read the symbols for a Huffman code. */ + void readHuffman(VideoFrame &video, Huffman &huffman); + /** Merge two Huffman symbol lists. */ + void mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size); + + /** Read and translate a symbol out of a Huffman code. */ + byte getHuffmanSymbol(VideoFrame &video, Huffman &huffman); + + /** Get a direct value out of a bundle. */ + int32 getBundleValue(Source source); + /** Read a count value out of a bundle. */ + uint32 readBundleCount(VideoFrame &video, Bundle &bundle); + + // Handle the block types + void blockSkip (DecodeContext &ctx); + void blockScaledSkip (DecodeContext &ctx); + void blockScaledRun (DecodeContext &ctx); + void blockScaledIntra (DecodeContext &ctx); + void blockScaledFill (DecodeContext &ctx); + void blockScaledPattern(DecodeContext &ctx); + void blockScaledRaw (DecodeContext &ctx); + void blockScaled (DecodeContext &ctx); + void blockMotion (DecodeContext &ctx); + void blockRun (DecodeContext &ctx); + void blockResidue (DecodeContext &ctx); + void blockIntra (DecodeContext &ctx); + void blockFill (DecodeContext &ctx); + void blockInter (DecodeContext &ctx); + void blockPattern (DecodeContext &ctx); + void blockRaw (DecodeContext &ctx); + + // Read the bundles + void readRuns (VideoFrame &video, Bundle &bundle); + void readMotionValues(VideoFrame &video, Bundle &bundle); + void readBlockTypes (VideoFrame &video, Bundle &bundle); + void readPatterns (VideoFrame &video, Bundle &bundle); + void readColors (VideoFrame &video, Bundle &bundle); + void readDCS (VideoFrame &video, Bundle &bundle, int startBits, bool hasSign); + void readDCTCoeffs (VideoFrame &video, int16 *block, bool isIntra); + void readResidue (VideoFrame &video, int16 *block, int masksCount); + + // Bink video IDCT + void IDCT(int16 *block); + void IDCTPut(DecodeContext &ctx, int16 *block); + void IDCTAdd(DecodeContext &ctx, int16 *block); }; - Common::SeekableReadStream *_bink; + class BinkAudioTrack : public AudioTrack { + public: + BinkAudioTrack(AudioInfo &audio); + ~BinkAudioTrack(); + + /** Decode an audio packet. */ + void decodePacket(); - uint32 _id; ///< The BIK FourCC. + protected: + Audio::AudioStream *getAudioStream() const; - Common::Rational _frameRate; + private: + AudioInfo *_audioInfo; + Audio::QueuingAudioStream *_audioStream; - Graphics::Surface _surface; + float getFloat(); - Audio::SoundHandle _audioHandle; - Audio::QueuingAudioStream *_audioStream; - int32 _audioStartOffset; + /** Decode an audio block. */ + void audioBlock(int16 *out); + /** Decode a DCT'd audio block. */ + void audioBlockDCT(); + /** Decode a RDFT'd audio block. */ + void audioBlockRDFT(); - uint32 _videoFlags; ///< Video frame features. + void readAudioCoeffs(float *coeffs); - bool _hasAlpha; ///< Do video frames have alpha? - bool _swapPlanes; ///< Are the planes ordered (A)YVU instead of (A)YUV? + static void floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels); + }; + + Common::SeekableReadStream *_bink; - Common::Array _audioTracks; ///< All audio tracks. + Common::Array _audioTracks; ///< All audio tracks. Common::Array _frames; ///< All video frames. - uint32 _audioTrack; ///< Audio track to use. - - Common::Huffman *_huffman[16]; ///< The 16 Huffman codebooks used in Bink decoding. - - Bundle _bundles[kSourceMAX]; ///< Bundles for decoding all data types. - - /** Huffman codebooks to use for decoding high nibbles in color data types. */ - Huffman _colHighHuffman[16]; - /** Value of the last decoded high nibble in color data types. */ - int _colLastVal; - - byte *_curPlanes[4]; ///< The 4 color planes, YUVA, current frame. - byte *_oldPlanes[4]; ///< The 4 color planes, YUVA, last frame. - - - /** Initialize the bundles. */ - void initBundles(); - /** Deinitialize the bundles. */ - void deinitBundles(); - - /** Initialize the Huffman decoders. */ - void initHuffman(); - - /** Decode an audio packet. */ - void audioPacket(AudioTrack &audio); - /** Decode a video packet. */ - virtual void videoPacket(VideoFrame &video); - - /** Decode a plane. */ - void decodePlane(VideoFrame &video, int planeIdx, bool isChroma); - - /** Read/Initialize a bundle for decoding a plane. */ - void readBundle(VideoFrame &video, Source source); - - /** Read the symbols for a Huffman code. */ - void readHuffman(VideoFrame &video, Huffman &huffman); - /** Merge two Huffman symbol lists. */ - void mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size); - - /** Read and translate a symbol out of a Huffman code. */ - byte getHuffmanSymbol(VideoFrame &video, Huffman &huffman); - - /** Get a direct value out of a bundle. */ - int32 getBundleValue(Source source); - /** Read a count value out of a bundle. */ - uint32 readBundleCount(VideoFrame &video, Bundle &bundle); - - // Handle the block types - void blockSkip (DecodeContext &ctx); - void blockScaledSkip (DecodeContext &ctx); - void blockScaledRun (DecodeContext &ctx); - void blockScaledIntra (DecodeContext &ctx); - void blockScaledFill (DecodeContext &ctx); - void blockScaledPattern(DecodeContext &ctx); - void blockScaledRaw (DecodeContext &ctx); - void blockScaled (DecodeContext &ctx); - void blockMotion (DecodeContext &ctx); - void blockRun (DecodeContext &ctx); - void blockResidue (DecodeContext &ctx); - void blockIntra (DecodeContext &ctx); - void blockFill (DecodeContext &ctx); - void blockInter (DecodeContext &ctx); - void blockPattern (DecodeContext &ctx); - void blockRaw (DecodeContext &ctx); - - // Read the bundles - void readRuns (VideoFrame &video, Bundle &bundle); - void readMotionValues(VideoFrame &video, Bundle &bundle); - void readBlockTypes (VideoFrame &video, Bundle &bundle); - void readPatterns (VideoFrame &video, Bundle &bundle); - void readColors (VideoFrame &video, Bundle &bundle); - void readDCS (VideoFrame &video, Bundle &bundle, int startBits, bool hasSign); - void readDCTCoeffs (VideoFrame &video, int16 *block, bool isIntra); - void readResidue (VideoFrame &video, int16 *block, int masksCount); - - void initAudioTrack(AudioTrack &audio); - - float getFloat(AudioTrack &audio); - - /** Decode an audio block. */ - void audioBlock (AudioTrack &audio, int16 *out); - /** Decode a DCT'd audio block. */ - void audioBlockDCT (AudioTrack &audio); - /** Decode a RDFT'd audio block. */ - void audioBlockRDFT(AudioTrack &audio); - - void readAudioCoeffs(AudioTrack &audio, float *coeffs); - - void floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels); - - // Bink video IDCT - void IDCT(int16 *block); - void IDCTPut(DecodeContext &ctx, int16 *block); - void IDCTAdd(DecodeContext &ctx, int16 *block); - - /** Start playing the audio track */ - void startAudio(); - /** Stop playing the audio track */ - void stopAudio(); + void initAudioTrack(AudioInfo &audio); }; } // End of namespace Video -- cgit v1.2.3 From af6e98ba0108fc87c5aea2e85a1aef80443937b5 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 26 Jul 2012 23:20:25 -0400 Subject: VIDEO: Ignore finished video tracks in findNextVideoTrack() --- video/video_decoder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 8b9a009b98..9282cd82d0 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -575,7 +575,7 @@ AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() { uint32 bestTime = 0xFFFFFFFF; for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) { - if ((*it)->getTrackType() == Track::kTrackTypeVideo) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) { VideoTrack *track = (VideoTrack *)*it; uint32 time = track->getNextFrameStartTime(); @@ -594,7 +594,7 @@ const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack uint32 bestTime = 0xFFFFFFFF; for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { - if ((*it)->getTrackType() == Track::kTrackTypeVideo) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) { const VideoTrack *track = (const VideoTrack *)*it; uint32 time = track->getNextFrameStartTime(); -- cgit v1.2.3 From 2eeee33bd878a5cd385b4423f6867d0e6a3ed0b6 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 26 Jul 2012 23:24:54 -0400 Subject: VIDEO: Move findNextVideoTrack() to protected --- video/video_decoder.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/video/video_decoder.h b/video/video_decoder.h index a6dbed8fc5..dfe0fff66b 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -679,12 +679,20 @@ protected: */ Graphics::PixelFormat getDefaultHighColorFormat() const { return _defaultHighColorFormat; } + /** + * Find the video track with the lowest start time for the next frame + */ + VideoTrack *findNextVideoTrack(); + + /** + * Find the video track with the lowest start time for the next frame + */ + const VideoTrack *findNextVideoTrack() const; + private: // Tracks owned by this AdvancedVideoDecoder typedef Common::Array TrackList; TrackList _tracks; - VideoTrack *findNextVideoTrack(); - const VideoTrack *findNextVideoTrack() const; // Current playback status bool _isPlaying, _needsRewind; -- cgit v1.2.3 From 84462fa088d64acc2a7b2811f88a5a292abe00db Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 26 Jul 2012 23:36:21 -0400 Subject: VIDEO: Document more of AdvancedVideoDecoder --- video/video_decoder.h | 83 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/video/video_decoder.h b/video/video_decoder.h index dfe0fff66b..0c569692fc 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -265,7 +265,7 @@ protected: */ virtual void updateBalance() {} - int32 _curFrame; + int32 _curFrame; // This variable is now deprecated. int32 _startTime; // FIXME: These are protected until the new API takes over this one @@ -500,15 +500,56 @@ protected: TrackType getTrackType() const { return kTrackTypeVideo; } - // TODO: Document + /** + * Get the width of this track + */ virtual uint16 getWidth() const = 0; + + /** + * Get the height of this track + */ virtual uint16 getHeight() const = 0; + + /** + * Get the pixel format of this track + */ virtual Graphics::PixelFormat getPixelFormat() const = 0; + + /** + * Get the current frame of this track + * + * @see VideoDecoder::getCurFrame() + */ virtual int getCurFrame() const = 0; + + /** + * Get the frame count of this track + * + * @note If the frame count is unknown, return 0 (which is also + * the default implementation of the function). However, one must + * also implement endOfTrack() in that case. + */ virtual int getFrameCount() const { return 0; } + + /** + * Get the start time of the next frame in milliseconds since + * the start of the video + */ virtual uint32 getNextFrameStartTime() const = 0; + + /** + * Decode the next frame + */ virtual const Graphics::Surface *decodeNextFrame() = 0; + + /** + * Get the palette currently in use by this track + */ virtual const byte *getPalette() const { return 0; } + + /** + * Does the palette currently in use by this track need to be updated? + */ virtual bool hasDirtyPalette() const { return false; } }; @@ -547,19 +588,43 @@ protected: void start(); void stop(); - // TODO: Document + /** + * Get the volume for this track + */ byte getVolume() const { return _volume; } + + /** + * Set the volume for this track + */ void setVolume(byte volume); + + /** + * Get the balance for this track + */ int8 getBalance() const { return _balance; } + + /** + * Set the balance for this track + */ void setBalance(int8 balance); + + /** + * Get the time the AudioStream behind this track has been + * running + */ uint32 getRunningTime() const; + /** + * Get the sound type to be used when playing this audio track + */ virtual Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kPlainSoundType; } protected: void pauseIntern(bool pause); - // TODO: Document + /** + * Get the AudioStream that is the representation of this AudioTrack + */ virtual Audio::AudioStream *getAudioStream() const = 0; private: @@ -583,7 +648,10 @@ protected: protected: Audio::AudioStream *getAudioStream() const; - // TODO: Document + /** + * Get the RewindableAudioStream pointer to be used by this class + * for rewind() and getAudioStream() + */ virtual Audio::RewindableAudioStream *getRewindableAudioStream() const = 0; }; @@ -604,7 +672,10 @@ protected: protected: Audio::AudioStream *getAudioStream() const; - // TODO: Document + /** + * Get the SeekableAudioStream pointer to be used by this class + * for seek(), getDuration(), and getAudioStream() + */ virtual Audio::SeekableAudioStream *getSeekableAudioStream() const = 0; }; -- cgit v1.2.3 From df5d6f7d08c30afa270fd7d3e2d0f885eaf3c7bc Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 26 Jul 2012 23:42:35 -0400 Subject: VIDEO: Force an update after a seek --- video/video_decoder.cpp | 8 +++++++- video/video_decoder.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 9282cd82d0..9d6d40f7fb 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -101,6 +101,7 @@ AdvancedVideoDecoder::AdvancedVideoDecoder() { _audioVolume = Audio::Mixer::kMaxChannelVolume; _audioBalance = 0; _pauseLevel = 0; + _needsUpdate = false; // Find the best format for output _defaultHighColorFormat = g_system->getScreenFormat(); @@ -124,6 +125,7 @@ void AdvancedVideoDecoder::close() { _audioVolume = Audio::Mixer::kMaxChannelVolume; _audioBalance = 0; _pauseLevel = 0; + _needsUpdate = false; } bool AdvancedVideoDecoder::isVideoLoaded() const { @@ -155,6 +157,8 @@ Graphics::PixelFormat AdvancedVideoDecoder::getPixelFormat() const { } const Graphics::Surface *AdvancedVideoDecoder::decodeNextFrame() { + _needsUpdate = false; + readNextPacket(); VideoTrack *track = findNextVideoTrack(); @@ -215,7 +219,7 @@ uint32 AdvancedVideoDecoder::getTime() const { } uint32 AdvancedVideoDecoder::getTimeToNextFrame() const { - if (endOfVideo()) + if (endOfVideo() || _needsUpdate) return 0; const VideoTrack *track = findNextVideoTrack(); @@ -310,6 +314,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { _audioStartOffset = time; _startTime = g_system->getMillis() - time.msecs(); + _needsUpdate = true; return true; } @@ -337,6 +342,7 @@ void AdvancedVideoDecoder::stop() { _audioStartOffset = 0; _palette = 0; _dirtyPalette = false; + _needsUpdate = false; stopAllTracks(); diff --git a/video/video_decoder.h b/video/video_decoder.h index 0c569692fc..ffeecd326d 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -766,7 +766,7 @@ private: TrackList _tracks; // Current playback status - bool _isPlaying, _needsRewind; + bool _isPlaying, _needsRewind, _needsUpdate; Audio::Timestamp _audioStartOffset; // Palette settings from individual tracks -- cgit v1.2.3 From 1f67c9dbbed5e92d8b9cb8f4d729366463a05937 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 26 Jul 2012 23:44:40 -0400 Subject: VIDEO: Reset pause time when seeking/rewinding --- video/video_decoder.cpp | 2 ++ video/video_decoder.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 9d6d40f7fb..77eab3a6e1 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -280,6 +280,7 @@ bool AdvancedVideoDecoder::rewind() { _audioStartOffset = 0; _startTime = g_system->getMillis(); + resetPauseStartTime(); return true; } @@ -314,6 +315,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { _audioStartOffset = time; _startTime = g_system->getMillis() - time.msecs(); + resetPauseStartTime(); _needsUpdate = true; return true; } diff --git a/video/video_decoder.h b/video/video_decoder.h index ffeecd326d..f0427668a6 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -249,7 +249,6 @@ protected: /** * Reset the pause start time (which should be called when seeking) - * @note This function is now deprecated. There is no replacement. */ void resetPauseStartTime(); -- cgit v1.2.3 From a364ef8f0fca2675f791a29ef231385e29945939 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 27 Jul 2012 11:01:21 -0400 Subject: VIDEO: Remove Track::getStartTime() That should be handled internally instead --- video/video_decoder.cpp | 17 ++++------------- video/video_decoder.h | 6 ------ 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 77eab3a6e1..cea3960fee 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -210,7 +210,7 @@ uint32 AdvancedVideoDecoder::getTime() const { uint32 time = ((const AudioTrack *)*it)->getRunningTime(); if (time != 0) - return time + (*it)->getStartTime().msecs() + _audioStartOffset.msecs(); + return time + _audioStartOffset.msecs(); } } } @@ -364,15 +364,10 @@ Audio::Timestamp AdvancedVideoDecoder::getDuration() const { Audio::Timestamp maxDuration(0, 1000); for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { - Audio::Timestamp startTime = (*it)->getStartTime(); Audio::Timestamp duration = (*it)->getDuration(); - if (duration.totalNumberOfFrames() != 0) { - // HACK: Timestamp's + operator doesn't do framerate conversion :( - duration = duration + startTime.convertToFramerate(duration.framerate()); - if (duration > maxDuration) - maxDuration = duration; - } + if (duration > maxDuration) + maxDuration = duration; } return maxDuration; @@ -406,11 +401,7 @@ bool AdvancedVideoDecoder::Track::isRewindable() const { } bool AdvancedVideoDecoder::Track::rewind() { - return seek(getStartTime()); -} - -Audio::Timestamp AdvancedVideoDecoder::Track::getStartTime() const { - return Audio::Timestamp(0, 1000); + return seek(Audio::Timestamp(0, 1000)); } Audio::Timestamp AdvancedVideoDecoder::Track::getDuration() const { diff --git a/video/video_decoder.h b/video/video_decoder.h index f0427668a6..18517c9ad2 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -466,12 +466,6 @@ protected: */ bool isPaused() const { return _paused; } - /** - * Get the start time of the track (starting from the beginning of the - * movie). - */ - virtual Audio::Timestamp getStartTime() const; - /** * Get the duration of the track (starting from this track's start time). * -- cgit v1.2.3 From 90b72e31e4a9f2a23d912d31343ba25f27da7b3e Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 27 Jul 2012 11:01:42 -0400 Subject: VIDEO: Cleanup AdvancedVideoDecoder --- video/video_decoder.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index cea3960fee..131c86fdb8 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -111,7 +111,7 @@ AdvancedVideoDecoder::AdvancedVideoDecoder() { } void AdvancedVideoDecoder::close() { - if (_isPlaying) + if (isPlaying()) stop(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) @@ -250,7 +250,7 @@ bool AdvancedVideoDecoder::endOfVideo() const { } bool AdvancedVideoDecoder::isRewindable() const { - if (_tracks.empty()) + if (!isVideoLoaded()) return false; for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) @@ -267,7 +267,7 @@ bool AdvancedVideoDecoder::rewind() { _needsRewind = false; // Stop all tracks so they can be rewound - if (_isPlaying) + if (isPlaying()) stopAllTracks(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) @@ -275,7 +275,7 @@ bool AdvancedVideoDecoder::rewind() { return false; // Now that we've rewound, start all tracks again - if (_isPlaying) + if (isPlaying()) startAllTracks(); _audioStartOffset = 0; @@ -285,7 +285,7 @@ bool AdvancedVideoDecoder::rewind() { } bool AdvancedVideoDecoder::isSeekable() const { - if (_tracks.empty()) + if (!isVideoLoaded()) return false; for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) @@ -302,7 +302,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { _needsRewind = false; // Stop all tracks so they can be seeked - if (_isPlaying) + if (isPlaying()) stopAllTracks(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) @@ -310,7 +310,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { return false; // Now that we've seeked, start all tracks again - if (_isPlaying) + if (isPlaying()) startAllTracks(); _audioStartOffset = time; @@ -321,7 +321,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { } void AdvancedVideoDecoder::start() { - if (_isPlaying || !isVideoLoaded()) + if (isPlaying() || !isVideoLoaded()) return; _isPlaying = true; @@ -336,7 +336,7 @@ void AdvancedVideoDecoder::start() { } void AdvancedVideoDecoder::stop() { - if (!_isPlaying) + if (!isPlaying()) return; _isPlaying = false; -- cgit v1.2.3 From 21d3fa71aff686f5b64361ae3410268fc0ab5968 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 27 Jul 2012 11:14:46 -0400 Subject: VIDEO: Add functions for getting TrackList iterators internally --- video/video_decoder.h | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/video/video_decoder.h b/video/video_decoder.h index 18517c9ad2..eff5a7c396 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -753,9 +753,24 @@ protected: */ const VideoTrack *findNextVideoTrack() const; + /** + * Typedef helpers for accessing tracks + */ + typedef Common::Array TrackList; + typedef TrackList::iterator TrackListIterator; + + /** + * Get the begin iterator of the tracks + */ + TrackListIterator getTrackListBegin() { return _tracks.begin(); } + + /** + * Get the end iterator of the tracks + */ + TrackListIterator getTrackListEnd() { return _tracks.end(); } + private: // Tracks owned by this AdvancedVideoDecoder - typedef Common::Array TrackList; TrackList _tracks; // Current playback status -- cgit v1.2.3 From 991710d0a158bfce4e54bd240482a4e3044271d3 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 27 Jul 2012 11:32:51 -0400 Subject: VIDEO: Adapt QuickTimeDecoder to the AdvancedVideoDecoder API --- common/quicktime.h | 1 + engines/mohawk/video.cpp | 13 +- engines/mohawk/video.h | 4 +- engines/sci/engine/kvideo.cpp | 4 +- video/qt_decoder.cpp | 650 +++++++++++++++--------------------------- video/qt_decoder.h | 183 +++--------- 6 files changed, 286 insertions(+), 569 deletions(-) diff --git a/common/quicktime.h b/common/quicktime.h index 974502d075..08ca35ad51 100644 --- a/common/quicktime.h +++ b/common/quicktime.h @@ -35,6 +35,7 @@ #include "common/scummsys.h" #include "common/stream.h" #include "common/rational.h" +#include "common/types.h" namespace Common { class MacResManager; diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 18d609c513..3b4e61646d 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -207,7 +207,7 @@ bool VideoManager::updateMovies() { // Remove any videos that are over if (_videoStreams[i].endOfVideo()) { if (_videoStreams[i].loop) { - _videoStreams[i]->seekToTime(_videoStreams[i].start); + _videoStreams[i]->seek(_videoStreams[i].start); } else { // Check the video time one last time before deleting it _vm->doVideoTimer(i, true); @@ -394,6 +394,8 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool entry.loop = loop; entry.enabled = true; + entry->start(); + // Search for any deleted videos so we can take a formerly used slot for (uint32 i = 0; i < _videoStreams.size(); i++) if (!_videoStreams[i].video) { @@ -430,6 +432,7 @@ VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint entry->loadStream(file); entry->setVolume(volume); + entry->start(); // Search for any deleted videos so we can take a formerly used slot for (uint32 i = 0; i < _videoStreams.size(); i++) @@ -492,7 +495,7 @@ uint32 VideoManager::getTime(VideoHandle handle) { uint32 VideoManager::getDuration(VideoHandle handle) { assert(handle != NULL_VID_HANDLE); - return _videoStreams[handle]->getDuration(); + return _videoStreams[handle]->getDuration().msecs(); } bool VideoManager::endOfVideo(VideoHandle handle) { @@ -512,13 +515,13 @@ void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Au assert(handle != NULL_VID_HANDLE); _videoStreams[handle].start = start; _videoStreams[handle].end = end; - _videoStreams[handle]->seekToTime(start); + _videoStreams[handle]->seek(start); } void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); _videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1); - _videoStreams[handle]->seekToTime(time); + _videoStreams[handle]->seek(time); updateMovies(); delete _videoStreams[handle].video; _videoStreams[handle].clear(); @@ -526,7 +529,7 @@ void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); - _videoStreams[handle]->seekToTime(time); + _videoStreams[handle]->seek(time); } void VideoManager::setVideoLooping(VideoHandle handle, bool loop) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 98bcadfb53..937cd0f2dd 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -45,7 +45,7 @@ struct MLSTRecord { struct VideoEntry { // Playback variables - Video::SeekableVideoDecoder *video; + Video::AdvancedVideoDecoder *video; uint16 x; uint16 y; bool loop; @@ -57,7 +57,7 @@ struct VideoEntry { int id; // Internal Mohawk files // Helper functions - Video::SeekableVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually + Video::AdvancedVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually void clear(); bool endOfVideo(); }; diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 456f860493..da63aa3a8d 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -170,8 +170,6 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { delete videoDecoder; videoDecoder = 0; } - - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete } } else { // Windows AVI @@ -212,7 +210,6 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { videoDecoder = 0; } else { s->_videoState.fileName = filename; - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); } break; } @@ -222,6 +219,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { } if (videoDecoder) { + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete playVideo(videoDecoder, s->_videoState); // HACK: Switch back to 8bpp if we played a true color video. diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp index aba545abc0..70dcdff9c6 100644 --- a/video/qt_decoder.cpp +++ b/video/qt_decoder.cpp @@ -33,14 +33,12 @@ #include "audio/audiostream.h" #include "common/debug.h" -#include "common/endian.h" #include "common/memstream.h" #include "common/system.h" #include "common/textconsole.h" #include "common/util.h" // Video codecs -#include "video/codecs/codec.h" #include "video/codecs/cinepak.h" #include "video/codecs/mjpeg.h" #include "video/codecs/qtrle.h" @@ -56,97 +54,43 @@ namespace Video { //////////////////////////////////////////// QuickTimeDecoder::QuickTimeDecoder() { - _setStartTime = false; _scaledSurface = 0; - _dirtyPalette = false; - _palette = 0; _width = _height = 0; - _needUpdate = false; } QuickTimeDecoder::~QuickTimeDecoder() { close(); } -int32 QuickTimeDecoder::getCurFrame() const { - // TODO: This is rather simplistic and doesn't take edits that - // repeat sections of the media into account. Doing that - // over-complicates things and shouldn't be necessary, but - // it would be nice to have in the future. - - int32 frame = -1; - - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo) - frame += ((VideoTrackHandler *)_handlers[i])->getCurFrame() + 1; - - return frame; -} - -uint32 QuickTimeDecoder::getFrameCount() const { - uint32 count = 0; - - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo) - count += ((VideoTrackHandler *)_handlers[i])->getFrameCount(); - - return count; -} - -void QuickTimeDecoder::startAudio() { - updateAudioBuffer(); - - for (uint32 i = 0; i < _audioTracks.size(); i++) { - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandles[i], _audioTracks[i], -1, getVolume(), getBalance(), DisposeAfterUse::NO); +bool QuickTimeDecoder::loadFile(const Common::String &filename) { + if (!Common::QuickTimeParser::parseFile(filename)) + return false; - // Pause the audio again if we're still paused - if (isPaused()) - g_system->getMixer()->pauseHandle(_audioHandles[i], true); - } + init(); + return true; } -void QuickTimeDecoder::stopAudio() { - for (uint32 i = 0; i < _audioHandles.size(); i++) - g_system->getMixer()->stopHandle(_audioHandles[i]); -} +bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) { + if (!Common::QuickTimeParser::parseStream(stream)) + return false; -void QuickTimeDecoder::pauseVideoIntern(bool pause) { - for (uint32 i = 0; i < _audioHandles.size(); i++) - g_system->getMixer()->pauseHandle(_audioHandles[i], pause); + init(); + return true; } -QuickTimeDecoder::VideoTrackHandler *QuickTimeDecoder::findNextVideoTrack() const { - VideoTrackHandler *bestTrack = 0; - uint32 bestTime = 0xffffffff; - - for (uint32 i = 0; i < _handlers.size(); i++) { - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) { - VideoTrackHandler *track = (VideoTrackHandler *)_handlers[i]; - uint32 time = track->getNextFrameStartTime(); +void QuickTimeDecoder::close() { + AdvancedVideoDecoder::close(); + Common::QuickTimeParser::close(); - if (time < bestTime) { - bestTime = time; - bestTrack = track; - } - } + if (_scaledSurface) { + _scaledSurface->free(); + delete _scaledSurface; + _scaledSurface = 0; } - - return bestTrack; } const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() { - if (!_nextVideoTrack) - return 0; - - const Graphics::Surface *frame = _nextVideoTrack->decodeNextFrame(); - - if (!_setStartTime) { - _startTime = g_system->getMillis(); - _setStartTime = true; - } - - _nextVideoTrack = findNextVideoTrack(); - _needUpdate = false; + const Graphics::Surface *frame = AdvancedVideoDecoder::decodeNextFrame(); // Update audio buffers too // (needs to be done after we find the next track) @@ -166,138 +110,7 @@ const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() { return frame; } -void QuickTimeDecoder::scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, Common::Rational scaleFactorX, Common::Rational scaleFactorY) { - assert(src && dst); - - for (int32 j = 0; j < dst->h; j++) - for (int32 k = 0; k < dst->w; k++) - memcpy(dst->getBasePtr(k, j), src->getBasePtr((k * scaleFactorX).toInt() , (j * scaleFactorY).toInt()), src->format.bytesPerPixel); -} - -bool QuickTimeDecoder::endOfVideo() const { - if (!isVideoLoaded()) - return true; - - for (uint32 i = 0; i < _handlers.size(); i++) - if (!_handlers[i]->endOfTrack()) - return false; - - return true; -} - -uint32 QuickTimeDecoder::getTime() const { - // Try to base sync off an active audio track - for (uint32 i = 0; i < _audioHandles.size(); i++) { - if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) { - uint32 time = g_system->getMixer()->getSoundElapsedTime(_audioHandles[i]) + _audioStartOffset.msecs(); - if (Audio::Timestamp(time, 1000) < _audioTracks[i]->getLength()) - return time; - } - } - - // Just use time elapsed since the beginning - return SeekableVideoDecoder::getTime(); -} - -uint32 QuickTimeDecoder::getTimeToNextFrame() const { - if (_needUpdate) - return 0; - - if (_nextVideoTrack) { - uint32 nextFrameStartTime = _nextVideoTrack->getNextFrameStartTime(); - - if (nextFrameStartTime == 0) - return 0; - - // TODO: Add support for rate modification - - uint32 elapsedTime = getTime(); - - if (elapsedTime < nextFrameStartTime) - return nextFrameStartTime - elapsedTime; - } - - return 0; -} - -bool QuickTimeDecoder::loadFile(const Common::String &filename) { - if (!Common::QuickTimeParser::parseFile(filename)) - return false; - - init(); - return true; -} - -bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) { - if (!Common::QuickTimeParser::parseStream(stream)) - return false; - - init(); - return true; -} - -void QuickTimeDecoder::updateVolume() { - for (uint32 i = 0; i < _audioHandles.size(); i++) - if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) - g_system->getMixer()->setChannelVolume(_audioHandles[i], getVolume()); -} - -void QuickTimeDecoder::updateBalance() { - for (uint32 i = 0; i < _audioHandles.size(); i++) - if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) - g_system->getMixer()->setChannelBalance(_audioHandles[i], getBalance()); -} - -void QuickTimeDecoder::init() { - Audio::QuickTimeAudioDecoder::init(); - - _startTime = 0; - _setStartTime = false; - - // Initialize all the audio tracks - if (!_audioTracks.empty()) { - _audioHandles.resize(_audioTracks.size()); - - for (uint32 i = 0; i < _audioTracks.size(); i++) - _handlers.push_back(new AudioTrackHandler(this, _audioTracks[i])); - } - - // Initialize all the video tracks - for (uint32 i = 0; i < _tracks.size(); i++) { - if (_tracks[i]->codecType == CODEC_TYPE_VIDEO) { - for (uint32 j = 0; j < _tracks[i]->sampleDescs.size(); j++) - ((VideoSampleDesc *)_tracks[i]->sampleDescs[j])->initCodec(); - - _handlers.push_back(new VideoTrackHandler(this, _tracks[i])); - } - } - - // Prepare the first video track - _nextVideoTrack = findNextVideoTrack(); - - if (_nextVideoTrack) { - if (_scaleFactorX != 1 || _scaleFactorY != 1) { - // We have to take the scale into consideration when setting width/height - _width = (_nextVideoTrack->getWidth() / _scaleFactorX).toInt(); - _height = (_nextVideoTrack->getHeight() / _scaleFactorY).toInt(); - } else { - _width = _nextVideoTrack->getWidth().toInt(); - _height = _nextVideoTrack->getHeight().toInt(); - } - - _needUpdate = true; - } else { - _needUpdate = false; - } - - // Now start any audio - if (!_audioTracks.empty()) { - startAudio(); - _audioStartOffset = Audio::Timestamp(0); - } -} - -Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *track, uint32 format) { +Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format) { if (track->codecType == CODEC_TYPE_VIDEO) { debug(0, "Video Codec FourCC: \'%s\'", tag2str(format)); @@ -395,61 +208,52 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *tra return Audio::QuickTimeAudioDecoder::readSampleDesc(track, format); } -void QuickTimeDecoder::close() { - stopAudio(); - freeAllTrackHandlers(); - - if (_scaledSurface) { - _scaledSurface->free(); - delete _scaledSurface; - _scaledSurface = 0; - } - - _width = _height = 0; - - Common::QuickTimeParser::close(); - SeekableVideoDecoder::reset(); -} - -void QuickTimeDecoder::freeAllTrackHandlers() { - for (uint32 i = 0; i < _handlers.size(); i++) - delete _handlers[i]; - - _handlers.clear(); -} +void QuickTimeDecoder::init() { + Audio::QuickTimeAudioDecoder::init(); -void QuickTimeDecoder::seekToTime(const Audio::Timestamp &time) { - stopAudio(); - _audioStartOffset = time; + // Initialize all the audio tracks + for (uint32 i = 0; i < _audioTracks.size(); i++) + addTrack(new AudioTrackHandler(this, _audioTracks[i])); - // Sets all tracks to this time - for (uint32 i = 0; i < _handlers.size(); i++) - _handlers[i]->seekToTime(time); + // Initialize all the video tracks + Common::Array &tracks = Common::QuickTimeParser::_tracks; + for (uint32 i = 0; i < tracks.size(); i++) { + if (tracks[i]->codecType == CODEC_TYPE_VIDEO) { + for (uint32 j = 0; j < tracks[i]->sampleDescs.size(); j++) + ((VideoSampleDesc *)tracks[i]->sampleDescs[j])->initCodec(); - startAudio(); + addTrack(new VideoTrackHandler(this, tracks[i])); + } + } - // Reset our start time - _startTime = g_system->getMillis() - time.msecs(); - _setStartTime = true; - resetPauseStartTime(); + // Prepare the first video track + VideoTrackHandler *nextVideoTrack = (VideoTrackHandler *)findNextVideoTrack(); - // Reset the next video track too - _nextVideoTrack = findNextVideoTrack(); - _needUpdate = _nextVideoTrack != 0; + if (nextVideoTrack) { + if (_scaleFactorX != 1 || _scaleFactorY != 1) { + // We have to take the scale into consideration when setting width/height + _width = (nextVideoTrack->getScaledWidth() / _scaleFactorX).toInt(); + _height = (nextVideoTrack->getScaledHeight() / _scaleFactorY).toInt(); + } else { + _width = nextVideoTrack->getWidth(); + _height = nextVideoTrack->getHeight(); + } + } } void QuickTimeDecoder::updateAudioBuffer() { // Updates the audio buffers for all audio tracks - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeAudio) - ((AudioTrackHandler *)_handlers[i])->updateBuffer(); + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) + if ((*it)->getTrackType() == AdvancedVideoDecoder::Track::kTrackTypeAudio) + ((AudioTrackHandler *)*it)->updateBuffer(); } -Graphics::PixelFormat QuickTimeDecoder::getPixelFormat() const { - if (_nextVideoTrack) - return _nextVideoTrack->getPixelFormat(); +void QuickTimeDecoder::scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY) { + assert(src && dst); - return Graphics::PixelFormat(); + for (int32 j = 0; j < dst->h; j++) + for (int32 k = 0; k < dst->w; k++) + memcpy(dst->getBasePtr(k, j), src->getBasePtr((k * scaleFactorX).toInt() , (j * scaleFactorY).toInt()), src->format.bytesPerPixel); } QuickTimeDecoder::VideoSampleDesc::VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag) : Common::QuickTimeParser::SampleDesc(parentTrack, codecTag) { @@ -504,25 +308,8 @@ void QuickTimeDecoder::VideoSampleDesc::initCodec() { } } -bool QuickTimeDecoder::endOfVideoTracks() const { - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) - return false; - - return true; -} - -QuickTimeDecoder::TrackHandler::TrackHandler(QuickTimeDecoder *decoder, Track *parent) : _decoder(decoder), _parent(parent), _fd(_decoder->_fd) { - _curEdit = 0; -} - -bool QuickTimeDecoder::TrackHandler::endOfTrack() { - // A track is over when we've finished going through all edits - return _curEdit == _parent->editCount; -} - QuickTimeDecoder::AudioTrackHandler::AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack) - : TrackHandler(decoder, audioTrack->getParent()), _audioTrack(audioTrack) { + : _decoder(decoder), _audioTrack(audioTrack) { } void QuickTimeDecoder::AudioTrackHandler::updateBuffer() { @@ -532,21 +319,20 @@ void QuickTimeDecoder::AudioTrackHandler::updateBuffer() { _audioTrack->queueAudio(Audio::Timestamp(_decoder->getTimeToNextFrame() + 500, 1000)); } -bool QuickTimeDecoder::AudioTrackHandler::endOfTrack() { - return _audioTrack->endOfData(); -} - -void QuickTimeDecoder::AudioTrackHandler::seekToTime(Audio::Timestamp time) { - _audioTrack->seek(time); +Audio::SeekableAudioStream *QuickTimeDecoder::AudioTrackHandler::getSeekableAudioStream() const { + return _audioTrack; } -QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : TrackHandler(decoder, parent) { +QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : _decoder(decoder), _parent(parent) { + _curEdit = 0; enterNewEditList(false); _holdNextFrameStartTime = false; _curFrame = -1; _durationOverride = -1; _scaledSurface = 0; + _curPalette = 0; + _dirtyPalette = false; } QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() { @@ -556,6 +342,88 @@ QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() { } } +bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const { + // A track is over when we've finished going through all edits + return _curEdit == _parent->editCount; +} + +bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requestedTime) { + // First, figure out what edit we're in + Audio::Timestamp time = requestedTime.convertToFramerate(_parent->timeScale); + + // Continue until we get to where we need to be + for (_curEdit = 0; !endOfTrack(); _curEdit++) + if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration()) + break; + + // This track is done + if (endOfTrack()) + return true; + + enterNewEditList(false); + + // One extra check for the end of a track + if (endOfTrack()) + return true; + + // Now we're in the edit and need to figure out what frame we need + while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) { + _curFrame++; + if (_durationOverride >= 0) { + _nextFrameStartTime += _durationOverride; + _durationOverride = -1; + } else { + _nextFrameStartTime += getFrameDuration(); + } + } + + // All that's left is to figure out what our starting time is going to be + // Compare the starting point for the frame to where we need to be + _holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames(); + + // If we went past the time, go back a frame + if (_holdNextFrameStartTime) + _curFrame--; + + // Handle the keyframe here + int32 destinationFrame = _curFrame + 1; + + assert(destinationFrame < (int32)_parent->frameCount); + _curFrame = findKeyFrame(destinationFrame) - 1; + while (_curFrame < destinationFrame - 1) + bufferNextFrame(); + + return true; +} + +Audio::Timestamp QuickTimeDecoder::VideoTrackHandler::getDuration() const { + return Audio::Timestamp(0, _parent->duration, _decoder->_timeScale); +} + +uint16 QuickTimeDecoder::VideoTrackHandler::getWidth() const { + return getScaledWidth().toInt(); +} + +uint16 QuickTimeDecoder::VideoTrackHandler::getHeight() const { + return getScaledHeight().toInt(); +} + +Graphics::PixelFormat QuickTimeDecoder::VideoTrackHandler::getPixelFormat() const { + return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat(); +} + +int QuickTimeDecoder::VideoTrackHandler::getFrameCount() const { + return _parent->frameCount; +} + +uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() const { + if (endOfTrack()) + return 0; + + // Convert to milliseconds so the tracks can be compared + return getRateAdjustedFrameTime() * 1000 / _parent->timeScale; +} + const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() { if (endOfTrack()) return 0; @@ -586,7 +454,7 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() if (frame && (_parent->scaleFactorX != 1 || _parent->scaleFactorY != 1)) { if (!_scaledSurface) { _scaledSurface = new Graphics::Surface(); - _scaledSurface->create(getWidth().toInt(), getHeight().toInt(), getPixelFormat()); + _scaledSurface->create(getScaledWidth().toInt(), getScaledHeight().toInt(), getPixelFormat()); } _decoder->scaleSurface(frame, _scaledSurface, _parent->scaleFactorX, _parent->scaleFactorY); @@ -596,6 +464,85 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() return frame; } +Common::Rational QuickTimeDecoder::VideoTrackHandler::getScaledWidth() const { + return Common::Rational(_parent->width) / _parent->scaleFactorX; +} + +Common::Rational QuickTimeDecoder::VideoTrackHandler::getScaledHeight() const { + return Common::Rational(_parent->height) / _parent->scaleFactorY; +} + +Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePacket(uint32 &descId) { + // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for. + int32 totalSampleCount = 0; + int32 sampleInChunk = 0; + int32 actualChunk = -1; + uint32 sampleToChunkIndex = 0; + + for (uint32 i = 0; i < _parent->chunkCount; i++) { + if (sampleToChunkIndex < _parent->sampleToChunkCount && i >= _parent->sampleToChunk[sampleToChunkIndex].first) + sampleToChunkIndex++; + + totalSampleCount += _parent->sampleToChunk[sampleToChunkIndex - 1].count; + + if (totalSampleCount > _curFrame) { + actualChunk = i; + descId = _parent->sampleToChunk[sampleToChunkIndex - 1].id; + sampleInChunk = _parent->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + _curFrame; + break; + } + } + + if (actualChunk < 0) { + warning("Could not find data for frame %d", _curFrame); + return 0; + } + + // Next seek to that frame + Common::SeekableReadStream *stream = _decoder->_fd; + stream->seek(_parent->chunkOffsets[actualChunk]); + + // Then, if the chunk holds more than one frame, seek to where the frame we want is located + for (int32 i = _curFrame - sampleInChunk; i < _curFrame; i++) { + if (_parent->sampleSize != 0) + stream->skip(_parent->sampleSize); + else + stream->skip(_parent->sampleSizes[i]); + } + + // Finally, read in the raw data for the frame + //debug("Frame Data[%d]: Offset = %d, Size = %d", _curFrame, stream->pos(), _parent->sampleSizes[_curFrame]); + + if (_parent->sampleSize != 0) + return stream->readStream(_parent->sampleSize); + + return stream->readStream(_parent->sampleSizes[_curFrame]); +} + +uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() { + uint32 curFrameIndex = 0; + for (int32 i = 0; i < _parent->timeToSampleCount; i++) { + curFrameIndex += _parent->timeToSample[i].count; + if ((uint32)_curFrame < curFrameIndex) { + // Ok, now we have what duration this frame has. + return _parent->timeToSample[i].duration; + } + } + + // This should never occur + error("Cannot find duration for frame %d", _curFrame); + return 0; +} + +uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const { + for (int i = _parent->keyframeCount - 1; i >= 0; i--) + if (_parent->keyframes[i] <= frame) + return _parent->keyframes[i]; + + // If none found, we'll assume the requested frame is a key frame + return frame; +} + void QuickTimeDecoder::VideoTrackHandler::enterNewEditList(bool bufferFrames) { // Bypass all empty edit lists first while (!endOfTrack() && _parent->editList[_curEdit].mediaTime == -1) @@ -667,166 +614,25 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame() if (entry->_videoCodec->containsPalette()) { // The codec itself contains a palette if (entry->_videoCodec->hasDirtyPalette()) { - _decoder->_palette = entry->_videoCodec->getPalette(); - _decoder->_dirtyPalette = true; + _curPalette = entry->_videoCodec->getPalette(); + _dirtyPalette = true; } } else { // Check if the video description has been updated byte *palette = entry->_palette; - if (palette !=_decoder-> _palette) { - _decoder->_palette = palette; - _decoder->_dirtyPalette = true; - } - } - - return frame; -} - -uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() { - if (endOfTrack()) - return 0; - - // Convert to milliseconds so the tracks can be compared - return getRateAdjustedFrameTime() * 1000 / _parent->timeScale; -} - -uint32 QuickTimeDecoder::VideoTrackHandler::getFrameCount() { - return _parent->frameCount; -} - -uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() { - uint32 curFrameIndex = 0; - for (int32 i = 0; i < _parent->timeToSampleCount; i++) { - curFrameIndex += _parent->timeToSample[i].count; - if ((uint32)_curFrame < curFrameIndex) { - // Ok, now we have what duration this frame has. - return _parent->timeToSample[i].duration; - } - } - - // This should never occur - error("Cannot find duration for frame %d", _curFrame); - return 0; -} - -Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePacket(uint32 &descId) { - // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for. - int32 totalSampleCount = 0; - int32 sampleInChunk = 0; - int32 actualChunk = -1; - uint32 sampleToChunkIndex = 0; - - for (uint32 i = 0; i < _parent->chunkCount; i++) { - if (sampleToChunkIndex < _parent->sampleToChunkCount && i >= _parent->sampleToChunk[sampleToChunkIndex].first) - sampleToChunkIndex++; - - totalSampleCount += _parent->sampleToChunk[sampleToChunkIndex - 1].count; - - if (totalSampleCount > _curFrame) { - actualChunk = i; - descId = _parent->sampleToChunk[sampleToChunkIndex - 1].id; - sampleInChunk = _parent->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + _curFrame; - break; + if (palette != _curPalette) { + _curPalette = palette; + _dirtyPalette = true; } } - if (actualChunk < 0) { - warning("Could not find data for frame %d", _curFrame); - return 0; - } - - // Next seek to that frame - _fd->seek(_parent->chunkOffsets[actualChunk]); - - // Then, if the chunk holds more than one frame, seek to where the frame we want is located - for (int32 i = _curFrame - sampleInChunk; i < _curFrame; i++) { - if (_parent->sampleSize != 0) - _fd->skip(_parent->sampleSize); - else - _fd->skip(_parent->sampleSizes[i]); - } - - // Finally, read in the raw data for the frame - //debug("Frame Data[%d]: Offset = %d, Size = %d", _curFrame, _fd->pos(), _parent->sampleSizes[_curFrame]); - - if (_parent->sampleSize != 0) - return _fd->readStream(_parent->sampleSize); - - return _fd->readStream(_parent->sampleSizes[_curFrame]); -} - -uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const { - for (int i = _parent->keyframeCount - 1; i >= 0; i--) - if (_parent->keyframes[i] <= frame) - return _parent->keyframes[i]; - - // If none found, we'll assume the requested frame is a key frame return frame; } -void QuickTimeDecoder::VideoTrackHandler::seekToTime(Audio::Timestamp time) { - // First, figure out what edit we're in - time = time.convertToFramerate(_parent->timeScale); - - // Continue until we get to where we need to be - for (_curEdit = 0; !endOfTrack(); _curEdit++) - if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration()) - break; - - // This track is done - if (endOfTrack()) - return; - - enterNewEditList(false); - - // One extra check for the end of a track - if (endOfTrack()) - return; - - // Now we're in the edit and need to figure out what frame we need - while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) { - _curFrame++; - if (_durationOverride >= 0) { - _nextFrameStartTime += _durationOverride; - _durationOverride = -1; - } else { - _nextFrameStartTime += getFrameDuration(); - } - } - - // All that's left is to figure out what our starting time is going to be - // Compare the starting point for the frame to where we need to be - _holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames(); - - // If we went past the time, go back a frame - if (_holdNextFrameStartTime) - _curFrame--; - - // Handle the keyframe here - int32 destinationFrame = _curFrame + 1; - - assert(destinationFrame < (int32)_parent->frameCount); - _curFrame = findKeyFrame(destinationFrame) - 1; - while (_curFrame < destinationFrame - 1) - bufferNextFrame(); -} - -Common::Rational QuickTimeDecoder::VideoTrackHandler::getWidth() const { - return Common::Rational(_parent->width) / _parent->scaleFactorX; -} - -Common::Rational QuickTimeDecoder::VideoTrackHandler::getHeight() const { - return Common::Rational(_parent->height) / _parent->scaleFactorY; -} - -Graphics::PixelFormat QuickTimeDecoder::VideoTrackHandler::getPixelFormat() const { - return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat(); -} - uint32 QuickTimeDecoder::VideoTrackHandler::getRateAdjustedFrameTime() const { // Figure out what time the next frame is at taking the edit list rate into account - uint32 convertedTime = (Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate).toInt(); + uint32 convertedTime = (Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate).toInt(); return convertedTime + getCurEditTimeOffset(); } diff --git a/video/qt_decoder.h b/video/qt_decoder.h index ce32562d64..7a251b8580 100644 --- a/video/qt_decoder.h +++ b/video/qt_decoder.h @@ -31,16 +31,17 @@ #ifndef VIDEO_QT_DECODER_H #define VIDEO_QT_DECODER_H -#include "audio/mixer.h" #include "audio/decoders/quicktime_intern.h" #include "common/scummsys.h" -#include "common/rational.h" -#include "graphics/pixelformat.h" #include "video/video_decoder.h" namespace Common { - class Rational; +class Rational; +} + +namespace Graphics { +struct PixelFormat; } namespace Video { @@ -54,68 +55,33 @@ class Codec; * - mohawk * - sci */ -class QuickTimeDecoder : public SeekableVideoDecoder, public Audio::QuickTimeAudioDecoder { +class QuickTimeDecoder : public AdvancedVideoDecoder, public Audio::QuickTimeAudioDecoder { public: QuickTimeDecoder(); virtual ~QuickTimeDecoder(); - /** - * Returns the width of the video - * @return the width of the video - */ - uint16 getWidth() const { return _width; } - - /** - * Returns the height of the video - * @return the height of the video - */ - uint16 getHeight() const { return _height; } - - /** - * Returns the amount of frames in the video - * @return the amount of frames in the video - */ - uint32 getFrameCount() const; - - /** - * Load a video file - * @param filename the filename to load - */ bool loadFile(const Common::String &filename); - - /** - * Load a QuickTime video file from a SeekableReadStream - * @param stream the stream to load - */ bool loadStream(Common::SeekableReadStream *stream); - - /** - * Close a QuickTime encoded video file - */ void close(); + uint16 getWidth() const { return _width; } + uint16 getHeight() const { return _height; } + const Graphics::Surface *decodeNextFrame(); + Audio::Timestamp getDuration() const { return Audio::Timestamp(0, _duration, _timeScale); } - /** - * Returns the palette of the video - * @return the palette of the video - */ - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } +protected: + Common::QuickTimeParser::SampleDesc *readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format); - int32 getCurFrame() const; +private: + void init(); - bool isVideoLoaded() const { return isOpen(); } - const Graphics::Surface *decodeNextFrame(); - bool endOfVideo() const; - uint32 getTime() const; - uint32 getTimeToNextFrame() const; - Graphics::PixelFormat getPixelFormat() const; + void updateAudioBuffer(); - // SeekableVideoDecoder API - void seekToFrame(uint32 frame); - void seekToTime(const Audio::Timestamp &time); - uint32 getDuration() const { return _duration * 1000 / _timeScale; } + uint16 _width, _height; + + Graphics::Surface *_scaledSurface; + void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, + const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY); -protected: class VideoSampleDesc : public Common::QuickTimeParser::SampleDesc { public: VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag); @@ -131,110 +97,59 @@ protected: Codec *_videoCodec; }; - Common::QuickTimeParser::SampleDesc *readSampleDesc(Track *track, uint32 format); - - // VideoDecoder API - void updateVolume(); - void updateBalance(); - -private: - void init(); - - void startAudio(); - void stopAudio(); - void updateAudioBuffer(); - void readNextAudioChunk(); - Common::Array _audioHandles; - Audio::Timestamp _audioStartOffset; - - Codec *createCodec(uint32 codecTag, byte bitsPerPixel); - uint32 findKeyFrame(uint32 frame) const; - - bool _dirtyPalette; - const byte *_palette; - bool _setStartTime; - bool _needUpdate; - - uint16 _width, _height; - - Graphics::Surface *_scaledSurface; - void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, - Common::Rational scaleFactorX, Common::Rational scaleFactorY); - - void pauseVideoIntern(bool pause); - bool endOfVideoTracks() const; - - // The TrackHandler is a class that wraps around a QuickTime Track - // and handles playback in this decoder class. - class TrackHandler { - public: - TrackHandler(QuickTimeDecoder *decoder, Track *parent); - virtual ~TrackHandler() {} - - enum TrackType { - kTrackTypeAudio, - kTrackTypeVideo - }; - - virtual TrackType getTrackType() const = 0; - - virtual void seekToTime(Audio::Timestamp time) = 0; - - virtual bool endOfTrack(); - - protected: - uint32 _curEdit; - QuickTimeDecoder *_decoder; - Common::SeekableReadStream *_fd; - Track *_parent; - }; - // The AudioTrackHandler is currently just a wrapper around some // QuickTimeDecoder functions. - class AudioTrackHandler : public TrackHandler { + class AudioTrackHandler : public SeekableAudioTrack { public: AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack); - TrackType getTrackType() const { return kTrackTypeAudio; } void updateBuffer(); - void seekToTime(Audio::Timestamp time); - bool endOfTrack(); + + protected: + Audio::SeekableAudioStream *getSeekableAudioStream() const; private: + QuickTimeDecoder *_decoder; QuickTimeAudioTrack *_audioTrack; }; // The VideoTrackHandler is the bridge between the time of playback // and the media for the given track. It calculates when to start // tracks and at what rate to play the media using the edit list. - class VideoTrackHandler : public TrackHandler { + class VideoTrackHandler : public VideoTrack { public: - VideoTrackHandler(QuickTimeDecoder *decoder, Track *parent); + VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent); ~VideoTrackHandler(); - TrackType getTrackType() const { return kTrackTypeVideo; } - - const Graphics::Surface *decodeNextFrame(); - - uint32 getNextFrameStartTime(); - - uint32 getFrameCount(); - - int32 getCurFrame() { return _curFrame; } + bool endOfTrack() const; + bool isSeekable() const { return true; } + bool seek(const Audio::Timestamp &time); + Audio::Timestamp getDuration() const; + uint16 getWidth() const; + uint16 getHeight() const; Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const; + uint32 getNextFrameStartTime() const; + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _curPalette; } + bool hasDirtyPalette() const { return _curPalette; } - void seekToTime(Audio::Timestamp time); - - Common::Rational getWidth() const; - Common::Rational getHeight() const; + Common::Rational getScaledWidth() const; + Common::Rational getScaledHeight() const; private: + QuickTimeDecoder *_decoder; + Common::QuickTimeParser::Track *_parent; + uint32 _curEdit; int32 _curFrame; uint32 _nextFrameStartTime; Graphics::Surface *_scaledSurface; bool _holdNextFrameStartTime; int32 _durationOverride; + const byte *_curPalette; + mutable bool _dirtyPalette; Common::SeekableReadStream *getNextFramePacket(uint32 &descId); uint32 getFrameDuration(); @@ -245,12 +160,6 @@ private: uint32 getCurEditTimeOffset() const; uint32 getCurEditTrackDuration() const; }; - - Common::Array _handlers; - VideoTrackHandler *_nextVideoTrack; - VideoTrackHandler *findNextVideoTrack() const; - - void freeAllTrackHandlers(); }; } // End of namespace Video -- cgit v1.2.3 From 9cca8ac9f2f9162d4201d59c9ed8be5ae2a32a2b Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 27 Jul 2012 11:47:49 -0400 Subject: VIDEO: Remove now unused Rewindable and Seekable classes --- video/video_decoder.h | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/video/video_decoder.h b/video/video_decoder.h index eff5a7c396..3f5dc2c2ff 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -809,45 +809,6 @@ private: uint32 getFrameBeginTime(uint32 frame) const; }; -/** - * A VideoDecoder that can be rewound back to the beginning. - * @note This class is now deprecated. Use AdvancedVideoDecoder instead. - */ -class RewindableVideoDecoder : public virtual VideoDecoder { -public: - /** - * Rewind to the beginning of the video. - */ - virtual void rewind() = 0; -}; - -/** - * A VideoDecoder that can seek to a frame or point in time. - * @note This class is now deprecated. Use AdvancedVideoDecoder instead. - */ -class SeekableVideoDecoder : public virtual RewindableVideoDecoder { -public: - /** - * Seek to the specified time. - */ - virtual void seekToTime(const Audio::Timestamp &time) = 0; - - /** - * Seek to the specified time (in ms). - */ - void seekToTime(uint32 msecs) { seekToTime(Audio::Timestamp(msecs, 1000)); } - - /** - * Implementation of RewindableVideoDecoder::rewind(). - */ - virtual void rewind() { seekToTime(0); } - - /** - * Get the total duration of the video (in ms). - */ - virtual uint32 getDuration() const = 0; -}; - } // End of namespace Video #endif -- cgit v1.2.3 From dd10e7191e4b373513e5a6fa73daa6312bd81f62 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 29 Jul 2012 12:30:34 -0400 Subject: VIDEO: Move Track's start()/stop() functions to AudioTrack --- video/video_decoder.cpp | 26 ++++++++++++++------------ video/video_decoder.h | 22 ++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 131c86fdb8..84ce8144a0 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -268,7 +268,7 @@ bool AdvancedVideoDecoder::rewind() { // Stop all tracks so they can be rewound if (isPlaying()) - stopAllTracks(); + stopAudio(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if (!(*it)->rewind()) @@ -276,7 +276,7 @@ bool AdvancedVideoDecoder::rewind() { // Now that we've rewound, start all tracks again if (isPlaying()) - startAllTracks(); + startAudio(); _audioStartOffset = 0; _startTime = g_system->getMillis(); @@ -303,7 +303,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { // Stop all tracks so they can be seeked if (isPlaying()) - stopAllTracks(); + stopAudio(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if (!(*it)->seek(time)) @@ -311,7 +311,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { // Now that we've seeked, start all tracks again if (isPlaying()) - startAllTracks(); + startAudio(); _audioStartOffset = time; _startTime = g_system->getMillis() - time.msecs(); @@ -332,7 +332,7 @@ void AdvancedVideoDecoder::start() { if (_needsRewind) rewind(); - startAllTracks(); + startAudio(); } void AdvancedVideoDecoder::stop() { @@ -346,7 +346,7 @@ void AdvancedVideoDecoder::stop() { _dirtyPalette = false; _needsUpdate = false; - stopAllTracks(); + stopAudio(); // Also reset the pause state. _pauseLevel = 0; @@ -532,8 +532,8 @@ void AdvancedVideoDecoder::addTrack(Track *track) { track->pause(true); // Start the track if we're playing - if (isPlaying()) - track->start(); + if (isPlaying() && track->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)track)->start(); } bool AdvancedVideoDecoder::addStreamFileTrack(const Common::String &baseName) { @@ -607,14 +607,16 @@ const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack return bestTrack; } -void AdvancedVideoDecoder::startAllTracks() { +void AdvancedVideoDecoder::startAudio() { for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - (*it)->start(); + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->start(); } -void AdvancedVideoDecoder::stopAllTracks() { +void AdvancedVideoDecoder::stopAudio() { for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - (*it)->stop(); + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->stop(); } ////////////////////////////////////////////// diff --git a/video/video_decoder.h b/video/video_decoder.h index 3f5dc2c2ff..ad9825cb25 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -446,16 +446,6 @@ protected: */ virtual bool seek(const Audio::Timestamp &time) { return false; } - /** - * Start playback of the track. - */ - virtual void start() {} - - /** - * Stop playback of the track. - */ - virtual void stop() {} - /** * Set the pause status of the track. */ @@ -578,7 +568,15 @@ protected: TrackType getTrackType() const { return kTrackTypeAudio; } virtual bool endOfTrack() const; + + /** + * Start playing this track + */ void start(); + + /** + * Stop playing this track + */ void stop(); /** @@ -785,8 +783,8 @@ private: Graphics::PixelFormat _defaultHighColorFormat; // Internal helper functions - void stopAllTracks(); - void startAllTracks(); + void stopAudio(); + void startAudio(); }; /** -- cgit v1.2.3 From 220ca52f4329ad3c1344c38e23280fde4570bd89 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Tue, 7 Aug 2012 14:24:32 -0400 Subject: VIDEO: Fix getTime() when a video is not playing --- video/video_decoder.cpp | 20 +++++++++++++------- video/video_decoder.h | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 84ce8144a0..44b05c4345 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -102,6 +102,7 @@ AdvancedVideoDecoder::AdvancedVideoDecoder() { _audioBalance = 0; _pauseLevel = 0; _needsUpdate = false; + _lastTimeChange = 0; // Find the best format for output _defaultHighColorFormat = g_system->getScreenFormat(); @@ -126,6 +127,7 @@ void AdvancedVideoDecoder::close() { _audioBalance = 0; _pauseLevel = 0; _needsUpdate = false; + _lastTimeChange = 0; } bool AdvancedVideoDecoder::isVideoLoaded() const { @@ -201,6 +203,9 @@ uint32 AdvancedVideoDecoder::getFrameCount() const { } uint32 AdvancedVideoDecoder::getTime() const { + if (!isPlaying()) + return _lastTimeChange.msecs(); + if (isPaused()) return _pauseStartTime - _startTime; @@ -210,7 +215,7 @@ uint32 AdvancedVideoDecoder::getTime() const { uint32 time = ((const AudioTrack *)*it)->getRunningTime(); if (time != 0) - return time + _audioStartOffset.msecs(); + return time + _lastTimeChange.msecs(); } } } @@ -278,7 +283,7 @@ bool AdvancedVideoDecoder::rewind() { if (isPlaying()) startAudio(); - _audioStartOffset = 0; + _lastTimeChange = 0; _startTime = g_system->getMillis(); resetPauseStartTime(); return true; @@ -313,7 +318,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { if (isPlaying()) startAudio(); - _audioStartOffset = time; + _lastTimeChange = time; _startTime = g_system->getMillis() - time.msecs(); resetPauseStartTime(); _needsUpdate = true; @@ -326,7 +331,7 @@ void AdvancedVideoDecoder::start() { _isPlaying = true; _startTime = g_system->getMillis(); - _audioStartOffset = 0; + _lastTimeChange = 0; // If someone previously called stop(), we'll rewind it. if (_needsRewind) @@ -341,7 +346,6 @@ void AdvancedVideoDecoder::stop() { _isPlaying = false; _startTime = 0; - _audioStartOffset = 0; _palette = 0; _dirtyPalette = false; _needsUpdate = false; @@ -354,10 +358,12 @@ void AdvancedVideoDecoder::stop() { // If this is a rewindable video, don't close it too. We'll just rewind() the video // the next time someone calls start(). Otherwise, since it can't be rewound, we // just close it. - if (isRewindable()) + if (isRewindable()) { + _lastTimeChange = getTime(); _needsRewind = true; - else + } else { close(); + } } Audio::Timestamp AdvancedVideoDecoder::getDuration() const { diff --git a/video/video_decoder.h b/video/video_decoder.h index ad9825cb25..26078d5750 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -773,7 +773,7 @@ private: // Current playback status bool _isPlaying, _needsRewind, _needsUpdate; - Audio::Timestamp _audioStartOffset; + Audio::Timestamp _lastTimeChange; // Palette settings from individual tracks mutable bool _dirtyPalette; -- cgit v1.2.3 From 813689d68cd055935eaa12f614608d1237866b83 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 00:08:13 -0400 Subject: AUDIO: Move LimitingAudioStream to audio/ --- audio/audiostream.cpp | 38 ++++++++++++++++++++++++++++++++++++++ audio/audiostream.h | 10 ++++++++++ audio/decoders/quicktime.cpp | 39 ++------------------------------------- 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/audio/audiostream.cpp b/audio/audiostream.cpp index 1c5c435359..6e185702f0 100644 --- a/audio/audiostream.cpp +++ b/audio/audiostream.cpp @@ -386,4 +386,42 @@ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo return Timestamp(result.secs(), result.numberOfFrames(), result.framerate()); } +/** + * An AudioStream wrapper that cuts off the amount of samples read after a + * given time length is reached. + */ +class LimitingAudioStream : public AudioStream { +public: + LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) : + _parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse), + _totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {} + + ~LimitingAudioStream() { + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _parentStream; + } + + int readBuffer(int16 *buffer, const int numSamples) { + // Cap us off so we don't read past _totalSamples + int samplesRead = _parentStream->readBuffer(buffer, MIN(numSamples, _totalSamples - _samplesRead)); + _samplesRead += samplesRead; + return samplesRead; + } + + bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } + bool isStereo() const { return _parentStream->isStereo(); } + int getRate() const { return _parentStream->getRate(); } + +private: + int getChannels() const { return isStereo() ? 2 : 1; } + + AudioStream *_parentStream; + DisposeAfterUse::Flag _disposeAfterUse; + uint32 _totalSamples, _samplesRead; +}; + +AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) { + return new LimitingAudioStream(parentStream, length, disposeAfterUse); +} + } // End of namespace Audio diff --git a/audio/audiostream.h b/audio/audiostream.h index 801f13d9d9..d6d4a16280 100644 --- a/audio/audiostream.h +++ b/audio/audiostream.h @@ -356,6 +356,16 @@ QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo); */ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo); +/** + * Factory function for an AudioStream wrapper that cuts off the amount of samples read after a + * given time length is reached. + * + * @param parentStream The stream to limit + * @param length The time length to limit the stream to + * @param disposeAfterUse Whether the parent stream object should be destroyed on destruction of the returned stream + */ +AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); + } // End of namespace Audio #endif diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index 8874a61c2e..5276cfc530 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -61,41 +61,6 @@ private: bool _isStereo; }; -/** - * An AudioStream wrapper that cuts off the amount of samples read after a - * given time length is reached. - */ -class LimitingAudioStream : public AudioStream { -public: - LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) : - _parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse), - _totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {} - - ~LimitingAudioStream() { - if (_disposeAfterUse == DisposeAfterUse::YES) - delete _parentStream; - } - - int readBuffer(int16 *buffer, const int numSamples) { - // Cap us off so we don't read past _totalSamples - int samplesRead = _parentStream->readBuffer(buffer, MIN(numSamples, _totalSamples - _samplesRead)); - _samplesRead += samplesRead; - return samplesRead; - } - - bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } - bool isStereo() const { return _parentStream->isStereo(); } - int getRate() const { return _parentStream->getRate(); } - -private: - int getChannels() const { return isStereo() ? 2 : 1; } - - AudioStream *_parentStream; - DisposeAfterUse::Flag _disposeAfterUse; - uint32 _totalSamples, _samplesRead; -}; - /** * An AudioStream wrapper that forces audio to be played in mono. * It currently just ignores the right channel if stereo. @@ -263,7 +228,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueAudio(const Timestamp &len _skipSamples = Timestamp(); } - queueStream(new LimitingAudioStream(new SilentAudioStream(getRate(), isStereo()), editLength), editLength); + queueStream(makeLimitingAudioStream(new SilentAudioStream(getRate(), isStereo()), editLength), editLength); _curEdit++; enterNewEdit(nextEditTime); } else { @@ -289,7 +254,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueAudio(const Timestamp &len // we move on to the next edit if (trackPosition >= nextEditTime || _curChunk >= _parentTrack->chunkCount) { chunkLength = nextEditTime.convertToFramerate(getRate()) - getCurrentTrackTime(); - stream = new LimitingAudioStream(stream, chunkLength); + stream = makeLimitingAudioStream(stream, chunkLength); _curEdit++; enterNewEdit(nextEditTime); -- cgit v1.2.3 From a458b91e7e4a1774d8dea1fe75966d834f43ee7b Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 00:09:23 -0400 Subject: VIDEO: Add set/getStopTime functions to AdvancedVideoDecoder A video can now be stopped at a requested time --- video/video_decoder.cpp | 76 ++++++++++++++++++++++++++++++++++++++++++++++--- video/video_decoder.h | 22 ++++++++++---- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 44b05c4345..b27a0c512b 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -103,6 +103,8 @@ AdvancedVideoDecoder::AdvancedVideoDecoder() { _pauseLevel = 0; _needsUpdate = false; _lastTimeChange = 0; + _stopTime = 0; + _stopTimeSet = false; // Find the best format for output _defaultHighColorFormat = g_system->getScreenFormat(); @@ -128,6 +130,8 @@ void AdvancedVideoDecoder::close() { _pauseLevel = 0; _needsUpdate = false; _lastTimeChange = 0; + _stopTime = 0; + _stopTimeSet = false; } bool AdvancedVideoDecoder::isVideoLoaded() const { @@ -247,6 +251,13 @@ bool AdvancedVideoDecoder::endOfVideo() const { if (!isVideoLoaded()) return true; + if (_stopTimeSet) { + const VideoTrack *track = findNextVideoTrack(); + + if (track && track->getNextFrameStartTime() >= (uint)_stopTime.msecs()) + return true; + } + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) if (!(*it)->endOfTrack()) return false; @@ -314,12 +325,15 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { if (!(*it)->seek(time)) return false; + _lastTimeChange = time; + // Now that we've seeked, start all tracks again - if (isPlaying()) + // Also reset our start time + if (isPlaying()) { startAudio(); + _startTime = g_system->getMillis() - time.msecs(); + } - _lastTimeChange = time; - _startTime = g_system->getMillis() - time.msecs(); resetPauseStartTime(); _needsUpdate = true; return true; @@ -331,7 +345,10 @@ void AdvancedVideoDecoder::start() { _isPlaying = true; _startTime = g_system->getMillis(); - _lastTimeChange = 0; + + // Adjust start time if we've seeked to something besides zero time + if (_lastTimeChange.totalNumberOfFrames() != 0) + _startTime -= _lastTimeChange.msecs(); // If someone previously called stop(), we'll rewind it. if (_needsRewind) @@ -471,6 +488,21 @@ void AdvancedVideoDecoder::AudioTrack::stop() { g_system->getMixer()->stopHandle(_handle); } +void AdvancedVideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) { + stop(); + + Audio::AudioStream *stream = getAudioStream(); + assert(stream); + + stream = Audio::makeLimitingAudioStream(stream, limit, DisposeAfterUse::NO); + + g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::YES); + + // Pause the audio again if we're still paused + if (isPaused()) + g_system->getMixer()->pauseHandle(_handle, true); +} + uint32 AdvancedVideoDecoder::AudioTrack::getRunningTime() const { if (g_system->getMixer()->isSoundHandleActive(_handle)) return g_system->getMixer()->getSoundElapsedTime(_handle); @@ -553,6 +585,29 @@ bool AdvancedVideoDecoder::addStreamFileTrack(const Common::String &baseName) { return result; } +void AdvancedVideoDecoder::setStopTime(const Audio::Timestamp &stopTime) { + Audio::Timestamp startTime = 0; + + if (isPlaying()) { + startTime = getTime(); + stopAudio(); + } + + _stopTime = stopTime; + _stopTimeSet = true; + + if (startTime > stopTime) + return; + + if (isPlaying()) { + // We'll assume the audio track is going to start up at the same time it just was + // and therefore not do any seeking. + // Might want to set it anyway if we're seekable. + startAudioLimit(_stopTime.msecs() - startTime.msecs()); + _lastTimeChange = startTime; + } +} + AdvancedVideoDecoder::Track *AdvancedVideoDecoder::getTrack(uint track) { if (track > _tracks.size()) return 0; @@ -614,6 +669,13 @@ const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack } void AdvancedVideoDecoder::startAudio() { + if (_stopTimeSet) { + // HACK: Timestamp's subtraction asserts out when subtracting two times + // with different rates. + startAudioLimit(_stopTime - _lastTimeChange.convertToFramerate(_stopTime.framerate())); + return; + } + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeAudio) ((AudioTrack *)*it)->start(); @@ -625,6 +687,12 @@ void AdvancedVideoDecoder::stopAudio() { ((AudioTrack *)*it)->stop(); } +void AdvancedVideoDecoder::startAudioLimit(const Audio::Timestamp &limit) { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->start(limit); +} + ////////////////////////////////////////////// ///////////////// DEPRECATED ///////////////// ////////////////////////////////////////////// diff --git a/video/video_decoder.h b/video/video_decoder.h index 26078d5750..7e89caee40 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -379,14 +379,20 @@ public: */ void setDefaultHighColorFormat(const Graphics::PixelFormat &format) { _defaultHighColorFormat = format; } + /** + * Set the time for this video to stop at. At this time in the video, + * all audio will stop and endOfVideo() will return true. + */ + void setStopTime(const Audio::Timestamp &stopTime); + + /** + * Get the stop time of the video (if not set, zero) + */ + Audio::Timestamp getStopTime() const { return _stopTime; } + // Future API //void setRate(const Common::Rational &rate); //Common::Rational getRate() const; - //void setStartTime(const Audio::Timestamp &startTime); - //Audio::Timestamp getStartTime() const; - //void setStopTime(const Audio::Timestamp &stopTime); - //Audio::Timestamp getStopTime() const; - //void setSegment(const Audio::Timestamp &startTime, const Audio::Timestamp &stopTime); protected: // Old API @@ -579,6 +585,8 @@ protected: */ void stop(); + void start(const Audio::Timestamp &limit); + /** * Get the volume for this track */ @@ -773,7 +781,8 @@ private: // Current playback status bool _isPlaying, _needsRewind, _needsUpdate; - Audio::Timestamp _lastTimeChange; + Audio::Timestamp _lastTimeChange, _stopTime; + bool _stopTimeSet; // Palette settings from individual tracks mutable bool _dirtyPalette; @@ -785,6 +794,7 @@ private: // Internal helper functions void stopAudio(); void startAudio(); + void startAudioLimit(const Audio::Timestamp &limit); }; /** -- cgit v1.2.3 From 0817a02a7d69313d4649af27062c7e3d89c0d2c5 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 01:20:13 -0400 Subject: MOHAWK: Use setStopTime() --- engines/mohawk/myst_stacks/dni.cpp | 2 +- engines/mohawk/video.cpp | 6 ++---- engines/mohawk/video.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp index cae165ccf0..d103105c2d 100644 --- a/engines/mohawk/myst_stacks/dni.cpp +++ b/engines/mohawk/myst_stacks/dni.cpp @@ -109,7 +109,7 @@ void Dni::o_handPage(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _vm->setMainCursor(kDefaultMystCursor); // Play movie end (atrus leaving) - _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), Audio::Timestamp(0xFFFFFFFF)); + _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), _vm->_video->getDuration(atrus)); _vm->_video->setVideoLooping(atrus, false); _atrusLeft = true; diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 3b4e61646d..5b811382ff 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -43,13 +43,12 @@ void VideoEntry::clear() { loop = false; enabled = false; start = Audio::Timestamp(0, 1); - end = Audio::Timestamp(0xFFFFFFFF, 1); // Largest possible, there is an endOfVideo() check anyway filename.clear(); id = -1; } bool VideoEntry::endOfVideo() { - return !video || video->endOfVideo() || video->getTime() >= (uint)end.msecs(); + return !video || video->endOfVideo(); } VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { @@ -514,13 +513,12 @@ bool VideoManager::isVideoPlaying() { void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end) { assert(handle != NULL_VID_HANDLE); _videoStreams[handle].start = start; - _videoStreams[handle].end = end; + _videoStreams[handle]->setStopTime(end); _videoStreams[handle]->seek(start); } void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); - _videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1); _videoStreams[handle]->seek(time); updateMovies(); delete _videoStreams[handle].video; diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 937cd0f2dd..4e34604bfd 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -50,7 +50,7 @@ struct VideoEntry { uint16 y; bool loop; bool enabled; - Audio::Timestamp start, end; + Audio::Timestamp start; // Identification Common::String filename; // External video files -- cgit v1.2.3 From 48c591a233b403193b897c76d2e61a0f8a4f6805 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 08:33:45 -0400 Subject: VIDEO: Don't allow adding external stream files to unopened videos --- video/video_decoder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index b27a0c512b..0108888613 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -575,6 +575,10 @@ void AdvancedVideoDecoder::addTrack(Track *track) { } bool AdvancedVideoDecoder::addStreamFileTrack(const Common::String &baseName) { + // Only allow adding external tracks if a video is already loaded + if (!isVideoLoaded()) + return false; + StreamFileAudioTrack *track = new StreamFileAudioTrack(); bool result = track->loadFromFile(baseName); -- cgit v1.2.3 From 5db42076b87766d29cbcdd153446992bc661aa73 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 08:43:32 -0400 Subject: VIDEO: Convert FlicDecoder to the new AdvancedVideoDecoder API The video no longer automatically loops (unused in-tree) and must have rewind() called manually --- engines/tucker/sequences.cpp | 4 +- video/flic_decoder.cpp | 299 ++++++++++++++++++++++++------------------- video/flic_decoder.h | 101 ++++++++------- 3 files changed, 226 insertions(+), 178 deletions(-) diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index 775fd6f1a0..16c4f4f6f0 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -28,6 +28,7 @@ #include "audio/decoders/wave.h" #include "graphics/palette.h" +#include "graphics/surface.h" #include "tucker/tucker.h" #include "tucker/graphics.h" @@ -749,6 +750,7 @@ void AnimationSequencePlayer::openAnimation(int index, const char *fileName) { _seqNum = 1; return; } + _flicPlayer[index].start(); _flicPlayer[index].decodeNextFrame(); if (index == 0) { getRGBPalette(index); @@ -801,7 +803,7 @@ void AnimationSequencePlayer::playIntroSeq19_20() { if (_flicPlayer[0].getCurFrame() >= 115) { surface = _flicPlayer[1].decodeNextFrame(); if (_flicPlayer[1].endOfVideo()) - _flicPlayer[1].reset(); + _flicPlayer[1].rewind(); } bool framesLeft = decodeNextAnimationFrame(0, false); diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp index bdcdedc142..564d73a9d7 100644 --- a/video/flic_decoder.cpp +++ b/video/flic_decoder.cpp @@ -26,13 +26,11 @@ #include "common/stream.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/surface.h" namespace Video { FlicDecoder::FlicDecoder() { - _paletteChanged = false; - _fileStream = 0; - _surface = 0; } FlicDecoder::~FlicDecoder() { @@ -42,35 +40,59 @@ FlicDecoder::~FlicDecoder() { bool FlicDecoder::loadStream(Common::SeekableReadStream *stream) { close(); - _fileStream = stream; - - /* uint32 frameSize = */ _fileStream->readUint32LE(); - uint16 frameType = _fileStream->readUint16LE(); + /* uint32 frameSize = */ stream->readUint32LE(); + uint16 frameType = stream->readUint16LE(); // Check FLC magic number if (frameType != 0xAF12) { - warning("FlicDecoder::FlicDecoder(): attempted to load non-FLC data (type = 0x%04X)", frameType); - delete _fileStream; - _fileStream = 0; + warning("FlicDecoder::loadStream(): attempted to load non-FLC data (type = 0x%04X)", frameType); return false; } - - _frameCount = _fileStream->readUint16LE(); - uint16 width = _fileStream->readUint16LE(); - uint16 height = _fileStream->readUint16LE(); - uint16 colorDepth = _fileStream->readUint16LE(); + uint16 frameCount = stream->readUint16LE(); + uint16 width = stream->readUint16LE(); + uint16 height = stream->readUint16LE(); + uint16 colorDepth = stream->readUint16LE(); if (colorDepth != 8) { - warning("FlicDecoder::FlicDecoder(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", frameType); - delete _fileStream; - _fileStream = 0; + warning("FlicDecoder::loadStream(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", colorDepth); return false; } + addTrack(new FlicVideoTrack(stream, frameCount, width, height)); + return true; +} + +const Common::List *FlicDecoder::getDirtyRects() const { + const Track *track = getTrack(0); + + if (track) + return ((const FlicVideoTrack *)track)->getDirtyRects(); + + return 0; +} + +void FlicDecoder::clearDirtyRects() { + Track *track = getTrack(0); + + if (track) + ((FlicVideoTrack *)track)->clearDirtyRects(); +} + +void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + Track *track = getTrack(0); + + if (track) + ((FlicVideoTrack *)track)->copyDirtyRectsToBuffer(dst, pitch); +} + +FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height) { + _fileStream = stream; + _frameCount = frameCount; + _fileStream->readUint16LE(); // flags // Note: The normal delay is a 32-bit integer (dword), whereas the overridden delay is a 16-bit integer (word) // the frame delay is the FLIC "speed", in milliseconds. - _frameRate = Common::Rational(1000, _fileStream->readUint32LE()); + _frameDelay = _startFrameDelay = _fileStream->readUint32LE(); _fileStream->seek(80); _offsetFrame1 = _fileStream->readUint32LE(); @@ -78,112 +100,53 @@ bool FlicDecoder::loadStream(Common::SeekableReadStream *stream) { _surface = new Graphics::Surface(); _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - _palette = (byte *)malloc(3 * 256); + _palette = new byte[3 * 256]; memset(_palette, 0, 3 * 256); - _paletteChanged = false; + _dirtyPalette = false; + + _curFrame = -1; + _nextFrameStartTime = 0; + _atRingFrame = false; // Seek to the first frame _fileStream->seek(_offsetFrame1); - return true; } -void FlicDecoder::close() { - if (!_fileStream) - return; - +FlicDecoder::FlicVideoTrack::~FlicVideoTrack() { delete _fileStream; - _fileStream = 0; + delete[] _palette; _surface->free(); delete _surface; - _surface = 0; - - free(_palette); - _dirtyRects.clear(); - - reset(); } -void FlicDecoder::decodeByteRun(uint8 *data) { - byte *ptr = (byte *)_surface->pixels; - while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) { - int chunks = *data++; - while (chunks--) { - int count = (int8)*data++; - if (count > 0) { - memset(ptr, *data++, count); - } else { - count = -count; - memcpy(ptr, data, count); - data += count; - } - ptr += count; - } - } - - // Redraw - _dirtyRects.clear(); - _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); +bool FlicDecoder::FlicVideoTrack::endOfTrack() const { + return getCurFrame() >= getFrameCount() - 1; } -#define OP_PACKETCOUNT 0 -#define OP_UNDEFINED 1 -#define OP_LASTPIXEL 2 -#define OP_LINESKIPCOUNT 3 +bool FlicDecoder::FlicVideoTrack::rewind() { + _curFrame = -1; + _nextFrameStartTime = 0; -void FlicDecoder::decodeDeltaFLC(uint8 *data) { - uint16 linesInChunk = READ_LE_UINT16(data); data += 2; - uint16 currentLine = 0; - uint16 packetCount = 0; - - while (linesInChunk--) { - uint16 opcode; - - // First process all the opcodes. - do { - opcode = READ_LE_UINT16(data); data += 2; + if (endOfTrack() && _fileStream->pos() < _fileStream->size()) + _atRingFrame = true; + else + _fileStream->seek(_offsetFrame1); - switch ((opcode >> 14) & 3) { - case OP_PACKETCOUNT: - packetCount = opcode; - break; - case OP_UNDEFINED: - break; - case OP_LASTPIXEL: - *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF); - _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1)); - break; - case OP_LINESKIPCOUNT: - currentLine += -(int16)opcode; - break; - } - } while (((opcode >> 14) & 3) != OP_PACKETCOUNT); + _frameDelay = _startFrameDelay; + return true; +} - uint16 column = 0; +uint16 FlicDecoder::FlicVideoTrack::getWidth() const { + return _surface->w; +} - // Now interpret the RLE data - while (packetCount--) { - column += *data++; - int rleCount = (int8)*data++; - if (rleCount > 0) { - memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + column, data, rleCount * 2); - data += rleCount * 2; - _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); - } else if (rleCount < 0) { - rleCount = -rleCount; - uint16 dataWord = READ_UINT16(data); data += 2; - for (int i = 0; i < rleCount; ++i) { - WRITE_UINT16((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord); - } - _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); - } else { // End of cutscene ? - return; - } - column += rleCount * 2; - } +uint16 FlicDecoder::FlicVideoTrack::getHeight() const { + return _surface->h; +} - currentLine++; - } +Graphics::PixelFormat FlicDecoder::FlicVideoTrack::getPixelFormat() const { + return _surface->format; } #define FLI_SETPAL 4 @@ -192,7 +155,7 @@ void FlicDecoder::decodeDeltaFLC(uint8 *data) { #define PSTAMP 18 #define FRAME_TYPE 0xF1FA -const Graphics::Surface *FlicDecoder::decodeNextFrame() { +const Graphics::Surface *FlicDecoder::FlicVideoTrack::decodeNextFrame() { // Read chunk uint32 frameSize = _fileStream->readUint32LE(); uint16 frameType = _fileStream->readUint16LE(); @@ -209,7 +172,7 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { // the frame delay is the FLIC "speed", in milliseconds. uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds if (newFrameDelay > 0) - _frameRate = Common::Rational(1000, newFrameDelay); + _frameDelay = newFrameDelay; _fileStream->readUint16LE(); // reserved, always 0 uint16 newWidth = _fileStream->readUint16LE(); @@ -240,10 +203,11 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { frameType = _fileStream->readUint16LE(); uint8 *data = new uint8[frameSize - 6]; _fileStream->read(data, frameSize - 6); + switch (frameType) { case FLI_SETPAL: unpackPalette(data); - _paletteChanged = true; + _dirtyPalette = true; break; case FLI_SS2: decodeDeltaFLC(data); @@ -264,26 +228,111 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { } _curFrame++; + _nextFrameStartTime += _frameDelay; - // If we just processed the ring frame, set the next frame - if (_curFrame == (int32)_frameCount) { - _curFrame = 0; + if (_atRingFrame) { + // If we decoded the ring frame, seek to the second frame + _atRingFrame = false; _fileStream->seek(_offsetFrame2); } - if (_curFrame == 0) - _startTime = g_system->getMillis(); - return _surface; } -void FlicDecoder::reset() { - FixedRateVideoDecoder::reset(); - if (_fileStream) - _fileStream->seek(_offsetFrame1); +void FlicDecoder::FlicVideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + for (Common::List::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { + for (int y = (*it).top; y < (*it).bottom; ++y) { + const int x = (*it).left; + memcpy(dst + y * pitch + x, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x); + } + } + + clearDirtyRects(); } -void FlicDecoder::unpackPalette(uint8 *data) { +void FlicDecoder::FlicVideoTrack::decodeByteRun(uint8 *data) { + byte *ptr = (byte *)_surface->pixels; + while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) { + int chunks = *data++; + while (chunks--) { + int count = (int8)*data++; + if (count > 0) { + memset(ptr, *data++, count); + } else { + count = -count; + memcpy(ptr, data, count); + data += count; + } + ptr += count; + } + } + + // Redraw + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); +} + +#define OP_PACKETCOUNT 0 +#define OP_UNDEFINED 1 +#define OP_LASTPIXEL 2 +#define OP_LINESKIPCOUNT 3 + +void FlicDecoder::FlicVideoTrack::decodeDeltaFLC(uint8 *data) { + uint16 linesInChunk = READ_LE_UINT16(data); data += 2; + uint16 currentLine = 0; + uint16 packetCount = 0; + + while (linesInChunk--) { + uint16 opcode; + + // First process all the opcodes. + do { + opcode = READ_LE_UINT16(data); data += 2; + + switch ((opcode >> 14) & 3) { + case OP_PACKETCOUNT: + packetCount = opcode; + break; + case OP_UNDEFINED: + break; + case OP_LASTPIXEL: + *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF); + _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1)); + break; + case OP_LINESKIPCOUNT: + currentLine += -(int16)opcode; + break; + } + } while (((opcode >> 14) & 3) != OP_PACKETCOUNT); + + uint16 column = 0; + + // Now interpret the RLE data + while (packetCount--) { + column += *data++; + int rleCount = (int8)*data++; + if (rleCount > 0) { + memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + column, data, rleCount * 2); + data += rleCount * 2; + _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); + } else if (rleCount < 0) { + rleCount = -rleCount; + uint16 dataWord = READ_UINT16(data); data += 2; + for (int i = 0; i < rleCount; ++i) { + WRITE_UINT16((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord); + } + _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); + } else { // End of cutscene ? + return; + } + column += rleCount * 2; + } + + currentLine++; + } +} + +void FlicDecoder::FlicVideoTrack::unpackPalette(uint8 *data) { uint16 numPackets = READ_LE_UINT16(data); data += 2; if (0 == READ_LE_UINT16(data)) { //special case @@ -308,14 +357,4 @@ void FlicDecoder::unpackPalette(uint8 *data) { } } -void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { - for (Common::List::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { - for (int y = (*it).top; y < (*it).bottom; ++y) { - const int x = (*it).left; - memcpy(dst + y * pitch + x, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x); - } - } - _dirtyRects.clear(); -} - } // End of namespace Video diff --git a/video/flic_decoder.h b/video/flic_decoder.h index 9badc3da2e..9b82161ca5 100644 --- a/video/flic_decoder.h +++ b/video/flic_decoder.h @@ -25,15 +25,17 @@ #include "video/video_decoder.h" #include "common/list.h" -#include "common/rational.h" #include "common/rect.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" namespace Common { class SeekableReadStream; } +namespace Graphics { +struct PixelFormat; +struct Surface; +} + namespace Video { /** @@ -42,58 +44,63 @@ namespace Video { * Video decoder used in engines: * - tucker */ -class FlicDecoder : public FixedRateVideoDecoder { +class FlicDecoder : public AdvancedVideoDecoder { public: FlicDecoder(); virtual ~FlicDecoder(); - /** - * Load a video file - * @param stream the stream to load - */ bool loadStream(Common::SeekableReadStream *stream); - void close(); - - /** - * Decode the next frame and return the frame's surface - * @note the return surface should *not* be freed - * @note this may return 0, in which case the last frame should be kept on screen - */ - const Graphics::Surface *decodeNextFrame(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _frameCount; } - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - - const Common::List *getDirtyRects() const { return &_dirtyRects; } - void clearDirtyRects() { _dirtyRects.clear(); } - void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); - - const byte *getPalette() { _paletteChanged = false; return _palette; } - bool hasDirtyPalette() const { return _paletteChanged; } - void reset(); -protected: - Common::Rational getFrameRate() const { return _frameRate; } + const Common::List *getDirtyRects() const; + void clearDirtyRects(); + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); private: - uint16 _offsetFrame1; - uint16 _offsetFrame2; - byte *_palette; - bool _paletteChanged; - - void decodeByteRun(uint8 *data); - void decodeDeltaFLC(uint8 *data); - void unpackPalette(uint8 *mem); - - Common::SeekableReadStream *_fileStream; - Graphics::Surface *_surface; - uint32 _frameCount; - Common::Rational _frameRate; - - Common::List _dirtyRects; + class FlicVideoTrack : public VideoTrack { + public: + FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height); + ~FlicVideoTrack(); + + bool endOfTrack() const; + bool isRewindable() const { return true; } + bool rewind(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + uint32 getNextFrameStartTime() const { return _nextFrameStartTime; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + const Common::List *getDirtyRects() const { return &_dirtyRects; } + void clearDirtyRects() { _dirtyRects.clear(); } + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); + + private: + Common::SeekableReadStream *_fileStream; + Graphics::Surface *_surface; + + int _curFrame; + bool _atRingFrame; + + uint16 _offsetFrame1; + uint16 _offsetFrame2; + byte *_palette; + mutable bool _dirtyPalette; + + uint32 _frameCount; + uint32 _frameDelay, _startFrameDelay; + uint32 _nextFrameStartTime; + + Common::List _dirtyRects; + + void decodeByteRun(uint8 *data); + void decodeDeltaFLC(uint8 *data); + void unpackPalette(uint8 *mem); + }; }; } // End of namespace Video -- cgit v1.2.3 From 7831225b280d08779bc0d40e76bbbef1e183471a Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 12 Aug 2012 08:58:00 -0400 Subject: VIDEO: Move TheoraDecoder to video/ --- engines/sword25/fmv/movieplayer.h | 4 +- engines/sword25/fmv/theora_decoder.cpp | 565 --------------------------------- engines/sword25/fmv/theora_decoder.h | 144 --------- engines/sword25/module.mk | 5 - video/module.mk | 5 + video/theora_decoder.cpp | 563 ++++++++++++++++++++++++++++++++ video/theora_decoder.h | 144 +++++++++ 7 files changed, 714 insertions(+), 716 deletions(-) delete mode 100644 engines/sword25/fmv/theora_decoder.cpp delete mode 100644 engines/sword25/fmv/theora_decoder.h create mode 100644 video/theora_decoder.cpp create mode 100644 video/theora_decoder.h diff --git a/engines/sword25/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h index 1d256e56ba..2f5614b505 100644 --- a/engines/sword25/fmv/movieplayer.h +++ b/engines/sword25/fmv/movieplayer.h @@ -39,7 +39,7 @@ #include "sword25/gfx/bitmap.h" #ifdef USE_THEORADEC -#include "sword25/fmv/theora_decoder.h" +#include "video/theora_decoder.h" #endif #define THEORA_INDIRECT_RENDERING @@ -141,7 +141,7 @@ private: #ifdef USE_THEORADEC - TheoraDecoder _decoder; + Video::TheoraDecoder _decoder; Graphics::Surface *_backSurface; int _outX, _outY; diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp deleted file mode 100644 index d38f5a26cf..0000000000 --- a/engines/sword25/fmv/theora_decoder.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -/* - * Source is based on the player example from libvorbis package, - * available at: http://svn.xiph.org/trunk/theora/examples/player_example.c - * - * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. - * - * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 - * by the Xiph.Org Foundation and contributors http://www.xiph.org/ - * - */ - -#include "sword25/fmv/theora_decoder.h" - -#ifdef USE_THEORADEC -#include "common/system.h" -#include "common/textconsole.h" -#include "common/util.h" -#include "graphics/yuv_to_rgb.h" -#include "audio/decoders/raw.h" -#include "sword25/kernel/common.h" - -namespace Sword25 { - -#define AUDIOFD_FRAGSIZE 10240 - -static double rint(double v) { - return floor(v + 0.5); -} - -TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) { - _fileStream = 0; - - _theoraPacket = 0; - _vorbisPacket = 0; - _theoraDecode = 0; - _theoraSetup = 0; - _nextFrameStartTime = 0.0; - - _soundType = soundType; - _audStream = 0; - _audHandle = new Audio::SoundHandle(); - - ogg_sync_init(&_oggSync); - - _curFrame = -1; - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - - reset(); -} - -TheoraDecoder::~TheoraDecoder() { - close(); - delete _fileStream; - delete _audHandle; - free(_audiobuf); -} - -void TheoraDecoder::queuePage(ogg_page *page) { - if (_theoraPacket) - ogg_stream_pagein(&_theoraOut, page); - - if (_vorbisPacket) - ogg_stream_pagein(&_vorbisOut, page); -} - -int TheoraDecoder::bufferData() { - char *buffer = ogg_sync_buffer(&_oggSync, 4096); - int bytes = _fileStream->read(buffer, 4096); - - ogg_sync_wrote(&_oggSync, bytes); - - return bytes; -} - -bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { - close(); - - _endOfAudio = false; - _endOfVideo = false; - _fileStream = stream; - - // start up Ogg stream synchronization layer - ogg_sync_init(&_oggSync); - - // init supporting Vorbis structures needed in header parsing - vorbis_info_init(&_vorbisInfo); - vorbis_comment_init(&_vorbisComment); - - // init supporting Theora structures needed in header parsing - th_comment_init(&_theoraComment); - th_info_init(&_theoraInfo); - - // Ogg file open; parse the headers - // Only interested in Vorbis/Theora streams - bool foundHeader = false; - while (!foundHeader) { - int ret = bufferData(); - - if (ret == 0) - break; - - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { - ogg_stream_state test; - - // is this a mandated initial header? If not, stop parsing - if (!ogg_page_bos(&_oggPage)) { - // don't leak the page; get it into the appropriate stream - queuePage(&_oggPage); - foundHeader = true; - break; - } - - ogg_stream_init(&test, ogg_page_serialno(&_oggPage)); - ogg_stream_pagein(&test, &_oggPage); - ogg_stream_packetout(&test, &_oggPacket); - - // identify the codec: try theora - if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) { - // it is theora - memcpy(&_theoraOut, &test, sizeof(test)); - _theoraPacket = 1; - } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) { - // it is vorbis - memcpy(&_vorbisOut, &test, sizeof(test)); - _vorbisPacket = 1; - } else { - // whatever it is, we don't care about it - ogg_stream_clear(&test); - } - } - // fall through to non-bos page parsing - } - - // we're expecting more header packets. - while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) { - int ret; - - // look for further theora headers - while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { - if (ret < 0) - error("Error parsing Theora stream headers; corrupt stream?"); - - if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket)) - error("Error parsing Theora stream headers; corrupt stream?"); - - _theoraPacket++; - } - - // look for more vorbis header packets - while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { - if (ret < 0) - error("Error parsing Vorbis stream headers; corrupt stream?"); - - if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket)) - error("Error parsing Vorbis stream headers; corrupt stream?"); - - _vorbisPacket++; - - if (_vorbisPacket == 3) - break; - } - - // The header pages/packets will arrive before anything else we - // care about, or the stream is not obeying spec - - if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { - queuePage(&_oggPage); // demux into the appropriate stream - } else { - ret = bufferData(); // someone needs more data - - if (ret == 0) - error("End of file while searching for codec headers."); - } - } - - // and now we have it all. initialize decoders - if (_theoraPacket) { - _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup); - debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps", - _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height, - (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator); - - switch (_theoraInfo.pixel_fmt) { - case TH_PF_420: - debug(1, " 4:2:0 video"); - break; - case TH_PF_422: - debug(1, " 4:2:2 video"); - break; - case TH_PF_444: - debug(1, " 4:4:4 video"); - break; - case TH_PF_RSVD: - default: - debug(1, " video\n (UNKNOWN Chroma sampling!)"); - break; - } - - if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height) - debug(1, " Frame content is %dx%d with offset (%d,%d).", - _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y); - - switch (_theoraInfo.colorspace){ - case TH_CS_UNSPECIFIED: - /* nothing to report */ - break; - case TH_CS_ITU_REC_470M: - debug(1, " encoder specified ITU Rec 470M (NTSC) color."); - break; - case TH_CS_ITU_REC_470BG: - debug(1, " encoder specified ITU Rec 470BG (PAL) color."); - break; - default: - debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace); - break; - } - - debug(1, "Encoded by %s", _theoraComment.vendor); - if (_theoraComment.comments) { - debug(1, "theora comment header:"); - for (int i = 0; i < _theoraComment.comments; i++) { - if (_theoraComment.user_comments[i]) { - int len = _theoraComment.comment_lengths[i]; - char *value = (char *)malloc(len + 1); - if (value) { - memcpy(value, _theoraComment.user_comments[i], len); - value[len] = '\0'; - debug(1, "\t%s", value); - free(value); - } - } - } - } - - th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax)); - _ppLevel = _ppLevelMax; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; - } else { - // tear down the partial theora setup - th_info_clear(&_theoraInfo); - th_comment_clear(&_theoraComment); - } - - th_setup_free(_theoraSetup); - _theoraSetup = 0; - - if (_vorbisPacket) { - vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo); - vorbis_block_init(&_vorbisDSP, &_vorbisBlock); - debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.", - _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate); - - _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); - - // Get enough audio data to start us off - while (_audStream->numQueuedStreams() == 0) { - // Queue more data - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - - queueAudio(); - } - - if (_audStream) - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance()); - } else { - // tear down the partial vorbis setup - vorbis_info_clear(&_vorbisInfo); - vorbis_comment_clear(&_vorbisComment); - _endOfAudio = true; - } - - _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat()); - - // Set up a display surface - _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y); - _displaySurface.w = _theoraInfo.pic_width; - _displaySurface.h = _theoraInfo.pic_height; - _displaySurface.format = _surface.format; - _displaySurface.pitch = _surface.pitch; - - // Set the frame rate - _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator); - - return true; -} - -void TheoraDecoder::close() { - if (_vorbisPacket) { - ogg_stream_clear(&_vorbisOut); - vorbis_block_clear(&_vorbisBlock); - vorbis_dsp_clear(&_vorbisDSP); - vorbis_comment_clear(&_vorbisComment); - vorbis_info_clear(&_vorbisInfo); - - g_system->getMixer()->stopHandle(*_audHandle); - - _audStream = 0; - _vorbisPacket = false; - } - if (_theoraPacket) { - ogg_stream_clear(&_theoraOut); - th_decode_free(_theoraDecode); - th_comment_clear(&_theoraComment); - th_info_clear(&_theoraInfo); - _theoraDecode = 0; - _theoraPacket = false; - } - - if (!_fileStream) - return; - - ogg_sync_clear(&_oggSync); - - delete _fileStream; - _fileStream = 0; - - _surface.free(); - _displaySurface.pixels = 0; - _displaySurface.free(); - - reset(); -} - -const Graphics::Surface *TheoraDecoder::decodeNextFrame() { - // First, let's get our frame - while (_theoraPacket) { - // theora is one in, one out... - if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { - - if (_ppInc) { - _ppLevel += _ppInc; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; - } - - if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) { - _curFrame++; - - // Convert YUV data to RGB data - th_ycbcr_buffer yuv; - th_decode_ycbcr_out(_theoraDecode, yuv); - translateYUVtoRGBA(yuv); - - if (_curFrame == 0) - _startTime = g_system->getMillis(); - - double time = th_granule_time(_theoraDecode, _oggPacket.granulepos); - - // We need to calculate when the next frame should be shown - // This is all in floating point because that's what the Ogg code gives us - // Ogg is a lossy container format, so it doesn't always list the time to the - // next frame. In such cases, we need to calculate it ourselves. - if (time == -1.0) - _nextFrameStartTime += _frameRate.getInverse().toDouble(); - else - _nextFrameStartTime = time; - - // break out - break; - } - } else { - // If we can't get any more frames, we're done. - if (_theoraOut.e_o_s || _fileStream->eos()) { - _endOfVideo = true; - break; - } - - // Queue more data - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - } - - // Update audio if we can - queueAudio(); - } - - // Force at least some audio to be buffered - // TODO: 5 is very arbitrary. We probably should do something like QuickTime does. - while (!_endOfAudio && _audStream->numQueuedStreams() < 5) { - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - - bool queuedAudio = queueAudio(); - if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) { - _endOfAudio = true; - break; - } - } - - return &_displaySurface; -} - -bool TheoraDecoder::queueAudio() { - if (!_audStream) - return false; - - // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer) - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Invalid audio buffer"); - return false; - } - - bool queuedAudio = false; - - for (;;) { - float **pcm; - - // if there's pending, decoded audio, grab it - int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm); - if (ret > 0) { - int count = _audiobufFill / 2; - int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1; - int i; - for (i = 0; i < ret && i < maxsamples; i++) - for (int j = 0; j < _vorbisInfo.channels; j++) { - int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767); - _audiobuf[count++] = val; - } - - vorbis_synthesis_read(&_vorbisDSP, i); - _audiobufFill += (i * _vorbisInfo.channels) << 1; - - if (_audiobufFill == AUDIOFD_FRAGSIZE) { - byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO; -#ifdef SCUMM_LITTLE_ENDIAN - flags |= Audio::FLAG_LITTLE_ENDIAN; -#endif - _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, flags); - - // The audio mixer is now responsible for the old audio buffer. - // We need to create a new one. - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer"); - return false; - } - - _audiobufFill = 0; - queuedAudio = true; - } - } else { - // no pending audio; is there a pending packet to decode? - if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) { - if (vorbis_synthesis(&_vorbisBlock, &_oggPacket) == 0) // test for success! - vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock); - } else // we've buffered all we have, break out for now - return queuedAudio; - } - } - - // Unreachable - return false; -} - -void TheoraDecoder::reset() { - VideoDecoder::reset(); - - // FIXME: This does a rewind() instead of a reset()! - - if (_fileStream) - _fileStream->seek(0); - - _audiobufFill = 0; - _audiobufReady = false; - - _curFrame = -1; - - _theoraPacket = 0; - _vorbisPacket = 0; -} - -bool TheoraDecoder::endOfVideo() const { - return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio))); -} - -uint32 TheoraDecoder::getTimeToNextFrame() const { - if (endOfVideo() || _curFrame < 0) - return 0; - - uint32 elapsedTime = getTime(); - uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000); - - if (nextFrameStartTime <= elapsedTime) - return 0; - - return nextFrameStartTime - elapsedTime; -} - -uint32 TheoraDecoder::getTime() const { - if (_audStream) - return g_system->getMixer()->getSoundElapsedTime(*_audHandle); - - return VideoDecoder::getTime(); -} - -void TheoraDecoder::pauseVideoIntern(bool pause) { - if (_audStream) - g_system->getMixer()->pauseHandle(*_audHandle, pause); -} - -enum TheoraYUVBuffers { - kBufferY = 0, - kBufferU = 1, - kBufferV = 2 -}; - -void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { - // Width and height of all buffers have to be divisible by 2. - assert((YUVBuffer[kBufferY].width & 1) == 0); - assert((YUVBuffer[kBufferY].height & 1) == 0); - assert((YUVBuffer[kBufferU].width & 1) == 0); - assert((YUVBuffer[kBufferV].width & 1) == 0); - - // UV images have to have a quarter of the Y image resolution - assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); - assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); - - Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); -} - -void TheoraDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelVolume(*_audHandle, getVolume()); -} - -void TheoraDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelBalance(*_audHandle, getBalance()); -} - -} // End of namespace Sword25 - -#endif diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h deleted file mode 100644 index 739040024f..0000000000 --- a/engines/sword25/fmv/theora_decoder.h +++ /dev/null @@ -1,144 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef SWORD25_THEORADECODER_H -#define SWORD25_THEORADECODER_H - -#include "common/scummsys.h" // for USE_THEORADEC - -#ifdef USE_THEORADEC - -#include "common/rational.h" -#include "video/video_decoder.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" - -#include -#include - -namespace Common { -class SeekableReadStream; -} - -namespace Sword25 { - -/** - * - * Decoder for Theora videos. - * Video decoder used in engines: - * - sword25 - */ -class TheoraDecoder : public Video::VideoDecoder { -public: - TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); - virtual ~TheoraDecoder(); - - /** - * Load a video file - * @param stream the stream to load - */ - bool loadStream(Common::SeekableReadStream *stream); - void close(); - void reset(); - - /** - * Decode the next frame and return the frame's surface - * @note the return surface should *not* be freed - * @note this may return 0, in which case the last frame should be kept on screen - */ - const Graphics::Surface *decodeNextFrame(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _displaySurface.w; } - uint16 getHeight() const { return _displaySurface.h; } - - uint32 getFrameCount() const { - // It is not possible to get frame count easily - // I.e. seeking is required - assert(0); - return 0; - } - - Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } - uint32 getTime() const; - uint32 getTimeToNextFrame() const; - - bool endOfVideo() const; - -protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - void pauseVideoIntern(bool pause); - -private: - void queuePage(ogg_page *page); - bool queueAudio(); - int bufferData(); - void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); - - Common::SeekableReadStream *_fileStream; - Graphics::Surface _surface; - Graphics::Surface _displaySurface; - Common::Rational _frameRate; - double _nextFrameStartTime; - bool _endOfVideo; - bool _endOfAudio; - - Audio::Mixer::SoundType _soundType; - Audio::SoundHandle *_audHandle; - Audio::QueuingAudioStream *_audStream; - - ogg_sync_state _oggSync; - ogg_page _oggPage; - ogg_packet _oggPacket; - ogg_stream_state _vorbisOut; - ogg_stream_state _theoraOut; - th_info _theoraInfo; - th_comment _theoraComment; - th_dec_ctx *_theoraDecode; - th_setup_info *_theoraSetup; - vorbis_info _vorbisInfo; - vorbis_dsp_state _vorbisDSP; - vorbis_block _vorbisBlock; - vorbis_comment _vorbisComment; - - int _theoraPacket; - int _vorbisPacket; - - int _ppLevelMax; - int _ppLevel; - int _ppInc; - - // single audio fragment audio buffering - int _audiobufFill; - bool _audiobufReady; - ogg_int16_t *_audiobuf; -}; - -} // End of namespace Sword25 - -#endif - -#endif diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk index 302120c500..e24a221244 100644 --- a/engines/sword25/module.mk +++ b/engines/sword25/module.mk @@ -85,11 +85,6 @@ MODULE_OBJS := \ util/pluto/pluto.o \ util/pluto/plzio.o -ifdef USE_THEORADEC -MODULE_OBJS += \ - fmv/theora_decoder.o -endif - # This module can be built as a plugin ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN) PLUGIN := 1 diff --git a/video/module.mk b/video/module.mk index cebd403ca2..287e14ce18 100644 --- a/video/module.mk +++ b/video/module.mk @@ -26,5 +26,10 @@ MODULE_OBJS += \ bink_decoder.o endif +ifdef USE_THEORADEC +MODULE_OBJS += \ + theora_decoder.o +endif + # Include common rules include $(srcdir)/rules.mk diff --git a/video/theora_decoder.cpp b/video/theora_decoder.cpp new file mode 100644 index 0000000000..f3d9cad096 --- /dev/null +++ b/video/theora_decoder.cpp @@ -0,0 +1,563 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * Source is based on the player example from libvorbis package, + * available at: http://svn.xiph.org/trunk/theora/examples/player_example.c + * + * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. + * + * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ + * + */ + +#include "video/theora_decoder.h" + +#include "common/debug.h" +#include "common/stream.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "common/util.h" +#include "graphics/yuv_to_rgb.h" +#include "audio/decoders/raw.h" + +namespace Video { + +#define AUDIOFD_FRAGSIZE 10240 + +static double rint(double v) { + return floor(v + 0.5); +} + +TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) { + _fileStream = 0; + + _theoraPacket = 0; + _vorbisPacket = 0; + _theoraDecode = 0; + _theoraSetup = 0; + _nextFrameStartTime = 0.0; + + _soundType = soundType; + _audStream = 0; + _audHandle = new Audio::SoundHandle(); + + ogg_sync_init(&_oggSync); + + _curFrame = -1; + _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); + + reset(); +} + +TheoraDecoder::~TheoraDecoder() { + close(); + delete _fileStream; + delete _audHandle; + free(_audiobuf); +} + +void TheoraDecoder::queuePage(ogg_page *page) { + if (_theoraPacket) + ogg_stream_pagein(&_theoraOut, page); + + if (_vorbisPacket) + ogg_stream_pagein(&_vorbisOut, page); +} + +int TheoraDecoder::bufferData() { + char *buffer = ogg_sync_buffer(&_oggSync, 4096); + int bytes = _fileStream->read(buffer, 4096); + + ogg_sync_wrote(&_oggSync, bytes); + + return bytes; +} + +bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + _endOfAudio = false; + _endOfVideo = false; + _fileStream = stream; + + // start up Ogg stream synchronization layer + ogg_sync_init(&_oggSync); + + // init supporting Vorbis structures needed in header parsing + vorbis_info_init(&_vorbisInfo); + vorbis_comment_init(&_vorbisComment); + + // init supporting Theora structures needed in header parsing + th_comment_init(&_theoraComment); + th_info_init(&_theoraInfo); + + // Ogg file open; parse the headers + // Only interested in Vorbis/Theora streams + bool foundHeader = false; + while (!foundHeader) { + int ret = bufferData(); + + if (ret == 0) + break; + + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { + ogg_stream_state test; + + // is this a mandated initial header? If not, stop parsing + if (!ogg_page_bos(&_oggPage)) { + // don't leak the page; get it into the appropriate stream + queuePage(&_oggPage); + foundHeader = true; + break; + } + + ogg_stream_init(&test, ogg_page_serialno(&_oggPage)); + ogg_stream_pagein(&test, &_oggPage); + ogg_stream_packetout(&test, &_oggPacket); + + // identify the codec: try theora + if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) { + // it is theora + memcpy(&_theoraOut, &test, sizeof(test)); + _theoraPacket = 1; + } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) { + // it is vorbis + memcpy(&_vorbisOut, &test, sizeof(test)); + _vorbisPacket = 1; + } else { + // whatever it is, we don't care about it + ogg_stream_clear(&test); + } + } + // fall through to non-bos page parsing + } + + // we're expecting more header packets. + while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) { + int ret; + + // look for further theora headers + while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { + if (ret < 0) + error("Error parsing Theora stream headers; corrupt stream?"); + + if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket)) + error("Error parsing Theora stream headers; corrupt stream?"); + + _theoraPacket++; + } + + // look for more vorbis header packets + while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { + if (ret < 0) + error("Error parsing Vorbis stream headers; corrupt stream?"); + + if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket)) + error("Error parsing Vorbis stream headers; corrupt stream?"); + + _vorbisPacket++; + + if (_vorbisPacket == 3) + break; + } + + // The header pages/packets will arrive before anything else we + // care about, or the stream is not obeying spec + + if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { + queuePage(&_oggPage); // demux into the appropriate stream + } else { + ret = bufferData(); // someone needs more data + + if (ret == 0) + error("End of file while searching for codec headers."); + } + } + + // and now we have it all. initialize decoders + if (_theoraPacket) { + _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup); + debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps", + _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height, + (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator); + + switch (_theoraInfo.pixel_fmt) { + case TH_PF_420: + debug(1, " 4:2:0 video"); + break; + case TH_PF_422: + debug(1, " 4:2:2 video"); + break; + case TH_PF_444: + debug(1, " 4:4:4 video"); + break; + case TH_PF_RSVD: + default: + debug(1, " video\n (UNKNOWN Chroma sampling!)"); + break; + } + + if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height) + debug(1, " Frame content is %dx%d with offset (%d,%d).", + _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y); + + switch (_theoraInfo.colorspace){ + case TH_CS_UNSPECIFIED: + /* nothing to report */ + break; + case TH_CS_ITU_REC_470M: + debug(1, " encoder specified ITU Rec 470M (NTSC) color."); + break; + case TH_CS_ITU_REC_470BG: + debug(1, " encoder specified ITU Rec 470BG (PAL) color."); + break; + default: + debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace); + break; + } + + debug(1, "Encoded by %s", _theoraComment.vendor); + if (_theoraComment.comments) { + debug(1, "theora comment header:"); + for (int i = 0; i < _theoraComment.comments; i++) { + if (_theoraComment.user_comments[i]) { + int len = _theoraComment.comment_lengths[i]; + char *value = (char *)malloc(len + 1); + if (value) { + memcpy(value, _theoraComment.user_comments[i], len); + value[len] = '\0'; + debug(1, "\t%s", value); + free(value); + } + } + } + } + + th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax)); + _ppLevel = _ppLevelMax; + th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); + _ppInc = 0; + } else { + // tear down the partial theora setup + th_info_clear(&_theoraInfo); + th_comment_clear(&_theoraComment); + } + + th_setup_free(_theoraSetup); + _theoraSetup = 0; + + if (_vorbisPacket) { + vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo); + vorbis_block_init(&_vorbisDSP, &_vorbisBlock); + debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.", + _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate); + + _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); + + // Get enough audio data to start us off + while (_audStream->numQueuedStreams() == 0) { + // Queue more data + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); + + queueAudio(); + } + + if (_audStream) + g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance()); + } else { + // tear down the partial vorbis setup + vorbis_info_clear(&_vorbisInfo); + vorbis_comment_clear(&_vorbisComment); + _endOfAudio = true; + } + + _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat()); + + // Set up a display surface + _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y); + _displaySurface.w = _theoraInfo.pic_width; + _displaySurface.h = _theoraInfo.pic_height; + _displaySurface.format = _surface.format; + _displaySurface.pitch = _surface.pitch; + + // Set the frame rate + _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator); + + return true; +} + +void TheoraDecoder::close() { + if (_vorbisPacket) { + ogg_stream_clear(&_vorbisOut); + vorbis_block_clear(&_vorbisBlock); + vorbis_dsp_clear(&_vorbisDSP); + vorbis_comment_clear(&_vorbisComment); + vorbis_info_clear(&_vorbisInfo); + + g_system->getMixer()->stopHandle(*_audHandle); + + _audStream = 0; + _vorbisPacket = false; + } + if (_theoraPacket) { + ogg_stream_clear(&_theoraOut); + th_decode_free(_theoraDecode); + th_comment_clear(&_theoraComment); + th_info_clear(&_theoraInfo); + _theoraDecode = 0; + _theoraPacket = false; + } + + if (!_fileStream) + return; + + ogg_sync_clear(&_oggSync); + + delete _fileStream; + _fileStream = 0; + + _surface.free(); + _displaySurface.pixels = 0; + _displaySurface.free(); + + reset(); +} + +const Graphics::Surface *TheoraDecoder::decodeNextFrame() { + // First, let's get our frame + while (_theoraPacket) { + // theora is one in, one out... + if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { + + if (_ppInc) { + _ppLevel += _ppInc; + th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); + _ppInc = 0; + } + + if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) { + _curFrame++; + + // Convert YUV data to RGB data + th_ycbcr_buffer yuv; + th_decode_ycbcr_out(_theoraDecode, yuv); + translateYUVtoRGBA(yuv); + + if (_curFrame == 0) + _startTime = g_system->getMillis(); + + double time = th_granule_time(_theoraDecode, _oggPacket.granulepos); + + // We need to calculate when the next frame should be shown + // This is all in floating point because that's what the Ogg code gives us + // Ogg is a lossy container format, so it doesn't always list the time to the + // next frame. In such cases, we need to calculate it ourselves. + if (time == -1.0) + _nextFrameStartTime += _frameRate.getInverse().toDouble(); + else + _nextFrameStartTime = time; + + // break out + break; + } + } else { + // If we can't get any more frames, we're done. + if (_theoraOut.e_o_s || _fileStream->eos()) { + _endOfVideo = true; + break; + } + + // Queue more data + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); + } + + // Update audio if we can + queueAudio(); + } + + // Force at least some audio to be buffered + // TODO: 5 is very arbitrary. We probably should do something like QuickTime does. + while (!_endOfAudio && _audStream->numQueuedStreams() < 5) { + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); + + bool queuedAudio = queueAudio(); + if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) { + _endOfAudio = true; + break; + } + } + + return &_displaySurface; +} + +bool TheoraDecoder::queueAudio() { + if (!_audStream) + return false; + + // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer) + if (!_audiobuf) { + warning("[TheoraDecoder::queueAudio] Invalid audio buffer"); + return false; + } + + bool queuedAudio = false; + + for (;;) { + float **pcm; + + // if there's pending, decoded audio, grab it + int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm); + if (ret > 0) { + int count = _audiobufFill / 2; + int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1; + int i; + for (i = 0; i < ret && i < maxsamples; i++) + for (int j = 0; j < _vorbisInfo.channels; j++) { + int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767); + _audiobuf[count++] = val; + } + + vorbis_synthesis_read(&_vorbisDSP, i); + _audiobufFill += (i * _vorbisInfo.channels) << 1; + + if (_audiobufFill == AUDIOFD_FRAGSIZE) { + byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO; +#ifdef SCUMM_LITTLE_ENDIAN + flags |= Audio::FLAG_LITTLE_ENDIAN; +#endif + _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, flags); + + // The audio mixer is now responsible for the old audio buffer. + // We need to create a new one. + _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); + if (!_audiobuf) { + warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer"); + return false; + } + + _audiobufFill = 0; + queuedAudio = true; + } + } else { + // no pending audio; is there a pending packet to decode? + if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) { + if (vorbis_synthesis(&_vorbisBlock, &_oggPacket) == 0) // test for success! + vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock); + } else // we've buffered all we have, break out for now + return queuedAudio; + } + } + + // Unreachable + return false; +} + +void TheoraDecoder::reset() { + VideoDecoder::reset(); + + // FIXME: This does a rewind() instead of a reset()! + + if (_fileStream) + _fileStream->seek(0); + + _audiobufFill = 0; + _audiobufReady = false; + + _curFrame = -1; + + _theoraPacket = 0; + _vorbisPacket = 0; +} + +bool TheoraDecoder::endOfVideo() const { + return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio))); +} + +uint32 TheoraDecoder::getTimeToNextFrame() const { + if (endOfVideo() || _curFrame < 0) + return 0; + + uint32 elapsedTime = getTime(); + uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000); + + if (nextFrameStartTime <= elapsedTime) + return 0; + + return nextFrameStartTime - elapsedTime; +} + +uint32 TheoraDecoder::getTime() const { + if (_audStream) + return g_system->getMixer()->getSoundElapsedTime(*_audHandle); + + return VideoDecoder::getTime(); +} + +void TheoraDecoder::pauseVideoIntern(bool pause) { + if (_audStream) + g_system->getMixer()->pauseHandle(*_audHandle, pause); +} + +enum TheoraYUVBuffers { + kBufferY = 0, + kBufferU = 1, + kBufferV = 2 +}; + +void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { + // Width and height of all buffers have to be divisible by 2. + assert((YUVBuffer[kBufferY].width & 1) == 0); + assert((YUVBuffer[kBufferY].height & 1) == 0); + assert((YUVBuffer[kBufferU].width & 1) == 0); + assert((YUVBuffer[kBufferV].width & 1) == 0); + + // UV images have to have a quarter of the Y image resolution + assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1); + assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1); + assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); + assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); + + Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); +} + +void TheoraDecoder::updateVolume() { + if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) + g_system->getMixer()->setChannelVolume(*_audHandle, getVolume()); +} + +void TheoraDecoder::updateBalance() { + if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) + g_system->getMixer()->setChannelBalance(*_audHandle, getBalance()); +} + +} // End of namespace Video diff --git a/video/theora_decoder.h b/video/theora_decoder.h new file mode 100644 index 0000000000..459fc064d3 --- /dev/null +++ b/video/theora_decoder.h @@ -0,0 +1,144 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" // for USE_THEORADEC + +#ifdef USE_THEORADEC + +#ifndef VIDEO_THEORA_DECODER_H +#define VIDEO_THEORA_DECODER_H + +#include "common/rational.h" +#include "video/video_decoder.h" +#include "audio/audiostream.h" +#include "audio/mixer.h" +#include "graphics/pixelformat.h" +#include "graphics/surface.h" + +#include +#include + +namespace Common { +class SeekableReadStream; +} + +namespace Video { + +/** + * + * Decoder for Theora videos. + * Video decoder used in engines: + * - sword25 + */ +class TheoraDecoder : public VideoDecoder { +public: + TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); + virtual ~TheoraDecoder(); + + /** + * Load a video file + * @param stream the stream to load + */ + bool loadStream(Common::SeekableReadStream *stream); + void close(); + void reset(); + + /** + * Decode the next frame and return the frame's surface + * @note the return surface should *not* be freed + * @note this may return 0, in which case the last frame should be kept on screen + */ + const Graphics::Surface *decodeNextFrame(); + + bool isVideoLoaded() const { return _fileStream != 0; } + uint16 getWidth() const { return _displaySurface.w; } + uint16 getHeight() const { return _displaySurface.h; } + + uint32 getFrameCount() const { + // It is not possible to get frame count easily + // I.e. seeking is required + assert(0); + return 0; + } + + Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } + uint32 getTime() const; + uint32 getTimeToNextFrame() const; + + bool endOfVideo() const; + +protected: + // VideoDecoder API + void updateVolume(); + void updateBalance(); + void pauseVideoIntern(bool pause); + +private: + void queuePage(ogg_page *page); + bool queueAudio(); + int bufferData(); + void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); + + Common::SeekableReadStream *_fileStream; + Graphics::Surface _surface; + Graphics::Surface _displaySurface; + Common::Rational _frameRate; + double _nextFrameStartTime; + bool _endOfVideo; + bool _endOfAudio; + + Audio::Mixer::SoundType _soundType; + Audio::SoundHandle *_audHandle; + Audio::QueuingAudioStream *_audStream; + + ogg_sync_state _oggSync; + ogg_page _oggPage; + ogg_packet _oggPacket; + ogg_stream_state _vorbisOut; + ogg_stream_state _theoraOut; + th_info _theoraInfo; + th_comment _theoraComment; + th_dec_ctx *_theoraDecode; + th_setup_info *_theoraSetup; + vorbis_info _vorbisInfo; + vorbis_dsp_state _vorbisDSP; + vorbis_block _vorbisBlock; + vorbis_comment _vorbisComment; + + int _theoraPacket; + int _vorbisPacket; + + int _ppLevelMax; + int _ppLevel; + int _ppInc; + + // single audio fragment audio buffering + int _audiobufFill; + bool _audiobufReady; + ogg_int16_t *_audiobuf; +}; + +} // End of namespace Video + +#endif + +#endif -- cgit v1.2.3 From 8982026661c5f64f67cb8565946d25f620dfb73c Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan SømaÌŠen Date: Mon, 13 Aug 2012 00:30:02 +0200 Subject: GRAPHICS: Add support for 32bpp BMPs --- graphics/decoders/bmp.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index 5f764e1bd3..f15d4e2519 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -82,7 +82,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { /* uint16 planes = */ stream.readUint16LE(); uint16 bitsPerPixel = stream.readUint16LE(); - if (bitsPerPixel != 8 && bitsPerPixel != 24) { + if (bitsPerPixel != 8 && bitsPerPixel != 24 && bitsPerPixel != 32) { warning("%dbpp bitmaps not supported", bitsPerPixel); return false; } @@ -119,8 +119,8 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); - // BGRA for 24bpp - if (bitsPerPixel == 24) + // BGRA for 24bpp and 32 bpp + if (bitsPerPixel == 24 || bitsPerPixel == 32) format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); _surface = new Graphics::Surface(); @@ -136,7 +136,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { stream.read(dst + (height - i - 1) * width, width); stream.skip(extraDataLength); } - } else { + } else if (bitsPerPixel == 24) { byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; for (int32 i = 0; i < height; i++) { @@ -150,6 +150,27 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { dst += format.bytesPerPixel; } + stream.skip(extraDataLength); + dst -= _surface->pitch * 2; + } + } else { // 32 bpp + byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; + + for (int32 i = 0; i < height; i++) { + for (uint32 j = 0; j < width; j++) { + byte b = stream.readByte(); + byte g = stream.readByte(); + byte r = stream.readByte(); + // Ignore the last byte, as in v3 it is unused + // and should thus NOT be used as alpha. + // ref: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx + stream.readByte(); + uint32 color = format.RGBToColor(r, g, b); + + *((uint32 *)dst) = color; + dst += format.bytesPerPixel; + } + stream.skip(extraDataLength); dst -= _surface->pitch * 2; } -- cgit v1.2.3 From 92432a136bff7c327b5328cc10a84198f571b0d0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 13 Aug 2012 16:23:47 -0400 Subject: VIDEO: Convert TheoraDecoder to the new AdvancedVideoDecoder API --- engines/sword25/fmv/movieplayer.cpp | 1 + video/theora_decoder.cpp | 610 ++++++++++++++++-------------------- video/theora_decoder.h | 129 ++++---- 3 files changed, 339 insertions(+), 401 deletions(-) diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp index 9ee13b4b6d..a95532ec65 100644 --- a/engines/sword25/fmv/movieplayer.cpp +++ b/engines/sword25/fmv/movieplayer.cpp @@ -61,6 +61,7 @@ bool MoviePlayer::loadMovie(const Common::String &filename, uint z) { // Get the file and load it into the decoder Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(filename); _decoder.loadStream(in); + _decoder.start(); GraphicEngine *pGfx = Kernel::getInstance()->getGfx(); diff --git a/video/theora_decoder.cpp b/video/theora_decoder.cpp index f3d9cad096..76007eadff 100644 --- a/video/theora_decoder.cpp +++ b/video/theora_decoder.cpp @@ -36,72 +36,32 @@ #include "video/theora_decoder.h" -#include "common/debug.h" +#include "audio/audiostream.h" +#include "audio/decoders/raw.h" #include "common/stream.h" #include "common/system.h" #include "common/textconsole.h" #include "common/util.h" +#include "graphics/pixelformat.h" #include "graphics/yuv_to_rgb.h" -#include "audio/decoders/raw.h" namespace Video { -#define AUDIOFD_FRAGSIZE 10240 - -static double rint(double v) { - return floor(v + 0.5); -} - -TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) { +TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { _fileStream = 0; - _theoraPacket = 0; - _vorbisPacket = 0; - _theoraDecode = 0; - _theoraSetup = 0; - _nextFrameStartTime = 0.0; - - _soundType = soundType; - _audStream = 0; - _audHandle = new Audio::SoundHandle(); - - ogg_sync_init(&_oggSync); - - _curFrame = -1; - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - - reset(); + _videoTrack = 0; + _audioTrack = 0; + _hasVideo = _hasAudio = false; } TheoraDecoder::~TheoraDecoder() { close(); - delete _fileStream; - delete _audHandle; - free(_audiobuf); -} - -void TheoraDecoder::queuePage(ogg_page *page) { - if (_theoraPacket) - ogg_stream_pagein(&_theoraOut, page); - - if (_vorbisPacket) - ogg_stream_pagein(&_vorbisOut, page); -} - -int TheoraDecoder::bufferData() { - char *buffer = ogg_sync_buffer(&_oggSync, 4096); - int bytes = _fileStream->read(buffer, 4096); - - ogg_sync_wrote(&_oggSync, bytes); - - return bytes; } bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { close(); - _endOfAudio = false; - _endOfVideo = false; _fileStream = stream; // start up Ogg stream synchronization layer @@ -109,11 +69,17 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { // init supporting Vorbis structures needed in header parsing vorbis_info_init(&_vorbisInfo); - vorbis_comment_init(&_vorbisComment); + vorbis_comment vorbisComment; + vorbis_comment_init(&vorbisComment); // init supporting Theora structures needed in header parsing - th_comment_init(&_theoraComment); - th_info_init(&_theoraInfo); + th_info theoraInfo; + th_info_init(&theoraInfo); + th_comment theoraComment; + th_comment_init(&theoraComment); + th_setup_info *theoraSetup = 0; + + uint theoraPackets = 0, vorbisPackets = 0; // Ogg file open; parse the headers // Only interested in Vorbis/Theora streams @@ -122,7 +88,7 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { int ret = bufferData(); if (ret == 0) - break; + break; // FIXME: Shouldn't this error out? while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { ogg_stream_state test; @@ -140,14 +106,16 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { ogg_stream_packetout(&test, &_oggPacket); // identify the codec: try theora - if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) { + if (theoraPackets == 0 && th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket) >= 0) { // it is theora memcpy(&_theoraOut, &test, sizeof(test)); - _theoraPacket = 1; - } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) { + theoraPackets = 1; + _hasVideo = true; + } else if (vorbisPackets == 0 && vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket) >= 0) { // it is vorbis memcpy(&_vorbisOut, &test, sizeof(test)); - _vorbisPacket = 1; + vorbisPackets = 1; + _hasAudio = true; } else { // whatever it is, we don't care about it ogg_stream_clear(&test); @@ -157,31 +125,31 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { } // we're expecting more header packets. - while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) { + while ((theoraPackets && theoraPackets < 3) || (vorbisPackets && vorbisPackets < 3)) { int ret; // look for further theora headers - while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { + while (theoraPackets && (theoraPackets < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { if (ret < 0) error("Error parsing Theora stream headers; corrupt stream?"); - if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket)) + if (!th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket)) error("Error parsing Theora stream headers; corrupt stream?"); - _theoraPacket++; + theoraPackets++; } // look for more vorbis header packets - while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { + while (vorbisPackets && (vorbisPackets < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { if (ret < 0) error("Error parsing Vorbis stream headers; corrupt stream?"); - if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket)) + if (vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket)) error("Error parsing Vorbis stream headers; corrupt stream?"); - _vorbisPacket++; + vorbisPackets++; - if (_vorbisPacket == 3) + if (vorbisPackets == 3) break; } @@ -198,88 +166,21 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { } } - // and now we have it all. initialize decoders - if (_theoraPacket) { - _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup); - debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps", - _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height, - (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator); - - switch (_theoraInfo.pixel_fmt) { - case TH_PF_420: - debug(1, " 4:2:0 video"); - break; - case TH_PF_422: - debug(1, " 4:2:2 video"); - break; - case TH_PF_444: - debug(1, " 4:4:4 video"); - break; - case TH_PF_RSVD: - default: - debug(1, " video\n (UNKNOWN Chroma sampling!)"); - break; - } - - if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height) - debug(1, " Frame content is %dx%d with offset (%d,%d).", - _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y); - - switch (_theoraInfo.colorspace){ - case TH_CS_UNSPECIFIED: - /* nothing to report */ - break; - case TH_CS_ITU_REC_470M: - debug(1, " encoder specified ITU Rec 470M (NTSC) color."); - break; - case TH_CS_ITU_REC_470BG: - debug(1, " encoder specified ITU Rec 470BG (PAL) color."); - break; - default: - debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace); - break; - } - - debug(1, "Encoded by %s", _theoraComment.vendor); - if (_theoraComment.comments) { - debug(1, "theora comment header:"); - for (int i = 0; i < _theoraComment.comments; i++) { - if (_theoraComment.user_comments[i]) { - int len = _theoraComment.comment_lengths[i]; - char *value = (char *)malloc(len + 1); - if (value) { - memcpy(value, _theoraComment.user_comments[i], len); - value[len] = '\0'; - debug(1, "\t%s", value); - free(value); - } - } - } - } - - th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax)); - _ppLevel = _ppLevelMax; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; - } else { - // tear down the partial theora setup - th_info_clear(&_theoraInfo); - th_comment_clear(&_theoraComment); + // And now we have it all. Initialize decoders next + if (_hasVideo) { + _videoTrack = new TheoraVideoTrack(getDefaultHighColorFormat(), theoraInfo, theoraSetup); + addTrack(_videoTrack); } - th_setup_free(_theoraSetup); - _theoraSetup = 0; - - if (_vorbisPacket) { - vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo); - vorbis_block_init(&_vorbisDSP, &_vorbisBlock); - debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.", - _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate); + th_info_clear(&theoraInfo); + th_comment_clear(&theoraComment); + th_setup_free(theoraSetup); - _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); + if (_hasAudio) { + _audioTrack = new VorbisAudioTrack(_soundType, _vorbisInfo); // Get enough audio data to start us off - while (_audStream->numQueuedStreams() == 0) { + while (!_audioTrack->hasAudio()) { // Queue more data bufferData(); while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) @@ -288,276 +189,299 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { queueAudio(); } - if (_audStream) - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance()); - } else { - // tear down the partial vorbis setup - vorbis_info_clear(&_vorbisInfo); - vorbis_comment_clear(&_vorbisComment); - _endOfAudio = true; + addTrack(_audioTrack); } - _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat()); - - // Set up a display surface - _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y); - _displaySurface.w = _theoraInfo.pic_width; - _displaySurface.h = _theoraInfo.pic_height; - _displaySurface.format = _surface.format; - _displaySurface.pitch = _surface.pitch; - - // Set the frame rate - _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator); + vorbis_comment_clear(&vorbisComment); return true; } void TheoraDecoder::close() { - if (_vorbisPacket) { - ogg_stream_clear(&_vorbisOut); - vorbis_block_clear(&_vorbisBlock); - vorbis_dsp_clear(&_vorbisDSP); - vorbis_comment_clear(&_vorbisComment); - vorbis_info_clear(&_vorbisInfo); + AdvancedVideoDecoder::close(); - g_system->getMixer()->stopHandle(*_audHandle); + if (!_fileStream) + return; - _audStream = 0; - _vorbisPacket = false; - } - if (_theoraPacket) { + if (_videoTrack) { ogg_stream_clear(&_theoraOut); - th_decode_free(_theoraDecode); - th_comment_clear(&_theoraComment); - th_info_clear(&_theoraInfo); - _theoraDecode = 0; - _theoraPacket = false; + _videoTrack = 0; } - if (!_fileStream) - return; + if (_audioTrack) { + ogg_stream_clear(&_vorbisOut); + _audioTrack = 0; + } ogg_sync_clear(&_oggSync); + vorbis_info_clear(&_vorbisInfo); delete _fileStream; _fileStream = 0; - _surface.free(); - _displaySurface.pixels = 0; - _displaySurface.free(); - - reset(); + _hasVideo = _hasAudio = false; } -const Graphics::Surface *TheoraDecoder::decodeNextFrame() { +void TheoraDecoder::readNextPacket() { // First, let's get our frame - while (_theoraPacket) { - // theora is one in, one out... - if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { - - if (_ppInc) { - _ppLevel += _ppInc; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; + if (_hasVideo) { + while (!_videoTrack->endOfTrack()) { + // theora is one in, one out... + if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { + if (_videoTrack->decodePacket(_oggPacket)) + break; + } else if (_theoraOut.e_o_s || _fileStream->eos()) { + // If we can't get any more frames, we're done. + _videoTrack->setEndOfVideo(); + } else { + // Queue more data + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); } - if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) { - _curFrame++; + // Update audio if we can + queueAudio(); + } + } - // Convert YUV data to RGB data - th_ycbcr_buffer yuv; - th_decode_ycbcr_out(_theoraDecode, yuv); - translateYUVtoRGBA(yuv); + // Then make sure we have enough audio buffered + ensureAudioBufferSize(); +} - if (_curFrame == 0) - _startTime = g_system->getMillis(); +TheoraDecoder::TheoraVideoTrack::TheoraVideoTrack(const Graphics::PixelFormat &format, th_info &theoraInfo, th_setup_info *theoraSetup) { + _theoraDecode = th_decode_alloc(&theoraInfo, theoraSetup); - double time = th_granule_time(_theoraDecode, _oggPacket.granulepos); + if (theoraInfo.pixel_fmt != TH_PF_420) + error("Only theora YUV420 is supported"); - // We need to calculate when the next frame should be shown - // This is all in floating point because that's what the Ogg code gives us - // Ogg is a lossy container format, so it doesn't always list the time to the - // next frame. In such cases, we need to calculate it ourselves. - if (time == -1.0) - _nextFrameStartTime += _frameRate.getInverse().toDouble(); - else - _nextFrameStartTime = time; + int postProcessingMax; + th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &postProcessingMax, sizeof(postProcessingMax)); + th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &postProcessingMax, sizeof(postProcessingMax)); - // break out - break; - } - } else { - // If we can't get any more frames, we're done. - if (_theoraOut.e_o_s || _fileStream->eos()) { - _endOfVideo = true; - break; - } + _surface.create(theoraInfo.frame_width, theoraInfo.frame_height, format); - // Queue more data - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - } + // Set up a display surface + _displaySurface.pixels = _surface.getBasePtr(theoraInfo.pic_x, theoraInfo.pic_y); + _displaySurface.w = theoraInfo.pic_width; + _displaySurface.h = theoraInfo.pic_height; + _displaySurface.format = format; + _displaySurface.pitch = _surface.pitch; - // Update audio if we can - queueAudio(); - } + // Set the frame rate + _frameRate = Common::Rational(theoraInfo.fps_numerator, theoraInfo.fps_denominator); - // Force at least some audio to be buffered - // TODO: 5 is very arbitrary. We probably should do something like QuickTime does. - while (!_endOfAudio && _audStream->numQueuedStreams() < 5) { - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); + _endOfVideo = false; + _nextFrameStartTime = 0.0; + _curFrame = -1; +} - bool queuedAudio = queueAudio(); - if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) { - _endOfAudio = true; - break; - } - } +TheoraDecoder::TheoraVideoTrack::~TheoraVideoTrack() { + th_decode_free(_theoraDecode); - return &_displaySurface; + _surface.free(); + _displaySurface.pixels = 0; } -bool TheoraDecoder::queueAudio() { - if (!_audStream) - return false; - - // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer) - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Invalid audio buffer"); - return false; +bool TheoraDecoder::TheoraVideoTrack::decodePacket(ogg_packet &oggPacket) { + if (th_decode_packetin(_theoraDecode, &oggPacket, 0) == 0) { + _curFrame++; + + // Convert YUV data to RGB data + th_ycbcr_buffer yuv; + th_decode_ycbcr_out(_theoraDecode, yuv); + translateYUVtoRGBA(yuv); + + double time = th_granule_time(_theoraDecode, oggPacket.granulepos); + + // We need to calculate when the next frame should be shown + // This is all in floating point because that's what the Ogg code gives us + // Ogg is a lossy container format, so it doesn't always list the time to the + // next frame. In such cases, we need to calculate it ourselves. + if (time == -1.0) + _nextFrameStartTime += _frameRate.getInverse().toDouble(); + else + _nextFrameStartTime = time; + + return true; } - bool queuedAudio = false; + return false; +} - for (;;) { - float **pcm; - - // if there's pending, decoded audio, grab it - int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm); - if (ret > 0) { - int count = _audiobufFill / 2; - int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1; - int i; - for (i = 0; i < ret && i < maxsamples; i++) - for (int j = 0; j < _vorbisInfo.channels; j++) { - int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767); - _audiobuf[count++] = val; - } - - vorbis_synthesis_read(&_vorbisDSP, i); - _audiobufFill += (i * _vorbisInfo.channels) << 1; - - if (_audiobufFill == AUDIOFD_FRAGSIZE) { - byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO; -#ifdef SCUMM_LITTLE_ENDIAN - flags |= Audio::FLAG_LITTLE_ENDIAN; -#endif - _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, flags); - - // The audio mixer is now responsible for the old audio buffer. - // We need to create a new one. - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer"); - return false; - } - - _audiobufFill = 0; - queuedAudio = true; - } - } else { - // no pending audio; is there a pending packet to decode? - if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) { - if (vorbis_synthesis(&_vorbisBlock, &_oggPacket) == 0) // test for success! - vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock); - } else // we've buffered all we have, break out for now - return queuedAudio; - } - } +enum TheoraYUVBuffers { + kBufferY = 0, + kBufferU = 1, + kBufferV = 2 +}; - // Unreachable - return false; +void TheoraDecoder::TheoraVideoTrack::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { + // Width and height of all buffers have to be divisible by 2. + assert((YUVBuffer[kBufferY].width & 1) == 0); + assert((YUVBuffer[kBufferY].height & 1) == 0); + assert((YUVBuffer[kBufferU].width & 1) == 0); + assert((YUVBuffer[kBufferV].width & 1) == 0); + + // UV images have to have a quarter of the Y image resolution + assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1); + assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1); + assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); + assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); + + Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); } -void TheoraDecoder::reset() { - VideoDecoder::reset(); +static vorbis_info *info = 0; - // FIXME: This does a rewind() instead of a reset()! +TheoraDecoder::VorbisAudioTrack::VorbisAudioTrack(Audio::Mixer::SoundType soundType, vorbis_info &vorbisInfo) : _soundType(soundType) { + vorbis_synthesis_init(&_vorbisDSP, &vorbisInfo); + vorbis_block_init(&_vorbisDSP, &_vorbisBlock); + info = &vorbisInfo; - if (_fileStream) - _fileStream->seek(0); + _audStream = Audio::makeQueuingAudioStream(vorbisInfo.rate, vorbisInfo.channels); - _audiobufFill = 0; - _audiobufReady = false; + _audioBufferFill = 0; + _audioBuffer = 0; + _endOfAudio = false; +} - _curFrame = -1; +TheoraDecoder::VorbisAudioTrack::~VorbisAudioTrack() { + vorbis_dsp_clear(&_vorbisDSP); + vorbis_block_clear(&_vorbisBlock); + delete _audStream; + free(_audioBuffer); +} - _theoraPacket = 0; - _vorbisPacket = 0; +Audio::AudioStream *TheoraDecoder::VorbisAudioTrack::getAudioStream() const { + return _audStream; } -bool TheoraDecoder::endOfVideo() const { - return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio))); +#define AUDIOFD_FRAGSIZE 10240 + +static double rint(double v) { + return floor(v + 0.5); } -uint32 TheoraDecoder::getTimeToNextFrame() const { - if (endOfVideo() || _curFrame < 0) - return 0; +bool TheoraDecoder::VorbisAudioTrack::decodeSamples() { + float **pcm; - uint32 elapsedTime = getTime(); - uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000); + // if there's pending, decoded audio, grab it + int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm); - if (nextFrameStartTime <= elapsedTime) - return 0; + if (ret > 0) { + if (!_audioBuffer) { + _audioBuffer = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); + assert(_audioBuffer); + } - return nextFrameStartTime - elapsedTime; + int channels = _audStream->isStereo() ? 2 : 1; + int count = _audioBufferFill / 2; + int maxsamples = ((AUDIOFD_FRAGSIZE - _audioBufferFill) / channels) >> 1; + int i; + + for (i = 0; i < ret && i < maxsamples; i++) { + for (int j = 0; j < channels; j++) { + int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767); + _audioBuffer[count++] = val; + } + } + + vorbis_synthesis_read(&_vorbisDSP, i); + _audioBufferFill += (i * channels) << 1; + + if (_audioBufferFill == AUDIOFD_FRAGSIZE) { + byte flags = Audio::FLAG_16BITS; + + if (_audStream->isStereo()) + flags |= Audio::FLAG_STEREO; + +#ifdef SCUMM_LITTLE_ENDIAN + flags |= Audio::FLAG_LITTLE_ENDIAN; +#endif + + _audStream->queueBuffer((byte *)_audioBuffer, AUDIOFD_FRAGSIZE, DisposeAfterUse::YES, flags); + + // The audio mixer is now responsible for the old audio buffer. + // We need to create a new one. + _audioBuffer = 0; + _audioBufferFill = 0; + } + + return true; + } + + return false; } -uint32 TheoraDecoder::getTime() const { - if (_audStream) - return g_system->getMixer()->getSoundElapsedTime(*_audHandle); +bool TheoraDecoder::VorbisAudioTrack::hasAudio() const { + return _audStream->numQueuedStreams() > 0; +} - return VideoDecoder::getTime(); +bool TheoraDecoder::VorbisAudioTrack::needsAudio() const { + // TODO: 5 is very arbitrary. We probably should do something like QuickTime does. + return !_endOfAudio && _audStream->numQueuedStreams() < 5; } -void TheoraDecoder::pauseVideoIntern(bool pause) { - if (_audStream) - g_system->getMixer()->pauseHandle(*_audHandle, pause); +void TheoraDecoder::VorbisAudioTrack::synthesizePacket(ogg_packet &oggPacket) { + if (vorbis_synthesis(&_vorbisBlock, &oggPacket) == 0) // test for success + vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock); } -enum TheoraYUVBuffers { - kBufferY = 0, - kBufferU = 1, - kBufferV = 2 -}; +void TheoraDecoder::queuePage(ogg_page *page) { + if (_hasVideo) + ogg_stream_pagein(&_theoraOut, page); -void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { - // Width and height of all buffers have to be divisible by 2. - assert((YUVBuffer[kBufferY].width & 1) == 0); - assert((YUVBuffer[kBufferY].height & 1) == 0); - assert((YUVBuffer[kBufferU].width & 1) == 0); - assert((YUVBuffer[kBufferV].width & 1) == 0); + if (_hasAudio) + ogg_stream_pagein(&_vorbisOut, page); +} - // UV images have to have a quarter of the Y image resolution - assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); - assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); +int TheoraDecoder::bufferData() { + char *buffer = ogg_sync_buffer(&_oggSync, 4096); + int bytes = _fileStream->read(buffer, 4096); - Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); + ogg_sync_wrote(&_oggSync, bytes); + + return bytes; } -void TheoraDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelVolume(*_audHandle, getVolume()); +bool TheoraDecoder::queueAudio() { + if (!_hasAudio) + return false; + + bool queuedAudio = false; + + for (;;) { + if (_audioTrack->decodeSamples()) { + // we queued some pending audio + queuedAudio = true; + } else if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) { + // no pending audio; is there a pending packet to decode? + _audioTrack->synthesizePacket(_oggPacket); + } else { + // we've buffered all we have, break out for now + break; + } + } + + return queuedAudio; } -void TheoraDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelBalance(*_audHandle, getBalance()); +void TheoraDecoder::ensureAudioBufferSize() { + if (!_hasAudio) + return; + + // Force at least some audio to be buffered + while (_audioTrack->needsAudio()) { + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); + + bool queuedAudio = queueAudio(); + if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) { + _audioTrack->setEndOfAudio(); + break; + } + } } } // End of namespace Video diff --git a/video/theora_decoder.h b/video/theora_decoder.h index 459fc064d3..2244f7550d 100644 --- a/video/theora_decoder.h +++ b/video/theora_decoder.h @@ -29,9 +29,7 @@ #include "common/rational.h" #include "video/video_decoder.h" -#include "audio/audiostream.h" #include "audio/mixer.h" -#include "graphics/pixelformat.h" #include "graphics/surface.h" #include @@ -41,6 +39,11 @@ namespace Common { class SeekableReadStream; } +namespace Audio { +class AudioStream; +class QueuingAudioStream; +} + namespace Video { /** @@ -49,7 +52,7 @@ namespace Video { * Video decoder used in engines: * - sword25 */ -class TheoraDecoder : public VideoDecoder { +class TheoraDecoder : public AdvancedVideoDecoder { public: TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); virtual ~TheoraDecoder(); @@ -60,81 +63,91 @@ public: */ bool loadStream(Common::SeekableReadStream *stream); void close(); - void reset(); - /** - * Decode the next frame and return the frame's surface - * @note the return surface should *not* be freed - * @note this may return 0, in which case the last frame should be kept on screen - */ - const Graphics::Surface *decodeNextFrame(); +protected: + void readNextPacket(); - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _displaySurface.w; } - uint16 getHeight() const { return _displaySurface.h; } +private: + class TheoraVideoTrack : public VideoTrack { + public: + TheoraVideoTrack(const Graphics::PixelFormat &format, th_info &theoraInfo, th_setup_info *theoraSetup); + ~TheoraVideoTrack(); - uint32 getFrameCount() const { - // It is not possible to get frame count easily - // I.e. seeking is required - assert(0); - return 0; - } + bool endOfTrack() const { return _endOfVideo; } + uint16 getWidth() const { return _displaySurface.w; } + uint16 getHeight() const { return _displaySurface.h; } + Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } + int getCurFrame() const { return _curFrame; } + uint32 getNextFrameStartTime() const { return (uint32)(_nextFrameStartTime * 1000); } + const Graphics::Surface *decodeNextFrame() { return &_displaySurface; } - Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } - uint32 getTime() const; - uint32 getTimeToNextFrame() const; + bool decodePacket(ogg_packet &oggPacket); + void setEndOfVideo() { _endOfVideo = true; } - bool endOfVideo() const; + private: + int _curFrame; + bool _endOfVideo; + Common::Rational _frameRate; + double _nextFrameStartTime; -protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - void pauseVideoIntern(bool pause); + Graphics::Surface _surface; + Graphics::Surface _displaySurface; + + th_dec_ctx *_theoraDecode; + + void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); + }; + + class VorbisAudioTrack : public AudioTrack { + public: + VorbisAudioTrack(Audio::Mixer::SoundType soundType, vorbis_info &vorbisInfo); + ~VorbisAudioTrack(); + + Audio::Mixer::SoundType getSoundType() const { return _soundType; } + + bool decodeSamples(); + bool hasAudio() const; + bool needsAudio() const; + void synthesizePacket(ogg_packet &oggPacket); + void setEndOfAudio() { _endOfAudio = true; } + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + // single audio fragment audio buffering + int _audioBufferFill; + ogg_int16_t *_audioBuffer; + + Audio::Mixer::SoundType _soundType; + Audio::QueuingAudioStream *_audStream; + + vorbis_block _vorbisBlock; + vorbis_dsp_state _vorbisDSP; + + bool _endOfAudio; + }; -private: void queuePage(ogg_page *page); - bool queueAudio(); int bufferData(); - void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); + bool queueAudio(); + void ensureAudioBufferSize(); Common::SeekableReadStream *_fileStream; - Graphics::Surface _surface; - Graphics::Surface _displaySurface; - Common::Rational _frameRate; - double _nextFrameStartTime; - bool _endOfVideo; - bool _endOfAudio; Audio::Mixer::SoundType _soundType; - Audio::SoundHandle *_audHandle; - Audio::QueuingAudioStream *_audStream; ogg_sync_state _oggSync; ogg_page _oggPage; ogg_packet _oggPacket; - ogg_stream_state _vorbisOut; - ogg_stream_state _theoraOut; - th_info _theoraInfo; - th_comment _theoraComment; - th_dec_ctx *_theoraDecode; - th_setup_info *_theoraSetup; - vorbis_info _vorbisInfo; - vorbis_dsp_state _vorbisDSP; - vorbis_block _vorbisBlock; - vorbis_comment _vorbisComment; - int _theoraPacket; - int _vorbisPacket; + ogg_stream_state _theoraOut, _vorbisOut; + bool _hasVideo, _hasAudio; - int _ppLevelMax; - int _ppLevel; - int _ppInc; + vorbis_info _vorbisInfo; - // single audio fragment audio buffering - int _audiobufFill; - bool _audiobufReady; - ogg_int16_t *_audiobuf; + TheoraVideoTrack *_videoTrack; + VorbisAudioTrack *_audioTrack; }; } // End of namespace Video -- cgit v1.2.3 From 2fd8bae31994e5581d0ef43da439d01ddd0d1ef5 Mon Sep 17 00:00:00 2001 From: Vincent Hamm Date: Mon, 13 Aug 2012 20:12:07 -0700 Subject: CINE: Fix restoring of savegame in cave --- engines/cine/anim.cpp | 13 +++++-- engines/cine/anim.h | 2 +- engines/cine/bg_list.cpp | 12 +++---- engines/cine/gfx.cpp | 86 ++++++++++++++++++++++++++++------------------- engines/cine/gfx.h | 9 ++--- engines/cine/saveload.cpp | 16 ++++----- 6 files changed, 80 insertions(+), 58 deletions(-) diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index 410fcca1f3..d81828d9f6 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -682,9 +682,10 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) { * Load image set * @param resourceName Image set filename * @param idx Target index in animDataTable (-1 if any empty space will do) + * @param frameIndex frame of animation to load (-1 for all frames) * @return The number of the animDataTable entry after the loaded image set (-1 if error) */ -int loadSet(const char *resourceName, int16 idx) { +int loadSet(const char *resourceName, int16 idx, int16 frameIndex =-1 ) { AnimHeader2Struct header2; uint16 numSpriteInAnim; int16 foundFileIdx = findFileInBundle(resourceName); @@ -708,6 +709,12 @@ int loadSet(const char *resourceName, int16 idx) { entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); + if(frameIndex>=0) + { + numSpriteInAnim = 1; + ptr += 0x10 * frameIndex; + } + for (int16 i = 0; i < numSpriteInAnim; i++, entry++) { Common::MemoryReadStream readS(ptr, 0x10); @@ -767,7 +774,7 @@ int loadSeq(const char *resourceName, int16 idx) { * @return The number of the animDataTable entry after the loaded resource (-1 if error) * @todo Implement loading of all resource types */ -int loadResource(const char *resourceName, int16 idx) { +int loadResource(const char *resourceName, int16 idx, int16 frameIndex) { int result = -1; // Return an error by default if (strstr(resourceName, ".SPL")) { result = loadSpl(resourceName, idx); @@ -778,7 +785,7 @@ int loadResource(const char *resourceName, int16 idx) { } else if (strstr(resourceName, ".ANM")) { result = loadAni(resourceName, idx); } else if (strstr(resourceName, ".SET")) { - result = loadSet(resourceName, idx); + result = loadSet(resourceName, idx, frameIndex); } else if (strstr(resourceName, ".SEQ")) { result = loadSeq(resourceName, idx); } else if (strstr(resourceName, ".H32")) { diff --git a/engines/cine/anim.h b/engines/cine/anim.h index 9c06c260ce..c5130aab82 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -98,7 +98,7 @@ public: void freeAnimDataTable(); void freeAnimDataRange(byte startIdx, byte numIdx); -int loadResource(const char *resourceName, int16 idx = -1); +int loadResource(const char *resourceName, int16 idx = -1, int16 frameIndex = -1); void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat); void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index 693fea3294..36ecf53dea 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -39,9 +39,9 @@ uint32 var8; * @param objIdx Sprite description */ void addToBGList(int16 objIdx) { - renderer->incrustSprite(g_cine->_objectTable[objIdx]); - createBgIncrustListElement(objIdx, 0); + + renderer->incrustSprite(g_cine->_bgIncrustList.back()); } /** @@ -49,9 +49,9 @@ void addToBGList(int16 objIdx) { * @param objIdx Sprite description */ void addSpriteFilledToBGList(int16 objIdx) { - renderer->incrustMask(g_cine->_objectTable[objIdx]); - createBgIncrustListElement(objIdx, 1); + + renderer->incrustMask(g_cine->_bgIncrustList.back()); } /** @@ -103,9 +103,9 @@ void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle) { g_cine->_bgIncrustList.push_back(tmp); if (tmp.param == 0) { - renderer->incrustSprite(g_cine->_objectTable[tmp.objIdx]); + renderer->incrustSprite(tmp); } else { - renderer->incrustMask(g_cine->_objectTable[tmp.objIdx]); + renderer->incrustMask(tmp); } } } diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index d448f134ff..c51420e62b 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -113,7 +113,7 @@ FWRenderer::FWRenderer() : _background(NULL), _backupPal(), _cmd(""), assert(_backBuffer); memset(_backBuffer, 0, _screenSize); - memset(_bgName, 0, sizeof(_bgName)); + memset(_bgName, 0, sizeof (_bgName)); } @@ -174,7 +174,8 @@ void FWRenderer::fillSprite(const ObjectStruct &obj, uint8 color) { * @param obj Object info * @param fillColor Sprite color */ -void FWRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { +void FWRenderer::incrustMask(const BGIncrust &incrust, uint8 color) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; @@ -218,7 +219,9 @@ void FWRenderer::drawSprite(const ObjectStruct &obj) { * Draw color sprite on background * @param obj Object info */ -void FWRenderer::incrustSprite(const ObjectStruct &obj) { +void FWRenderer::incrustSprite(const BGIncrust &incrust) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; + const byte *data = g_cine->_animDataTable[obj.frame].data(); const byte *mask = g_cine->_animDataTable[obj.frame].mask(); int x, y, width, height; @@ -301,7 +304,7 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color while (str[i] == ' ') i++; line = fitLine(str + i, tw, words, cw); - if (str[i + line] != '\0' && str[i + line] != 0x7C && words) { + if ( str[i + line] != '\0' && str[i + line] != 0x7C && words) { space = (tw - cw) / words; extraSpace = (tw - cw) % words; } else { @@ -1119,7 +1122,8 @@ void OSRenderer::clear() { * @param obj Object info * @param fillColor Sprite color */ -void OSRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { +void OSRenderer::incrustMask(const BGIncrust &incrust, uint8 color) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; @@ -1154,15 +1158,16 @@ void OSRenderer::drawSprite(const ObjectStruct &obj) { * Draw color sprite * @param obj Object info */ -void OSRenderer::incrustSprite(const ObjectStruct &obj) { - const byte *data = g_cine->_animDataTable[obj.frame].data(); +void OSRenderer::incrustSprite(const BGIncrust &incrust) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; + const byte *data = g_cine->_animDataTable[incrust.frame].data(); int x, y, width, height, transColor; - x = obj.x; - y = obj.y; + x = incrust.x; + y = incrust.y; transColor = obj.part; - width = g_cine->_animDataTable[obj.frame]._realWidth; - height = g_cine->_animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[incrust.frame]._realWidth; + height = g_cine->_animDataTable[incrust.frame]._height; if (_bgTable[_currentBg].bg) { drawSpriteRaw2(data, transColor, width, height, _bgTable[_currentBg].bg, x, y); @@ -1416,7 +1421,7 @@ void OSRenderer::selectBg(unsigned int idx) { if (_bgTable[idx].bg) { assert(_bgTable[idx].pal.isValid() && !(_bgTable[idx].pal.empty())); - _currentBg = idx; + _currentBg = idx; } else warning("OSRenderer::selectBg(%d) - attempt to select null background", idx); reloadPalette(); @@ -1737,43 +1742,53 @@ void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int1 } } -void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp) { - byte *pMask = NULL; +void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp) +{ + byte* pMask = NULL; // draw the mask based on next objects in the list Common::List::iterator it; - for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { - if (&(*it) == overlayPtr) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) + { + if(&(*it) == overlayPtr) + { break; } } - while (it != g_cine->_overlayList.end()) { - overlay *pCurrentOverlay = &(*it); - if ((pCurrentOverlay->type == 5) || ((pCurrentOverlay->type == 21) && (pCurrentOverlay->x == overlayPtr->objIdx))) { - AnimData *sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; + while(it != g_cine->_overlayList.end()) + { + overlay* pCurrentOverlay = &(*it); + if((pCurrentOverlay->type==5) || ((pCurrentOverlay->type==21) && (pCurrentOverlay->x==overlayPtr->objIdx))) + { + AnimData* sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; - if (pMask == NULL) { - pMask = new byte[width * height]; + if(pMask == NULL) + { + pMask = new byte[width*height]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - byte spriteColor = spritePtr[width * i + j]; - pMask[width * i + j] = spriteColor; + byte spriteColor= spritePtr[width*i+j]; + pMask[width*i+j] = spriteColor; } } } for (int i = 0; i < sprite->_realWidth; i++) { for (int j = 0; j < sprite->_height; j++) { - int inMaskX = (g_cine->_objectTable[it->objIdx].x + i) - x; - int inMaskY = (g_cine->_objectTable[it->objIdx].y + j) - y; - - if (inMaskX >= 0 && inMaskX < width) { - if (inMaskY >= 0 && inMaskY < height) { - if (sprite->_bpp == 1) { - if (!sprite->getColor(i, j)) { - pMask[inMaskY * width + inMaskX] = page[x + y * 320 + inMaskX + inMaskY * 320]; + int inMaskX = (g_cine->_objectTable[it->objIdx].x+i) - x; + int inMaskY = (g_cine->_objectTable[it->objIdx].y+j) - y; + + if(inMaskX >=0 && inMaskX < width) + { + if(inMaskY >=0 && inMaskY < height) + { + if(sprite->_bpp == 1) + { + if(!sprite->getColor(i, j)) + { + pMask[inMaskY*width+inMaskX] = page[x + y * 320 + inMaskX + inMaskY * 320]; } } } @@ -1787,7 +1802,8 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi } // now, draw with the mask we created - if (pMask) { + if(pMask) + { spritePtr = pMask; } { @@ -1796,7 +1812,7 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi destPtr += i * 320; for (int j = 0; j < width; j++) { - byte color = *(spritePtr++); + byte color= *(spritePtr++); if ((transparentColor != color) && x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200) { *(destPtr++) = color; } else { @@ -1807,7 +1823,7 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi } delete[] pMask; -} +}; void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height, byte *page, int16 x, int16 y) { int16 i, j; diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index 6ff5b08b77..3434cf9fc2 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -27,6 +27,7 @@ #include "common/rect.h" #include "common/stack.h" #include "cine/object.h" +#include "cine/bg_list.h" namespace Cine { @@ -177,8 +178,8 @@ public: void drawFrame(); void setCommand(Common::String cmd); - virtual void incrustMask(const ObjectStruct &obj, uint8 color = 0); - virtual void incrustSprite(const ObjectStruct &obj); + virtual void incrustMask(const BGIncrust &incrust, uint8 color = 0); + virtual void incrustSprite(const BGIncrust &incrust); virtual void loadBg16(const byte *bg, const char *name, unsigned int idx = 0); virtual void loadCt16(const byte *ct, const char *name); @@ -239,8 +240,8 @@ public: void clear(); - void incrustMask(const ObjectStruct &obj, uint8 color = 0); - void incrustSprite(const ObjectStruct &obj); + void incrustMask(const BGIncrust &incrust, uint8 color = 0); + void incrustSprite(const BGIncrust &incrust); void loadBg16(const byte *bg, const char *name, unsigned int idx = 0); void loadCt16(const byte *ct, const char *name); diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp index 223099a587..20952eea52 100644 --- a/engines/cine/saveload.cpp +++ b/engines/cine/saveload.cpp @@ -991,7 +991,7 @@ void CineEngine::makeSave(char *saveFileName) { * at a time. */ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) { - int16 currentAnim, foundFileIdx; + int16 foundFileIdx; char *animName, part[256], name[10]; strcpy(part, currentPartName); @@ -1001,10 +1001,10 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30); const int fileStartPos = fHandle.pos(); - currentAnim = 0; - while (currentAnim < NUM_MAX_ANIMDATA) { + + for(int resourceIndex=0; resourceIndex_partBuffer[foundFileIdx].partName; loadRelatedPalette(animName); // Is this for Future Wars only? - const int16 prevAnim = currentAnim; - currentAnim = loadResource(animName, currentAnim); - assert(currentAnim > prevAnim); // Make sure we advance forward + loadResource(animName, resourceIndex, frameIndex); } loadPart(part); -- cgit v1.2.3 From 1d6a0ad8b20b5c223f3dbab50298be5cdf5f36f5 Mon Sep 17 00:00:00 2001 From: Vincent Hamm Date: Mon, 13 Aug 2012 21:35:49 -0700 Subject: Fix swimming sequence by allowing mouse click to be held down --- engines/cine/main_loop.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 971830ce8f..7cd3cac3d6 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -56,6 +56,12 @@ static void processEvent(Common::Event &event) { case Common::EVENT_RBUTTONDOWN: mouseRight = 1; break; + case Common::EVENT_LBUTTONUP: + mouseLeft = 0; + break; + case Common::EVENT_RBUTTONUP: + mouseRight = 0; + break; case Common::EVENT_MOUSEMOVE: break; case Common::EVENT_KEYDOWN: @@ -214,8 +220,6 @@ void manageEvents() { g_sound->update(); mouseData.left = mouseLeft; mouseData.right = mouseRight; - mouseLeft = 0; - mouseRight = 0; } void getMouseData(uint16 param, uint16 *pButton, uint16 *pX, uint16 *pY) { @@ -311,6 +315,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // HACK: Force amount of oxygen left to maximum during Operation Stealth's first arcade sequence. // This makes it possible to pass the arcade sequence for now. // FIXME: Remove the hack and make the first arcade sequence normally playable. + /* if (g_cine->getGameType() == Cine::GType_OS) { Common::String bgName(renderer->getBgName()); // Check if the background is one of the three backgrounds @@ -320,7 +325,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // Force the amount of oxygen left to the maximum. g_cine->_objectTable[oxygenObjNum].x = maxOxygen; } - } + }*/ // HACK: In Operation Stealth after the first arcade sequence jump player's position to avoid getting stuck. // After the first arcade sequence the player comes up stairs from -- cgit v1.2.3 From ca54d69addbbb4257514b007a656138c8f60c4cd Mon Sep 17 00:00:00 2001 From: Vincent Hamm Date: Mon, 13 Aug 2012 21:35:49 -0700 Subject: Cine: Fix swimming sequence by allowing mouse click to be held down --- engines/cine/main_loop.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 971830ce8f..7cd3cac3d6 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -56,6 +56,12 @@ static void processEvent(Common::Event &event) { case Common::EVENT_RBUTTONDOWN: mouseRight = 1; break; + case Common::EVENT_LBUTTONUP: + mouseLeft = 0; + break; + case Common::EVENT_RBUTTONUP: + mouseRight = 0; + break; case Common::EVENT_MOUSEMOVE: break; case Common::EVENT_KEYDOWN: @@ -214,8 +220,6 @@ void manageEvents() { g_sound->update(); mouseData.left = mouseLeft; mouseData.right = mouseRight; - mouseLeft = 0; - mouseRight = 0; } void getMouseData(uint16 param, uint16 *pButton, uint16 *pX, uint16 *pY) { @@ -311,6 +315,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // HACK: Force amount of oxygen left to maximum during Operation Stealth's first arcade sequence. // This makes it possible to pass the arcade sequence for now. // FIXME: Remove the hack and make the first arcade sequence normally playable. + /* if (g_cine->getGameType() == Cine::GType_OS) { Common::String bgName(renderer->getBgName()); // Check if the background is one of the three backgrounds @@ -320,7 +325,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // Force the amount of oxygen left to the maximum. g_cine->_objectTable[oxygenObjNum].x = maxOxygen; } - } + }*/ // HACK: In Operation Stealth after the first arcade sequence jump player's position to avoid getting stuck. // After the first arcade sequence the player comes up stairs from -- cgit v1.2.3 From 478be5f07a8528d19542802a7714cf4fd652f340 Mon Sep 17 00:00:00 2001 From: Vincent Hamm Date: Mon, 13 Aug 2012 23:20:10 -0700 Subject: CINE: Fix regression in savegame system --- engines/cine/anim.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index d81828d9f6..60168831a1 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -709,13 +709,17 @@ int loadSet(const char *resourceName, int16 idx, int16 frameIndex =-1 ) { entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); + int16 startFrame = 0; + int16 endFrame = numSpriteInAnim; + if(frameIndex>=0) { - numSpriteInAnim = 1; + startFrame = frameIndex; + endFrame = frameIndex+1; ptr += 0x10 * frameIndex; } - for (int16 i = 0; i < numSpriteInAnim; i++, entry++) { + for (int16 i = startFrame; i < endFrame; i++, entry++) { Common::MemoryReadStream readS(ptr, 0x10); header2.field_0 = readS.readUint32BE(); -- cgit v1.2.3 From 54e6283cfa5018401b793ce993cf308fec1cb3ef Mon Sep 17 00:00:00 2001 From: Travis Howell Date: Tue, 14 Aug 2012 16:46:19 +1000 Subject: CINE: Fix compile error caused by excess ; --- engines/cine/gfx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index c51420e62b..d080d4300b 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -1823,7 +1823,7 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi } delete[] pMask; -}; +} void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height, byte *page, int16 x, int16 y) { int16 i, j; -- cgit v1.2.3 From 92df76fbb3802bf28819c2684d188251c249cdbb Mon Sep 17 00:00:00 2001 From: Vincent Hamm Date: Mon, 13 Aug 2012 23:58:32 -0700 Subject: CINE: Fix system menu sometimes not appearing in OS --- engines/cine/cine.cpp | 2 ++ engines/cine/gfx.cpp | 15 +++++++++------ engines/cine/main_loop.cpp | 6 +++--- engines/cine/script_fw.cpp | 2 +- engines/cine/various.cpp | 21 ++++++++++++--------- engines/cine/various.h | 2 +- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 6b94c33c31..bbe2cd4896 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -189,6 +189,8 @@ void CineEngine::initialize() { g_cine->_messageTable.clear(); resetObjectTable(); + disableSystemMenu = 1; + var8 = 0; var2 = var3 = var4 = var5 = 0; diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index c51420e62b..adc501b67d 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -249,14 +249,17 @@ void FWRenderer::drawCommand() { unsigned int i; int x = 10, y = _cmdY; - drawPlainBox(x, y, 301, 11, 0); - drawBorder(x - 1, y - 1, 302, 12, 2); + if(disableSystemMenu == 0) + { + drawPlainBox(x, y, 301, 11, 0); + drawBorder(x - 1, y - 1, 302, 12, 2); - x += 2; - y += 2; + x += 2; + y += 2; - for (i = 0; i < _cmd.size(); i++) { - x = drawChar(_cmd[i], x, y); + for (i = 0; i < _cmd.size(); i++) { + x = drawChar(_cmd[i], x, y); + } } } diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 7cd3cac3d6..f13f38a45e 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -121,7 +121,7 @@ static void processEvent(Common::Event &event) { } break; case Common::KEYCODE_F10: - if (!disableSystemMenu && !inMenu) { + if (!inMenu) { g_cine->makeSystemMenu(); } break; @@ -384,8 +384,8 @@ void CineEngine::mainLoop(int bootScriptIdx) { playerAction = false; _messageLen <<= 3; - if (_messageLen < 0x800) - _messageLen = 0x800; + if (_messageLen < 800) + _messageLen = 800; do { manageEvents(); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 66150cc5b2..a34bf7ba2c 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -1861,7 +1861,7 @@ int FWScript::o1_disableSystemMenu() { byte param = getNextByte(); debugC(5, kCineDebugScript, "Line: %d: disableSystemMenu(%d)", _line, param); - disableSystemMenu = (param != 0); + disableSystemMenu = param; return 0; } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9b73ae1101..eccd71cf05 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -36,7 +36,7 @@ namespace Cine { -bool disableSystemMenu = false; +int16 disableSystemMenu = 0; bool inMenu; int16 commandVar3[4]; @@ -341,7 +341,7 @@ void CineEngine::makeSystemMenu() { int16 mouseX, mouseY, mouseButton; int16 selectedSave; - if (!disableSystemMenu) { + if (disableSystemMenu != 1) { inMenu = true; do { @@ -544,14 +544,16 @@ int16 buildObjectListCommand(int16 param) { int16 selectSubObject(int16 x, int16 y, int16 param) { int16 listSize = buildObjectListCommand(param); - int16 selectedObject; + int16 selectedObject = -1; bool osExtras = g_cine->getGameType() == Cine::GType_OS; if (!listSize) { return -2; } - selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras); + if (disableSystemMenu == 0) { + selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras); + } if (selectedObject == -1) return -1; @@ -691,9 +693,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, int16 var_4; SelectionMenu *menu; - if (disableSystemMenu) - return -1; - paramY = (height * 9) + 10; if (X + width > 319) { @@ -810,14 +809,18 @@ void makeActionMenu() { getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY); if (g_cine->getGameType() == Cine::GType_OS) { - playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true); + if(disableSystemMenu == 0) { + playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true); + } if (playerCommand >= 8000) { playerCommand -= 8000; canUseOnObject = canUseOnItemTable[playerCommand]; } } else { - playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70); + if(disableSystemMenu == 0) { + playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70); + } } inMenu = false; diff --git a/engines/cine/various.h b/engines/cine/various.h index 0c1883c323..813619816d 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -41,7 +41,7 @@ void makeActionMenu(); void waitPlayerInput(); void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4); -extern bool disableSystemMenu; +extern int16 disableSystemMenu; extern bool inMenu; extern CommandeType currentSaveName[10]; -- cgit v1.2.3 From 629d55cdfad91a993eff7406fa2ca2b09d0d295d Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Tue, 14 Aug 2012 09:09:08 +0200 Subject: CINE: Apply some ScummVM formatting conventions --- engines/cine/gfx.cpp | 59 ++++++++++++++++++++-------------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index 3fac973855..cce8154d84 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -249,8 +249,7 @@ void FWRenderer::drawCommand() { unsigned int i; int x = 10, y = _cmdY; - if(disableSystemMenu == 0) - { + if(disableSystemMenu == 0) { drawPlainBox(x, y, 301, 11, 0); drawBorder(x - 1, y - 1, 302, 12, 2); @@ -304,7 +303,8 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color for (i = 0; str[i]; i++, line--) { // Fit line of text into textbox if (!line) { - while (str[i] == ' ') i++; + while (str[i] == ' ') + i++; line = fitLine(str + i, tw, words, cw); if ( str[i + line] != '\0' && str[i + line] != 0x7C && words) { @@ -1745,68 +1745,55 @@ void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int1 } } -void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp) -{ - byte* pMask = NULL; +void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 width, int16 height, byte *page, int16 x, int16 y, byte transparentColor, byte bpp) { + byte *pMask = NULL; // draw the mask based on next objects in the list Common::List::iterator it; - for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) - { - if(&(*it) == overlayPtr) - { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { + if(&(*it) == overlayPtr) { break; } } - while(it != g_cine->_overlayList.end()) - { - overlay* pCurrentOverlay = &(*it); - if((pCurrentOverlay->type==5) || ((pCurrentOverlay->type==21) && (pCurrentOverlay->x==overlayPtr->objIdx))) - { - AnimData* sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; + while(it != g_cine->_overlayList.end()) { + overlay *pCurrentOverlay = &(*it); + if ((pCurrentOverlay->type == 5) || ((pCurrentOverlay->type == 21) && (pCurrentOverlay->x == overlayPtr->objIdx))) { + AnimData *sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; - if(pMask == NULL) - { + if (pMask == NULL) { pMask = new byte[width*height]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - byte spriteColor= spritePtr[width*i+j]; - pMask[width*i+j] = spriteColor; + byte spriteColor= spritePtr[width * i + j]; + pMask[width * i + j] = spriteColor; } } } for (int i = 0; i < sprite->_realWidth; i++) { for (int j = 0; j < sprite->_height; j++) { - int inMaskX = (g_cine->_objectTable[it->objIdx].x+i) - x; - int inMaskY = (g_cine->_objectTable[it->objIdx].y+j) - y; - - if(inMaskX >=0 && inMaskX < width) - { - if(inMaskY >=0 && inMaskY < height) - { - if(sprite->_bpp == 1) - { - if(!sprite->getColor(i, j)) - { - pMask[inMaskY*width+inMaskX] = page[x + y * 320 + inMaskX + inMaskY * 320]; + int inMaskX = (g_cine->_objectTable[it->objIdx].x + i) - x; + int inMaskY = (g_cine->_objectTable[it->objIdx].y + j) - y; + + if (inMaskX >=0 && inMaskX < width) { + if (inMaskY >= 0 && inMaskY < height) { + if (sprite->_bpp == 1) { + if (!sprite->getColor(i, j)) { + pMask[inMaskY * width + inMaskX] = page[x + y * 320 + inMaskX + inMaskY * 320]; } } } } } } - - } it++; } // now, draw with the mask we created - if(pMask) - { + if(pMask) { spritePtr = pMask; } { -- cgit v1.2.3 From c9f3d83c9eed2134b89e59cf32f2489a99e4139f Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Tue, 14 Aug 2012 23:48:24 +0200 Subject: GUI: Fix out-of-bounds in new chooser. --- gui/saveload-dialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp index d1a66dc28a..850dfcc78f 100644 --- a/gui/saveload-dialog.cpp +++ b/gui/saveload-dialog.cpp @@ -535,7 +535,7 @@ const Common::String &SaveLoadChooserGrid::getResultString() const { } void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { - if (cmd <= _entriesPerPage) { + if (cmd <= _entriesPerPage && cmd + _curPage * _entriesPerPage <= _saveList.size()) { const SaveStateDescriptor &desc = _saveList[cmd - 1 + _curPage * _entriesPerPage]; if (_saveMode) { -- cgit v1.2.3 From b5a63d6709e87005c9b02fa02d4ae8802b7ce915 Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Wed, 15 Aug 2012 00:15:29 +0200 Subject: COMMON: Remove fprintf/stderr usage from xmlparser. --- common/xmlparser.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index ea3d44cf87..f0b7f1cc81 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -20,15 +20,11 @@ * */ -// FIXME: Avoid using fprintf -#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf -#define FORBIDDEN_SYMBOL_EXCEPTION_stderr - - #include "common/xmlparser.h" #include "common/archive.h" #include "common/fs.h" #include "common/memstream.h" +#include "common/system.h" namespace Common { @@ -123,17 +119,19 @@ bool XMLParser::parserError(const String &errStr) { keyClosing = currentPosition; } - fprintf(stderr, "\n File <%s>, line %d:\n", _fileName.c_str(), lineCount); + Common::String errorMessage = Common::String::format("\n File <%s>, line %d:\n", _fileName.c_str(), lineCount); currentPosition = (keyClosing - keyOpening); _stream->seek(keyOpening, SEEK_SET); while (currentPosition--) - fprintf(stderr, "%c", _stream->readByte()); + errorMessage += (char)_stream->readByte(); + + errorMessage += "\n\nParser error: "; + errorMessage += errStr; + errorMessage += "\n\n"; - fprintf(stderr, "\n\nParser error: "); - fprintf(stderr, "%s", errStr.c_str()); - fprintf(stderr, "\n\n"); + g_system->logMessage(LogMessageType::kError, errorMessage.c_str()); return false; } -- cgit v1.2.3 From 92bcb1801a3d25af9f822d901cbd6613ecdff365 Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Wed, 15 Aug 2012 09:47:19 +0200 Subject: SCUMM: Replace detector printf usage with logMessage. --- engines/scumm/detection.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 87305921c9..5404c7f8b1 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -20,9 +20,6 @@ * */ -// FIXME: Avoid using printf -#define FORBIDDEN_SYMBOL_EXCEPTION_printf - #include "base/plugins.h" #include "common/archive.h" @@ -1066,15 +1063,19 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co // unknown MD5, or with a medium debug level in case of a known MD5 (for // debugging purposes). if (!findInMD5Table(res.md5.c_str())) { - printf("Your game version appears to be unknown. If this is *NOT* a fan-modified\n"); - printf("version (in particular, not a fan-made translation), please, report the\n"); - printf("following data to the ScummVM team along with name of the game you tried\n"); - printf("to add and its version/language/etc.:\n"); + Common::String md5Warning; + + md5Warning = "Your game version appears to be unknown. If this is *NOT* a fan-modified\n"; + md5Warning += "version (in particular, not a fan-made translation), please, report the\n"; + md5Warning += "following data to the ScummVM team along with name of the game you tried\n"; + md5Warning += "to add and its version/language/etc.:\n"; - printf(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", + md5Warning += Common::String::format(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", res.game.gameid, generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(), res.md5.c_str()); + + g_system->logMessage(LogMessageType::kWarning, md5Warning.c_str()); } else { debug(1, "Using MD5 '%s'", res.md5.c_str()); } -- cgit v1.2.3 From 067db748e446fb456584d53bc8e206fadbbac9de Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Wed, 15 Aug 2012 09:51:55 +0200 Subject: AGI: Replace detector printf usage with logMessage. --- engines/agi/detection.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 805fe7d366..5f7780bfe3 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -20,9 +20,6 @@ * */ -// FIXME: Avoid using printf -#define FORBIDDEN_SYMBOL_EXCEPTION_printf - #include "base/plugins.h" #include "engines/advancedDetector.h" @@ -491,10 +488,14 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX g_fallbackDesc.desc.gameid = _gameid.c_str(); g_fallbackDesc.desc.extra = _extra.c_str(); - printf("Your game version has been detected using fallback matching as a\n"); - printf("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); - printf("If this is an original and unmodified version or new made Fanmade game,\n"); - printf("please report any, information previously printed by ScummVM to the team.\n"); + Common::String fallbackWarning; + + fallbackWarning = "Your game version has been detected using fallback matching as a\n"; + fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); + fallbackWarning += "If this is an original and unmodified version or new made Fanmade game,\n"; + fallbackWarning += "please report any, information previously printed by ScummVM to the team.\n"; + + g_system->logMessage(LogMessageType::kWarning, fallbackWarning.c_str()); return (const ADGameDescription *)&g_fallbackDesc; } -- cgit v1.2.3 From 9c561c0287b9d1a48caa9d8178f083afc3cf2c89 Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Wed, 15 Aug 2012 10:00:23 +0200 Subject: ANDROID: Remove unused GL_OES_draw_texture code. --- backends/platform/android/texture.cpp | 63 +++++++++++------------------------ 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 95c96e0d25..b174e93191 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -52,9 +52,6 @@ // Supported GL extensions static bool npot_supported = false; -#ifdef GL_OES_draw_texture -static bool draw_tex_supported = false; -#endif static inline GLfixed xdiv(int numerator, int denominator) { assert(numerator < (1 << 16)); @@ -85,11 +82,6 @@ void GLESBaseTexture::initGLExtensions() { if (token == "GL_ARB_texture_non_power_of_two") npot_supported = true; - -#ifdef GL_OES_draw_texture - if (token == "GL_OES_draw_texture") - draw_tex_supported = true; -#endif } } @@ -180,45 +172,28 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) { void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); -#ifdef GL_OES_draw_texture - // Great extension, but only works under specific conditions. - // Still a work-in-progress - disabled for now. - if (false && draw_tex_supported && !hasPalette()) { - //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); - const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; + const GLfixed tex_width = xdiv(_surface.w, _texture_width); + const GLfixed tex_height = xdiv(_surface.h, _texture_height); + const GLfixed texcoords[] = { + 0, 0, + tex_width, 0, + 0, tex_height, + tex_width, tex_height, + }; - GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop)); + GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); - // Android GLES bug? - GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); + const GLshort vertices[] = { + x, y, + x + w, y, + x, y + h, + x + w, y + h, + }; - GLCALL(glDrawTexiOES(x, y, 0, w, h)); - } else -#endif - { - const GLfixed tex_width = xdiv(_surface.w, _texture_width); - const GLfixed tex_height = xdiv(_surface.h, _texture_height); - const GLfixed texcoords[] = { - 0, 0, - tex_width, 0, - 0, tex_height, - tex_width, tex_height, - }; - - GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); - - const GLshort vertices[] = { - x, y, - x + w, y, - x, y + h, - x + w, y + h, - }; - - GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); - - assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); - GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); - } + GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); + + assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); + GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); clearDirty(); } -- cgit v1.2.3 From 8b022a4983ba179e46a47c10e31fda8ea02c16ce Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Wed, 15 Aug 2012 21:33:55 +0100 Subject: I18N: Update Polish translation from patch #3552055 --- po/pl_PL.po | 150 +++++++++++++++++++++++++++--------------------------------- 1 file changed, 68 insertions(+), 82 deletions(-) diff --git a/po/pl_PL.po b/po/pl_PL.po index c2c5c09e19..1bf44d1a66 100644 --- a/po/pl_PL.po +++ b/po/pl_PL.po @@ -1,14 +1,14 @@ # Polish translation for ScummVM. # Copyright (C) 2010-2012 ScummVM Team # This file is distributed under the same license as the ScummVM package. -# Grajpopolsku.pl , 2011. +# Grajpopolsku.pl , 2011-2012. # msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" "POT-Creation-Date: 2012-08-12 14:57+0200\n" -"PO-Revision-Date: 2011-10-24 21:14+0100\n" +"PO-Revision-Date: 2012-07-29 15:49+0100\n" "Last-Translator: Micha³ Zi±bkowski \n" "Language-Team: Grajpopolsku.pl \n" "Language: Polski\n" @@ -82,7 +82,6 @@ msgid "Remap keys" msgstr "Dostosuj klawisze" #: gui/gui-manager.cpp:129 base/main.cpp:307 -#, fuzzy msgid "Toggle FullScreen" msgstr "W³±cz/wy³±cz pe³ny ekran" @@ -196,9 +195,8 @@ msgid "Platform:" msgstr "Platforma:" #: gui/launcher.cpp:231 -#, fuzzy msgid "Engine" -msgstr "Zbadaj" +msgstr "Silnik" #: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 msgid "Graphics" @@ -1197,19 +1195,18 @@ msgstr "" "sprawd¼ plik README." #: engines/dialogs.cpp:228 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate save failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Przepraszamy, ten silnik obecnie nie oferuje pomocy wewn±trz gry. Aby " -"uzyskaæ podstawowe informacje oraz dowiedzieæ jak szukaæ dalszej pomocy, " -"sprawd¼ plik README." +"Zapis stanu gry nie powiód³ siê (%s)! Aby uzyskaæ podstawowe informacje oraz " +"dowiedzieæ jak szukaæ dalszej pomocy, sprawd¼ plik README." #: engines/dialogs.cpp:301 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:174 msgid "~O~K" -msgstr "~O~K" +msgstr "" #: engines/dialogs.cpp:302 engines/mohawk/dialogs.cpp:110 #: engines/mohawk/dialogs.cpp:175 @@ -1261,14 +1258,13 @@ msgstr "" "Dalsze informacje s± dostêpne w pliku README." #: engines/engine.cpp:426 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate load failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Przepraszamy, ten silnik obecnie nie oferuje pomocy wewn±trz gry. Aby " -"uzyskaæ podstawowe informacje oraz dowiedzieæ jak szukaæ dalszej pomocy, " -"sprawd¼ plik README." +"Odczyt stanu gry nie powiód³ siê (%s)! Aby uzyskaæ podstawowe informacje " +"oraz dowiedzieæ jak szukaæ dalszej pomocy, sprawd¼ plik README." #: engines/engine.cpp:439 msgid "" @@ -1287,12 +1283,12 @@ msgstr "W #: engines/agi/detection.cpp:145 engines/dreamweb/detection.cpp:47 #: engines/sci/detection.cpp:390 msgid "Use original save/load screens" -msgstr "" +msgstr "U¿yj oryginalnych ekranów odczytu/zapisu" #: engines/agi/detection.cpp:146 engines/dreamweb/detection.cpp:48 #: engines/sci/detection.cpp:391 msgid "Use the original save/load screens, instead of the ScummVM ones" -msgstr "" +msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast tych ze ScummVM" #: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 msgid "Restore game:" @@ -1303,68 +1299,68 @@ msgid "Restore" msgstr "Wznów" #: engines/dreamweb/detection.cpp:57 -#, fuzzy msgid "Use bright palette mode" -msgstr "Przedmiot u góry, z prawej" +msgstr "U¿yj trybu jasnej palety" #: engines/dreamweb/detection.cpp:58 msgid "Display graphics using the game's bright palette" -msgstr "" +msgstr "Wy¶wietlaj grafikê za pomoc± jasnej palety gry" #: engines/sci/detection.cpp:370 msgid "EGA undithering" msgstr "Anty-dithering EGA" #: engines/sci/detection.cpp:371 -#, fuzzy msgid "Enable undithering in EGA games" msgstr "W³±cz anty-dithering we wspieranych grach EGA" #: engines/sci/detection.cpp:380 -#, fuzzy msgid "Prefer digital sound effects" -msgstr "G³o¶no¶æ efektów d¼w." +msgstr "Preferuj cyfrowe efekty d¼wiêkowe" #: engines/sci/detection.cpp:381 msgid "Prefer digital sound effects instead of synthesized ones" -msgstr "" +msgstr "Preferuj cyfrowe efekty d¼wiêkowe zamiast syntezowanych" #: engines/sci/detection.cpp:400 msgid "Use IMF/Yamaha FB-01 for MIDI output" -msgstr "" +msgstr "U¿yj IMF/Yamaha FB-01 dla wyj¶cia MIDI" #: engines/sci/detection.cpp:401 msgid "" "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " "output" msgstr "" +"U¿yj karty IBM Music Feature lub modu³u syntezy FM Yamaha FB-01 dla wyj¶cia " +"MIDI" #: engines/sci/detection.cpp:411 msgid "Use CD audio" -msgstr "" +msgstr "U¿yj CD audio" #: engines/sci/detection.cpp:412 msgid "Use CD audio instead of in-game audio, if available" -msgstr "" +msgstr "U¿yj CD audio zamiast muzyki w grze, je¶li jest dostêpne" #: engines/sci/detection.cpp:422 msgid "Use Windows cursors" -msgstr "" +msgstr "U¿yj windowsowych kursorów" #: engines/sci/detection.cpp:423 msgid "" "Use the Windows cursors (smaller and monochrome) instead of the DOS ones" msgstr "" +"U¿yj windowsowych kursorów (mniejsze i monochromatyczne) zamiast DOS-owych" #: engines/sci/detection.cpp:433 -#, fuzzy msgid "Use silver cursors" -msgstr "Zwyk³y kursor" +msgstr "U¿yj srebrnych kursorów" #: engines/sci/detection.cpp:434 msgid "" "Use the alternate set of silver cursors, instead of the normal golden ones" msgstr "" +"U¿yj alternatywnego zestawu srebrnych kursorów zamiast zwyk³ych z³otych" #: engines/scumm/dialogs.cpp:175 #, c-format @@ -1482,24 +1478,23 @@ msgstr "Mowa i napisy" #: engines/scumm/dialogs.cpp:653 msgid "Select a Proficiency Level." -msgstr "" +msgstr "Wybierz poziom umiejêtno¶ci." #: engines/scumm/dialogs.cpp:655 msgid "Refer to your Loom(TM) manual for help." -msgstr "" +msgstr "Pomocy szukaj w instrukcji do³±czonej do Loom(TM)." #: engines/scumm/dialogs.cpp:658 -#, fuzzy msgid "Standard" -msgstr "Standardowy (16bpp)" +msgstr "Standardowy" #: engines/scumm/dialogs.cpp:659 msgid "Practice" -msgstr "" +msgstr "Trening" #: engines/scumm/dialogs.cpp:660 msgid "Expert" -msgstr "" +msgstr "Ekspert" #: engines/scumm/help.cpp:73 msgid "Common keyboard commands:" @@ -2118,118 +2113,109 @@ msgstr "Nie uda #. Malcolm makes a joke. #: engines/kyra/detection.cpp:62 msgid "Studio audience" -msgstr "" +msgstr "Publiczno¶æ studyjna" #: engines/kyra/detection.cpp:63 msgid "Enable studio audience" -msgstr "" +msgstr "W³±cz publiczno¶æ studyjn±" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 msgid "Skip support" -msgstr "" +msgstr "Obs³uga pomijania" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" -msgstr "" +msgstr "Pozwól pomijaæ tekst i przerywniki" #. I18N: Helium mode makes people sound like they've inhaled Helium. #: engines/kyra/detection.cpp:84 msgid "Helium mode" -msgstr "" +msgstr "Tryb helowy" #: engines/kyra/detection.cpp:85 -#, fuzzy msgid "Enable helium mode" -msgstr "W³±cz tryb Roland GS" +msgstr "W³±cz tryb helowy" #. I18N: When enabled, this option makes scrolling smoother when #. changing from one screen to another. #: engines/kyra/detection.cpp:99 msgid "Smooth scrolling" -msgstr "" +msgstr "P³ynne przewijanie" #: engines/kyra/detection.cpp:100 msgid "Enable smooth scrolling when walking" -msgstr "" +msgstr "W³±cz p³ynne przewijanie przy chodzeniu" #. I18N: When enabled, this option changes the cursor when it floats to the #. edge of the screen to a directional arrow. The player can then click to #. walk towards that direction. #: engines/kyra/detection.cpp:112 -#, fuzzy msgid "Floating cursors" -msgstr "Zwyk³y kursor" +msgstr "P³ywaj±ce kursory" #: engines/kyra/detection.cpp:113 msgid "Enable floating cursors" -msgstr "" +msgstr "W³±cz p³ywaj±ce kursory" #. I18N: HP stands for Hit Points #: engines/kyra/detection.cpp:127 msgid "HP bar graphs" -msgstr "" +msgstr "Histogramy HP" #: engines/kyra/detection.cpp:128 msgid "Enable hit point bar graphs" -msgstr "" +msgstr "W³±cz histogramy punktów ¿ycia" #: engines/kyra/lol.cpp:478 msgid "Attack 1" -msgstr "" +msgstr "Atak 1" #: engines/kyra/lol.cpp:479 msgid "Attack 2" -msgstr "" +msgstr "Atak 2" #: engines/kyra/lol.cpp:480 msgid "Attack 3" -msgstr "" +msgstr "Atak 3" #: engines/kyra/lol.cpp:481 msgid "Move Forward" -msgstr "" +msgstr "Ruch naprzód" #: engines/kyra/lol.cpp:482 msgid "Move Back" -msgstr "" +msgstr "Ruch wstecz" #: engines/kyra/lol.cpp:483 msgid "Slide Left" -msgstr "" +msgstr "¦lizg w lewo" #: engines/kyra/lol.cpp:484 -#, fuzzy msgid "Slide Right" -msgstr "W prawo" +msgstr "¦lizg w prawo" #: engines/kyra/lol.cpp:485 -#, fuzzy msgid "Turn Left" -msgstr "Wy³±cz" +msgstr "Obrót w lewo" #: engines/kyra/lol.cpp:486 -#, fuzzy msgid "Turn Right" -msgstr "Kursor w prawo" +msgstr "Obrót w prawo" #: engines/kyra/lol.cpp:487 -#, fuzzy msgid "Rest" -msgstr "Wznów" +msgstr "Odpoczynek" #: engines/kyra/lol.cpp:488 -#, fuzzy msgid "Options" -msgstr "~O~pcje" +msgstr "Opcje" #: engines/kyra/lol.cpp:489 -#, fuzzy msgid "Choose Spell" -msgstr "Wybierz" +msgstr "Wybierz zaklêcie" #: engines/kyra/sound_midi.cpp:475 -#, fuzzy msgid "" "You appear to be using a General MIDI device,\n" "but your game only supports Roland MT32 MIDI.\n" @@ -2247,8 +2233,9 @@ msgid "Alternative intro" msgstr "" #: engines/queen/queen.cpp:60 +#, fuzzy msgid "Use an alternative game intro (CD version only)" -msgstr "" +msgstr "U¿yj intra z wersji dyskietkowej (tylko dla wersji CD)" #: engines/sky/compact.cpp:130 msgid "" @@ -2268,16 +2255,18 @@ msgstr "" #: engines/sky/detection.cpp:44 msgid "Floppy intro" -msgstr "" +msgstr "Intro z wersji dyskietkowej" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" -msgstr "" +msgstr "U¿yj intra z wersji dyskietkowej (tylko dla wersji CD)" #: engines/sword1/animation.cpp:539 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" msgstr "" +"Przerywnik w formacie strumieniowym PSX '%s' nie mo¿e zostaæ odtworzony w " +"trybie indeksowanym" #: engines/sword1/animation.cpp:560 engines/sword2/animation.cpp:455 msgid "DXA cutscenes found but ScummVM has been built without zlib support" @@ -2334,20 +2323,19 @@ msgid "This is the end of the Broken Sword 1 Demo" msgstr "To koniec dema Broken Sword 1" #: engines/sword2/animation.cpp:435 -#, fuzzy msgid "" "PSX cutscenes found but ScummVM has been built without RGB color support" msgstr "" -"Znaleziono przerywniki w formacie DXA, ale ScummVM jest skompilowany bez " -"obs³ugi zlib" +"Znaleziono przerywniki PSX, ale ScummVM jest skompilowany bez obs³ugi trybu " +"RGB" #: engines/sword2/sword2.cpp:79 msgid "Show object labels" -msgstr "" +msgstr "Poka¿ etykiety obiektów" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "" +msgstr "Poka¿ etykiety obiektów przy najechaniu myszk±" #: engines/teenagent/resources.cpp:68 msgid "" @@ -2499,9 +2487,8 @@ msgid "Keymap:" msgstr "Klawisze:" #: backends/keymapper/remap-dialog.cpp:66 -#, fuzzy msgid " (Effective)" -msgstr " (Aktywny)" +msgstr " (Dzia³a)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Active)" @@ -2509,7 +2496,7 @@ msgstr " (Aktywny)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Blocked)" -msgstr "" +msgstr " (Zablokowany)" #: backends/keymapper/remap-dialog.cpp:119 msgid " (Global)" @@ -2613,7 +2600,7 @@ msgstr "Tryb touchpada wy #: backends/platform/maemo/maemo.cpp:209 msgid "Click Mode" -msgstr "" +msgstr "Tryb klikania" #: backends/platform/maemo/maemo.cpp:215 #: backends/platform/symbian/src/SymbianActions.cpp:42 @@ -2624,9 +2611,8 @@ msgid "Left Click" msgstr "Klikniêcie LPM" #: backends/platform/maemo/maemo.cpp:218 -#, fuzzy msgid "Middle Click" -msgstr "Przedmiot na ¶rodku, z lewej" +msgstr "¦rodkowy przycisk" #: backends/platform/maemo/maemo.cpp:221 #: backends/platform/symbian/src/SymbianActions.cpp:43 -- cgit v1.2.3 From e55018ffdb8809574def41cd45f1f0b43dbf0b3c Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Wed, 15 Aug 2012 21:34:55 +0100 Subject: I18N: Update Hungarian translation from patch #3557212 --- po/hu_HU.po | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/po/hu_HU.po b/po/hu_HU.po index a34138c1bf..b263d2c539 100644 --- a/po/hu_HU.po +++ b/po/hu_HU.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" "POT-Creation-Date: 2012-08-12 14:57+0200\n" -"PO-Revision-Date: 2012-07-09 05:58+0100\n" +"PO-Revision-Date: 2012-08-14 07:29+0100\n" "Last-Translator: George Kormendi \n" "Language-Team: Hungarian\n" "Language: Magyar\n" @@ -921,11 +921,11 @@ msgstr "" #: gui/saveload-dialog.cpp:158 msgid "List view" -msgstr "" +msgstr "Lista nézet" #: gui/saveload-dialog.cpp:159 msgid "Grid view" -msgstr "" +msgstr "Rács nézet" #: gui/saveload-dialog.cpp:202 gui/saveload-dialog.cpp:350 msgid "No date saved" @@ -965,31 +965,28 @@ msgstr "N #: gui/saveload-dialog.cpp:517 msgid "Next" -msgstr "" +msgstr "Következõ" #: gui/saveload-dialog.cpp:520 msgid "Prev" -msgstr "" +msgstr "Elõzõ" #: gui/saveload-dialog.cpp:684 -#, fuzzy msgid "New Save" -msgstr "Mentés" +msgstr "Új Mentés" #: gui/saveload-dialog.cpp:684 -#, fuzzy msgid "Create a new save game" -msgstr "Játék mentés nem sikerült" +msgstr "Új játékmentés készítése" #: gui/saveload-dialog.cpp:789 -#, fuzzy msgid "Name: " msgstr "Név:" #: gui/saveload-dialog.cpp:861 #, c-format msgid "Enter a description for slot %d:" -msgstr "" +msgstr "Adj meg egy leírást a %d slothoz:" #: gui/themebrowser.cpp:44 msgid "Select a Theme" @@ -2230,12 +2227,11 @@ msgstr "" #: engines/queen/queen.cpp:59 msgid "Alternative intro" -msgstr "" +msgstr "Alternatív intro" #: engines/queen/queen.cpp:60 -#, fuzzy msgid "Use an alternative game intro (CD version only)" -msgstr "A floppy verzió intro használata (csak CD verziónál)" +msgstr "Alternatív játékintro használata (csak CD verziónál)" #: engines/sky/compact.cpp:130 msgid "" @@ -2336,13 +2332,15 @@ msgstr "T #: engines/teenagent/resources.cpp:68 msgid "" "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "" +msgstr "Hiányzik a 'teenagent.dat' fájl. Szerezd be a ScummVM website-ról" #: engines/teenagent/resources.cpp:89 msgid "" "The teenagent.dat file is compressed and zlib hasn't been included in this " "executable. Please decompress it" msgstr "" +"A teenagent.dat fájl tömörített és a zlib nem része ennek a futtatható " +"állománynak. Kérlek tömörítsd ki" #: engines/parallaction/saveload.cpp:133 #, c-format -- cgit v1.2.3 From 037cdaefac98fe6c8e541c86075ae5d8696934cb Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Wed, 15 Aug 2012 21:35:28 +0100 Subject: I18N: Regenerate translations data file --- gui/themes/translations.dat | Bin 342397 -> 345659 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat index cabad0c0c4..d81c1a0475 100644 Binary files a/gui/themes/translations.dat and b/gui/themes/translations.dat differ -- cgit v1.2.3 From e7ae58f2e47b32b77c9165d73e7e8a556bd710b5 Mon Sep 17 00:00:00 2001 From: David-John Willis Date: Thu, 16 Aug 2012 10:54:39 +0100 Subject: CONFIGURE: Set DISABLE_SAVELOADCHOOSER_GRID for the GPH backend. * Move some backend settings from the host selection to the backend. * Also remove stale referances to the old GP2X backend. --- configure | 32 ++++++++++---------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/configure b/configure index 06492ff305..d4fec02c64 100755 --- a/configure +++ b/configure @@ -712,7 +712,7 @@ Usage: $0 [OPTIONS]... Configuration: -h, --help display this help and exit - --backend=BACKEND backend to build (android, bada, dc, dingux, ds, gp2x, gph, + --backend=BACKEND backend to build (android, bada, dc, dingux, ds, gph, iphone, linuxmoto, maemo, n64, null, openpandora, ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl] @@ -2202,13 +2202,8 @@ if test -n "$_host"; then bfin*) ;; caanoo) - # This uses the GPH backend. - DEFINES="$DEFINES -DGPH_DEVICE" DEFINES="$DEFINES -DCAANOO" - DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" - if test "$_debug_build" = yes; then - DEFINES="$DEFINES -DGPH_DEBUG" - else + if test "$_debug_build" = no; then # Use -O3 on the Caanoo for non-debug builds. _optimization_level=-O3 fi @@ -2299,13 +2294,7 @@ if test -n "$_host"; then add_line_to_config_h "#define USE_WII_DI" ;; gp2x) - # This uses the GPH backend. - DEFINES="$DEFINES -DGPH_DEVICE" DEFINES="$DEFINES -DGP2X" - DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" - if test "$_debug_build" = yes; then - DEFINES="$DEFINES -DGPH_DEBUG" - fi CXXFLAGS="$CXXFLAGS -march=armv4t" ASFLAGS="$ASFLAGS -mfloat-abi=soft" LDFLAGS="$LDFLAGS -static" @@ -2319,13 +2308,7 @@ if test -n "$_host"; then _port_mk="backends/platform/gph/gp2x-bundle.mk" ;; gp2xwiz) - # This uses the GPH backend. - DEFINES="$DEFINES -DGPH_DEVICE" DEFINES="$DEFINES -DGP2XWIZ" - DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" - if test "$_debug_build" = yes; then - DEFINES="$DEFINES -DGPH_DEBUG" - fi CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s" CXXFLAGS="$CXXFLAGS -mtune=arm926ej-s" ASFLAGS="$ASFLAGS -mfloat-abi=soft" @@ -2611,9 +2594,14 @@ case $_backend in INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/ds/commoninclude' INCLUDES="$INCLUDES "'-Ibackends/platform/ds/arm9/data' ;; - gp2x) - ;; gph) + # On the GPH devices we want fancy themes but do not want the load/save thumbnail grid. + DEFINES="$DEFINES -DDISABLE_SAVELOADCHOOSER_GRID" + DEFINES="$DEFINES -DGPH_DEVICE" + DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" + if test "$_debug_build" = yes; then + DEFINES="$DEFINES -DGPH_DEBUG" + fi ;; iphone) LIBS="$LIBS -lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES" @@ -2709,7 +2697,7 @@ MODULES="$MODULES backends/platform/$_backend" # Setup SDL specifics for SDL based backends # case $_backend in - dingux | gp2x | gph | linuxmoto | maemo | openpandora | samsungtv | sdl) + dingux | gph | linuxmoto | maemo | openpandora | samsungtv | sdl) find_sdlconfig INCLUDES="$INCLUDES `$_sdlconfig --prefix="$_sdlpath" --cflags`" LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`" -- cgit v1.2.3 From 7294a1cbcf1cf5e8c846faf8838e537bd8c638dc Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 16 Aug 2012 12:17:23 -0400 Subject: VIDEO: Remove the Coktel video code from using the VideoDecoder API After discussing with DrMcCoy, we felt this the best way to proceed. A wrapper class that implements AdvancedVideoDecoder is still around for use in SCI. --- engines/sci/console.cpp | 5 +- engines/sci/engine/kvideo.cpp | 7 +- video/coktel_decoder.cpp | 166 ++++++++++++++++++++++++++++++++++-------- video/coktel_decoder.h | 116 +++++++++++++++++++++++------ 4 files changed, 231 insertions(+), 63 deletions(-) diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 9b5ef35e92..de852ca9c0 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -253,7 +253,7 @@ void Console::postEnter() { videoDecoder = new SEQDecoder(_videoFrameDelay); #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { - videoDecoder = new Video::VMDDecoder(g_system->getMixer()); + videoDecoder = new Video::AdvancedVMDDecoder(); } else if (_videoFile.hasSuffix(".rbt")) { videoDecoder = new RobotDecoder(_engine->getPlatform() == Common::kPlatformMacintosh); } else if (_videoFile.hasSuffix(".duk")) { @@ -267,8 +267,7 @@ void Console::postEnter() { } if (videoDecoder && videoDecoder->loadFile(_videoFile)) { - if (!_videoFile.hasSuffix(".vmd")) // TODO: Remove after new API is complete - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); _engine->_gfxCursor->kernelHide(); diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index da63aa3a8d..3e0f35c037 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -50,6 +50,8 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { if (!videoDecoder) return; + ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); + byte *scaleBuffer = 0; byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel; uint16 width = videoDecoder->getWidth(); @@ -219,7 +221,6 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { } if (videoDecoder) { - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); // TODO: Remove after new API is complete playVideo(videoDecoder, s->_videoState); // HACK: Switch back to 8bpp if we played a true color video. @@ -349,7 +350,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { break; } case 6: // Play - videoDecoder = new Video::VMDDecoder(g_system->getMixer()); + videoDecoder = new Video::AdvancedVMDDecoder(); if (s->_videoState.fileName.empty()) { // Happens in Lighthouse @@ -414,8 +415,6 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) { break; } - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); - if (reshowCursor) g_sci->_gfxCursor->kernelHide(); diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp index 0c7ade1b8a..42033fb01f 100644 --- a/video/coktel_decoder.cpp +++ b/video/coktel_decoder.cpp @@ -53,7 +53,8 @@ CoktelDecoder::CoktelDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT _mixer(mixer), _soundType(soundType), _width(0), _height(0), _x(0), _y(0), _defaultX(0), _defaultY(0), _features(0), _frameCount(0), _paletteDirty(false), _ownSurface(true), _frameRate(12), _hasSound(false), _soundEnabled(false), - _soundStage(kSoundNone), _audioStream(0) { + _soundStage(kSoundNone), _audioStream(0), _startTime(0), _pauseStartTime(0), + _isPaused(false) { assert(_mixer); @@ -261,6 +262,10 @@ bool CoktelDecoder::isPaletted() const { return true; } +int CoktelDecoder::getCurFrame() const { + return _curFrame; +} + void CoktelDecoder::close() { disableSound(); freeSurface(); @@ -273,9 +278,14 @@ void CoktelDecoder::close() { _features = 0; - _frameCount = 0; + _curFrame = -1; + _frameCount = 0; + + _startTime = 0; _hasSound = false; + + _isPaused = false; } uint16 CoktelDecoder::getWidth() const { @@ -291,6 +301,7 @@ uint32 CoktelDecoder::getFrameCount() const { } const byte *CoktelDecoder::getPalette() { + _paletteDirty = false; return _palette; } @@ -625,14 +636,45 @@ Common::Rational CoktelDecoder::getFrameRate() const { return _frameRate; } +uint32 CoktelDecoder::getTimeToNextFrame() const { + if (endOfVideo() || _curFrame < 0) + return 0; + + uint32 elapsedTime = g_system->getMillis() - _startTime; + uint32 nextFrameStartTime = (Common::Rational((_curFrame + 1) * 1000) / getFrameRate()).toInt(); + + if (nextFrameStartTime <= elapsedTime) + return 0; + + return nextFrameStartTime - elapsedTime; +} + uint32 CoktelDecoder::getStaticTimeToNextFrame() const { return (1000 / _frameRate).toInt(); } +void CoktelDecoder::pauseVideo(bool pause) { + if (_isPaused != pause) { + if (_isPaused) { + // Add the time we were paused to the initial starting time + _startTime += g_system->getMillis() - _pauseStartTime; + } else { + // Store the time we paused for use later + _pauseStartTime = g_system->getMillis(); + } + + _isPaused = pause; + } +} + inline void CoktelDecoder::unsignedToSigned(byte *buffer, int length) { while (length-- > 0) *buffer++ ^= 0x80; } +bool CoktelDecoder::endOfVideo() const { + return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1); +} + PreIMDDecoder::PreIMDDecoder(uint16 width, uint16 height, Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType), @@ -705,8 +747,6 @@ bool PreIMDDecoder::loadStream(Common::SeekableReadStream *stream) { } void PreIMDDecoder::close() { - reset(); - CoktelDecoder::close(); delete _stream; @@ -1159,8 +1199,6 @@ bool IMDDecoder::loadFrameTables(uint32 framePosPos, uint32 frameCoordsPos) { } void IMDDecoder::close() { - reset(); - CoktelDecoder::close(); delete _stream; @@ -1225,8 +1263,6 @@ void IMDDecoder::processFrame() { _dirtyRects.clear(); - _paletteDirty = false; - uint32 cmd = 0; bool hasNextCmd = false; bool startSound = false; @@ -1273,7 +1309,7 @@ void IMDDecoder::processFrame() { // Set palette if (cmd == kCommandPalette) { _stream->skip(2); - + _paletteDirty = true; for (int i = 0; i < 768; i++) @@ -1322,7 +1358,7 @@ void IMDDecoder::processFrame() { // Start the audio stream if necessary if (startSound && _soundEnabled) { _mixer->playStream(_soundType, &_audioHandle, _audioStream, - -1, getVolume(), getBalance(), DisposeAfterUse::NO); + -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); _soundStage = kSoundPlaying; } @@ -1504,16 +1540,6 @@ Graphics::PixelFormat IMDDecoder::getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } -void IMDDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); -} - -void IMDDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); -} - VMDDecoder::File::File() { offset = 0; @@ -1552,7 +1578,7 @@ VMDDecoder::VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _soundLastFilledFrame(0), _audioFormat(kAudioFormat8bitRaw), _hasVideo(false), _videoCodec(0), _blitMode(0), _bytesPerPixel(0), _firstFramePos(0), _videoBufferSize(0), _externalCodec(false), _codec(0), - _subtitle(-1), _isPaletted(true) { + _subtitle(-1), _isPaletted(true), _autoStartSound(true) { _videoBuffer [0] = 0; _videoBuffer [1] = 0; @@ -2014,8 +2040,6 @@ bool VMDDecoder::readFiles() { } void VMDDecoder::close() { - reset(); - CoktelDecoder::close(); delete _stream; @@ -2095,7 +2119,6 @@ void VMDDecoder::processFrame() { _dirtyRects.clear(); - _paletteDirty = false; _subtitle = -1; bool startSound = false; @@ -2215,8 +2238,9 @@ void VMDDecoder::processFrame() { if (startSound && _soundEnabled) { if (_hasSound && _audioStream) { - _mixer->playStream(_soundType, &_audioHandle, _audioStream, - -1, getVolume(), getBalance(), DisposeAfterUse::NO); + if (_autoStartSound) + _mixer->playStream(_soundType, &_audioHandle, _audioStream, + -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); _soundStage = kSoundPlaying; } else _soundStage = kSoundNone; @@ -2742,14 +2766,92 @@ bool VMDDecoder::isPaletted() const { return _isPaletted; } -void VMDDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); +void VMDDecoder::setAutoStartSound(bool autoStartSound) { + _autoStartSound = autoStartSound; +} + +AdvancedVMDDecoder::AdvancedVMDDecoder(Audio::Mixer::SoundType soundType) { + _decoder = new VMDDecoder(g_system->getMixer(), soundType); + _decoder->setAutoStartSound(false); +} + +AdvancedVMDDecoder::~AdvancedVMDDecoder() { + close(); + delete _decoder; +} + +bool AdvancedVMDDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + if (!_decoder->loadStream(stream)) + return false; + + if (_decoder->hasVideo()) { + _videoTrack = new VMDVideoTrack(_decoder); + addTrack(_videoTrack); + } + + if (_decoder->hasSound()) { + _audioTrack = new VMDAudioTrack(_decoder); + addTrack(_audioTrack); + } + + return true; +} + +void AdvancedVMDDecoder::close() { + AdvancedVideoDecoder::close(); + _decoder->close(); +} + +AdvancedVMDDecoder::VMDVideoTrack::VMDVideoTrack(VMDDecoder *decoder) : _decoder(decoder) { +} + +uint16 AdvancedVMDDecoder::VMDVideoTrack::getWidth() const { + return _decoder->getWidth(); +} + +uint16 AdvancedVMDDecoder::VMDVideoTrack::getHeight() const { + return _decoder->getHeight(); +} + +Graphics::PixelFormat AdvancedVMDDecoder::VMDVideoTrack::getPixelFormat() const { + return _decoder->getPixelFormat(); +} + +int AdvancedVMDDecoder::VMDVideoTrack::getCurFrame() const { + return _decoder->getCurFrame(); +} + +int AdvancedVMDDecoder::VMDVideoTrack::getFrameCount() const { + return _decoder->getFrameCount(); +} + +const Graphics::Surface *AdvancedVMDDecoder::VMDVideoTrack::decodeNextFrame() { + return _decoder->decodeNextFrame(); +} + +const byte *AdvancedVMDDecoder::VMDVideoTrack::getPalette() const { + return _decoder->getPalette(); +} + +bool AdvancedVMDDecoder::VMDVideoTrack::hasDirtyPalette() const { + return _decoder->hasDirtyPalette(); +} + +Common::Rational AdvancedVMDDecoder::VMDVideoTrack::getFrameRate() const { + return _decoder->getFrameRate(); +} + +AdvancedVMDDecoder::VMDAudioTrack::VMDAudioTrack(VMDDecoder *decoder) : _decoder(decoder) { +} + +Audio::Mixer::SoundType AdvancedVMDDecoder::VMDAudioTrack::getSoundType() const { + return _decoder->_soundType; } -void VMDDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); +Audio::AudioStream *AdvancedVMDDecoder::VMDAudioTrack::getAudioStream() const { + return _decoder->_audioStream; } } // End of namespace Video diff --git a/video/coktel_decoder.h b/video/coktel_decoder.h index c88d982191..117a55658f 100644 --- a/video/coktel_decoder.h +++ b/video/coktel_decoder.h @@ -64,7 +64,7 @@ class Codec; * - gob * - sci */ -class CoktelDecoder : public FixedRateVideoDecoder { +class CoktelDecoder { public: struct State { /** Set accordingly to what was done. */ @@ -77,7 +77,7 @@ public: CoktelDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); - ~CoktelDecoder(); + virtual ~CoktelDecoder(); /** Replace the current video stream with this identical one. */ virtual bool reloadStream(Common::SeekableReadStream *stream) = 0; @@ -138,21 +138,47 @@ public: /** Is the video paletted or true color? */ virtual bool isPaletted() const; + /** + * Get the current frame + * @see VideoDecoder::getCurFrame() + */ + int getCurFrame() const; - // VideoDecoder interface + /** + * Decode the next frame + * @see VideoDecoder::decodeNextFrame() + */ + virtual const Graphics::Surface *decodeNextFrame() = 0; + /** + * Load a video from a stream + * @see VideoDecoder::loadStream() + */ + virtual bool loadStream(Common::SeekableReadStream *stream) = 0; + + /** Has a video been loaded? */ + virtual bool isVideoLoaded() const = 0; + + /** Has the end of the video been reached? */ + bool endOfVideo() const; + + /** Close the video. */ void close(); uint16 getWidth() const; uint16 getHeight() const; + virtual Graphics::PixelFormat getPixelFormat() const = 0; uint32 getFrameCount() const; const byte *getPalette(); bool hasDirtyPalette() const; + uint32 getTimeToNextFrame() const; uint32 getStaticTimeToNextFrame() const; + void pauseVideo(bool pause); + protected: enum SoundStage { kSoundNone = 0, ///< No sound. @@ -186,8 +212,11 @@ protected: uint32 _features; + int32 _curFrame; uint32 _frameCount; + uint32 _startTime; + byte _palette[768]; bool _paletteDirty; @@ -208,6 +237,8 @@ protected: bool evaluateSeekFrame(int32 &frame, int whence) const; + Common::Rational getFrameRate() const; + // Surface management bool hasSurface(); void createSurface(); @@ -228,10 +259,9 @@ protected: // Sound helper functions inline void unsignedToSigned(byte *buffer, int length); - - // FixedRateVideoDecoder interface - - Common::Rational getFrameRate() const; +private: + uint32 _pauseStartTime; + bool _isPaused; }; class PreIMDDecoder : public CoktelDecoder { @@ -244,9 +274,6 @@ public: bool seek(int32 frame, int whence = SEEK_SET, bool restart = false); - - // VideoDecoder interface - bool loadStream(Common::SeekableReadStream *stream); void close(); @@ -279,9 +306,6 @@ public: void setXY(uint16 x, uint16 y); - - // VideoDecoder interface - bool loadStream(Common::SeekableReadStream *stream); void close(); @@ -291,11 +315,6 @@ public: Graphics::PixelFormat getPixelFormat() const; -protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - private: enum Command { kCommandNextSound = 0xFF00, @@ -367,6 +386,8 @@ private: }; class VMDDecoder : public CoktelDecoder { +friend class AdvancedVMDDecoder; + public: VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); ~VMDDecoder(); @@ -390,9 +411,6 @@ public: bool hasVideo() const; bool isPaletted() const; - - // VideoDecoder interface - bool loadStream(Common::SeekableReadStream *stream); void close(); @@ -403,9 +421,7 @@ public: Graphics::PixelFormat getPixelFormat() const; protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void setAutoStartSound(bool autoStartSound); private: enum PartType { @@ -478,6 +494,7 @@ private: uint32 _soundDataSize; uint32 _soundLastFilledFrame; AudioFormat _audioFormat; + bool _autoStartSound; // Video properties bool _hasVideo; @@ -532,6 +549,57 @@ private: bool getPartCoords(int16 frame, PartType type, int16 &x, int16 &y, int16 &width, int16 &height); }; +/** + * A wrapper around the VMD code that implements the AdvancedVideoDecoder + * API. + */ +class AdvancedVMDDecoder : public AdvancedVideoDecoder { +public: + AdvancedVMDDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + ~AdvancedVMDDecoder(); + + bool loadStream(Common::SeekableReadStream *stream); + void close(); + +private: + class VMDVideoTrack : public FixedRateVideoTrack { + public: + VMDVideoTrack(VMDDecoder *decoder); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const; + int getFrameCount() const; + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const; + bool hasDirtyPalette() const; + + protected: + Common::Rational getFrameRate() const; + + private: + VMDDecoder *_decoder; + }; + + class VMDAudioTrack : public AudioTrack { + public: + VMDAudioTrack(VMDDecoder *decoder); + + Audio::Mixer::SoundType getSoundType() const; + + protected: + virtual Audio::AudioStream *getAudioStream() const; + + private: + VMDDecoder *_decoder; + }; + + VMDDecoder *_decoder; + VMDVideoTrack *_videoTrack; + VMDAudioTrack *_audioTrack; +}; + } // End of namespace Video #endif // VIDEO_COKTELDECODER_H -- cgit v1.2.3 From 9e7f0e4753636ace510d626be4b0ee22ab682269 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 16 Aug 2012 12:27:05 -0400 Subject: VIDEO: Begin removing some of the deprecated functions from VideoDecoder --- video/video_decoder.cpp | 40 +++++----------------------------------- video/video_decoder.h | 37 ++----------------------------------- 2 files changed, 7 insertions(+), 70 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 0108888613..a7d3789b65 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -34,7 +34,10 @@ namespace Video { VideoDecoder::VideoDecoder() { - reset(); + _startTime = 0; + _pauseLevel = 0; + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; } bool VideoDecoder::loadFile(const Common::String &filename) { @@ -74,7 +77,7 @@ void VideoDecoder::pauseVideo(bool pause) { pauseVideoIntern(true); } else if (_pauseLevel == 0) { pauseVideoIntern(false); - addPauseTime(g_system->getMillis() - _pauseStartTime); + _startTime += (g_system->getMillis() - _pauseStartTime); } } @@ -701,41 +704,8 @@ void AdvancedVideoDecoder::startAudioLimit(const Audio::Timestamp &limit) { ///////////////// DEPRECATED ///////////////// ////////////////////////////////////////////// -void VideoDecoder::reset() { - _curFrame = -1; - _startTime = 0; - _pauseLevel = 0; - _audioVolume = Audio::Mixer::kMaxChannelVolume; - _audioBalance = 0; -} - -bool VideoDecoder::endOfVideo() const { - return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1); -} - void VideoDecoder::setSystemPalette() { g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); } -uint32 FixedRateVideoDecoder::getTimeToNextFrame() const { - if (endOfVideo() || _curFrame < 0) - return 0; - - uint32 elapsedTime = getTime(); - uint32 nextFrameStartTime = getFrameBeginTime(_curFrame + 1); - - // If the time that the next frame should be shown has past - // the frame should be shown ASAP. - if (nextFrameStartTime <= elapsedTime) - return 0; - - return nextFrameStartTime - elapsedTime; -} - -uint32 FixedRateVideoDecoder::getFrameBeginTime(uint32 frame) const { - Common::Rational beginTime = frame * 1000; - beginTime /= getFrameRate(); - return beginTime.toInt(); -} - } // End of namespace Video diff --git a/video/video_decoder.h b/video/video_decoder.h index 7e89caee40..0135425bac 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -124,7 +124,7 @@ public: * Returns the current frame number of the video. * @return the last frame decoded by the video */ - virtual int32 getCurFrame() const { return _curFrame; } + virtual int32 getCurFrame() const = 0; /** * Returns the number of frames in the video. @@ -173,7 +173,7 @@ public: * Returns if the video has finished playing or not. * @return true if the video has finished playing or if none is loaded, false otherwise */ - virtual bool endOfVideo() const; + virtual bool endOfVideo() const = 0; /** * Pause or resume the video. This should stop/resume any audio playback @@ -228,12 +228,6 @@ public: virtual void setBalance(int8 balance); protected: - /** - * Resets _curFrame and _startTime. Should be called from every close() function. - * @note This function is now deprecated. There is no replacement. - */ - void reset(); - /** * Actual implementation of pause by subclasses. See pause() * for details. @@ -241,12 +235,6 @@ protected: */ virtual void pauseVideoIntern(bool pause) {} - /** - * Add the time the video has been paused to maintain sync - * @note This function is now deprecated. There is no replacement. - */ - virtual void addPauseTime(uint32 ms) { _startTime += ms; } - /** * Reset the pause start time (which should be called when seeking) */ @@ -264,7 +252,6 @@ protected: */ virtual void updateBalance() {} - int32 _curFrame; // This variable is now deprecated. int32 _startTime; // FIXME: These are protected until the new API takes over this one @@ -797,26 +784,6 @@ private: void startAudioLimit(const Audio::Timestamp &limit); }; -/** - * A VideoDecoder wrapper that implements getTimeToNextFrame() based on getFrameRate(). - * @note This class is now deprecated. Use AdvancedVideoDecoder instead. - */ -class FixedRateVideoDecoder : public virtual VideoDecoder { -public: - uint32 getTimeToNextFrame() const; - -protected: - /** - * Return the frame rate in frames per second. - * This returns a Rational because videos can have rates that are not integers and - * there are some videos with frame rates < 1. - */ - virtual Common::Rational getFrameRate() const = 0; - -private: - uint32 getFrameBeginTime(uint32 frame) const; -}; - } // End of namespace Video #endif -- cgit v1.2.3 From fb35c7f46f986a22235638e2946ba8492e735109 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 16 Aug 2012 13:30:32 -0400 Subject: VIDEO: Remove setSystemPalette() --- engines/agos/animation.cpp | 4 ++-- engines/mohawk/video.cpp | 3 ++- engines/saga/introproc_saga2.cpp | 3 ++- engines/sci/graphics/frameout.cpp | 5 +++-- engines/sword1/animation.cpp | 2 +- engines/sword2/animation.cpp | 4 +++- engines/toon/movie.cpp | 3 ++- video/video_decoder.cpp | 8 -------- video/video_decoder.h | 7 ------- 9 files changed, 15 insertions(+), 24 deletions(-) diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index ec8293c91f..8fc93e4153 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -278,7 +278,7 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } while (--h); if (hasDirtyPalette()) - setSystemPalette(); + g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); } void MoviePlayerDXA::playVideo() { @@ -445,7 +445,7 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } while (--h); if (hasDirtyPalette()) - setSystemPalette(); + g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); } void MoviePlayerSMK::playVideo() { diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 5b811382ff..13adfcb1cd 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -29,6 +29,7 @@ #include "common/textconsole.h" #include "common/system.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "video/qt_decoder.h" @@ -238,7 +239,7 @@ bool VideoManager::updateMovies() { frame = convertedFrame; } else if (pixelFormat.bytesPerPixel == 1 && _videoStreams[i]->hasDirtyPalette()) { // Set the palette when running in 8bpp mode only - _videoStreams[i]->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_videoStreams[i]->getPalette(), 0, 256); } // Clip the width/height to make sure we stay on the screen (Myst does this a few times) diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp index 15f7f4dc15..260eca98e6 100644 --- a/engines/saga/introproc_saga2.cpp +++ b/engines/saga/introproc_saga2.cpp @@ -32,6 +32,7 @@ #include "common/keyboard.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "video/smk_decoder.h" @@ -110,7 +111,7 @@ void Scene::playMovie(const char *filename) { _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (smkDecoder->hasDirtyPalette()) - smkDecoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(smkDecoder->getPalette(), 0, 256); _vm->_system->updateScreen(); } diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index fedae2eb6f..0056f6c78b 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -28,6 +28,7 @@ #include "common/system.h" #include "common/textconsole.h" #include "engines/engine.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "sci/sci.h" @@ -494,7 +495,7 @@ void GfxFrameout::showVideo() { uint16 y = videoDecoder->getPos().y; if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { @@ -503,7 +504,7 @@ void GfxFrameout::showVideo() { g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); g_system->updateScreen(); } diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 70f1e5dc03..98725a302a 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -312,7 +312,7 @@ bool MoviePlayer::playVideo() { } if (_decoder->hasDirtyPalette()) { - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); if (!_movieTexts.empty()) { // Look for the best color indexes to use to display the subtitles diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index e603925e73..24b52cd85a 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -38,6 +38,8 @@ #include "sword2/screen.h" #include "sword2/animation.h" +#include "graphics/palette.h" + #include "gui/message.h" #include "video/dxa_decoder.h" @@ -330,7 +332,7 @@ bool MoviePlayer::playVideo() { } if (_decoder->hasDirtyPalette()) { - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); uint32 maxWeight = 0; uint32 minWeight = 0xFFFFFFFF; diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index d988a3ed60..8c85e20f7c 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -25,6 +25,7 @@ #include "common/keyboard.h" #include "common/stream.h" #include "common/system.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "toon/audio.h" @@ -126,7 +127,7 @@ bool Movie::playVideo(bool isFirstIntroVideo) { } } } - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); _vm->_system->updateScreen(); } diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index a7d3789b65..1ead6af54e 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -700,12 +700,4 @@ void AdvancedVideoDecoder::startAudioLimit(const Audio::Timestamp &limit) { ((AudioTrack *)*it)->start(limit); } -////////////////////////////////////////////// -///////////////// DEPRECATED ///////////////// -////////////////////////////////////////////// - -void VideoDecoder::setSystemPalette() { - g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); -} - } // End of namespace Video diff --git a/video/video_decoder.h b/video/video_decoder.h index 0135425bac..72be634f17 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -113,13 +113,6 @@ public: */ virtual bool hasDirtyPalette() const { return false; } - /** - * Set the system palette to the palette returned by getPalette. - * @see getPalette - * @note This function is now deprecated. There is no replacement. - */ - void setSystemPalette(); - /** * Returns the current frame number of the video. * @return the last frame decoded by the video -- cgit v1.2.3 From 7569ec7dc00e95e0643cde7f413a7cf46a4770f0 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 16 Aug 2012 13:34:28 -0400 Subject: VIDEO: Rename setStopTime() to setEndTime() To better differentiate with stop() --- engines/mohawk/video.cpp | 2 +- video/video_decoder.cpp | 26 +++++++++++++------------- video/video_decoder.h | 10 +++++----- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 13adfcb1cd..0ed4f38b53 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -514,7 +514,7 @@ bool VideoManager::isVideoPlaying() { void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end) { assert(handle != NULL_VID_HANDLE); _videoStreams[handle].start = start; - _videoStreams[handle]->setStopTime(end); + _videoStreams[handle]->setEndTime(end); _videoStreams[handle]->seek(start); } diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 1ead6af54e..fc4d7e1ae7 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -106,8 +106,8 @@ AdvancedVideoDecoder::AdvancedVideoDecoder() { _pauseLevel = 0; _needsUpdate = false; _lastTimeChange = 0; - _stopTime = 0; - _stopTimeSet = false; + _endTime = 0; + _endTimeSet = false; // Find the best format for output _defaultHighColorFormat = g_system->getScreenFormat(); @@ -133,8 +133,8 @@ void AdvancedVideoDecoder::close() { _pauseLevel = 0; _needsUpdate = false; _lastTimeChange = 0; - _stopTime = 0; - _stopTimeSet = false; + _endTime = 0; + _endTimeSet = false; } bool AdvancedVideoDecoder::isVideoLoaded() const { @@ -254,10 +254,10 @@ bool AdvancedVideoDecoder::endOfVideo() const { if (!isVideoLoaded()) return true; - if (_stopTimeSet) { + if (_endTimeSet) { const VideoTrack *track = findNextVideoTrack(); - if (track && track->getNextFrameStartTime() >= (uint)_stopTime.msecs()) + if (track && track->getNextFrameStartTime() >= (uint)_endTime.msecs()) return true; } @@ -592,7 +592,7 @@ bool AdvancedVideoDecoder::addStreamFileTrack(const Common::String &baseName) { return result; } -void AdvancedVideoDecoder::setStopTime(const Audio::Timestamp &stopTime) { +void AdvancedVideoDecoder::setEndTime(const Audio::Timestamp &endTime) { Audio::Timestamp startTime = 0; if (isPlaying()) { @@ -600,17 +600,17 @@ void AdvancedVideoDecoder::setStopTime(const Audio::Timestamp &stopTime) { stopAudio(); } - _stopTime = stopTime; - _stopTimeSet = true; + _endTime = endTime; + _endTimeSet = true; - if (startTime > stopTime) + if (startTime > endTime) return; if (isPlaying()) { // We'll assume the audio track is going to start up at the same time it just was // and therefore not do any seeking. // Might want to set it anyway if we're seekable. - startAudioLimit(_stopTime.msecs() - startTime.msecs()); + startAudioLimit(_endTime.msecs() - startTime.msecs()); _lastTimeChange = startTime; } } @@ -676,10 +676,10 @@ const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack } void AdvancedVideoDecoder::startAudio() { - if (_stopTimeSet) { + if (_endTimeSet) { // HACK: Timestamp's subtraction asserts out when subtracting two times // with different rates. - startAudioLimit(_stopTime - _lastTimeChange.convertToFramerate(_stopTime.framerate())); + startAudioLimit(_endTime - _lastTimeChange.convertToFramerate(_endTime.framerate())); return; } diff --git a/video/video_decoder.h b/video/video_decoder.h index 72be634f17..d6cfcde0b4 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -360,15 +360,15 @@ public: void setDefaultHighColorFormat(const Graphics::PixelFormat &format) { _defaultHighColorFormat = format; } /** - * Set the time for this video to stop at. At this time in the video, + * Set the time for this video to end at. At this time in the video, * all audio will stop and endOfVideo() will return true. */ - void setStopTime(const Audio::Timestamp &stopTime); + void setEndTime(const Audio::Timestamp &endTime); /** * Get the stop time of the video (if not set, zero) */ - Audio::Timestamp getStopTime() const { return _stopTime; } + Audio::Timestamp getEndTime() const { return _endTime; } // Future API //void setRate(const Common::Rational &rate); @@ -761,8 +761,8 @@ private: // Current playback status bool _isPlaying, _needsRewind, _needsUpdate; - Audio::Timestamp _lastTimeChange, _stopTime; - bool _stopTimeSet; + Audio::Timestamp _lastTimeChange, _endTime; + bool _endTimeSet; // Palette settings from individual tracks mutable bool _dirtyPalette; -- cgit v1.2.3 From 18823198ad4e7dedd0ca33760eb453e9fe673551 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 16 Aug 2012 14:00:14 -0400 Subject: VIDEO: Merge AdvancedVideoDecoder into VideoDecoder --- engines/agos/animation.cpp | 2 +- engines/mohawk/video.h | 4 +- engines/sci/console.cpp | 2 - engines/sci/engine/kvideo.cpp | 2 +- engines/sci/video/robot_decoder.cpp | 2 +- engines/sci/video/robot_decoder.h | 2 +- engines/sci/video/seq_decoder.h | 2 +- engines/scumm/he/animation_he.cpp | 4 +- engines/sword1/animation.cpp | 6 +- engines/sword2/animation.cpp | 6 +- video/avi_decoder.cpp | 2 +- video/avi_decoder.h | 2 +- video/bink_decoder.cpp | 2 +- video/bink_decoder.h | 2 +- video/coktel_decoder.cpp | 2 +- video/coktel_decoder.h | 4 +- video/dxa_decoder.h | 2 +- video/flic_decoder.h | 2 +- video/psx_decoder.cpp | 2 +- video/psx_decoder.h | 2 +- video/qt_decoder.cpp | 6 +- video/qt_decoder.h | 2 +- video/smk_decoder.cpp | 4 +- video/smk_decoder.h | 2 +- video/theora_decoder.cpp | 2 +- video/theora_decoder.h | 2 +- video/video_decoder.cpp | 219 ++++++++++++++++-------------------- video/video_decoder.h | 123 +++++--------------- 28 files changed, 164 insertions(+), 250 deletions(-) diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 8fc93e4153..10f274b37f 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -342,7 +342,7 @@ bool MoviePlayerDXA::processFrame() { _vm->_system->unlockScreen(); uint32 soundTime = _mixer->getSoundElapsedTime(_bgSound); - uint32 nextFrameStartTime = ((Video::AdvancedVideoDecoder::VideoTrack *)getTrack(0))->getNextFrameStartTime(); + uint32 nextFrameStartTime = ((Video::VideoDecoder::VideoTrack *)getTrack(0))->getNextFrameStartTime(); if ((_bgSoundStream == NULL) || soundTime < nextFrameStartTime) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 4e34604bfd..9dddcde09b 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -45,7 +45,7 @@ struct MLSTRecord { struct VideoEntry { // Playback variables - Video::AdvancedVideoDecoder *video; + Video::VideoDecoder *video; uint16 x; uint16 y; bool loop; @@ -57,7 +57,7 @@ struct VideoEntry { int id; // Internal Mohawk files // Helper functions - Video::AdvancedVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually + Video::VideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually void clear(); bool endOfVideo(); }; diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index de852ca9c0..1889d53480 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -267,8 +267,6 @@ void Console::postEnter() { } if (videoDecoder && videoDecoder->loadFile(_videoFile)) { - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); - _engine->_gfxCursor->kernelHide(); #ifdef ENABLE_SCI32 diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 3e0f35c037..6bf9aff2fe 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -50,7 +50,7 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { if (!videoDecoder) return; - ((Video::AdvancedVideoDecoder *)videoDecoder)->start(); + videoDecoder->start(); byte *scaleBuffer = 0; byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel; diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp index 6fe4c645f4..608c77136f 100644 --- a/engines/sci/video/robot_decoder.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -132,7 +132,7 @@ bool RobotDecoder::load(GuiResourceId id) { } void RobotDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); delete _fileStream; _fileStream = 0; diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h index de5b669ab8..ebc3262939 100644 --- a/engines/sci/video/robot_decoder.h +++ b/engines/sci/video/robot_decoder.h @@ -37,7 +37,7 @@ class SeekableSubReadStreamEndian; namespace Sci { -class RobotDecoder : public Video::AdvancedVideoDecoder { +class RobotDecoder : public Video::VideoDecoder { public: RobotDecoder(bool isBigEndian); virtual ~RobotDecoder(); diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h index 82254990d6..890f349feb 100644 --- a/engines/sci/video/seq_decoder.h +++ b/engines/sci/video/seq_decoder.h @@ -40,7 +40,7 @@ namespace Sci { /** * Implementation of the Sierra SEQ decoder, used in KQ6 DOS floppy/CD and GK1 DOS */ -class SEQDecoder : public Video::AdvancedVideoDecoder { +class SEQDecoder : public Video::VideoDecoder { public: SEQDecoder(uint frameDelay); virtual ~SEQDecoder(); diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 8329511c14..be17a3b305 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -62,14 +62,14 @@ int MoviePlayer::load(const char *filename, int flags, int image) { _video->close(); // Ensure that Bink will use our PixelFormat - ((Video::AdvancedVideoDecoder *)_video)->setDefaultHighColorFormat(g_system->getScreenFormat()); + _video->setDefaultHighColorFormat(g_system->getScreenFormat()); if (!_video->loadFile(filename)) { warning("Failed to load video file %s", filename); return -1; } - ((Video::AdvancedVideoDecoder *)_video)->start(); + _video->start(); debug(1, "Playing video %s", filename); diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index 98725a302a..f7add4eed2 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -183,7 +183,7 @@ bool MoviePlayer::load(uint32 id) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { - ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + _decoder->start(); return true; } else { initGraphics(g_system->getWidth(), g_system->getHeight(), true); @@ -197,9 +197,9 @@ bool MoviePlayer::load(uint32 id) { // For DXA, also add the external sound file if (_decoderType == kVideoDecoderDXA) - ((Video::AdvancedVideoDecoder *)_decoder)->addStreamFileTrack(sequenceList[id]); + _decoder->addStreamFileTrack(sequenceList[id]); - ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + _decoder->start(); return true; } diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 24b52cd85a..00260f789a 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -95,7 +95,7 @@ bool MoviePlayer::load(const char *name) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { - ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + _decoder->start(); return true; } else { initGraphics(640, 480, true); @@ -108,9 +108,9 @@ bool MoviePlayer::load(const char *name) { // For DXA, also add the external sound file if (_decoderType == kVideoDecoderDXA) - ((Video::AdvancedVideoDecoder *)_decoder)->addStreamFileTrack(name); + _decoder->addStreamFileTrack(name); - ((Video::AdvancedVideoDecoder *)_decoder)->start(); // TODO: Remove after new API is complete + _decoder->start(); return true; } diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 375cc6f0f3..0850d5656a 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -289,7 +289,7 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { } void AVIDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); delete _fileStream; _fileStream = 0; diff --git a/video/avi_decoder.h b/video/avi_decoder.h index 010702cce3..a3a262db36 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -53,7 +53,7 @@ class Codec; * Video decoder used in engines: * - sci */ -class AVIDecoder : public AdvancedVideoDecoder { +class AVIDecoder : public VideoDecoder { public: AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); virtual ~AVIDecoder(); diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index cac0b356c5..620316806f 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -147,7 +147,7 @@ bool BinkDecoder::loadStream(Common::SeekableReadStream *stream) { } void BinkDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); delete _bink; _bink = 0; diff --git a/video/bink_decoder.h b/video/bink_decoder.h index 836238ce99..150e91aab7 100644 --- a/video/bink_decoder.h +++ b/video/bink_decoder.h @@ -62,7 +62,7 @@ namespace Video { * Video decoder used in engines: * - scumm (he) */ -class BinkDecoder : public AdvancedVideoDecoder { +class BinkDecoder : public VideoDecoder { public: BinkDecoder(); ~BinkDecoder(); diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp index 42033fb01f..6a60b0e7d7 100644 --- a/video/coktel_decoder.cpp +++ b/video/coktel_decoder.cpp @@ -2800,7 +2800,7 @@ bool AdvancedVMDDecoder::loadStream(Common::SeekableReadStream *stream) { } void AdvancedVMDDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); _decoder->close(); } diff --git a/video/coktel_decoder.h b/video/coktel_decoder.h index 117a55658f..2a97eadf00 100644 --- a/video/coktel_decoder.h +++ b/video/coktel_decoder.h @@ -550,10 +550,10 @@ private: }; /** - * A wrapper around the VMD code that implements the AdvancedVideoDecoder + * A wrapper around the VMD code that implements the VideoDecoder * API. */ -class AdvancedVMDDecoder : public AdvancedVideoDecoder { +class AdvancedVMDDecoder : public VideoDecoder { public: AdvancedVMDDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); ~AdvancedVMDDecoder(); diff --git a/video/dxa_decoder.h b/video/dxa_decoder.h index a0caca4b95..b3f2eca5e2 100644 --- a/video/dxa_decoder.h +++ b/video/dxa_decoder.h @@ -41,7 +41,7 @@ namespace Video { * - sword1 * - sword2 */ -class DXADecoder : public AdvancedVideoDecoder { +class DXADecoder : public VideoDecoder { public: DXADecoder(); virtual ~DXADecoder(); diff --git a/video/flic_decoder.h b/video/flic_decoder.h index 9b82161ca5..9037af05d6 100644 --- a/video/flic_decoder.h +++ b/video/flic_decoder.h @@ -44,7 +44,7 @@ namespace Video { * Video decoder used in engines: * - tucker */ -class FlicDecoder : public AdvancedVideoDecoder { +class FlicDecoder : public VideoDecoder { public: FlicDecoder(); virtual ~FlicDecoder(); diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp index 93bf711c25..fa7f1e8cfe 100644 --- a/video/psx_decoder.cpp +++ b/video/psx_decoder.cpp @@ -174,7 +174,7 @@ bool PSXStreamDecoder::loadStream(Common::SeekableReadStream *stream) { } void PSXStreamDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); _audioTrack = 0; _videoTrack = 0; _frameCount = 0; diff --git a/video/psx_decoder.h b/video/psx_decoder.h index 2a9dedf77f..11f311594d 100644 --- a/video/psx_decoder.h +++ b/video/psx_decoder.h @@ -56,7 +56,7 @@ namespace Video { * - sword1 (psx) * - sword2 (psx) */ -class PSXStreamDecoder : public AdvancedVideoDecoder { +class PSXStreamDecoder : public VideoDecoder { public: // CD speed in sectors/second // Calling code should use these enum values instead of the constants diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp index 70dcdff9c6..87c530dba0 100644 --- a/video/qt_decoder.cpp +++ b/video/qt_decoder.cpp @@ -79,7 +79,7 @@ bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) { } void QuickTimeDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); Common::QuickTimeParser::close(); if (_scaledSurface) { @@ -90,7 +90,7 @@ void QuickTimeDecoder::close() { } const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() { - const Graphics::Surface *frame = AdvancedVideoDecoder::decodeNextFrame(); + const Graphics::Surface *frame = VideoDecoder::decodeNextFrame(); // Update audio buffers too // (needs to be done after we find the next track) @@ -244,7 +244,7 @@ void QuickTimeDecoder::init() { void QuickTimeDecoder::updateAudioBuffer() { // Updates the audio buffers for all audio tracks for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) - if ((*it)->getTrackType() == AdvancedVideoDecoder::Track::kTrackTypeAudio) + if ((*it)->getTrackType() == VideoDecoder::Track::kTrackTypeAudio) ((AudioTrackHandler *)*it)->updateBuffer(); } diff --git a/video/qt_decoder.h b/video/qt_decoder.h index 7a251b8580..71d33711a6 100644 --- a/video/qt_decoder.h +++ b/video/qt_decoder.h @@ -55,7 +55,7 @@ class Codec; * - mohawk * - sci */ -class QuickTimeDecoder : public AdvancedVideoDecoder, public Audio::QuickTimeAudioDecoder { +class QuickTimeDecoder : public VideoDecoder, public Audio::QuickTimeAudioDecoder { public: QuickTimeDecoder(); virtual ~QuickTimeDecoder(); diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp index d707ad519f..d01ec730f4 100644 --- a/video/smk_decoder.cpp +++ b/video/smk_decoder.cpp @@ -396,7 +396,7 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { } void SmackerDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); delete _fileStream; _fileStream = 0; @@ -411,7 +411,7 @@ void SmackerDecoder::close() { bool SmackerDecoder::rewind() { // Call the parent method to rewind the tracks first // In particular, only videos without sound can be rewound - if (!AdvancedVideoDecoder::rewind()) + if (!VideoDecoder::rewind()) return false; // And seek back to where the first frame begins diff --git a/video/smk_decoder.h b/video/smk_decoder.h index 78a4ded0fc..6bded64a37 100644 --- a/video/smk_decoder.h +++ b/video/smk_decoder.h @@ -57,7 +57,7 @@ class BigHuffmanTree; * - sword2 * - toon */ -class SmackerDecoder : public AdvancedVideoDecoder { +class SmackerDecoder : public VideoDecoder { public: SmackerDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); virtual ~SmackerDecoder(); diff --git a/video/theora_decoder.cpp b/video/theora_decoder.cpp index 76007eadff..d7260469e6 100644 --- a/video/theora_decoder.cpp +++ b/video/theora_decoder.cpp @@ -198,7 +198,7 @@ bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { } void TheoraDecoder::close() { - AdvancedVideoDecoder::close(); + VideoDecoder::close(); if (!_fileStream) return; diff --git a/video/theora_decoder.h b/video/theora_decoder.h index 2244f7550d..7e36d829e7 100644 --- a/video/theora_decoder.h +++ b/video/theora_decoder.h @@ -52,7 +52,7 @@ namespace Video { * Video decoder used in engines: * - sword25 */ -class TheoraDecoder : public AdvancedVideoDecoder { +class TheoraDecoder : public VideoDecoder { public: TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); virtual ~TheoraDecoder(); diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index fc4d7e1ae7..cf11649c10 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -35,9 +35,44 @@ namespace Video { VideoDecoder::VideoDecoder() { _startTime = 0; + _needsRewind = false; + _dirtyPalette = false; + _palette = 0; + _isPlaying = false; + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; _pauseLevel = 0; + _needsUpdate = false; + _lastTimeChange = 0; + _endTime = 0; + _endTimeSet = false; + + // Find the best format for output + _defaultHighColorFormat = g_system->getScreenFormat(); + + if (_defaultHighColorFormat.bytesPerPixel == 1) + _defaultHighColorFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); +} + +void VideoDecoder::close() { + if (isPlaying()) + stop(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + delete *it; + + _tracks.clear(); + _needsRewind = false; + _dirtyPalette = false; + _palette = 0; + _startTime = 0; _audioVolume = Audio::Mixer::kMaxChannelVolume; _audioBalance = 0; + _pauseLevel = 0; + _needsUpdate = false; + _lastTimeChange = 0; + _endTime = 0; + _endTimeSet = false; } bool VideoDecoder::loadFile(const Common::String &filename) { @@ -51,10 +86,6 @@ bool VideoDecoder::loadFile(const Common::String &filename) { return loadStream(file); } -uint32 VideoDecoder::getTime() const { - return g_system->getMillis() - _startTime; -} - bool VideoDecoder::needsUpdate() const { return !endOfVideo() && getTimeToNextFrame() == 0; } @@ -74,9 +105,13 @@ void VideoDecoder::pauseVideo(bool pause) { if (_pauseLevel == 1 && pause) { _pauseStartTime = g_system->getMillis(); // Store the starting time from pausing to keep it for later - pauseVideoIntern(true); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->pause(true); } else if (_pauseLevel == 0) { - pauseVideoIntern(false); + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->pause(false); + _startTime += (g_system->getMillis() - _pauseStartTime); } } @@ -88,60 +123,25 @@ void VideoDecoder::resetPauseStartTime() { void VideoDecoder::setVolume(byte volume) { _audioVolume = volume; - updateVolume(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->setVolume(_audioVolume); } void VideoDecoder::setBalance(int8 balance) { _audioBalance = balance; - updateBalance(); -} - -AdvancedVideoDecoder::AdvancedVideoDecoder() { - _needsRewind = false; - _dirtyPalette = false; - _palette = 0; - _isPlaying = false; - _audioVolume = Audio::Mixer::kMaxChannelVolume; - _audioBalance = 0; - _pauseLevel = 0; - _needsUpdate = false; - _lastTimeChange = 0; - _endTime = 0; - _endTimeSet = false; - - // Find the best format for output - _defaultHighColorFormat = g_system->getScreenFormat(); - - if (_defaultHighColorFormat.bytesPerPixel == 1) - _defaultHighColorFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); -} - -void AdvancedVideoDecoder::close() { - if (isPlaying()) - stop(); for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - delete *it; - - _tracks.clear(); - _needsRewind = false; - _dirtyPalette = false; - _palette = 0; - _startTime = 0; - _audioVolume = Audio::Mixer::kMaxChannelVolume; - _audioBalance = 0; - _pauseLevel = 0; - _needsUpdate = false; - _lastTimeChange = 0; - _endTime = 0; - _endTimeSet = false; + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->setBalance(_audioBalance); } -bool AdvancedVideoDecoder::isVideoLoaded() const { +bool VideoDecoder::isVideoLoaded() const { return !_tracks.empty(); } -uint16 AdvancedVideoDecoder::getWidth() const { +uint16 VideoDecoder::getWidth() const { for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeVideo) return ((VideoTrack *)*it)->getWidth(); @@ -149,7 +149,7 @@ uint16 AdvancedVideoDecoder::getWidth() const { return 0; } -uint16 AdvancedVideoDecoder::getHeight() const { +uint16 VideoDecoder::getHeight() const { for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeVideo) return ((VideoTrack *)*it)->getHeight(); @@ -157,7 +157,7 @@ uint16 AdvancedVideoDecoder::getHeight() const { return 0; } -Graphics::PixelFormat AdvancedVideoDecoder::getPixelFormat() const { +Graphics::PixelFormat VideoDecoder::getPixelFormat() const { for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeVideo) return ((VideoTrack *)*it)->getPixelFormat(); @@ -165,7 +165,7 @@ Graphics::PixelFormat AdvancedVideoDecoder::getPixelFormat() const { return Graphics::PixelFormat(); } -const Graphics::Surface *AdvancedVideoDecoder::decodeNextFrame() { +const Graphics::Surface *VideoDecoder::decodeNextFrame() { _needsUpdate = false; readNextPacket(); @@ -184,12 +184,12 @@ const Graphics::Surface *AdvancedVideoDecoder::decodeNextFrame() { return frame; } -const byte *AdvancedVideoDecoder::getPalette() { +const byte *VideoDecoder::getPalette() { _dirtyPalette = false; return _palette; } -int AdvancedVideoDecoder::getCurFrame() const { +int VideoDecoder::getCurFrame() const { int32 frame = -1; for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) @@ -199,7 +199,7 @@ int AdvancedVideoDecoder::getCurFrame() const { return frame; } -uint32 AdvancedVideoDecoder::getFrameCount() const { +uint32 VideoDecoder::getFrameCount() const { int count = 0; for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) @@ -209,7 +209,7 @@ uint32 AdvancedVideoDecoder::getFrameCount() const { return count; } -uint32 AdvancedVideoDecoder::getTime() const { +uint32 VideoDecoder::getTime() const { if (!isPlaying()) return _lastTimeChange.msecs(); @@ -230,7 +230,7 @@ uint32 AdvancedVideoDecoder::getTime() const { return g_system->getMillis() - _startTime; } -uint32 AdvancedVideoDecoder::getTimeToNextFrame() const { +uint32 VideoDecoder::getTimeToNextFrame() const { if (endOfVideo() || _needsUpdate) return 0; @@ -248,9 +248,7 @@ uint32 AdvancedVideoDecoder::getTimeToNextFrame() const { return nextFrameStartTime - elapsedTime; } -bool AdvancedVideoDecoder::endOfVideo() const { - // TODO: Bring _isPlaying into account? - +bool VideoDecoder::endOfVideo() const { if (!isVideoLoaded()) return true; @@ -268,7 +266,7 @@ bool AdvancedVideoDecoder::endOfVideo() const { return true; } -bool AdvancedVideoDecoder::isRewindable() const { +bool VideoDecoder::isRewindable() const { if (!isVideoLoaded()) return false; @@ -279,7 +277,7 @@ bool AdvancedVideoDecoder::isRewindable() const { return true; } -bool AdvancedVideoDecoder::rewind() { +bool VideoDecoder::rewind() { if (!isRewindable()) return false; @@ -303,7 +301,7 @@ bool AdvancedVideoDecoder::rewind() { return true; } -bool AdvancedVideoDecoder::isSeekable() const { +bool VideoDecoder::isSeekable() const { if (!isVideoLoaded()) return false; @@ -314,7 +312,7 @@ bool AdvancedVideoDecoder::isSeekable() const { return true; } -bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { +bool VideoDecoder::seek(const Audio::Timestamp &time) { if (!isSeekable()) return false; @@ -342,7 +340,7 @@ bool AdvancedVideoDecoder::seek(const Audio::Timestamp &time) { return true; } -void AdvancedVideoDecoder::start() { +void VideoDecoder::start() { if (isPlaying() || !isVideoLoaded()) return; @@ -360,7 +358,7 @@ void AdvancedVideoDecoder::start() { startAudio(); } -void AdvancedVideoDecoder::stop() { +void VideoDecoder::stop() { if (!isPlaying()) return; @@ -386,7 +384,7 @@ void AdvancedVideoDecoder::stop() { } } -Audio::Timestamp AdvancedVideoDecoder::getDuration() const { +Audio::Timestamp VideoDecoder::getDuration() const { Audio::Timestamp maxDuration(0, 1000); for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { @@ -399,42 +397,23 @@ Audio::Timestamp AdvancedVideoDecoder::getDuration() const { return maxDuration; } -void AdvancedVideoDecoder::pauseVideoIntern(bool pause) { - for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - (*it)->pause(pause); -} - -void AdvancedVideoDecoder::updateVolume() { - // For API compatibility only - for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - if ((*it)->getTrackType() == Track::kTrackTypeAudio) - ((AudioTrack *)*it)->setVolume(_audioVolume); -} - -void AdvancedVideoDecoder::updateBalance() { - // For API compatibility only - for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) - if ((*it)->getTrackType() == Track::kTrackTypeAudio) - ((AudioTrack *)*it)->setBalance(_audioBalance); -} - -AdvancedVideoDecoder::Track::Track() { +VideoDecoder::Track::Track() { _paused = false; } -bool AdvancedVideoDecoder::Track::isRewindable() const { +bool VideoDecoder::Track::isRewindable() const { return isSeekable(); } -bool AdvancedVideoDecoder::Track::rewind() { +bool VideoDecoder::Track::rewind() { return seek(Audio::Timestamp(0, 1000)); } -Audio::Timestamp AdvancedVideoDecoder::Track::getDuration() const { +Audio::Timestamp VideoDecoder::Track::getDuration() const { return Audio::Timestamp(0, 1000); } -uint32 AdvancedVideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { +uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { if (endOfTrack() || getCurFrame() < 0) return 0; @@ -443,11 +422,11 @@ uint32 AdvancedVideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const return time.toInt(); } -bool AdvancedVideoDecoder::FixedRateVideoTrack::endOfTrack() const { +bool VideoDecoder::FixedRateVideoTrack::endOfTrack() const { return getCurFrame() >= (getFrameCount() - 1); } -Audio::Timestamp AdvancedVideoDecoder::FixedRateVideoTrack::getDuration() const { +Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const { // Since Audio::Timestamp doesn't support a fractional frame rate, we're currently // just converting to milliseconds. Common::Rational time = getFrameCount() * 1000; @@ -455,26 +434,26 @@ Audio::Timestamp AdvancedVideoDecoder::FixedRateVideoTrack::getDuration() const return time.toInt(); } -bool AdvancedVideoDecoder::AudioTrack::endOfTrack() const { +bool VideoDecoder::AudioTrack::endOfTrack() const { Audio::AudioStream *stream = getAudioStream(); return !stream || !g_system->getMixer()->isSoundHandleActive(_handle) || stream->endOfData(); } -void AdvancedVideoDecoder::AudioTrack::setVolume(byte volume) { +void VideoDecoder::AudioTrack::setVolume(byte volume) { _volume = volume; if (g_system->getMixer()->isSoundHandleActive(_handle)) g_system->getMixer()->setChannelVolume(_handle, _volume); } -void AdvancedVideoDecoder::AudioTrack::setBalance(int8 balance) { +void VideoDecoder::AudioTrack::setBalance(int8 balance) { _balance = balance; if (g_system->getMixer()->isSoundHandleActive(_handle)) g_system->getMixer()->setChannelBalance(_handle, _balance); } -void AdvancedVideoDecoder::AudioTrack::start() { +void VideoDecoder::AudioTrack::start() { stop(); Audio::AudioStream *stream = getAudioStream(); @@ -487,11 +466,11 @@ void AdvancedVideoDecoder::AudioTrack::start() { g_system->getMixer()->pauseHandle(_handle, true); } -void AdvancedVideoDecoder::AudioTrack::stop() { +void VideoDecoder::AudioTrack::stop() { g_system->getMixer()->stopHandle(_handle); } -void AdvancedVideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) { +void VideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) { stop(); Audio::AudioStream *stream = getAudioStream(); @@ -506,60 +485,60 @@ void AdvancedVideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) { g_system->getMixer()->pauseHandle(_handle, true); } -uint32 AdvancedVideoDecoder::AudioTrack::getRunningTime() const { +uint32 VideoDecoder::AudioTrack::getRunningTime() const { if (g_system->getMixer()->isSoundHandleActive(_handle)) return g_system->getMixer()->getSoundElapsedTime(_handle); return 0; } -void AdvancedVideoDecoder::AudioTrack::pauseIntern(bool shouldPause) { +void VideoDecoder::AudioTrack::pauseIntern(bool shouldPause) { if (g_system->getMixer()->isSoundHandleActive(_handle)) g_system->getMixer()->pauseHandle(_handle, shouldPause); } -Audio::AudioStream *AdvancedVideoDecoder::RewindableAudioTrack::getAudioStream() const { +Audio::AudioStream *VideoDecoder::RewindableAudioTrack::getAudioStream() const { return getRewindableAudioStream(); } -bool AdvancedVideoDecoder::RewindableAudioTrack::rewind() { +bool VideoDecoder::RewindableAudioTrack::rewind() { Audio::RewindableAudioStream *stream = getRewindableAudioStream(); assert(stream); return stream->rewind(); } -Audio::Timestamp AdvancedVideoDecoder::SeekableAudioTrack::getDuration() const { +Audio::Timestamp VideoDecoder::SeekableAudioTrack::getDuration() const { Audio::SeekableAudioStream *stream = getSeekableAudioStream(); assert(stream); return stream->getLength(); } -Audio::AudioStream *AdvancedVideoDecoder::SeekableAudioTrack::getAudioStream() const { +Audio::AudioStream *VideoDecoder::SeekableAudioTrack::getAudioStream() const { return getSeekableAudioStream(); } -bool AdvancedVideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time) { +bool VideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time) { Audio::SeekableAudioStream *stream = getSeekableAudioStream(); assert(stream); return stream->seek(time); } -AdvancedVideoDecoder::StreamFileAudioTrack::StreamFileAudioTrack() { +VideoDecoder::StreamFileAudioTrack::StreamFileAudioTrack() { _stream = 0; } -AdvancedVideoDecoder::StreamFileAudioTrack::~StreamFileAudioTrack() { +VideoDecoder::StreamFileAudioTrack::~StreamFileAudioTrack() { delete _stream; } -bool AdvancedVideoDecoder::StreamFileAudioTrack::loadFromFile(const Common::String &baseName) { +bool VideoDecoder::StreamFileAudioTrack::loadFromFile(const Common::String &baseName) { // TODO: Make sure the stream isn't being played delete _stream; _stream = Audio::SeekableAudioStream::openStreamFile(baseName); return _stream != 0; } -void AdvancedVideoDecoder::addTrack(Track *track) { +void VideoDecoder::addTrack(Track *track) { _tracks.push_back(track); // Update volume settings if it's an audio track @@ -577,7 +556,7 @@ void AdvancedVideoDecoder::addTrack(Track *track) { ((AudioTrack *)track)->start(); } -bool AdvancedVideoDecoder::addStreamFileTrack(const Common::String &baseName) { +bool VideoDecoder::addStreamFileTrack(const Common::String &baseName) { // Only allow adding external tracks if a video is already loaded if (!isVideoLoaded()) return false; @@ -592,7 +571,7 @@ bool AdvancedVideoDecoder::addStreamFileTrack(const Common::String &baseName) { return result; } -void AdvancedVideoDecoder::setEndTime(const Audio::Timestamp &endTime) { +void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) { Audio::Timestamp startTime = 0; if (isPlaying()) { @@ -615,21 +594,21 @@ void AdvancedVideoDecoder::setEndTime(const Audio::Timestamp &endTime) { } } -AdvancedVideoDecoder::Track *AdvancedVideoDecoder::getTrack(uint track) { +VideoDecoder::Track *VideoDecoder::getTrack(uint track) { if (track > _tracks.size()) return 0; return _tracks[track]; } -const AdvancedVideoDecoder::Track *AdvancedVideoDecoder::getTrack(uint track) const { +const VideoDecoder::Track *VideoDecoder::getTrack(uint track) const { if (track > _tracks.size()) return 0; return _tracks[track]; } -bool AdvancedVideoDecoder::endOfVideoTracks() const { +bool VideoDecoder::endOfVideoTracks() const { for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) return false; @@ -637,7 +616,7 @@ bool AdvancedVideoDecoder::endOfVideoTracks() const { return true; } -AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() { +VideoDecoder::VideoTrack *VideoDecoder::findNextVideoTrack() { VideoTrack *bestTrack = 0; uint32 bestTime = 0xFFFFFFFF; @@ -656,7 +635,7 @@ AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() { return bestTrack; } -const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack() const { +const VideoDecoder::VideoTrack *VideoDecoder::findNextVideoTrack() const { const VideoTrack *bestTrack = 0; uint32 bestTime = 0xFFFFFFFF; @@ -675,7 +654,7 @@ const AdvancedVideoDecoder::VideoTrack *AdvancedVideoDecoder::findNextVideoTrack return bestTrack; } -void AdvancedVideoDecoder::startAudio() { +void VideoDecoder::startAudio() { if (_endTimeSet) { // HACK: Timestamp's subtraction asserts out when subtracting two times // with different rates. @@ -688,13 +667,13 @@ void AdvancedVideoDecoder::startAudio() { ((AudioTrack *)*it)->start(); } -void AdvancedVideoDecoder::stopAudio() { +void VideoDecoder::stopAudio() { for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeAudio) ((AudioTrack *)*it)->stop(); } -void AdvancedVideoDecoder::startAudioLimit(const Audio::Timestamp &limit) { +void VideoDecoder::startAudioLimit(const Audio::Timestamp &limit) { for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) if ((*it)->getTrackType() == Track::kTrackTypeAudio) ((AudioTrack *)*it)->start(limit); diff --git a/video/video_decoder.h b/video/video_decoder.h index d6cfcde0b4..abb9f8df20 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -48,7 +48,6 @@ namespace Video { /** * Generic interface for video decoder classes. - * @note This class is now deprecated in favor of AdvancedVideoDecoder. */ class VideoDecoder { public: @@ -77,53 +76,51 @@ public: /** * Close the active video stream and free any associated resources. */ - virtual void close() = 0; + virtual void close(); /** * Returns if a video stream is currently loaded or not. */ - virtual bool isVideoLoaded() const = 0; - - + bool isVideoLoaded() const; /** * Returns the width of the video's frames. * @return the width of the video's frames */ - virtual uint16 getWidth() const = 0; + virtual uint16 getWidth() const; /** * Returns the height of the video's frames. * @return the height of the video's frames */ - virtual uint16 getHeight() const = 0; + virtual uint16 getHeight() const; /** * Get the pixel format of the currently loaded video. */ - virtual Graphics::PixelFormat getPixelFormat() const = 0; + virtual Graphics::PixelFormat getPixelFormat() const; /** * Get the palette for the video in RGB format (if 8bpp or less). */ - virtual const byte *getPalette() { return 0; } + const byte *getPalette(); /** * Returns if the palette is dirty or not. */ - virtual bool hasDirtyPalette() const { return false; } + bool hasDirtyPalette() const { return _dirtyPalette; } /** * Returns the current frame number of the video. * @return the last frame decoded by the video */ - virtual int32 getCurFrame() const = 0; + int32 getCurFrame() const; /** * Returns the number of frames in the video. * @return the number of frames in the video */ - virtual uint32 getFrameCount() const = 0; + uint32 getFrameCount() const; /** * Returns the time position (in ms) of the current video. @@ -139,12 +136,12 @@ public: * completely accurate (since our mixer does not have precise * timing). */ - virtual uint32 getTime() const; + uint32 getTime() const; /** * Return the time (in ms) until the next frame should be displayed. */ - virtual uint32 getTimeToNextFrame() const = 0; + uint32 getTimeToNextFrame() const; /** * Check whether a new frame should be decoded, i.e. because enough @@ -160,13 +157,13 @@ public: * hence the caller must *not* free it. * @note this may return 0, in which case the last frame should be kept on screen */ - virtual const Graphics::Surface *decodeNextFrame() = 0; + virtual const Graphics::Surface *decodeNextFrame(); /** * Returns if the video has finished playing or not. * @return true if the video has finished playing or if none is loaded, false otherwise */ - virtual bool endOfVideo() const = 0; + bool endOfVideo() const; /** * Pause or resume the video. This should stop/resume any audio playback @@ -190,7 +187,7 @@ public: * Get the current volume at which the audio in the video is being played * @return the current volume at which the audio in the video is being played */ - virtual byte getVolume() const { return _audioVolume; } + byte getVolume() const { return _audioVolume; } /** * Set the volume at which the audio in the video should be played. @@ -201,13 +198,13 @@ public: * * @param volume The volume at which to play the audio in the video */ - virtual void setVolume(byte volume); + void setVolume(byte volume); /** * Get the current balance at which the audio in the video is being played * @return the current balance at which the audio in the video is being played */ - virtual int8 getBalance() const { return _audioBalance; } + int8 getBalance() const { return _audioBalance; } /** * Set the balance at which the audio in the video should be played. @@ -218,72 +215,8 @@ public: * * @param balance The balance at which to play the audio in the video */ - virtual void setBalance(int8 balance); - -protected: - /** - * Actual implementation of pause by subclasses. See pause() - * for details. - * @note This function is now deprecated. There is no replacement. - */ - virtual void pauseVideoIntern(bool pause) {} - - /** - * Reset the pause start time (which should be called when seeking) - */ - void resetPauseStartTime(); - - /** - * Update currently playing audio tracks with the new volume setting - * @note This function is now deprecated. There is no replacement. - */ - virtual void updateVolume() {} - - /** - * Update currently playing audio tracks with the new balance setting - * @note This function is now deprecated. There is no replacement. - */ - virtual void updateBalance() {} - - int32 _startTime; - -// FIXME: These are protected until the new API takes over this one -//private: - uint32 _pauseLevel; - uint32 _pauseStartTime; - byte _audioVolume; - int8 _audioBalance; -}; - -/** - * Improved interface for video decoder classes. - */ -class AdvancedVideoDecoder : public VideoDecoder { -public: - AdvancedVideoDecoder(); - virtual ~AdvancedVideoDecoder() {} - - // Old API Non-changing - // loadFile() - // loadStream() - // needsUpdate() - - // Old API Changing - virtual void close(); - bool isVideoLoaded() const; - virtual uint16 getWidth() const; - virtual uint16 getHeight() const; - virtual Graphics::PixelFormat getPixelFormat() const; - virtual const Graphics::Surface *decodeNextFrame(); - const byte *getPalette(); - bool hasDirtyPalette() const { return _dirtyPalette; } - int getCurFrame() const; - uint32 getFrameCount() const; - uint32 getTime() const; - uint32 getTimeToNextFrame() const; - bool endOfVideo() const; + void setBalance(int8 balance); - // New API /** * Returns if a video is rewindable or not. The default implementation * polls each track for rewindability. @@ -352,7 +285,7 @@ public: /** * Set the default high color format for videos that convert from YUV. * - * By default, AdvancedVideoDecoder will attempt to use the screen format + * By default, VideoDecoder will attempt to use the screen format * if it's >8bpp and use a 32bpp format when not. * * This must be set before calling loadStream(). @@ -375,13 +308,6 @@ public: //Common::Rational getRate() const; protected: - // Old API - void pauseVideoIntern(bool pause); - void updateVolume(); - void updateBalance(); - - // New API - /** * An abstract representation of a track in a movie. */ @@ -679,6 +605,11 @@ protected: Audio::SeekableAudioStream *getSeekableAudioStream() const { return _stream; } }; + /** + * Reset the pause start time (which should be called when seeking) + */ + void resetPauseStartTime(); + /** * Decode enough data for the next frame and enough audio to last that long. * @@ -756,7 +687,7 @@ protected: TrackListIterator getTrackListEnd() { return _tracks.end(); } private: - // Tracks owned by this AdvancedVideoDecoder + // Tracks owned by this VideoDecoder TrackList _tracks; // Current playback status @@ -775,6 +706,12 @@ private: void stopAudio(); void startAudio(); void startAudioLimit(const Audio::Timestamp &limit); + + int32 _startTime; + uint32 _pauseLevel; + uint32 _pauseStartTime; + byte _audioVolume; + int8 _audioBalance; }; } // End of namespace Video -- cgit v1.2.3 From e24fd2ffe66f17e0b5e3f58871ca22586cad757e Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 16 Aug 2012 22:49:22 -0400 Subject: VIDEO: Cleanup VideoDecoder a bit Functions and their comments now line up better --- video/video_decoder.cpp | 8 +- video/video_decoder.h | 311 +++++++++++++++++++++++++++++------------------- 2 files changed, 193 insertions(+), 126 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index cf11649c10..14826642d7 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -413,6 +413,10 @@ Audio::Timestamp VideoDecoder::Track::getDuration() const { return Audio::Timestamp(0, 1000); } +bool VideoDecoder::VideoTrack::endOfTrack() const { + return getCurFrame() >= (getFrameCount() - 1); +} + uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { if (endOfTrack() || getCurFrame() < 0) return 0; @@ -422,10 +426,6 @@ uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { return time.toInt(); } -bool VideoDecoder::FixedRateVideoTrack::endOfTrack() const { - return getCurFrame() >= (getFrameCount() - 1); -} - Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const { // Since Audio::Timestamp doesn't support a fractional frame rate, we're currently // just converting to milliseconds. diff --git a/video/video_decoder.h b/video/video_decoder.h index abb9f8df20..5fba85358c 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -54,10 +54,14 @@ public: VideoDecoder(); virtual ~VideoDecoder() {} + ///////////////////////////////////////// + // Opening/Closing a Video + ///////////////////////////////////////// + /** * Load a video from a file with the given name. * - * A default implementation using loadStream is provided. + * A default implementation using Common::File and loadStream is provided. * * @param filename the filename to load * @return whether loading the file succeeded @@ -68,6 +72,10 @@ public: * Load a video from a generic read stream. The ownership of the * stream object transfers to this VideoDecoder instance, which is * hence also responsible for eventually deleting it. + * + * Implementations of this function are required to call addTrack() + * for each track in the video upon success. + * * @param stream the stream to load * @return whether loading the stream succeeded */ @@ -75,6 +83,9 @@ public: /** * Close the active video stream and free any associated resources. + * + * All subclasses that need to close their own resources should still + * call the base class' close() function at the start of their function. */ virtual void close(); @@ -83,87 +94,66 @@ public: */ bool isVideoLoaded() const; - /** - * Returns the width of the video's frames. - * @return the width of the video's frames - */ - virtual uint16 getWidth() const; - - /** - * Returns the height of the video's frames. - * @return the height of the video's frames - */ - virtual uint16 getHeight() const; - /** - * Get the pixel format of the currently loaded video. - */ - virtual Graphics::PixelFormat getPixelFormat() const; + ///////////////////////////////////////// + // Playback Control + ///////////////////////////////////////// /** - * Get the palette for the video in RGB format (if 8bpp or less). + * Begin playback of the video. + * + * @note This has no effect is the video is already playing. */ - const byte *getPalette(); + void start(); /** - * Returns if the palette is dirty or not. + * Stop playback of the video. + * + * @note This will close() the video if it is not rewindable. + * @note If the video is rewindable, the video will be rewound on the + * next start() call unless rewind() or seek() is called before then. */ - bool hasDirtyPalette() const { return _dirtyPalette; } + void stop(); /** - * Returns the current frame number of the video. - * @return the last frame decoded by the video + * Returns if the video is currently playing or not. + * @todo Differentiate this function from endOfVideo() */ - int32 getCurFrame() const; + bool isPlaying() const { return _isPlaying; } /** - * Returns the number of frames in the video. - * @return the number of frames in the video + * Returns if a video is rewindable or not. The default implementation + * polls each track for rewindability. */ - uint32 getFrameCount() const; + virtual bool isRewindable() const; /** - * Returns the time position (in ms) of the current video. - * This can be based on the "wall clock" time as determined by - * OSystem::getMillis() or the current time of any audio track - * running in the video, and takes pausing the video into account. + * Rewind a video to its beginning. * - * As such, it will differ from what multiplying getCurFrame() by - * some constant would yield, e.g. for a video with non-constant - * frame rate. + * If the video is playing, it will continue to play. The default + * implementation will rewind each track. * - * Due to the nature of the timing, this value may not always be - * completely accurate (since our mixer does not have precise - * timing). - */ - uint32 getTime() const; - - /** - * Return the time (in ms) until the next frame should be displayed. - */ - uint32 getTimeToNextFrame() const; - - /** - * Check whether a new frame should be decoded, i.e. because enough - * time has elapsed since the last frame was decoded. - * @return whether a new frame should be decoded or not + * @return true on success, false otherwise */ - virtual bool needsUpdate() const; + virtual bool rewind(); /** - * Decode the next frame into a surface and return the latter. - * @return a surface containing the decoded frame, or 0 - * @note Ownership of the returned surface stays with the VideoDecoder, - * hence the caller must *not* free it. - * @note this may return 0, in which case the last frame should be kept on screen + * Returns if a video is seekable or not. The default implementation + * polls each track for seekability. */ - virtual const Graphics::Surface *decodeNextFrame(); + virtual bool isSeekable() const; /** - * Returns if the video has finished playing or not. - * @return true if the video has finished playing or if none is loaded, false otherwise + * Seek to a given time in the video. + * + * If the video is playing, it will continue to play. The default + * implementation will seek each track and must still be called + * from any other implementation. + * + * @param time The time to seek to + * @return true on success, false otherwise */ - bool endOfVideo() const; + virtual bool seek(const Audio::Timestamp &time); /** * Pause or resume the video. This should stop/resume any audio playback @@ -184,103 +174,141 @@ public: bool isPaused() const { return _pauseLevel != 0; } /** - * Get the current volume at which the audio in the video is being played - * @return the current volume at which the audio in the video is being played + * Set the time for this video to end at. At this time in the video, + * all audio will stop and endOfVideo() will return true. */ - byte getVolume() const { return _audioVolume; } + void setEndTime(const Audio::Timestamp &endTime); /** - * Set the volume at which the audio in the video should be played. - * This setting remains until reset() is called (which may be called - * from loadStream() or close()). The default volume is the maximum. - * - * @note This function calls updateVolume() by default. - * - * @param volume The volume at which to play the audio in the video + * Get the stop time of the video (if not set, zero) */ - void setVolume(byte volume); + Audio::Timestamp getEndTime() const { return _endTime; } + + + ///////////////////////////////////////// + // Playback Status + ///////////////////////////////////////// /** - * Get the current balance at which the audio in the video is being played - * @return the current balance at which the audio in the video is being played + * Returns if the video has reached the end or not. + * @return true if the video has finished playing or if none is loaded, false otherwise */ - int8 getBalance() const { return _audioBalance; } + bool endOfVideo() const; /** - * Set the balance at which the audio in the video should be played. - * This setting remains until reset() is called (which may be called - * from loadStream() or close()). The default balance is 0. - * - * @note This function calls updateBalance() by default. - * - * @param balance The balance at which to play the audio in the video + * Returns the current frame number of the video. + * @return the last frame decoded by the video */ - void setBalance(int8 balance); + int32 getCurFrame() const; /** - * Returns if a video is rewindable or not. The default implementation - * polls each track for rewindability. + * Returns the number of frames in the video. + * @return the number of frames in the video */ - virtual bool isRewindable() const; + uint32 getFrameCount() const; /** - * Rewind a video to its beginning. + * Returns the time position (in ms) of the current video. + * This can be based on the "wall clock" time as determined by + * OSystem::getMillis() or the current time of any audio track + * running in the video, and takes pausing the video into account. * - * If the video is playing, it will continue to play. The default - * implementation will rewind each track. + * As such, it will differ from what multiplying getCurFrame() by + * some constant would yield, e.g. for a video with non-constant + * frame rate. * - * @return true on success, false otherwise + * Due to the nature of the timing, this value may not always be + * completely accurate (since our mixer does not have precise + * timing). */ - virtual bool rewind(); + uint32 getTime() const; + + + ///////////////////////////////////////// + // Video Info + ///////////////////////////////////////// /** - * Returns if a video is seekable or not. The default implementation - * polls each track for seekability. + * Returns the width of the video's frames. + * + * By default, this finds the largest width between all of the loaded + * tracks. However, a subclass may override this if it does any kind + * of post-processing on it. + * + * @return the width of the video's frames */ - virtual bool isSeekable() const; + virtual uint16 getWidth() const; /** - * Seek to a given time in the video. + * Returns the height of the video's frames. * - * If the video is playing, it will continue to play. The default - * implementation will seek each track. + * By default, this finds the largest height between all of the loaded + * tracks. However, a subclass may override this if it does any kind + * of post-processing on it. * - * @param time The time to seek to - * @return true on success, false otherwise + * @return the height of the video's frames */ - virtual bool seek(const Audio::Timestamp &time); + virtual uint16 getHeight() const; /** - * Begin playback of the video. + * Get the pixel format of the currently loaded video. + */ + Graphics::PixelFormat getPixelFormat() const; + + /** + * Get the duration of the video. * - * @note This has no effect is the video is already playing. + * If the duration is unknown, this will return 0. If this is not + * overriden, it will take the length of the longest track. */ - void start(); + virtual Audio::Timestamp getDuration() const; + + + ///////////////////////////////////////// + // Frame Decoding + ///////////////////////////////////////// /** - * Stop playback of the video. + * Get the palette for the video in RGB format (if 8bpp or less). * - * @note This will close() the video if it is not rewindable. + * The palette's format is the same as PaletteManager's palette + * (interleaved RGB values). */ - void stop(); + const byte *getPalette(); /** - * Returns if the video is currently playing or not. - * @todo Differentiate this function from endOfVideo() + * Returns if the palette is dirty or not. */ - bool isPlaying() const { return _isPlaying; } + bool hasDirtyPalette() const { return _dirtyPalette; } /** - * Get the duration of the video. - * - * If the duration is unknown, this will return 0. + * Return the time (in ms) until the next frame should be displayed. */ - virtual Audio::Timestamp getDuration() const; + uint32 getTimeToNextFrame() const; /** - * Add an audio track from a stream file. + * Check whether a new frame should be decoded, i.e. because enough + * time has elapsed since the last frame was decoded. + * @return whether a new frame should be decoded or not */ - bool addStreamFileTrack(const Common::String &baseName); + bool needsUpdate() const; + + /** + * Decode the next frame into a surface and return the latter. + * + * A subclass may override this, but must still call this function. As an + * example, a subclass may do this to apply some global video scale to + * individual track's frame. + * + * Note that this will call readNextPacket() internally first before calling + * the next video track's decodeNextFrame() function. + * + * @return a surface containing the decoded frame, or 0 + * @note Ownership of the returned surface stays with the VideoDecoder, + * hence the caller must *not* free it. + * @note this may return 0, in which case the last frame should be kept on screen + */ + virtual const Graphics::Surface *decodeNextFrame(); /** * Set the default high color format for videos that convert from YUV. @@ -292,16 +320,48 @@ public: */ void setDefaultHighColorFormat(const Graphics::PixelFormat &format) { _defaultHighColorFormat = format; } + + ///////////////////////////////////////// + // Audio Control + ///////////////////////////////////////// + /** - * Set the time for this video to end at. At this time in the video, - * all audio will stop and endOfVideo() will return true. + * Get the current volume at which the audio in the video is being played + * @return the current volume at which the audio in the video is being played */ - void setEndTime(const Audio::Timestamp &endTime); + byte getVolume() const { return _audioVolume; } /** - * Get the stop time of the video (if not set, zero) + * Set the volume at which the audio in the video should be played. + * This setting remains until close() is called (which may be called + * from loadStream()). The default volume is the maximum. + * + * @param volume The volume at which to play the audio in the video */ - Audio::Timestamp getEndTime() const { return _endTime; } + void setVolume(byte volume); + + /** + * Get the current balance at which the audio in the video is being played + * @return the current balance at which the audio in the video is being played + */ + int8 getBalance() const { return _audioBalance; } + + /** + * Set the balance at which the audio in the video should be played. + * This setting remains until close() is called (which may be called + * from loadStream()). The default balance is 0. + * + * @param balance The balance at which to play the audio in the video + */ + void setBalance(int8 balance); + + /** + * Add an audio track from a stream file. + * + * This calls SeekableAudioStream::openStreamFile() internally + */ + bool addStreamFileTrack(const Common::String &baseName); + // Future API //void setRate(const Common::Rational &rate); @@ -337,11 +397,18 @@ protected: /** * Return if the track is rewindable. + * + * If a video is seekable, it does not need to implement this + * for it to also be rewindable. */ virtual bool isRewindable() const; /** * Rewind the video to the beginning. + * + * If a video is seekable, it does not need to implement this + * for it to also be rewindable. + * * @return true on success, false otherwise. */ virtual bool rewind(); @@ -394,6 +461,7 @@ protected: virtual ~VideoTrack() {} TrackType getTrackType() const { return kTrackTypeVideo; } + virtual bool endOfTrack() const; /** * Get the width of this track @@ -458,7 +526,6 @@ protected: FixedRateVideoTrack() {} virtual ~FixedRateVideoTrack() {} - virtual bool endOfTrack() const; uint32 getNextFrameStartTime() const; virtual Audio::Timestamp getDuration() const; @@ -540,7 +607,7 @@ protected: /** * An AudioTrack that implements isRewindable() and rewind() using - * the RewindableAudioStream API. + * RewindableAudioStream. */ class RewindableAudioTrack : public AudioTrack { public: @@ -562,7 +629,7 @@ protected: /** * An AudioTrack that implements isSeekable() and seek() using - * the SeekableAudioStream API. + * SeekableAudioStream. */ class SeekableAudioTrack : public AudioTrack { public: @@ -613,7 +680,7 @@ protected: /** * Decode enough data for the next frame and enough audio to last that long. * - * This function is used by the default decodeNextFrame() function. A subclass + * This function is used by the decodeNextFrame() function. A subclass * of a Track may decide to just have its decodeNextFrame() function read * and decode the frame. */ @@ -629,7 +696,7 @@ protected: /** * Whether or not getTime() will sync with a playing audio track. * - * A subclass should override this to disable this feature. + * A subclass can override this to disable this feature. */ virtual bool useAudioSync() const { return true; } -- cgit v1.2.3 From da9695ddc6a46c709753026055d6060746006c2c Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 17 Aug 2012 23:31:26 -0400 Subject: AGOS: Fix regressions in the feeble demo --- engines/agos/animation.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 10f274b37f..cf12ee120a 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -268,6 +268,10 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { uint w = getWidth(); const Graphics::Surface *surface = decodeNextFrame(); + + if (!surface) + return; + byte *src = (byte *)surface->pixels; dst += y * pitch + x; @@ -289,6 +293,8 @@ void MoviePlayerDXA::playVideo() { _vm->clearSurfaces(); } + start(); + while (!endOfVideo() && !_skipMovie && !_vm->shouldQuit()) handleNextFrame(); } @@ -421,8 +427,6 @@ bool MoviePlayerSMK::load() { if (!loadStream(videoStream)) error("Failed to load video stream from file %s", videoName.c_str()); - start(); - debug(0, "Playing video %s", videoName.c_str()); CursorMan.showMouse(false); @@ -435,6 +439,10 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { uint w = getWidth(); const Graphics::Surface *surface = decodeNextFrame(); + + if (!surface) + return; + byte *src = (byte *)surface->pixels; dst += y * pitch + x; @@ -449,6 +457,8 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } void MoviePlayerSMK::playVideo() { + start(); + while (!endOfVideo() && !_skipMovie && !_vm->shouldQuit()) handleNextFrame(); } @@ -491,7 +501,7 @@ bool MoviePlayerSMK::processFrame() { uint32 waitTime = getTimeToNextFrame(); - if (!waitTime) { + if (!waitTime && !endOfVideoTracks()) { warning("dropped frame %i", getCurFrame()); return false; } -- cgit v1.2.3 From 7af4e403042c9d67c6f00bb151225cee6abc5e0d Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 18 Aug 2012 10:22:54 -0400 Subject: AGOS: Fix regression with sound in Smacker OmniTV videos --- engines/agos/animation.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index cf12ee120a..9176412e0e 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -293,8 +293,6 @@ void MoviePlayerDXA::playVideo() { _vm->clearSurfaces(); } - start(); - while (!endOfVideo() && !_skipMovie && !_vm->shouldQuit()) handleNextFrame(); } @@ -305,6 +303,8 @@ void MoviePlayerDXA::stopVideo() { } void MoviePlayerDXA::startSound() { + start(); + if (_bgSoundStream != NULL) { _vm->_mixer->stopHandle(_bgSound); _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_bgSound, _bgSoundStream, -1, getVolume(), getBalance()); @@ -457,8 +457,6 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } void MoviePlayerSMK::playVideo() { - start(); - while (!endOfVideo() && !_skipMovie && !_vm->shouldQuit()) handleNextFrame(); } @@ -468,6 +466,7 @@ void MoviePlayerSMK::stopVideo() { } void MoviePlayerSMK::startSound() { + start(); } void MoviePlayerSMK::handleNextFrame() { -- cgit v1.2.3 From 8524ebd699254a6786033f0e41b9a45c563feb11 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 20 Aug 2012 02:58:37 +0300 Subject: SCI: Fix script bug #3555404 - "SCI: KQ6 Spider Scene Game Freeze" --- engines/sci/sound/soundcmd.cpp | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index cbb5cab4fe..1570e360e8 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -367,29 +367,36 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) { case 4: // SCI01+ case 5: // SCI1+ (SCI1 late sound scheme), with fade and continue - musicSlot->fadeTo = CLIP(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX); - // Check if the song is already at the requested volume. If it is, don't - // perform any fading. Happens for example during the intro of Longbow. - if (musicSlot->fadeTo == musicSlot->volume) - return acc; - - // sometimes we get objects in that position, fix it up (ffs. workarounds) - if (!argv[1].getSegment()) - musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); - else - musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; - musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo(); - musicSlot->fadeTicker = 0; - if (argc == 5) { // TODO: We currently treat this argument as a boolean, but may // have to handle different non-zero values differently. (e.g., - // some KQ6 scripts pass 3 here) - musicSlot->stopAfterFading = (argv[4].toUint16() != 0); + // some KQ6 scripts pass 3 here). + // There is a script bug in KQ6, room 460 (the room with the flying + // books). An object is passed here, which should not be treated as + // a true flag. Fixes bugs #3555404 and #3291115. + musicSlot->stopAfterFading = (argv[4].isNumber() && argv[4].toUint16() != 0); } else { musicSlot->stopAfterFading = false; } + musicSlot->fadeTo = CLIP(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX); + // Check if the song is already at the requested volume. If it is, don't + // perform any fading. Happens for example during the intro of Longbow. + if (musicSlot->fadeTo != musicSlot->volume) { + // sometimes we get objects in that position, fix it up (ffs. workarounds) + if (!argv[1].getSegment()) + musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); + else + musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; + musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo(); + } else { + // Stop the music, if requested. Fixes bug #3555404. + if (musicSlot->stopAfterFading) + processStopSound(obj, false); + } + + musicSlot->fadeTicker = 0; + // WORKAROUND/HACK: In the labyrinth in KQ6, when falling in the pit and // lighting the lantern, the game scripts perform a fade in of the game // music, but set it to stop after fading. Remove that flag here. This is -- cgit v1.2.3 From b19ccb9d1edcdf238727f0c3b0a731b2f00e9d3d Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 20 Aug 2012 03:22:56 +0300 Subject: SCI: Set the correct audio type for SCI1.1 sound effects, fixing bug #3554709 Now, sound effects in SCI1.1 games will no longer be incorrectly using the speech sound volume. This avoids them being silenced in floppy games that are flagged as not having speech. Fixes bug #3554709 - "SCI: Digital SFX don't play when Override Global Audio set" --- engines/sci/sound/audio.cpp | 3 ++- engines/sci/sound/soundcmd.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp index 123dd21894..528bb51393 100644 --- a/engines/sci/sound/audio.cpp +++ b/engines/sci/sound/audio.cpp @@ -67,7 +67,8 @@ int AudioPlayer::startAudio(uint16 module, uint32 number) { if (audioStream) { _wPlayFlag = false; - _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream); + Audio::Mixer::SoundType soundType = (module == 65535) ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType; + _mixer->playStream(soundType, &_audioHandle, audioStream); return sampleLen; } else { // Don't throw a warning in this case. getAudioStream() already has. Some games diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 1570e360e8..5d32f40f18 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -96,7 +96,7 @@ void SoundCommandParser::initSoundResource(MusicEntry *newSound) { if (_useDigitalSFX || !newSound->soundRes) { int sampleLen; newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen); - newSound->soundType = Audio::Mixer::kSpeechSoundType; + newSound->soundType = Audio::Mixer::kSFXSoundType; } } -- cgit v1.2.3 From 23db3cd9f225d40ff1900dd806630800ecf54aeb Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Mon, 20 Aug 2012 03:28:02 +0300 Subject: SAGA: Remove incorrect free() in loadShortenFromStream() This removes a warning and fixes bug #3558052 - "SAGA: use-after-free warning" --- engines/saga/shorten.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp index 5efc8d1f67..69c27b6a6b 100644 --- a/engines/saga/shorten.cpp +++ b/engines/saga/shorten.cpp @@ -519,9 +519,6 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by if (maxLPC > 0) free(lpc); - if (size > 0) - free(unpackedBuffer); - delete gReader; return unpackedBuffer; } -- cgit v1.2.3 From eccb55570e3ed27276573b23093ffedcf3e794cc Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 19 Aug 2012 20:40:03 -0400 Subject: BUILD: Fix statically compiling with libfluidsynth on Mac OS X --- configure | 2 +- ports.mk | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/configure b/configure index d4fec02c64..211d9e6e8d 100755 --- a/configure +++ b/configure @@ -3363,7 +3363,7 @@ if test "$_fluidsynth" = yes ; then esac INCLUDES="$INCLUDES $FLUIDSYNTH_CFLAGS" fi -define_in_config_h_if_yes "$_fluidsynth" 'USE_FLUIDSYNTH' +define_in_config_if_yes "$_fluidsynth" 'USE_FLUIDSYNTH' echo "$_fluidsynth" # diff --git a/ports.mk b/ports.mk index 9a20331924..ed6781a1a9 100644 --- a/ports.mk +++ b/ports.mk @@ -96,6 +96,12 @@ ifdef USE_FLAC OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libFLAC.a endif +ifdef USE_FLUIDSYNTH +OSX_STATIC_LIBS += \ + -framework CoreAudio \ + $(STATICLIBPATH)/lib/libfluidsynth.a +endif + ifdef USE_MAD OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libmad.a endif -- cgit v1.2.3 From bd6751cb4a2cb5f34697392a82e8d5ab35a6a006 Mon Sep 17 00:00:00 2001 From: Vincent Hamm Date: Fri, 17 Aug 2012 21:38:20 -0700 Subject: CINE: Fix drawing of sprite with mask. Protects against cases where a non-existing script is referenced. --- engines/cine/gfx.cpp | 6 ++++++ engines/cine/script_fw.cpp | 17 +++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index cce8154d84..7a988227f6 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -1796,6 +1796,12 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi if(pMask) { spritePtr = pMask; } + + // ignore transparent color in 1bpp + if (bpp == 1) { + transparentColor = 1; + } + { for (int i = 0; i < height; i++) { byte *destPtr = page + x + y * 320; diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index a34bf7ba2c..9cbe3c3fab 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -533,7 +533,6 @@ void RawScript::setData(const FWScriptInfo &info, const byte *data) { * @return Precalculated script labels */ const ScriptVars &RawScript::labels() const { - assert(_data); return _labels; } @@ -687,7 +686,7 @@ const char *FWScript::getNextString() { * @param pos Restored script position */ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) { - assert(pos < _script._size); + assert(pos <= _script._size); _labels = labels; _localVars = local; _compare = compare; @@ -705,13 +704,15 @@ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 co int FWScript::execute() { int ret = 0; - while (!ret) { - _line = _pos; - byte opcode = getNextByte(); - OpFunc handler = _info->opcodeHandler(opcode); + if(_script._size) { + while (!ret) { + _line = _pos; + byte opcode = getNextByte(); + OpFunc handler = _info->opcodeHandler(opcode); - if (handler) { - ret = (this->*handler)(); + if (handler) { + ret = (this->*handler)(); + } } } -- cgit v1.2.3 From b1af75f2c38e1997577599308f75ee0d1299b13e Mon Sep 17 00:00:00 2001 From: Alyssa Milburn Date: Mon, 20 Aug 2012 21:10:40 +0200 Subject: SWORD25: Improve sound persistence. Keep track of volume/panning state, and don't restart sounds which already finished playing. --- engines/sword25/sfx/soundengine.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp index 78b2db19eb..69fae3dc4e 100644 --- a/engines/sword25/sfx/soundengine.cpp +++ b/engines/sword25/sfx/soundengine.cpp @@ -239,16 +239,20 @@ void SoundEngine::setSoundVolume(uint handle, float volume) { debugC(1, kDebugSound, "SoundEngine::setSoundVolume(%d, %f)", handle, volume); SndHandle* sndHandle = findHandle(handle); - if (sndHandle != NULL) + if (sndHandle != NULL) { + sndHandle->volume = volume; _mixer->setChannelVolume(sndHandle->handle, (byte)(volume * 255)); + } } void SoundEngine::setSoundPanning(uint handle, float pan) { debugC(1, kDebugSound, "SoundEngine::setSoundPanning(%d, %f)", handle, pan); SndHandle* sndHandle = findHandle(handle); - if (sndHandle != NULL) + if (sndHandle != NULL) { + sndHandle->pan = pan; _mixer->setChannelBalance(sndHandle->handle, (int8)(pan * 127)); + } } void SoundEngine::pauseSound(uint handle) { @@ -324,13 +328,16 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) { return fname.hasSuffix(".ogg"); } - - bool SoundEngine::persist(OutputPersistenceBlock &writer) { +bool SoundEngine::persist(OutputPersistenceBlock &writer) { writer.write(_maxHandleId); for (uint i = 0; i < SOUND_HANDLES; i++) { writer.write(_handles[i].id); + // Don't restart sounds which already finished playing. + if (_handles[i].type != kFreeHandle && !_mixer->isSoundHandleActive(_handles[i].handle)) + _handles[i].type = kFreeHandle; + writer.writeString(_handles[i].fileName); writer.write((int)_handles[i].sndType); writer.write(_handles[i].volume); @@ -374,7 +381,8 @@ bool SoundEngine::unpersist(InputPersistenceBlock &reader) { reader.read(layer); if (reader.isGood()) { - playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); + if (sndType != kFreeHandle) + playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); } else return false; } -- cgit v1.2.3 From af05b1b80edfc8674845d6e42c9872fea9eeb381 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan SømaÌŠen Date: Sun, 12 Aug 2012 23:50:25 +0200 Subject: GRAPHICS: Reimplement the PNG-decoder using libpng --- configure | 2 +- graphics/decoders/png.cpp | 578 +++++++++++++--------------------------------- graphics/decoders/png.h | 78 +------ 3 files changed, 160 insertions(+), 498 deletions(-) diff --git a/configure b/configure index 06492ff305..f98c1c9ff2 100755 --- a/configure +++ b/configure @@ -97,7 +97,7 @@ _sndio=auto _timidity=auto _zlib=auto _sparkle=auto -_png=no +_png=auto _theoradec=auto _faad=auto _fluidsynth=auto diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index 492c69779f..f0471899a6 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -19,87 +19,23 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#include "common/scummsys.h" + +#ifdef USE_PNG +#include +#endif #include "graphics/decoders/png.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" -#include "common/endian.h" -#include "common/memstream.h" #include "common/stream.h" -#include "common/types.h" -#include "common/util.h" -#include "common/zlib.h" - -// PNG decoder, based on the W3C specs: -// http://www.w3.org/TR/PNG/ -// Parts of the code have been adapted from LodePNG, by Lode Vandevenne: -// http://members.gamedev.net/lode/projects/LodePNG/ - -/* -LodePNG version 20101211 - -Copyright (c) 2005-2010 Lode Vandevenne - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ namespace Graphics { -enum PNGChunks { - // == Critical chunks ===================================================== - kChunkIHDR = MKTAG('I','H','D','R'), // Image header - kChunkIDAT = MKTAG('I','D','A','T'), // Image data - kChunkPLTE = MKTAG('P','L','T','E'), // Palette - kChunkIEND = MKTAG('I','E','N','D'), // Image trailer - // == Ancillary chunks ==================================================== - kChunktRNS = MKTAG('t','R','N','S') // Transparency - // All of the other ancillary chunks are ignored. They're added here for - // reference only. - // cHRM - Primary chromacities and white point - // gAMA - Image gamma - // iCCP - Embedded ICC profile - // sBIT - Significant bits - // sRGB - Standard RGB color space - // tEXT - Textual data - // sTXt - Compressed textual data - // iTXt - International textual data - // bKGD - Background color - // hIST - Image histogram - // pHYs - Physical pixel dimensions - // sPLT - Suggested palette - // tIME - Image last-modification time -}; - -// Refer to http://www.w3.org/TR/PNG/#9Filters -enum PNGFilters { - kFilterNone = 0, - kFilterSub = 1, - kFilterUp = 2, - kFilterAverage = 3, - kFilterPaeth = 4 -}; - -PNGDecoder::PNGDecoder() : _compressedBuffer(0), _compressedBufferSize(0), - _transparentColorSpecified(false), _outputSurface(0), _paletteEntries(0) { +PNGDecoder::PNGDecoder() : _outputSurface(0), _palette(0), _paletteColorCount(0) { } PNGDecoder::~PNGDecoder() { @@ -112,16 +48,43 @@ void PNGDecoder::destroy() { delete _outputSurface; _outputSurface = 0; } + delete[] _palette; + _palette = NULL; +} + +#ifdef USE_PNG +// libpng-error-handling: +void pngError(png_structp pngptr, png_const_charp errorMsg) { + error("%s", errorMsg); +} - _paletteEntries = 0; +void pngWarning(png_structp pngptr, png_const_charp warningMsg) { + warning("%s", warningMsg); } +// libpng-I/O-helper: +void pngReadFromStream(png_structp pngPtr, png_bytep data, png_size_t length) { + void *readIOptr = png_get_io_ptr(pngPtr); + Common::SeekableReadStream *stream = (Common::SeekableReadStream *)readIOptr; + stream->read(data, length); +} +#endif + +/* + * This code is based on Broken Sword 2.5 engine + * + * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer + * + * Licensed under GNU GPL v2 + * + */ + bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { +#ifdef USE_PNG destroy(); - uint32 chunkLength = 0, chunkType = 0; _stream = &stream; - + // First, check the PNG signature if (_stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) { delete _stream; @@ -132,374 +95,143 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { return false; } - // Start reading chunks till we reach an IEND chunk - while (chunkType != kChunkIEND) { - // The chunk length does not include the type or CRC bytes - chunkLength = _stream->readUint32BE(); - chunkType = _stream->readUint32BE(); - - switch (chunkType) { - case kChunkIHDR: - readHeaderChunk(); - break; - case kChunkIDAT: - if (_compressedBufferSize == 0) { - _compressedBufferSize += chunkLength; - _compressedBuffer = (byte *)malloc(_compressedBufferSize); - _stream->read(_compressedBuffer, chunkLength); - } else { - // Expand the buffer - uint32 prevSize = _compressedBufferSize; - _compressedBufferSize += chunkLength; - byte *tmp = new byte[prevSize]; - memcpy(tmp, _compressedBuffer, prevSize); - free(_compressedBuffer); - _compressedBuffer = (byte *)malloc(_compressedBufferSize); - memcpy(_compressedBuffer, tmp, prevSize); - delete[] tmp; - _stream->read(_compressedBuffer + prevSize, chunkLength); - } - break; - case kChunkPLTE: // only available in indexed PNGs - if (_header.colorType != kIndexed) - error("A palette chunk has been found in a non-indexed PNG file"); - if (chunkLength % 3 != 0) - error("Palette chunk not divisible by 3"); - - _paletteEntries = chunkLength / 3; - _stream->read(_palette, _paletteEntries * 3); - memset(_paletteTransparency, 0xff, sizeof(_paletteTransparency)); - break; - case kChunkIEND: - // End of stream - break; - case kChunktRNS: - readTransparencyChunk(chunkLength); - break; - default: - // Skip the chunk content - _stream->skip(chunkLength); - break; - } - - if (chunkType != kChunkIEND) - _stream->skip(4); // skip the chunk CRC checksum + // The following is based on the guide provided in: + //http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3 + //http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf + // along with the png-loading code used in the sword25-engine. + png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!pngPtr) { + delete _stream; + return false; } - - // We no longer need the file stream, thus close it here - _stream = 0; - - // Unpack the compressed buffer - Common::MemoryReadStream *compData = new Common::MemoryReadStream(_compressedBuffer, _compressedBufferSize, DisposeAfterUse::YES); - _imageData = Common::wrapCompressedReadStream(compData); - - // Construct the final image - constructImage(); - - // Close the uncompressed stream, which will also delete the memory stream, - // and thus the original compressed buffer - delete _imageData; - - return true; -} - -/** - * Paeth predictor, used by PNG filter type 4 - * The parameters are of signed 16-bit integers, but should come - * from unsigned chars. The integers are only needed to make - * the paeth calculation correct. - * - * Taken from lodePNG, with a slight patch: - * http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx - */ -byte PNGDecoder::paethPredictor(int16 a, int16 b, int16 c) { - int16 pa = ABS(b - c); - int16 pb = ABS(a - c); - int16 pc = ABS(a + b - c - c); - - if (pa <= MIN(pb, pc)) - return (byte)a; - else if (pb <= pc) - return (byte)b; - else - return (byte)c; -} - -/** - * Unfilters a filtered PNG scan line. - * PNG filters are defined in: http://www.w3.org/TR/PNG/#9Filters - * Note that filters are always applied to bytes - * - * Taken from lodePNG - */ -void PNGDecoder::unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length) { - uint16 i; - - switch (filterType) { - case kFilterNone: // no change - for (i = 0; i < length; i++) - dest[i] = scanLine[i]; - break; - case kFilterSub: // add the bytes to the left - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + dest[i - byteWidth]; - break; - case kFilterUp: // add the bytes of the above scanline - if (prevLine) { - for (i = 0; i < length; i++) - dest[i] = scanLine[i] + prevLine[i]; - } else { - for (i = 0; i < length; i++) - dest[i] = scanLine[i]; - } - break; - case kFilterAverage: // average value of the left and top left - if (prevLine) { - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i] + prevLine[i] / 2; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + ((dest[i - byteWidth] + prevLine[i]) / 2); - } else { - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + dest[i - byteWidth] / 2; - } - break; - case kFilterPaeth: // Paeth filter: http://www.w3.org/TR/PNG/#9Filter-type-4-Paeth - if (prevLine) { - for(i = 0; i < byteWidth; i++) - dest[i] = (scanLine[i] + prevLine[i]); // paethPredictor(0, prevLine[i], 0) is always prevLine[i] - for(i = byteWidth; i < length; i++) - dest[i] = (scanLine[i] + paethPredictor(dest[i - byteWidth], prevLine[i], prevLine[i - byteWidth])); - } else { - for(i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for(i = byteWidth; i < length; i++) - dest[i] = (scanLine[i] + dest[i - byteWidth]); // paethPredictor(dest[i - byteWidth], 0, 0) is always dest[i - byteWidth] - } - break; - default: - error("Unknown line filter"); + png_infop infoPtr = png_create_info_struct(pngPtr); + if (!infoPtr) { + png_destroy_read_struct(&pngPtr, NULL, NULL); + delete _stream; + return false; } - -} - -int PNGDecoder::getBytesPerPixel() const { - return (getNumColorChannels() * _header.bitDepth + 7) / 8; -} - -void PNGDecoder::constructImage() { - assert (_header.bitDepth != 0); - - int bytesPerPixel = getBytesPerPixel(); - int pitch = bytesPerPixel * _header.width; - byte *unfilteredSurface = new byte[pitch * _header.height]; - byte *dest = unfilteredSurface; - uint16 scanLineWidth = (_header.width * getNumColorChannels() * _header.bitDepth + 7) / 8; - byte *scanLine = new byte[scanLineWidth]; - byte *prevLine = 0; - - switch(_header.interlaceType) { - case kNonInterlaced: - for (uint16 y = 0; y < _header.height; y++) { - byte filterType = _imageData->readByte(); - _imageData->read(scanLine, scanLineWidth); - unfilterScanLine(dest, scanLine, prevLine, bytesPerPixel, filterType, scanLineWidth); - prevLine = dest; - dest += pitch; - } - break; - case kInterlaced: - // Theoretically, this shouldn't be needed, as interlacing is only - // useful for web images. Interlaced PNG images require more complex - // handling, so unless having support for such images is needed, there - // is no reason to add support for them. - error("TODO: Support for interlaced PNG images"); - break; + png_infop endInfo = png_create_info_struct(pngPtr); + if (!endInfo) { + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + delete _stream; + return false; } - delete[] scanLine; + png_set_error_fn(pngPtr, NULL, pngError, pngWarning); + // TODO: The manual says errors should be handled via setjmp - constructOutput(unfilteredSurface); - delete[] unfilteredSurface; -} + png_set_read_fn(pngPtr, _stream, pngReadFromStream); + png_set_crc_action(pngPtr, PNG_CRC_DEFAULT, PNG_CRC_WARN_USE); + // We already verified the PNG-header + png_set_sig_bytes(pngPtr, 8); -Graphics::PixelFormat PNGDecoder::findPixelFormat() const { - // Try to find the best pixel format based on what we have here - // Which is basically 8bpp for paletted non-transparent - // and 32bpp for everything else + // Read PNG header + png_read_info(pngPtr, infoPtr); - switch (_header.colorType) { - case kIndexed: - if (!_transparentColorSpecified) - return Graphics::PixelFormat::createFormatCLUT8(); - // fall through - case kGrayScale: - case kTrueColor: - case kGrayScaleWithAlpha: - case kTrueColorWithAlpha: - // We'll go with standard RGBA 32-bit - return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); - } - - error("Unknown PNG color type"); - return Graphics::PixelFormat(); -} + // No handling for unknown chunks yet. + int bitDepth, colorType, width, height, interlaceType; + png_uint_32 w, h; + png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL); + width = w; + height = h; -void PNGDecoder::constructOutput(const byte *surface) { + // Allocate memory for the final image data. + // To keep memory framentation low this happens before allocating memory for temporary image data. _outputSurface = new Graphics::Surface(); - _outputSurface->create(_header.width, _header.height, findPixelFormat()); - const byte *src = surface; - byte a = 0xFF; - int bytesPerPixel = getBytesPerPixel(); - - if (_header.colorType != kIndexed) { - if (_header.colorType == kTrueColor || - _header.colorType == kTrueColorWithAlpha) { - if (bytesPerPixel != 3 && bytesPerPixel != 4) - error("Unsupported truecolor PNG format"); - } else if (_header.colorType == kGrayScale || - _header.colorType == kGrayScaleWithAlpha) { - if (bytesPerPixel != 1 && bytesPerPixel != 2) - error("Unsupported grayscale PNG format"); + // Images of all color formats except PNG_COLOR_TYPE_PALETTE + // will be transformed into ARGB images + if (colorType == PNG_COLOR_TYPE_PALETTE && !png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { + int numPalette = 0; + png_colorp palette = NULL; + uint32 success = png_get_PLTE(pngPtr, infoPtr, &palette, &numPalette); + if (success != PNG_INFO_PLTE) { + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + return false; } - - for (uint16 i = 0; i < _outputSurface->h; i++) { - for (uint16 j = 0; j < _outputSurface->w; j++) { - uint32 result = 0; - - switch (bytesPerPixel) { - case 1: // Grayscale - if (_transparentColorSpecified) - a = (src[0] == _transparentColor[0]) ? 0 : 0xFF; - result = _outputSurface->format.ARGBToColor(a, src[0], src[0], src[0]); - break; - case 2: // Grayscale + alpha - result = _outputSurface->format.ARGBToColor(src[1], src[0], src[0], src[0]); - break; - case 3: // RGB - if (_transparentColorSpecified) { - bool isTransparentColor = (src[0] == _transparentColor[0] && - src[1] == _transparentColor[1] && - src[2] == _transparentColor[2]); - a = isTransparentColor ? 0 : 0xFF; - } - - result = _outputSurface->format.ARGBToColor(a, src[0], src[1], src[2]); - break; - case 4: // RGBA - result = _outputSurface->format.ARGBToColor(src[3], src[0], src[1], src[2]); - break; - } - - *((uint32 *)_outputSurface->getBasePtr(j, i)) = result; - src += bytesPerPixel; - } + _paletteColorCount = numPalette; + _palette = new byte[_paletteColorCount * 3]; + for (int i = 0; i < _paletteColorCount; i++) { + _palette[(i * 3)] = palette[i].red; + _palette[(i * 3) + 1] = palette[i].green; + _palette[(i * 3) + 2] = palette[i].blue; + } + _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + png_set_packing(pngPtr); } else { - uint32 mask = (0xff >> (8 - _header.bitDepth)) << (8 - _header.bitDepth); - - // Convert the indexed surface to the target pixel format - for (uint16 i = 0; i < _outputSurface->h; i++) { - int data = 0; - int bitCount = 8; - const byte *src1 = src; - - for (uint16 j = 0; j < _outputSurface->w; j++) { - if (bitCount == 8) { - data = *src; - src++; - } - - byte index = (data & mask) >> (8 - _header.bitDepth); - data = (data << _header.bitDepth) & 0xff; - bitCount -= _header.bitDepth; - - if (bitCount == 0) - bitCount = 8; - - if (_transparentColorSpecified) { - byte r = _palette[index * 3 + 0]; - byte g = _palette[index * 3 + 1]; - byte b = _palette[index * 3 + 2]; - a = _paletteTransparency[index]; - *((uint32 *)_outputSurface->getBasePtr(j, i)) = _outputSurface->format.ARGBToColor(a, r, g, b); - } else { - *((byte *)_outputSurface->getBasePtr(j, i)) = index; - } - } - - src = src1 + _outputSurface->w; + _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); + if (!_outputSurface->pixels) { + error("Could not allocate memory for output image."); } - } -} + if (bitDepth == 16) + png_set_strip_16(pngPtr); + if (bitDepth < 8) + png_set_expand(pngPtr); + if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) + png_set_expand(pngPtr); + if (colorType == PNG_COLOR_TYPE_GRAY || + colorType == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(pngPtr); + + // PNGs are Big-Endian: +#ifdef SCUMM_LITTLE_ENDIAN + png_set_bgr(pngPtr); + png_set_swap_alpha(pngPtr); + if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) + png_set_filler(pngPtr, 0xff, PNG_FILLER_BEFORE); +#else + if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) + png_set_filler(pngPtr, 0xff, PNG_FILLER_AFTER); +#endif -void PNGDecoder::readHeaderChunk() { - _header.width = _stream->readUint32BE(); - _header.height = _stream->readUint32BE(); - _header.bitDepth = _stream->readByte(); - if (_header.bitDepth > 8) - error("Only PNGs with a bit depth of 1-8 bits are supported (i.e. PNG24)"); - _header.colorType = (PNGColorType)_stream->readByte(); - _header.compressionMethod = _stream->readByte(); - // Compression methods: http://www.w3.org/TR/PNG/#10Compression - // Only compression method 0 (deflate) is documented and supported - if (_header.compressionMethod != 0) - error("Unknown PNG compression method: %d", _header.compressionMethod); - _header.filterMethod = _stream->readByte(); - // Filter methods: http://www.w3.org/TR/PNG/#9Filters - // Only filter method 0 is documented and supported - if (_header.filterMethod != 0) - error("Unknown PNG filter method: %d", _header.filterMethod); - _header.interlaceType = (PNGInterlaceType)_stream->readByte(); -} - -byte PNGDecoder::getNumColorChannels() const { - switch (_header.colorType) { - case kGrayScale: - return 1; // Gray - case kTrueColor: - return 3; // RGB - case kIndexed: - return 1; // Indexed - case kGrayScaleWithAlpha: - return 2; // Gray + Alpha - case kTrueColorWithAlpha: - return 4; // RGBA - default: - error("Unknown color type"); } -} + + // After the transformations have been registered, the image data is read again. + png_read_update_info(pngPtr, infoPtr); + png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); + width = w; + height = h; + + if (interlaceType == PNG_INTERLACE_NONE) { + // PNGs without interlacing can simply be read row by row. + for (int i = 0; i < height; i++) { + png_read_row(pngPtr, (png_bytep)_outputSurface->getBasePtr(0, i), NULL); + } + } else { + // PNGs with interlacing require us to allocate an auxillary + // buffer with pointers to all row starts. + + // Allocate row pointer buffer + png_bytep *rowPtr = new png_bytep[height]; + if (!rowPtr) { + error("Could not allocate memory for row pointers."); + } + + // Initialize row pointers + for (int i = 0; i < height; i++) + rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); + + // Read image data + png_read_image(pngPtr, rowPtr); + + // Free row pointer buffer + delete[] rowPtr; + } + + // Read additional data at the end. + png_read_end(pngPtr, NULL); -void PNGDecoder::readTransparencyChunk(uint32 chunkLength) { - _transparentColorSpecified = true; + // Destroy libpng structures + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); - switch(_header.colorType) { - case kGrayScale: - _transparentColor[0] = _stream->readUint16BE(); - _transparentColor[1] = _transparentColor[0]; - _transparentColor[2] = _transparentColor[0]; - break; - case kTrueColor: - _transparentColor[0] = _stream->readUint16BE(); - _transparentColor[1] = _stream->readUint16BE(); - _transparentColor[2] = _stream->readUint16BE(); - break; - case kIndexed: - _stream->read(_paletteTransparency, chunkLength); + // We no longer need the file stream, thus close it here + _stream = 0; - // A transparency chunk may have less entries - // than the palette entries. The remaining ones - // are unmodified (set to 255). Check here: - // http://www.w3.org/TR/PNG/#11tRNS - break; - default: - error("Transparency chunk found in a PNG that has a separate transparency channel"); - } + return true; +#else + return false; +#endif } } // End of Graphics namespace diff --git a/graphics/decoders/png.h b/graphics/decoders/png.h index ca204f6dd3..e52ddabd7d 100644 --- a/graphics/decoders/png.h +++ b/graphics/decoders/png.h @@ -24,33 +24,12 @@ * PNG decoder used in engines: * - sword25 * Dependencies: - * - zlib + * - libpng */ #ifndef GRAPHICS_PNG_H #define GRAPHICS_PNG_H -// PNG decoder, based on the W3C specs: -// http://www.w3.org/TR/PNG/ -// Parts of the code have been adapted from LodePNG, by Lode Vandevenne: -// http://members.gamedev.net/lode/projects/LodePNG/ - -// All the numbers are BE: http://www.w3.org/TR/PNG/#7Integers-and-byte-order - -// Note: At the moment, this decoder only supports non-interlaced images, and -// does not support truecolor/grayscale images with 16bit depth. -// -// Theoretically, interlaced images shouldn't be needed for games, as -// interlacing is only useful for images in websites. -// -// PNG images with 16bit depth (i.e. 48bit images) are quite rare, and can -// theoretically contain more than 16.7 millions of colors (the so-called "deep -// color" representation). In essence, each of the R, G, B and A components in -// them is specified with 2 bytes, instead of 1. However, the PNG specification -// always refers to color components with 1 byte each, so this part of the spec -// is a bit unclear. For now, these won't be supported, until a suitable sample -// is found. - #include "common/scummsys.h" #include "common/textconsole.h" #include "graphics/decoders/image_decoder.h" @@ -73,62 +52,13 @@ public: void destroy(); const Graphics::Surface *getSurface() const { return _outputSurface; } const byte *getPalette() const { return _palette; } - uint16 getPaletteColorCount() const { return _paletteEntries; } - + uint16 getPaletteColorCount() const { return _paletteColorCount; } private: - enum PNGColorType { - kGrayScale = 0, // bit depths: 1, 2, 4, 8, 16 - kTrueColor = 2, // bit depths: 8, 16 - kIndexed = 3, // bit depths: 1, 2, 4, 8 - kGrayScaleWithAlpha = 4, // bit depths: 8, 16 - kTrueColorWithAlpha = 6 // bit depths: 8, 16 - }; - - enum PNGInterlaceType { - kNonInterlaced = 0, - kInterlaced = 1 - }; - - struct PNGHeader { - uint32 width; - uint32 height; - byte bitDepth; - PNGColorType colorType; - byte compressionMethod; - byte filterMethod; - PNGInterlaceType interlaceType; - }; - - void readHeaderChunk(); - byte getNumColorChannels() const; - - void readPaletteChunk(); - void readTransparencyChunk(uint32 chunkLength); - - void constructImage(); - void unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length); - byte paethPredictor(int16 a, int16 b, int16 c); - - // The original file stream Common::SeekableReadStream *_stream; - // The unzipped image data stream - Common::SeekableReadStream *_imageData; - - PNGHeader _header; - - byte _palette[256 * 3]; // RGB - byte _paletteTransparency[256]; - uint16 _paletteEntries; - uint16 _transparentColor[3]; - bool _transparentColorSpecified; - - byte *_compressedBuffer; - uint32 _compressedBufferSize; + byte *_palette; + uint16 _paletteColorCount; Graphics::Surface *_outputSurface; - Graphics::PixelFormat findPixelFormat() const; - int getBytesPerPixel() const; - void constructOutput(const byte *surface); }; } // End of namespace Graphics -- cgit v1.2.3 From f34924bc3940ff1f9972ed4920feb7e5708f3099 Mon Sep 17 00:00:00 2001 From: upthorn Date: Mon, 9 Jul 2012 04:25:08 -0700 Subject: SWORD25: Fix loading savegames on 64-bit archs. --- engines/sword25/util/pluto/pluto.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp index d645e5ed2a..b7f5e30340 100644 --- a/engines/sword25/util/pluto/pluto.cpp +++ b/engines/sword25/util/pluto/pluto.cpp @@ -895,10 +895,10 @@ static void unpersistnumber(UnpersistInfo *upi) static void unpersiststring(UnpersistInfo *upi) { /* perms reftbl sptbl ref */ - int length; + size_t length; char* string; lua_checkstack(upi->L, 1); - verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0); + verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0); string = pdep_newvector(upi->L, length, char); verify(LIF(Z,read)(&upi->zio, string, length) == 0); lua_pushlstring(upi->L, string, length); -- cgit v1.2.3 From 6c155b6b36f77a932a54e9b01c08f938c73e24eb Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 20 Aug 2012 17:06:58 -0400 Subject: VIDEO: Implement rewinding Smacker audio tracks --- video/smk_decoder.cpp | 7 ++++++- video/smk_decoder.h | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp index d01ec730f4..bea65142a1 100644 --- a/video/smk_decoder.cpp +++ b/video/smk_decoder.cpp @@ -410,7 +410,6 @@ void SmackerDecoder::close() { bool SmackerDecoder::rewind() { // Call the parent method to rewind the tracks first - // In particular, only videos without sound can be rewound if (!VideoDecoder::rewind()) return false; @@ -755,6 +754,12 @@ SmackerDecoder::SmackerAudioTrack::~SmackerAudioTrack() { delete _audioStream; } +bool SmackerDecoder::SmackerAudioTrack::rewind() { + delete _audioStream; + _audioStream = Audio::makeQueuingAudioStream(_audioInfo.sampleRate, _audioInfo.isStereo); + return true; +} + Audio::AudioStream *SmackerDecoder::SmackerAudioTrack::getAudioStream() const { return _audioStream; } diff --git a/video/smk_decoder.h b/video/smk_decoder.h index 6bded64a37..7227238373 100644 --- a/video/smk_decoder.h +++ b/video/smk_decoder.h @@ -156,6 +156,9 @@ private: SmackerAudioTrack(const AudioInfo &audioInfo, Audio::Mixer::SoundType soundType); ~SmackerAudioTrack(); + bool isRewindable() const { return true; } + bool rewind(); + Audio::Mixer::SoundType getSoundType() const { return _soundType; } void queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize); -- cgit v1.2.3 From eff6ea09fbf1b64bc37011e5c94cf8798f658150 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 21 Aug 2012 02:13:19 +0200 Subject: Revert "CONFIGURE: Don't disable the sword25 engine when libpng is not found" This reverts commit 7543c3ba5fcc914a4031fc8328aacd3d28c7055d. We depend on libpng for PNG decoding again, thus disable sword25 when libpng is not available. --- configure | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure b/configure index 5ab145c5f4..4b54832294 100755 --- a/configure +++ b/configure @@ -3201,6 +3201,11 @@ fi define_in_config_if_yes "$_png" 'USE_PNG' echo "$_png" +if test `get_engine_build sword25` = yes && test ! "$_png" = yes ; then + echo "...disabling Broken Sword 2.5 engine. PNG is required" + engine_disable sword25 +fi + # # Check for Theora Decoder # -- cgit v1.2.3 From 5df8c99768205ad6e2380dbc7cbc838e4ab5cc85 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 21 Aug 2012 02:17:45 +0200 Subject: GPRAHICS: Slight cleanup in png.cpp. This adds an explanation why we use FORBIDDEN_SYMBOL_ALLOW_ALL and removes some trailing whitespaces. --- graphics/decoders/png.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index f0471899a6..bfaab6dc35 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -19,6 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ + +// Since we need to work with libpng here, we need to allow all symbols +// to avoid compilation issues. #define FORBIDDEN_SYMBOL_ALLOW_ALL #include "common/scummsys.h" @@ -84,7 +87,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { destroy(); _stream = &stream; - + // First, check the PNG signature if (_stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) { delete _stream; @@ -155,7 +158,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { _palette[(i * 3)] = palette[i].red; _palette[(i * 3) + 1] = palette[i].green; _palette[(i * 3) + 2] = palette[i].blue; - + } _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); png_set_packing(pngPtr); @@ -173,7 +176,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(pngPtr); - + // PNGs are Big-Endian: #ifdef SCUMM_LITTLE_ENDIAN png_set_bgr(pngPtr); @@ -186,7 +189,7 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { #endif } - + // After the transformations have been registered, the image data is read again. png_read_update_info(pngPtr, infoPtr); png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); @@ -201,24 +204,24 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { } else { // PNGs with interlacing require us to allocate an auxillary // buffer with pointers to all row starts. - + // Allocate row pointer buffer png_bytep *rowPtr = new png_bytep[height]; if (!rowPtr) { error("Could not allocate memory for row pointers."); } - + // Initialize row pointers for (int i = 0; i < height; i++) rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); - + // Read image data png_read_image(pngPtr, rowPtr); - + // Free row pointer buffer delete[] rowPtr; } - + // Read additional data at the end. png_read_end(pngPtr, NULL); -- cgit v1.2.3 From 9568b78babdbdf350fd6c47b261c3f21902c31fc Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 21 Aug 2012 03:28:34 +0300 Subject: SCI: Use a simpler atan implementation for kGetAngle in SCI1 and newer games SCI1 games (QFG2 and newer) use a simpler and more accurate atan implementation for kGetAngle. This properly fixes bug #3540976. --- engines/sci/engine/kmath.cpp | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp index a643fbe37a..4b8fadbb84 100644 --- a/engines/sci/engine/kmath.cpp +++ b/engines/sci/engine/kmath.cpp @@ -84,27 +84,10 @@ reg_t kSqrt(EngineState *s, int argc, reg_t *argv) { * accurate. */ uint16 kGetAngleWorker(int16 x1, int16 y1, int16 x2, int16 y2) { - // TODO: This has been implemented based on behavior observed with a test - // program created with SCI Studio. However, the return values have subtle - // differences from the original, which uses custom implementation of atan(). - // The differences in the return values are the cause of bug #3540976 - // and perhaps bug #3037267 as well. - // The results of this function match the expected results of SCI0, but not - // SCI1 (hence the bug in Longbow). We need to find the point in history - // when this function was changed. - - // HACK: Return the expected value for Longbow, scene 150 (bug #3540976). - // This is a temporary solution, till the function returns the expected - // results. - if (g_sci->getGameId() == GID_LONGBOW && g_sci->getEngineState()->currentRoomNumber() == 150) { - if (x1 == 207 && y1 == 88 && x2 == 107 && y2 == 184) - return 226; - } - -#if 0 - // A simpler atan2-based implementation - return (int16)(360 - atan2((double)(x1 - x2), (double)(y1 - y2)) * 57.2958) % 360; -#endif + // SCI1 games (QFG2 and newer) use a simple atan implementation. SCI0 games + // use a somewhat less accurate calculation (below). + if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY) + return (int16)(360 - atan2((double)(x1 - x2), (double)(y1 - y2)) * 57.2958) % 360; int16 xRel = x2 - x1; int16 yRel = y1 - y2; // y-axis is mirrored. -- cgit v1.2.3 From 1a61056b06dc4ea5fe534f6ff13eb4e281bb9c03 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 21 Aug 2012 03:29:55 +0300 Subject: SCI: Extend a workaround for the dream sequence in QFG4 --- engines/sci/engine/workarounds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index a4c2355e8f..9fa0368784 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -399,7 +399,7 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = { { GID_LSL6, 740, 740, 0, "showCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during ending, 4 additional parameters are passed by accident { GID_LSL6HIRES, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident { GID_SQ1, 43, 303, 0, "slotGuy", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when leaving ulence flats bar, parameter 1 is not passed - script error - { GID_QFG4, 770, 110, 0, "dreamer", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during the dream sequence, a 3rd parameter is passed by accident + { GID_QFG4, -1, 110, 0, "dreamer", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during the dream sequence, a 3rd parameter is passed by accident SCI_WORKAROUNDENTRY_TERMINATOR }; -- cgit v1.2.3 From 7d436622a8e10437488f6dfa930e3ff15e254a55 Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 21 Aug 2012 03:31:00 +0300 Subject: SCI: More work on kRemapColors This implements some more color remap-based palette effects, found in QFG4 --- engines/sci/engine/kgraphics32.cpp | 21 ++++++++++++--------- engines/sci/graphics/palette.cpp | 21 +++++++++++++++++++++ engines/sci/graphics/palette.h | 1 + 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 685b3c0bd3..8b3afeef99 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -771,20 +771,23 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) { } break; case 3: { // remap to gray - // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0 + // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0. + // In this room, it's used for the cloud before Baba Yaga appears. int16 color = argv[1].toSint16(); int16 percent = argv[2].toSint16(); // 0 - 100 - uint16 unk3 = (argc >= 4) ? argv[3].toUint16() : 0; - warning("kRemapColors: RemapToGray color %d by %d percent (unk3 = %d)", color, percent, unk3); - // TODO + if (argc >= 4) + warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); + g_sci->_gfxPalette->setRemappingPercentGray(color, percent); } break; case 4: { // remap to percent gray - //int16 unk1 = argv[1].toSint16(); - //uint16 unk2 = argv[2].toUint16(); - //uint16 unk3 = argv[3].toUint16(); - //uint16 unk4 = (argc >= 5) ? argv[4].toUint16() : 0; - kStub(s, argc, argv); + // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200 + int16 color = argv[1].toSint16(); + int16 percent = argv[2].toSint16(); // 0 - 100 + // argv[3] is unknown (a number, e.g. 200) - start color, perhaps? + if (argc >= 5) + warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16()); + g_sci->_gfxPalette->setRemappingPercentGray(color, percent); } break; case 5: { // don't map to range diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 68104b0ac8..53d69cdcca 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -375,6 +375,27 @@ void GfxPalette::setRemappingPercent(byte color, byte percent) { _remappingType[color] = kRemappingByPercent; } +void GfxPalette::setRemappingPercentGray(byte color, byte percent) { + _remapOn = true; + + // We need to defer the setup of the remapping table every time the screen + // palette is changed, so that kernelFindColor() can find the correct + // colors. Set it once here, in case the palette stays the same and update + // it on each palette change by copySysPaletteToScreen(). + _remappingPercentToSet = percent; + + // Note: This is not what the original does, but the results are the same visually + for (int i = 0; i < 256; i++) { + byte rComponent = _sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100; + byte gComponent = _sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100; + byte bComponent = _sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100; + byte luminosity = rComponent + gComponent + bComponent; + _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity); + } + + _remappingType[color] = kRemappingByPercent; +} + void GfxPalette::setRemappingRange(byte color, byte from, byte to, byte base) { _remapOn = true; diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index 9898315897..e974781d49 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -61,6 +61,7 @@ public: void resetRemapping(); void setRemappingPercent(byte color, byte percent); + void setRemappingPercentGray(byte color, byte percent); void setRemappingRange(byte color, byte from, byte to, byte base); bool isRemapped(byte color) const { return _remapOn && (_remappingType[color] != kRemappingNone); -- cgit v1.2.3 From a391599403faf864f1583ababdba577fb6393afd Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 21 Aug 2012 11:55:21 +0300 Subject: SCI: Update a comment --- engines/sci/graphics/frameout.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 0098728e5d..6628247127 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -728,7 +728,9 @@ void GfxFrameout::kernelFrameout() { g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); } - // FIXME: When does this happen, and why? + // Don't attempt to draw sprites that are outside the visible + // screen area. An example is the random people walking in + // Jackson Square in GK1. if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= _screen->getDisplayHeight() || itemEntry->celRect.right < 0 || itemEntry->celRect.left >= _screen->getDisplayWidth()) continue; -- cgit v1.2.3 From 1d58ebe133c274643a89f2f4f0d24a2a8ab343c3 Mon Sep 17 00:00:00 2001 From: Bastien Bouclet Date: Tue, 21 Aug 2012 16:21:10 +0200 Subject: PS3: Force use of freetype from ps3toolchain --- configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 4b54832294..5c6deace41 100755 --- a/configure +++ b/configure @@ -2079,8 +2079,9 @@ case $_host_os in DEFINES="$DEFINES -D__PLAYSTATION2__" ;; ps3) - # Force use of SDL from the ps3 toolchain + # Force use of SDL and freetype from the ps3 toolchain _sdlpath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin" + _freetypepath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin" DEFINES="$DEFINES -DPLAYSTATION3" CXXFLAGS="$CXXFLAGS -mcpu=cell -mminimal-toc -I$PSL1GHT/ppu/include -I$PS3DEV/portlibs/ppu/include" -- cgit v1.2.3 From 829c836e0b86edc07aed4ed1846ac19ba76c6788 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 23 Aug 2012 22:44:02 -0400 Subject: VIDEO: Update the isPlaying() comment --- video/video_decoder.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/video/video_decoder.h b/video/video_decoder.h index 5fba85358c..5abe1d917c 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -117,7 +117,11 @@ public: /** * Returns if the video is currently playing or not. - * @todo Differentiate this function from endOfVideo() + * + * This is not equivalent to the inverse of endOfVideo(). A video keeps + * its playing status even after reaching the end of the video. This will + * return true after calling start() and will continue to return true + * until stop() (or close()) is called. */ bool isPlaying() const { return _isPlaying; } -- cgit v1.2.3 From dcdb40f79e4e02101ddd7c017762ec61298f1833 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Thu, 23 Aug 2012 23:11:09 -0400 Subject: VIDEO: Adjust start time after calling rewind() in start() This wasn't an actual bug, but it makes more sense this way --- video/video_decoder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 14826642d7..559880acee 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -347,14 +347,14 @@ void VideoDecoder::start() { _isPlaying = true; _startTime = g_system->getMillis(); - // Adjust start time if we've seeked to something besides zero time - if (_lastTimeChange.totalNumberOfFrames() != 0) - _startTime -= _lastTimeChange.msecs(); - // If someone previously called stop(), we'll rewind it. if (_needsRewind) rewind(); + // Adjust start time if we've seeked to something besides zero time + if (_lastTimeChange.totalNumberOfFrames() != 0) + _startTime -= _lastTimeChange.msecs(); + startAudio(); } -- cgit v1.2.3 From c7222ed5a4428c51cdf325fc0eb172f46a991d86 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sat, 25 Aug 2012 12:30:28 -0400 Subject: VIDEO: Remove obsolete FIXME in the FLIC code --- video/flic_decoder.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp index 564d73a9d7..1a0627615b 100644 --- a/video/flic_decoder.cpp +++ b/video/flic_decoder.cpp @@ -164,9 +164,6 @@ const Graphics::Surface *FlicDecoder::FlicVideoTrack::decodeNextFrame() { switch (frameType) { case FRAME_TYPE: { - // FIXME: FLIC should be switched over to a variable frame rate VideoDecoder to handle - // this properly. - chunkCount = _fileStream->readUint16LE(); // Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword) // the frame delay is the FLIC "speed", in milliseconds. -- cgit v1.2.3 From 6f9d84665fd090ae55386b1373a69e080b34e089 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 26 Aug 2012 12:38:35 -0400 Subject: COMMON: Add MKTAG16 for 16-bit multi-character constants --- common/endian.h | 6 ++++++ common/winexe_pe.cpp | 2 +- video/avi_decoder.cpp | 6 +++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/common/endian.h b/common/endian.h index 394437ec67..759513efef 100644 --- a/common/endian.h +++ b/common/endian.h @@ -146,6 +146,12 @@ */ #define MKTAG(a0,a1,a2,a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24))) +/** + * A wrapper macro used around two character constants, like 'wb', to + * ensure portability. Typical usage: MKTAG16('w','b'). + */ +#define MKTAG16(a0,a1) ((uint16)((a1) | ((a0) << 8))) + // Functions for reading/writing native integers. // They also transparently handle the need for alignment. diff --git a/common/winexe_pe.cpp b/common/winexe_pe.cpp index 6c0f9c9962..b3c45ffe73 100644 --- a/common/winexe_pe.cpp +++ b/common/winexe_pe.cpp @@ -64,7 +64,7 @@ bool PEResources::loadFromEXE(SeekableReadStream *stream) { if (!stream) return false; - if (stream->readUint16BE() != 'MZ') + if (stream->readUint16BE() != MKTAG16('M', 'Z')) return false; stream->skip(58); diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 0850d5656a..09b95d38ad 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -334,14 +334,14 @@ void AVIDecoder::readNextPacket() { _fileStream->skip(chunkSize & 1); if (track->getTrackType() == Track::kTrackTypeAudio) { - if (getStreamType(nextTag) != 'wb') + if (getStreamType(nextTag) != MKTAG16('w', 'b')) error("Invalid audio track tag '%s'", tag2str(nextTag)); ((AVIAudioTrack *)track)->queueSound(chunk); } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; - if (getStreamType(nextTag) == 'pc') { + if (getStreamType(nextTag) == MKTAG16('p', 'c')) { // Palette Change byte firstEntry = chunk->readByte(); uint16 numEntries = chunk->readByte(); @@ -362,7 +362,7 @@ void AVIDecoder::readNextPacket() { delete chunk; videoTrack->markPaletteDirty(); - } else if (getStreamType(nextTag) == 'db') { + } else if (getStreamType(nextTag) == MKTAG16('d', 'b')) { // TODO: Check if this really is uncompressed. Many videos // falsely put compressed data in here. error("Uncompressed AVI frame found"); -- cgit v1.2.3 From 18e7573dafbffdd509943c8f90f91933b17b0435 Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 26 Aug 2012 15:13:57 -0400 Subject: NEWS: Mention VideoDecoder rewrite --- NEWS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 3f5f10ce05..26f3640336 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,8 @@ For a more comprehensive changelog of the latest experimental code, see: https://github.com/scummvm/scummvm/commits/ 1.6.0 (????-??-??) - + General: + - Rewrote VideoDecoder subsystem. 1.5.0 (2012-07-27) New Games: -- cgit v1.2.3 From 3e2ff0a4437224a5d9de0b63d983e414b236992a Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Sun, 26 Aug 2012 20:30:32 -0400 Subject: VIDEO: Fix compilation with some compilers --- video/coktel_decoder.cpp | 12 ++++++++++-- video/coktel_decoder.h | 9 +++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp index 6a60b0e7d7..5d7efe87af 100644 --- a/video/coktel_decoder.cpp +++ b/video/coktel_decoder.cpp @@ -288,6 +288,14 @@ void CoktelDecoder::close() { _isPaused = false; } +Audio::Mixer::SoundType CoktelDecoder::getSoundType() const { + return _soundType; +} + +Audio::AudioStream *CoktelDecoder::getAudioStream() const { + return _audioStream; +} + uint16 CoktelDecoder::getWidth() const { return _width; } @@ -2847,11 +2855,11 @@ AdvancedVMDDecoder::VMDAudioTrack::VMDAudioTrack(VMDDecoder *decoder) : _decoder } Audio::Mixer::SoundType AdvancedVMDDecoder::VMDAudioTrack::getSoundType() const { - return _decoder->_soundType; + return _decoder->getSoundType(); } Audio::AudioStream *AdvancedVMDDecoder::VMDAudioTrack::getAudioStream() const { - return _decoder->_audioStream; + return _decoder->getAudioStream(); } } // End of namespace Video diff --git a/video/coktel_decoder.h b/video/coktel_decoder.h index 2a97eadf00..91d52b65e6 100644 --- a/video/coktel_decoder.h +++ b/video/coktel_decoder.h @@ -98,6 +98,8 @@ public: /** Override the video's frame rate. */ void setFrameRate(Common::Rational frameRate); + /** Get the video's frame rate. */ + Common::Rational getFrameRate() const; /** Get the video's default X position. */ uint16 getDefaultX() const; @@ -165,6 +167,11 @@ public: /** Close the video. */ void close(); + /** Get the Mixer SoundType audio is being played with. */ + Audio::Mixer::SoundType getSoundType() const; + /** Get the AudioStream for the audio. */ + Audio::AudioStream *getAudioStream() const; + uint16 getWidth() const; uint16 getHeight() const; virtual Graphics::PixelFormat getPixelFormat() const = 0; @@ -237,8 +244,6 @@ protected: bool evaluateSeekFrame(int32 &frame, int whence) const; - Common::Rational getFrameRate() const; - // Surface management bool hasSurface(); void createSurface(); -- cgit v1.2.3 From d2fb451f9ebf3f4131eb3ecd3d4de3523b305fdd Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Mon, 27 Aug 2012 11:41:47 +0100 Subject: I18N: Add Galician translation from patch #3557885 --- po/gl_ES.po | 3092 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3092 insertions(+) create mode 100644 po/gl_ES.po diff --git a/po/gl_ES.po b/po/gl_ES.po new file mode 100644 index 0000000000..d08867b717 --- /dev/null +++ b/po/gl_ES.po @@ -0,0 +1,3092 @@ +# LANGUAGE translation for ScummVM. +# Copyright (C) YEAR ScummVM Team +# This file is distributed under the same license as the ScummVM package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ScummVM 1.6.0git\n" +"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" +"POT-Creation-Date: 2012-08-12 14:57+0200\n" +"PO-Revision-Date: 2012-08-15 13:33+0100\n" +"Last-Translator: Santiago G. Sanz \n" +"Language-Team: \n" +"Language: Galego\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gui/about.cpp:91 +#, c-format +msgid "(built on %s)" +msgstr "(compilado o %s)" + +#: gui/about.cpp:98 +msgid "Features compiled in:" +msgstr "Funcionalidades compiladas:" + +#: gui/about.cpp:107 +msgid "Available engines:" +msgstr "Motores dispoñibles:" + +#: gui/browser.cpp:66 +msgid "Go up" +msgstr "Arriba" + +#: gui/browser.cpp:66 gui/browser.cpp:68 +msgid "Go to previous directory level" +msgstr "Ir ao directorio superior" + +#: gui/browser.cpp:68 +msgctxt "lowres" +msgid "Go up" +msgstr "Arriba" + +#: gui/browser.cpp:69 gui/chooser.cpp:45 gui/KeysDialog.cpp:43 +#: gui/launcher.cpp:345 gui/massadd.cpp:94 gui/options.cpp:1228 +#: gui/saveload-dialog.cpp:207 gui/saveload-dialog.cpp:267 +#: gui/saveload-dialog.cpp:516 gui/saveload-dialog.cpp:843 +#: gui/themebrowser.cpp:54 engines/engine.cpp:442 +#: engines/scumm/dialogs.cpp:190 engines/sword1/control.cpp:865 +#: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:48 +#: backends/events/default/default-events.cpp:191 +#: backends/events/default/default-events.cpp:213 +msgid "Cancel" +msgstr "Cancelar" + +#: gui/browser.cpp:70 gui/chooser.cpp:46 gui/themebrowser.cpp:55 +msgid "Choose" +msgstr "Elexir" + +#: gui/gui-manager.cpp:115 engines/scumm/help.cpp:125 +#: engines/scumm/help.cpp:140 engines/scumm/help.cpp:165 +#: engines/scumm/help.cpp:191 engines/scumm/help.cpp:209 +#: backends/keymapper/remap-dialog.cpp:52 +msgid "Close" +msgstr "Pechar" + +#: gui/gui-manager.cpp:118 +msgid "Mouse click" +msgstr "Premer co rato" + +#: gui/gui-manager.cpp:122 base/main.cpp:300 +msgid "Display keyboard" +msgstr "Mostrar teclado" + +#: gui/gui-manager.cpp:126 base/main.cpp:304 +msgid "Remap keys" +msgstr "Asignar teclas" + +#: gui/gui-manager.cpp:129 base/main.cpp:307 +msgid "Toggle FullScreen" +msgstr "Activar/desactivar pantalla completa" + +#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145 +msgid "Choose an action to map" +msgstr "Elixe unha acción para asignala" + +#: gui/KeysDialog.cpp:41 +msgid "Map" +msgstr "Asignar" + +#: gui/KeysDialog.cpp:42 gui/launcher.cpp:346 gui/launcher.cpp:1001 +#: gui/launcher.cpp:1005 gui/massadd.cpp:91 gui/options.cpp:1229 +#: gui/saveload-dialog.cpp:844 engines/engine.cpp:361 engines/engine.cpp:372 +#: engines/scumm/dialogs.cpp:192 engines/scumm/scumm.cpp:1775 +#: engines/agos/animation.cpp:561 engines/groovie/script.cpp:420 +#: engines/sky/compact.cpp:131 engines/sky/compact.cpp:141 +#: engines/sword1/animation.cpp:539 engines/sword1/animation.cpp:560 +#: engines/sword1/animation.cpp:570 engines/sword1/animation.cpp:577 +#: engines/sword1/control.cpp:865 engines/sword1/logic.cpp:1633 +#: engines/sword2/animation.cpp:435 engines/sword2/animation.cpp:455 +#: engines/sword2/animation.cpp:465 engines/sword2/animation.cpp:474 +#: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:47 +#: backends/platform/wince/CELauncherDialog.cpp:54 +msgid "OK" +msgstr "Aceptar" + +#: gui/KeysDialog.cpp:49 +msgid "Select an action and click 'Map'" +msgstr "Selecciona unha acción e preme en Asignar" + +#: gui/KeysDialog.cpp:80 gui/KeysDialog.cpp:102 gui/KeysDialog.cpp:141 +#, c-format +msgid "Associated key : %s" +msgstr "Tecla asociada: %s" + +#: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143 +#, c-format +msgid "Associated key : none" +msgstr "Tecla asociada: ningunha" + +#: gui/KeysDialog.cpp:90 +msgid "Please select an action" +msgstr "Selecciona unha acción" + +#: gui/KeysDialog.cpp:106 +msgid "Press the key to associate" +msgstr "Preme a tecla para asociala" + +#: gui/launcher.cpp:187 +msgid "Game" +msgstr "Xogo" + +#: gui/launcher.cpp:191 +msgid "ID:" +msgstr "ID:" + +#: gui/launcher.cpp:191 gui/launcher.cpp:193 gui/launcher.cpp:194 +msgid "" +"Short game identifier used for referring to savegames and running the game " +"from the command line" +msgstr "" +"Identificador curto do xogo para os ficheiros de gardado e a execución do " +"xogo dende a liña de comandos" + +#: gui/launcher.cpp:193 +msgctxt "lowres" +msgid "ID:" +msgstr "ID:" + +#: gui/launcher.cpp:198 +msgid "Name:" +msgstr "Nome:" + +#: gui/launcher.cpp:198 gui/launcher.cpp:200 gui/launcher.cpp:201 +msgid "Full title of the game" +msgstr "Título completo do xogo" + +#: gui/launcher.cpp:200 +msgctxt "lowres" +msgid "Name:" +msgstr "Nome:" + +#: gui/launcher.cpp:204 +msgid "Language:" +msgstr "Idioma:" + +#: gui/launcher.cpp:204 gui/launcher.cpp:205 +msgid "" +"Language of the game. This will not turn your Spanish game version into " +"English" +msgstr "Idioma do xogo. Non converterá a versión galega do xogo en inglesa" + +#: gui/launcher.cpp:206 gui/launcher.cpp:220 gui/options.cpp:80 +#: gui/options.cpp:730 gui/options.cpp:743 gui/options.cpp:1199 +#: audio/null.cpp:40 +msgid "" +msgstr "" + +#: gui/launcher.cpp:216 +msgid "Platform:" +msgstr "Plataforma:" + +#: gui/launcher.cpp:216 gui/launcher.cpp:218 gui/launcher.cpp:219 +msgid "Platform the game was originally designed for" +msgstr "Plataforma para a que se desenvolvera o xogo inicialmente" + +#: gui/launcher.cpp:218 +msgctxt "lowres" +msgid "Platform:" +msgstr "Plataforma:" + +#: gui/launcher.cpp:231 +msgid "Engine" +msgstr "Motor" + +#: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 +msgid "Graphics" +msgstr "Gráficos" + +#: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 +msgid "GFX" +msgstr "Efectos gráficos" + +#: gui/launcher.cpp:242 +msgid "Override global graphic settings" +msgstr "Anular a configuración dos gráficos" + +#: gui/launcher.cpp:244 +msgctxt "lowres" +msgid "Override global graphic settings" +msgstr "Anular a configuración dos gráficos" + +#: gui/launcher.cpp:251 gui/options.cpp:1085 +msgid "Audio" +msgstr "Son" + +#: gui/launcher.cpp:254 +msgid "Override global audio settings" +msgstr "Anular a configuración do son" + +#: gui/launcher.cpp:256 +msgctxt "lowres" +msgid "Override global audio settings" +msgstr "Anular a configuración do son" + +#: gui/launcher.cpp:265 gui/options.cpp:1090 +msgid "Volume" +msgstr "Volume" + +#: gui/launcher.cpp:267 gui/options.cpp:1092 +msgctxt "lowres" +msgid "Volume" +msgstr "Volume" + +#: gui/launcher.cpp:270 +msgid "Override global volume settings" +msgstr "Anular a configuración do volume" + +#: gui/launcher.cpp:272 +msgctxt "lowres" +msgid "Override global volume settings" +msgstr "Anular a configuración do volume" + +#: gui/launcher.cpp:280 gui/options.cpp:1100 +msgid "MIDI" +msgstr "MIDI" + +#: gui/launcher.cpp:283 +msgid "Override global MIDI settings" +msgstr "Anular a configuración de MIDI" + +#: gui/launcher.cpp:285 +msgctxt "lowres" +msgid "Override global MIDI settings" +msgstr "Anular a configuración de MIDI" + +#: gui/launcher.cpp:294 gui/options.cpp:1106 +msgid "MT-32" +msgstr "MT-32" + +#: gui/launcher.cpp:297 +msgid "Override global MT-32 settings" +msgstr "Anular a configuración de MT-32" + +#: gui/launcher.cpp:299 +msgctxt "lowres" +msgid "Override global MT-32 settings" +msgstr "Anular a configuración de MT-32" + +#: gui/launcher.cpp:308 gui/options.cpp:1113 +msgid "Paths" +msgstr "Camiños" + +#: gui/launcher.cpp:310 gui/options.cpp:1115 +msgctxt "lowres" +msgid "Paths" +msgstr "Camiños" + +#: gui/launcher.cpp:317 +msgid "Game Path:" +msgstr "Camiño do xogo:" + +#: gui/launcher.cpp:319 +msgctxt "lowres" +msgid "Game Path:" +msgstr "Camiño do xogo:" + +#: gui/launcher.cpp:324 gui/options.cpp:1139 +msgid "Extra Path:" +msgstr "Camiño adicional:" + +#: gui/launcher.cpp:324 gui/launcher.cpp:326 gui/launcher.cpp:327 +msgid "Specifies path to additional data used the game" +msgstr "Especifica o camiño dos datos adicionais usados no xogo" + +#: gui/launcher.cpp:326 gui/options.cpp:1141 +msgctxt "lowres" +msgid "Extra Path:" +msgstr "Camiño adicional:" + +#: gui/launcher.cpp:333 gui/options.cpp:1123 +msgid "Save Path:" +msgstr "Camiño de gardado:" + +#: gui/launcher.cpp:333 gui/launcher.cpp:335 gui/launcher.cpp:336 +#: gui/options.cpp:1123 gui/options.cpp:1125 gui/options.cpp:1126 +msgid "Specifies where your savegames are put" +msgstr "Especifica o lugar dos ficheiros de gardado" + +#: gui/launcher.cpp:335 gui/options.cpp:1125 +msgctxt "lowres" +msgid "Save Path:" +msgstr "Camiño de gardado:" + +#: gui/launcher.cpp:354 gui/launcher.cpp:453 gui/launcher.cpp:511 +#: gui/launcher.cpp:565 gui/options.cpp:1134 gui/options.cpp:1142 +#: gui/options.cpp:1151 gui/options.cpp:1258 gui/options.cpp:1264 +#: gui/options.cpp:1272 gui/options.cpp:1302 gui/options.cpp:1308 +#: gui/options.cpp:1315 gui/options.cpp:1408 gui/options.cpp:1411 +#: gui/options.cpp:1423 +msgctxt "path" +msgid "None" +msgstr "Ningún" + +#: gui/launcher.cpp:359 gui/launcher.cpp:459 gui/launcher.cpp:569 +#: gui/options.cpp:1252 gui/options.cpp:1296 gui/options.cpp:1414 +#: backends/platform/wii/options.cpp:56 +msgid "Default" +msgstr "Predefinido" + +#: gui/launcher.cpp:504 gui/options.cpp:1417 +msgid "Select SoundFont" +msgstr "Seleccionar SoundFont" + +#: gui/launcher.cpp:523 gui/launcher.cpp:677 +msgid "Select directory with game data" +msgstr "Selecciona un directorio con datos de xogo" + +#: gui/launcher.cpp:541 +msgid "Select additional game directory" +msgstr "Selecciona un directorio con datos adicionais" + +#: gui/launcher.cpp:553 +msgid "Select directory for saved games" +msgstr "Selecciona un directorio para ficheiros de gardado" + +#: gui/launcher.cpp:580 +msgid "This game ID is already taken. Please choose another one." +msgstr "Este ID de xogo xa está en uso. Selecciona outro." + +#: gui/launcher.cpp:621 engines/dialogs.cpp:110 +msgid "~Q~uit" +msgstr "~S~aír" + +#: gui/launcher.cpp:621 backends/platform/sdl/macosx/appmenu_osx.mm:96 +msgid "Quit ScummVM" +msgstr "Saír de ScummVM" + +#: gui/launcher.cpp:622 +msgid "A~b~out..." +msgstr "Ace~r~ca de..." + +#: gui/launcher.cpp:622 backends/platform/sdl/macosx/appmenu_osx.mm:70 +msgid "About ScummVM" +msgstr "Acerca de ScummVM" + +#: gui/launcher.cpp:623 +msgid "~O~ptions..." +msgstr "~O~pcións..." + +#: gui/launcher.cpp:623 +msgid "Change global ScummVM options" +msgstr "Cambiar as opcións de ScummVM" + +#: gui/launcher.cpp:625 +msgid "~S~tart" +msgstr "~I~niciar" + +#: gui/launcher.cpp:625 +msgid "Start selected game" +msgstr "Iniciar o xogo seleccionado" + +#: gui/launcher.cpp:628 +msgid "~L~oad..." +msgstr "~C~argar..." + +#: gui/launcher.cpp:628 +msgid "Load savegame for selected game" +msgstr "Cargar partida do xogo seleccionado" + +#: gui/launcher.cpp:633 gui/launcher.cpp:1120 +msgid "~A~dd Game..." +msgstr "Eng~a~dir xogo..." + +#: gui/launcher.cpp:633 gui/launcher.cpp:640 +msgid "Hold Shift for Mass Add" +msgstr "Manter premido MAIÚS para engadir en masa" + +#: gui/launcher.cpp:635 +msgid "~E~dit Game..." +msgstr "~E~ditar xogo..." + +#: gui/launcher.cpp:635 gui/launcher.cpp:642 +msgid "Change game options" +msgstr "Cambiar as opcións do xogo" + +#: gui/launcher.cpp:637 +msgid "~R~emove Game" +msgstr "Elimina~r~ xogo" + +#: gui/launcher.cpp:637 gui/launcher.cpp:644 +msgid "Remove game from the list. The game data files stay intact" +msgstr "Eliminar o xogo da lista. Os ficheiros de datos non se modifican" + +#: gui/launcher.cpp:640 gui/launcher.cpp:1120 +msgctxt "lowres" +msgid "~A~dd Game..." +msgstr "Eng~a~dir xogo..." + +#: gui/launcher.cpp:642 +msgctxt "lowres" +msgid "~E~dit Game..." +msgstr "~E~ditar xogo..." + +#: gui/launcher.cpp:644 +msgctxt "lowres" +msgid "~R~emove Game" +msgstr "Elimina~r~ xogo" + +#: gui/launcher.cpp:652 +msgid "Search in game list" +msgstr "Buscar na lista de xogos" + +#: gui/launcher.cpp:656 gui/launcher.cpp:1167 +msgid "Search:" +msgstr "Buscar:" + +#: gui/launcher.cpp:680 engines/dialogs.cpp:114 engines/mohawk/myst.cpp:245 +#: engines/mohawk/riven.cpp:716 engines/cruise/menu.cpp:214 +msgid "Load game:" +msgstr "Cargar partida:" + +#: gui/launcher.cpp:680 engines/dialogs.cpp:114 engines/scumm/dialogs.cpp:188 +#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:716 +#: engines/cruise/menu.cpp:214 backends/platform/wince/CEActionsPocket.cpp:267 +#: backends/platform/wince/CEActionsSmartphone.cpp:231 +msgid "Load" +msgstr "Cargar" + +#: gui/launcher.cpp:788 +msgid "" +"Do you really want to run the mass game detector? This could potentially add " +"a huge number of games." +msgstr "" +"Queres executar o detector de xogos en masa? É posible que se engada un gran " +"número de xogos." + +#: gui/launcher.cpp:789 gui/launcher.cpp:937 +#: backends/events/symbiansdl/symbiansdl-events.cpp:184 +#: backends/platform/wince/CEActionsPocket.cpp:326 +#: backends/platform/wince/CEActionsSmartphone.cpp:287 +#: backends/platform/wince/CELauncherDialog.cpp:83 +msgid "Yes" +msgstr "Si" + +#: gui/launcher.cpp:789 gui/launcher.cpp:937 +#: backends/events/symbiansdl/symbiansdl-events.cpp:184 +#: backends/platform/wince/CEActionsPocket.cpp:326 +#: backends/platform/wince/CEActionsSmartphone.cpp:287 +#: backends/platform/wince/CELauncherDialog.cpp:83 +msgid "No" +msgstr "Non" + +#: gui/launcher.cpp:837 +msgid "ScummVM couldn't open the specified directory!" +msgstr "ScummVM non foi quen de abrir o directorio!" + +#: gui/launcher.cpp:849 +msgid "ScummVM could not find any game in the specified directory!" +msgstr "ScummVM non foi quen de atopar xogos no directorio!" + +#: gui/launcher.cpp:863 +msgid "Pick the game:" +msgstr "Elixe o xogo:" + +#: gui/launcher.cpp:937 +msgid "Do you really want to remove this game configuration?" +msgstr "Seguro que queres eliminar esta configuración de xogo?" + +#: gui/launcher.cpp:1001 +msgid "This game does not support loading games from the launcher." +msgstr "O xogo non permite cargar partidas dende o iniciador." + +#: gui/launcher.cpp:1005 +msgid "ScummVM could not find any engine capable of running the selected game!" +msgstr "ScummVM non foi quen de atopar un motor para executar o xogo!" + +#: gui/launcher.cpp:1119 +msgctxt "lowres" +msgid "Mass Add..." +msgstr "Engadir en masa..." + +#: gui/launcher.cpp:1119 +msgid "Mass Add..." +msgstr "Engadir en masa..." + +#: gui/massadd.cpp:78 gui/massadd.cpp:81 +msgid "... progress ..." +msgstr "...progreso..." + +#: gui/massadd.cpp:258 +msgid "Scan complete!" +msgstr "Análise finalizada!" + +#: gui/massadd.cpp:261 +#, c-format +msgid "Discovered %d new games, ignored %d previously added games." +msgstr "%d xogos novos atopados; %d xogos xa engadidos ignorados." + +#: gui/massadd.cpp:265 +#, c-format +msgid "Scanned %d directories ..." +msgstr "%d directorios analizados..." + +#: gui/massadd.cpp:268 +#, c-format +msgid "Discovered %d new games, ignored %d previously added games ..." +msgstr "%d xogos novos atopados; %d xogos xa engadidos ignorados..." + +#: gui/options.cpp:78 +msgid "Never" +msgstr "Nunca" + +#: gui/options.cpp:78 +msgid "every 5 mins" +msgstr "cada 5 min" + +#: gui/options.cpp:78 +msgid "every 10 mins" +msgstr "cada 10 min" + +#: gui/options.cpp:78 +msgid "every 15 mins" +msgstr "cada 15 min" + +#: gui/options.cpp:78 +msgid "every 30 mins" +msgstr "cada 30 min" + +#: gui/options.cpp:80 +msgid "8 kHz" +msgstr "8 kHz" + +#: gui/options.cpp:80 +msgid "11kHz" +msgstr "11 kHz" + +#: gui/options.cpp:80 +msgid "22 kHz" +msgstr "22 kHz" + +#: gui/options.cpp:80 +msgid "44 kHz" +msgstr "44 kHz" + +#: gui/options.cpp:80 +msgid "48 kHz" +msgstr "48 kHz" + +#: gui/options.cpp:248 gui/options.cpp:474 gui/options.cpp:575 +#: gui/options.cpp:644 gui/options.cpp:852 +msgctxt "soundfont" +msgid "None" +msgstr "Ningunha" + +#: gui/options.cpp:382 +msgid "Failed to apply some of the graphic options changes:" +msgstr "Erro ao aplicar os cambios na configuración dos gráficos:" + +#: gui/options.cpp:394 +msgid "the video mode could not be changed." +msgstr "non se puido cambiar o modo de vídeo." + +#: gui/options.cpp:400 +msgid "the fullscreen setting could not be changed" +msgstr "non se puido cambiar a configuración de pantalla completa." + +#: gui/options.cpp:406 +msgid "the aspect ratio setting could not be changed" +msgstr "non se puido cambiar a proporción." + +#: gui/options.cpp:727 +msgid "Graphics mode:" +msgstr "Modo de gráficos:" + +#: gui/options.cpp:741 +msgid "Render mode:" +msgstr "Modo de procesamento:" + +#: gui/options.cpp:741 gui/options.cpp:742 +msgid "Special dithering modes supported by some games" +msgstr "Modos de interpolación de cores compatibles con algúns xogos" + +#: gui/options.cpp:753 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2236 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:472 +msgid "Fullscreen mode" +msgstr "Pantalla completa" + +#: gui/options.cpp:756 +msgid "Aspect ratio correction" +msgstr "Corrección de proporción" + +#: gui/options.cpp:756 +msgid "Correct aspect ratio for 320x200 games" +msgstr "Corrixir a proporción para os xogos en 320x200" + +#: gui/options.cpp:764 +msgid "Preferred Device:" +msgstr "Dispositivo preferido:" + +#: gui/options.cpp:764 +msgid "Music Device:" +msgstr "Dispositivo de música:" + +#: gui/options.cpp:764 gui/options.cpp:766 +msgid "Specifies preferred sound device or sound card emulator" +msgstr "Especifica o dispositivo ou emulador de tarxeta de son preferido" + +#: gui/options.cpp:764 gui/options.cpp:766 gui/options.cpp:767 +msgid "Specifies output sound device or sound card emulator" +msgstr "Especifica o dispositivo ou emulador de tarxeta de son de saída" + +#: gui/options.cpp:766 +msgctxt "lowres" +msgid "Preferred Dev.:" +msgstr "Disp. preferido:" + +#: gui/options.cpp:766 +msgctxt "lowres" +msgid "Music Device:" +msgstr "Disp. música:" + +#: gui/options.cpp:793 +msgid "AdLib emulator:" +msgstr "Emulador de AdLib:" + +#: gui/options.cpp:793 gui/options.cpp:794 +msgid "AdLib is used for music in many games" +msgstr "Moitos xogos empregan AdLib para a música" + +#: gui/options.cpp:804 +msgid "Output rate:" +msgstr "Taxa de saída:" + +#: gui/options.cpp:804 gui/options.cpp:805 +msgid "" +"Higher value specifies better sound quality but may be not supported by your " +"soundcard" +msgstr "" +"A maior valor, maior calidade do son, mais talvez non sexa compatible coa " +"tarxeta" + +#: gui/options.cpp:815 +msgid "GM Device:" +msgstr "Dispositivo de GM:" + +#: gui/options.cpp:815 +msgid "Specifies default sound device for General MIDI output" +msgstr "" +"Especifica o dispositivo de son por defecto para a saída de General MIDI" + +#: gui/options.cpp:826 +msgid "Don't use General MIDI music" +msgstr "Non empregar música en General MIDI" + +#: gui/options.cpp:837 gui/options.cpp:899 +msgid "Use first available device" +msgstr "Empregar o primeiro dispositivo dispoñible" + +#: gui/options.cpp:849 +msgid "SoundFont:" +msgstr "SoundFont:" + +#: gui/options.cpp:849 gui/options.cpp:851 gui/options.cpp:852 +msgid "SoundFont is supported by some audio cards, Fluidsynth and Timidity" +msgstr "" +"SoundFont é compatible con algunhas tarxetas de son, Fluidsynth e Timidity" + +#: gui/options.cpp:851 +msgctxt "lowres" +msgid "SoundFont:" +msgstr "SoundFont:" + +#: gui/options.cpp:857 +msgid "Mixed AdLib/MIDI mode" +msgstr "Modo AdLib/MIDI mixto" + +#: gui/options.cpp:857 +msgid "Use both MIDI and AdLib sound generation" +msgstr "Empregar xeración de son MIDI e máis AdLib" + +#: gui/options.cpp:860 +msgid "MIDI gain:" +msgstr "Ganancia de MIDI:" + +#: gui/options.cpp:870 +msgid "MT-32 Device:" +msgstr "Dispositivo de MT-32:" + +#: gui/options.cpp:870 +msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output" +msgstr "" +"Especifica o dispositivo por defecto para a saída de Roland MT-32/LAPC1/" +"CM32l/CM64" + +#: gui/options.cpp:875 +msgid "True Roland MT-32 (disable GM emulation)" +msgstr "Roland MT-32 verdadeiro (sen emulación de GM)" + +#: gui/options.cpp:875 gui/options.cpp:877 +msgid "" +"Check if you want to use your real hardware Roland-compatible sound device " +"connected to your computer" +msgstr "" +"Marcar para empregar o hardware compatible con Roland conectado ao sistema" + +#: gui/options.cpp:877 +msgctxt "lowres" +msgid "True Roland MT-32 (no GM emulation)" +msgstr "Roland MT-32 (sen emulación de GM)" + +#: gui/options.cpp:880 +msgid "Enable Roland GS Mode" +msgstr "Activar modo Roland GS" + +#: gui/options.cpp:880 +msgid "Turns off General MIDI mapping for games with Roland MT-32 soundtrack" +msgstr "Desactiva o General MIDI para os xogos con música en Roland MT-32" + +#: gui/options.cpp:889 +msgid "Don't use Roland MT-32 music" +msgstr "Non empregar música en Roland MT-32" + +#: gui/options.cpp:916 +msgid "Text and Speech:" +msgstr "Texto e voz:" + +#: gui/options.cpp:920 gui/options.cpp:930 +msgid "Speech" +msgstr "Voz" + +#: gui/options.cpp:921 gui/options.cpp:931 +msgid "Subtitles" +msgstr "Subtítulos" + +#: gui/options.cpp:922 +msgid "Both" +msgstr "Ambos" + +#: gui/options.cpp:924 +msgid "Subtitle speed:" +msgstr "Velocidade dos subtítulos:" + +#: gui/options.cpp:926 +msgctxt "lowres" +msgid "Text and Speech:" +msgstr "Texto e voz:" + +#: gui/options.cpp:930 +msgid "Spch" +msgstr "Voz" + +#: gui/options.cpp:931 +msgid "Subs" +msgstr "Subs" + +#: gui/options.cpp:932 +msgctxt "lowres" +msgid "Both" +msgstr "Ambos" + +#: gui/options.cpp:932 +msgid "Show subtitles and play speech" +msgstr "Mostrar os subtítulos e reproducir as voces" + +#: gui/options.cpp:934 +msgctxt "lowres" +msgid "Subtitle speed:" +msgstr "Velocidade subs:" + +#: gui/options.cpp:950 +msgid "Music volume:" +msgstr "Volume de música:" + +#: gui/options.cpp:952 +msgctxt "lowres" +msgid "Music volume:" +msgstr "Volume música:" + +#: gui/options.cpp:959 +msgid "Mute All" +msgstr "Silenciar todo" + +#: gui/options.cpp:962 +msgid "SFX volume:" +msgstr "Volume de efectos:" + +#: gui/options.cpp:962 gui/options.cpp:964 gui/options.cpp:965 +msgid "Special sound effects volume" +msgstr "Volume dos efectos de son" + +#: gui/options.cpp:964 +msgctxt "lowres" +msgid "SFX volume:" +msgstr "Volume efectos:" + +#: gui/options.cpp:972 +msgid "Speech volume:" +msgstr "Volume de voz:" + +#: gui/options.cpp:974 +msgctxt "lowres" +msgid "Speech volume:" +msgstr "Volume voz:" + +#: gui/options.cpp:1131 +msgid "Theme Path:" +msgstr "Camiño do tema:" + +#: gui/options.cpp:1133 +msgctxt "lowres" +msgid "Theme Path:" +msgstr "Camiño tema:" + +#: gui/options.cpp:1139 gui/options.cpp:1141 gui/options.cpp:1142 +msgid "Specifies path to additional data used by all games or ScummVM" +msgstr "" +"Especificar o camiño dos datos adicionais de todos os xogos ou de ScummVM" + +#: gui/options.cpp:1148 +msgid "Plugins Path:" +msgstr "Camiño dos complementos:" + +#: gui/options.cpp:1150 +msgctxt "lowres" +msgid "Plugins Path:" +msgstr "Camiño complementos:" + +#: gui/options.cpp:1159 +msgid "Misc" +msgstr "Misc." + +#: gui/options.cpp:1161 +msgctxt "lowres" +msgid "Misc" +msgstr "Misc." + +#: gui/options.cpp:1163 +msgid "Theme:" +msgstr "Tema:" + +#: gui/options.cpp:1167 +msgid "GUI Renderer:" +msgstr "Procesamento da interfaz:" + +#: gui/options.cpp:1179 +msgid "Autosave:" +msgstr "Autogardado:" + +#: gui/options.cpp:1181 +msgctxt "lowres" +msgid "Autosave:" +msgstr "Autogardado:" + +#: gui/options.cpp:1189 +msgid "Keys" +msgstr "Teclas" + +#: gui/options.cpp:1196 +msgid "GUI Language:" +msgstr "Idioma de interfaz:" + +#: gui/options.cpp:1196 +msgid "Language of ScummVM GUI" +msgstr "Idioma da interfaz de ScummVM" + +#: gui/options.cpp:1347 +msgid "You have to restart ScummVM before your changes will take effect." +msgstr "Debes reiniciar ScummVM para que os cambios teñan efecto." + +#: gui/options.cpp:1360 +msgid "Select directory for savegames" +msgstr "Seleccionar directorio para ficheiros de gardado" + +#: gui/options.cpp:1367 +msgid "The chosen directory cannot be written to. Please select another one." +msgstr "Non é posible escribir no directorio elixido. Selecciona outro." + +#: gui/options.cpp:1376 +msgid "Select directory for GUI themes" +msgstr "Seleccionar directorio para temas de interfaz" + +#: gui/options.cpp:1386 +msgid "Select directory for extra files" +msgstr "Seleccionar directorio para ficheiros adicionais" + +#: gui/options.cpp:1397 +msgid "Select directory for plugins" +msgstr "Seleccionar directorio para complementos" + +#: gui/options.cpp:1450 +msgid "" +"The theme you selected does not support your current language. If you want " +"to use this theme you need to switch to another language first." +msgstr "" +"O tema seleccionado non é compatible co idioma actual. Para empregar o tema, " +"deberás cambiar antes o idioma da interfaz." + +#: gui/saveload-dialog.cpp:158 +msgid "List view" +msgstr "Lista" + +#: gui/saveload-dialog.cpp:159 +msgid "Grid view" +msgstr "Grade" + +#: gui/saveload-dialog.cpp:202 gui/saveload-dialog.cpp:350 +msgid "No date saved" +msgstr "Non hai data gardada" + +#: gui/saveload-dialog.cpp:203 gui/saveload-dialog.cpp:351 +msgid "No time saved" +msgstr "Non hai hora gardada" + +#: gui/saveload-dialog.cpp:204 gui/saveload-dialog.cpp:352 +msgid "No playtime saved" +msgstr "Non hai tempo de xogo gardado" + +#: gui/saveload-dialog.cpp:211 gui/saveload-dialog.cpp:267 +msgid "Delete" +msgstr "Eliminar" + +#: gui/saveload-dialog.cpp:266 +msgid "Do you really want to delete this savegame?" +msgstr "Seguro que queres eliminar esta partida?" + +#: gui/saveload-dialog.cpp:375 gui/saveload-dialog.cpp:796 +msgid "Date: " +msgstr "Data:" + +#: gui/saveload-dialog.cpp:379 gui/saveload-dialog.cpp:802 +msgid "Time: " +msgstr "Hora:" + +#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:810 +msgid "Playtime: " +msgstr "Tempo de xogo:" + +#: gui/saveload-dialog.cpp:398 gui/saveload-dialog.cpp:465 +msgid "Untitled savestate" +msgstr "Partida sen título" + +#: gui/saveload-dialog.cpp:517 +msgid "Next" +msgstr "Seg." + +#: gui/saveload-dialog.cpp:520 +msgid "Prev" +msgstr "Ant." + +#: gui/saveload-dialog.cpp:684 +msgid "New Save" +msgstr "Novo ficheiro" + +#: gui/saveload-dialog.cpp:684 +msgid "Create a new save game" +msgstr "Crea un novo ficheiro de gardado" + +#: gui/saveload-dialog.cpp:789 +msgid "Name: " +msgstr "Nome:" + +#: gui/saveload-dialog.cpp:861 +#, c-format +msgid "Enter a description for slot %d:" +msgstr "Introduce unha descrición para o espazo %d:" + +#: gui/themebrowser.cpp:44 +msgid "Select a Theme" +msgstr "Seleccionar tema" + +#: gui/ThemeEngine.cpp:337 +msgid "Disabled GFX" +msgstr "Efectos gráficos desactivados" + +#: gui/ThemeEngine.cpp:337 +msgctxt "lowres" +msgid "Disabled GFX" +msgstr "Efectos desactivados" + +#: gui/ThemeEngine.cpp:338 +msgid "Standard Renderer (16bpp)" +msgstr "Procesamento estándar (16 bpp)" + +#: gui/ThemeEngine.cpp:338 +msgid "Standard (16bpp)" +msgstr "Estándar (16 bpp)" + +#: gui/ThemeEngine.cpp:340 +msgid "Antialiased Renderer (16bpp)" +msgstr "Procesamento antidistorsión (16 bpp)" + +#: gui/ThemeEngine.cpp:340 +msgid "Antialiased (16bpp)" +msgstr "Antidistorsión (16 bpp)" + +#: gui/widget.cpp:322 gui/widget.cpp:324 gui/widget.cpp:330 gui/widget.cpp:332 +msgid "Clear value" +msgstr "Limpar valor" + +#: base/main.cpp:209 +#, c-format +msgid "Engine does not support debug level '%s'" +msgstr "O motor non é compatible co nivel de depuración %s" + +#: base/main.cpp:287 +msgid "Menu" +msgstr "Menú" + +#: base/main.cpp:290 backends/platform/symbian/src/SymbianActions.cpp:45 +#: backends/platform/wince/CEActionsPocket.cpp:45 +#: backends/platform/wince/CEActionsSmartphone.cpp:46 +msgid "Skip" +msgstr "Omitir" + +#: base/main.cpp:293 backends/platform/symbian/src/SymbianActions.cpp:50 +#: backends/platform/wince/CEActionsPocket.cpp:42 +msgid "Pause" +msgstr "Pausa" + +#: base/main.cpp:296 +msgid "Skip line" +msgstr "Omitir liña" + +#: base/main.cpp:467 +msgid "Error running game:" +msgstr "Erro de execución do xogo:" + +#: base/main.cpp:491 +msgid "Could not find any engine capable of running the selected game" +msgstr "Non se puido atopar un motor para executar o xogo seleccionado" + +#: common/error.cpp:38 +msgid "No error" +msgstr "Non hai erros" + +#: common/error.cpp:40 +msgid "Game data not found" +msgstr "Non se atoparon datos de xogo" + +#: common/error.cpp:42 +msgid "Game id not supported" +msgstr "ID de xogo non compatible" + +#: common/error.cpp:44 +msgid "Unsupported color mode" +msgstr "Modo de color non compatible" + +#: common/error.cpp:47 +msgid "Read permission denied" +msgstr "Permiso de lectura denegado" + +#: common/error.cpp:49 +msgid "Write permission denied" +msgstr "Permiso de escritura denegado" + +#: common/error.cpp:52 +msgid "Path does not exist" +msgstr "O camiño non existe" + +#: common/error.cpp:54 +msgid "Path not a directory" +msgstr "O camiño non é un directorio" + +#: common/error.cpp:56 +msgid "Path not a file" +msgstr "O camiño non é un ficheiro" + +#: common/error.cpp:59 +msgid "Cannot create file" +msgstr "Erro ao crear o ficheiro" + +#: common/error.cpp:61 +msgid "Reading data failed" +msgstr "Erro ao ler os datos" + +#: common/error.cpp:63 +msgid "Writing data failed" +msgstr "Erro ao escribir os datos" + +#: common/error.cpp:66 +msgid "Could not find suitable engine plugin" +msgstr "Non se atopou un complemento axeitado para o motor" + +#: common/error.cpp:68 +msgid "Engine plugin does not support save states" +msgstr "O complemento do motor non é compatible cos ficheiros de gardado" + +#: common/error.cpp:71 +msgid "User canceled" +msgstr "Usuario cancelado" + +#: common/error.cpp:75 +msgid "Unknown error" +msgstr "Erro descoñecido" + +#: engines/advancedDetector.cpp:316 +#, c-format +msgid "The game in '%s' seems to be unknown." +msgstr "O xogo de %s semella ser descoñecido." + +#: engines/advancedDetector.cpp:317 +msgid "Please, report the following data to the ScummVM team along with name" +msgstr "Facilita esta información ao equipo de ScummVM, xunto co nome" + +#: engines/advancedDetector.cpp:319 +msgid "of the game you tried to add and its version/language/etc.:" +msgstr "do xogo que tentaches engadir, xunto coa versión, lingua, etc.:" + +#: engines/dialogs.cpp:84 +msgid "~R~esume" +msgstr "~R~etomar" + +#: engines/dialogs.cpp:86 +msgid "~L~oad" +msgstr "~C~argar" + +#: engines/dialogs.cpp:90 +msgid "~S~ave" +msgstr "~G~ardar" + +#: engines/dialogs.cpp:94 +msgid "~O~ptions" +msgstr "~O~pcións" + +#: engines/dialogs.cpp:99 +msgid "~H~elp" +msgstr "~A~xuda" + +#: engines/dialogs.cpp:101 +msgid "~A~bout" +msgstr "Acerca ~d~e" + +#: engines/dialogs.cpp:104 engines/dialogs.cpp:180 +msgid "~R~eturn to Launcher" +msgstr "~V~olver ao Iniciador" + +#: engines/dialogs.cpp:106 engines/dialogs.cpp:182 +msgctxt "lowres" +msgid "~R~eturn to Launcher" +msgstr "~V~olver ao Iniciador" + +#: engines/dialogs.cpp:115 engines/agi/saveload.cpp:803 +#: engines/cruise/menu.cpp:212 engines/sci/engine/kfile.cpp:742 +msgid "Save game:" +msgstr "Gardar partida:" + +#: engines/dialogs.cpp:115 engines/agi/saveload.cpp:803 +#: engines/scumm/dialogs.cpp:187 engines/cruise/menu.cpp:212 +#: engines/sci/engine/kfile.cpp:742 +#: backends/platform/symbian/src/SymbianActions.cpp:44 +#: backends/platform/wince/CEActionsPocket.cpp:43 +#: backends/platform/wince/CEActionsPocket.cpp:267 +#: backends/platform/wince/CEActionsSmartphone.cpp:45 +#: backends/platform/wince/CEActionsSmartphone.cpp:231 +msgid "Save" +msgstr "Gardar" + +#: engines/dialogs.cpp:144 +msgid "" +"Sorry, this engine does not currently provide in-game help. Please consult " +"the README for basic information, and for instructions on how to obtain " +"further assistance." +msgstr "" +"Este motor non ofrece axuda no xogo actualmente. Consulta o ficheiro README " +"para obter información básica e máis instrucións para acadar asistencia " +"adicional." + +#: engines/dialogs.cpp:228 +#, c-format +msgid "" +"Gamestate save failed (%s)! Please consult the README for basic information, " +"and for instructions on how to obtain further assistance." +msgstr "" +"Erro ao gardar (%s)! Consulta o ficheiro README para obter información " +"básica e máis instrucións para acadar asistencia adicional." + +#: engines/dialogs.cpp:301 engines/mohawk/dialogs.cpp:109 +#: engines/mohawk/dialogs.cpp:174 +msgid "~O~K" +msgstr "~A~ceptar" + +#: engines/dialogs.cpp:302 engines/mohawk/dialogs.cpp:110 +#: engines/mohawk/dialogs.cpp:175 +msgid "~C~ancel" +msgstr "~C~ancelar" + +#: engines/dialogs.cpp:305 +msgid "~K~eys" +msgstr "~T~eclas" + +#: engines/engine.cpp:235 +msgid "Could not initialize color format." +msgstr "Non se puido iniciar o formato de cor." + +#: engines/engine.cpp:243 +msgid "Could not switch to video mode: '" +msgstr "Non se puido cambiar ao modo de vídeo: '" + +#: engines/engine.cpp:252 +msgid "Could not apply aspect ratio setting." +msgstr "Non se puido aplicar a configuración de proporción." + +#: engines/engine.cpp:257 +msgid "Could not apply fullscreen setting." +msgstr "Non se puido aplicar a configuración de pantalla completa." + +#: engines/engine.cpp:357 +msgid "" +"You appear to be playing this game directly\n" +"from the CD. This is known to cause problems,\n" +"and it is therefore recommended that you copy\n" +"the data files to your hard disk instead.\n" +"See the README file for details." +msgstr "" +"Semella que estás a xogar directamente\n" +"dende o CD. Temos constancia de que causa,\n" +"problemas. Por iso, recomendámosche copiar\n" +"os ficheiros de datos ao disco duro. Consulta\n" +"o ficheiro README para obter máis información." + +#: engines/engine.cpp:368 +msgid "" +"This game has audio tracks in its disk. These\n" +"tracks need to be ripped from the disk using\n" +"an appropriate CD audio extracting tool in\n" +"order to listen to the game's music.\n" +"See the README file for details." +msgstr "" +"O xogo ten pistas de son no disco. Debes\n" +"extraelas por medio dunha ferramenta\n" +"axeitada para poder escoitar a música\n" +"do xogo. Consulta o ficheiro README\n" +"para obter máis información." + +#: engines/engine.cpp:426 +#, c-format +msgid "" +"Gamestate load failed (%s)! Please consult the README for basic information, " +"and for instructions on how to obtain further assistance." +msgstr "" +"Erro ao cargar (%s)! Consulta o ficheiro README para obter información " +"básica e máis instrucións para acadar asistencia adicional." + +#: engines/engine.cpp:439 +msgid "" +"WARNING: The game you are about to start is not yet fully supported by " +"ScummVM. As such, it is likely to be unstable, and any saves you make might " +"not work in future versions of ScummVM." +msgstr "" +"Ollo: o xogo que vas iniciar non é aínda totalmente compatible con ScummVM. " +"Por iso, talvez sexa inestable e os ficheiros de gardado talvez non " +"funcionen en futuras versións de ScummVM." + +#: engines/engine.cpp:442 +msgid "Start anyway" +msgstr "Iniciar de todos os xeitos" + +#: engines/agi/detection.cpp:145 engines/dreamweb/detection.cpp:47 +#: engines/sci/detection.cpp:390 +msgid "Use original save/load screens" +msgstr "Empregar pantallas orixinais de gardado e carga" + +#: engines/agi/detection.cpp:146 engines/dreamweb/detection.cpp:48 +#: engines/sci/detection.cpp:391 +msgid "Use the original save/load screens, instead of the ScummVM ones" +msgstr "" +"Empregar as pantallas orixinais de gardado e carga, no canto das de ScummVM" + +#: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 +msgid "Restore game:" +msgstr "Restaurar xogo:" + +#: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 +msgid "Restore" +msgstr "Restaurar" + +#: engines/dreamweb/detection.cpp:57 +msgid "Use bright palette mode" +msgstr "Empregar modo de paleta intensa" + +#: engines/dreamweb/detection.cpp:58 +msgid "Display graphics using the game's bright palette" +msgstr "Mostrar os gráficos coa paletta intensa do xogo" + +#: engines/sci/detection.cpp:370 +msgid "EGA undithering" +msgstr "Non interpolación EGA" + +#: engines/sci/detection.cpp:371 +msgid "Enable undithering in EGA games" +msgstr "Activar a non interpolación nos xogos en EGA" + +#: engines/sci/detection.cpp:380 +msgid "Prefer digital sound effects" +msgstr "Preferir efectos de son dixitais" + +#: engines/sci/detection.cpp:381 +msgid "Prefer digital sound effects instead of synthesized ones" +msgstr "Dar preferencia aos efectos de son dixitais no canto dos sintéticos" + +#: engines/sci/detection.cpp:400 +msgid "Use IMF/Yamaha FB-01 for MIDI output" +msgstr "Empregar IMF/Yamaha FB-01 para a saída de MIDI" + +#: engines/sci/detection.cpp:401 +msgid "" +"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " +"output" +msgstr "" +"Empregar unha tarxeta IBM Music Feature ou un módulo de sintetizador Yamaha " +"FB-01 FM para a saída de MIDI" + +#: engines/sci/detection.cpp:411 +msgid "Use CD audio" +msgstr "Empregar son de CD" + +#: engines/sci/detection.cpp:412 +msgid "Use CD audio instead of in-game audio, if available" +msgstr "Empregar son de CD no canto do do xogo, de ser o caso" + +#: engines/sci/detection.cpp:422 +msgid "Use Windows cursors" +msgstr "Empregar cursores de Windows" + +#: engines/sci/detection.cpp:423 +msgid "" +"Use the Windows cursors (smaller and monochrome) instead of the DOS ones" +msgstr "" +"Empregar os cursores de Windows (máis pequenos e monocromos) no canto dos de " +"DOS" + +#: engines/sci/detection.cpp:433 +msgid "Use silver cursors" +msgstr "Empregar cursores prateados" + +#: engines/sci/detection.cpp:434 +msgid "" +"Use the alternate set of silver cursors, instead of the normal golden ones" +msgstr "" +"Empregar o xogo de cursores prateados alternativo, no canto dos dourados " +"normais" + +#: engines/scumm/dialogs.cpp:175 +#, c-format +msgid "Insert Disk %c and Press Button to Continue." +msgstr "Insire o disco %c e preme o botón para continuar." + +#: engines/scumm/dialogs.cpp:176 +#, c-format +msgid "Unable to Find %s, (%c%d) Press Button." +msgstr "Non se puido atopar %s, (%c%d). Preme o botón." + +#: engines/scumm/dialogs.cpp:177 +#, c-format +msgid "Error reading disk %c, (%c%d) Press Button." +msgstr "Erro ao ler o disco %c, (%c%d). Preme o botón." + +#: engines/scumm/dialogs.cpp:178 +msgid "Game Paused. Press SPACE to Continue." +msgstr "Xogo en pausa. Pulsa a barra espazadora para continuar." + +#. I18N: You may specify 'Yes' symbol at the end of the line, like this: +#. "Moechten Sie wirklich neu starten? (J/N)J" +#. Will react to J as 'Yes' +#: engines/scumm/dialogs.cpp:182 +msgid "Are you sure you want to restart? (Y/N)" +msgstr "Seguro que queres reiniciar? (S/N)S" + +#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment +#: engines/scumm/dialogs.cpp:184 +msgid "Are you sure you want to quit? (Y/N)" +msgstr "Seguro que queres saír? (S/N)S" + +#: engines/scumm/dialogs.cpp:189 +msgid "Play" +msgstr "Xogar" + +#: engines/scumm/dialogs.cpp:191 engines/scumm/help.cpp:82 +#: engines/scumm/help.cpp:84 +#: backends/platform/symbian/src/SymbianActions.cpp:52 +#: backends/platform/wince/CEActionsPocket.cpp:44 +#: backends/platform/wince/CEActionsSmartphone.cpp:52 +#: backends/events/default/default-events.cpp:213 +msgid "Quit" +msgstr "Saír" + +#: engines/scumm/dialogs.cpp:193 +msgid "Insert save/load game disk" +msgstr "Inserir disco de gardado/carga" + +#: engines/scumm/dialogs.cpp:194 +msgid "You must enter a name" +msgstr "Debes introducir un nome" + +#: engines/scumm/dialogs.cpp:195 +msgid "The game was NOT saved (disk full?)" +msgstr "Non se puido gardar a partida (disco cheo?)" + +#: engines/scumm/dialogs.cpp:196 +msgid "The game was NOT loaded" +msgstr "Non se puido cargar a partida" + +#: engines/scumm/dialogs.cpp:197 +#, c-format +msgid "Saving '%s'" +msgstr "Gardando %s" + +#: engines/scumm/dialogs.cpp:198 +#, c-format +msgid "Loading '%s'" +msgstr "Cargando %s" + +#: engines/scumm/dialogs.cpp:199 +msgid "Name your SAVE game" +msgstr "Introduce un nome para a partida gardada" + +#: engines/scumm/dialogs.cpp:200 +msgid "Select a game to LOAD" +msgstr "Selecciona unha partida para cargala" + +#: engines/scumm/dialogs.cpp:201 +msgid "Game title)" +msgstr "Título)" + +#. I18N: Previous page button +#: engines/scumm/dialogs.cpp:287 +msgid "~P~revious" +msgstr "~A~nterior" + +#. I18N: Next page button +#: engines/scumm/dialogs.cpp:289 +msgid "~N~ext" +msgstr "~S~eguinte" + +#: engines/scumm/dialogs.cpp:290 +#: backends/platform/ds/arm9/source/dsoptions.cpp:56 +msgid "~C~lose" +msgstr "~P~echar" + +#: engines/scumm/dialogs.cpp:597 +msgid "Speech Only" +msgstr "Só voz" + +#: engines/scumm/dialogs.cpp:598 +msgid "Speech and Subtitles" +msgstr "Voz e subtítulos" + +#: engines/scumm/dialogs.cpp:599 +msgid "Subtitles Only" +msgstr "Só subtítulos" + +#: engines/scumm/dialogs.cpp:607 +msgctxt "lowres" +msgid "Speech & Subs" +msgstr "Voz e subs" + +#: engines/scumm/dialogs.cpp:653 +msgid "Select a Proficiency Level." +msgstr "Selecciona un nivel de habilidade." + +#: engines/scumm/dialogs.cpp:655 +msgid "Refer to your Loom(TM) manual for help." +msgstr "Consulta o manual de Loom(TM) para obter axuda." + +#: engines/scumm/dialogs.cpp:658 +msgid "Standard" +msgstr "Estándar" + +#: engines/scumm/dialogs.cpp:659 +msgid "Practice" +msgstr "Práctica" + +#: engines/scumm/dialogs.cpp:660 +msgid "Expert" +msgstr "Experto" + +#: engines/scumm/help.cpp:73 +msgid "Common keyboard commands:" +msgstr "Comandos de teclado comúns:" + +#: engines/scumm/help.cpp:74 +msgid "Save / Load dialog" +msgstr "Gardar/cargar diálogo" + +#: engines/scumm/help.cpp:76 +msgid "Skip line of text" +msgstr "Omitir liña de texto" + +#: engines/scumm/help.cpp:77 +msgid "Esc" +msgstr "ESC" + +#: engines/scumm/help.cpp:77 +msgid "Skip cutscene" +msgstr "Omitir secuencia" + +#: engines/scumm/help.cpp:78 +msgid "Space" +msgstr "Barra espazadora" + +#: engines/scumm/help.cpp:78 +msgid "Pause game" +msgstr "Pausar xogo" + +#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84 +#: engines/scumm/help.cpp:95 engines/scumm/help.cpp:96 +#: engines/scumm/help.cpp:97 engines/scumm/help.cpp:98 +#: engines/scumm/help.cpp:99 engines/scumm/help.cpp:100 +#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102 +msgid "Ctrl" +msgstr "CTRL" + +#: engines/scumm/help.cpp:79 +msgid "Load game state 1-10" +msgstr "Cargar partida 1-10" + +#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84 +#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100 +#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102 +msgid "Alt" +msgstr "ALT" + +#: engines/scumm/help.cpp:80 +msgid "Save game state 1-10" +msgstr "Gardar partida 1-10" + +#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89 +msgid "Enter" +msgstr "INTRO" + +#: engines/scumm/help.cpp:86 +msgid "Toggle fullscreen" +msgstr "Activar/desactivar pantalla completa" + +#: engines/scumm/help.cpp:87 +msgid "Music volume up / down" +msgstr "Subir/baixar volume de música" + +#: engines/scumm/help.cpp:88 +msgid "Text speed slower / faster" +msgstr "Acelerar/frear texto" + +#: engines/scumm/help.cpp:89 +msgid "Simulate left mouse button" +msgstr "Simular botón primario do rato" + +#: engines/scumm/help.cpp:90 +msgid "Tab" +msgstr "TAB" + +#: engines/scumm/help.cpp:90 +msgid "Simulate right mouse button" +msgstr "Simular botón secundario do rato" + +#: engines/scumm/help.cpp:93 +msgid "Special keyboard commands:" +msgstr "Comandos de teclado especiais:" + +#: engines/scumm/help.cpp:94 +msgid "Show / Hide console" +msgstr "Mostrar/ocultar consola" + +#: engines/scumm/help.cpp:95 +msgid "Start the debugger" +msgstr "Iniciar o depurador" + +#: engines/scumm/help.cpp:96 +msgid "Show memory consumption" +msgstr "Mostrar consumo de memoria" + +#: engines/scumm/help.cpp:97 +msgid "Run in fast mode (*)" +msgstr "Executar en modo rápido (*)" + +#: engines/scumm/help.cpp:98 +msgid "Run in really fast mode (*)" +msgstr "Executar en modo moi rápido (*)" + +#: engines/scumm/help.cpp:99 +msgid "Toggle mouse capture" +msgstr "Activar/desactivar captura de rato" + +#: engines/scumm/help.cpp:100 +msgid "Switch between graphics filters" +msgstr "Cambiar filtro de gráficos" + +#: engines/scumm/help.cpp:101 +msgid "Increase / Decrease scale factor" +msgstr "Aumentar/reducir factor de escala" + +#: engines/scumm/help.cpp:102 +msgid "Toggle aspect-ratio correction" +msgstr "Activar/desactivar corrección de proporción" + +#: engines/scumm/help.cpp:107 +msgid "* Note that using ctrl-f and" +msgstr "* Nota: non recomendamos" + +#: engines/scumm/help.cpp:108 +msgid " ctrl-g are not recommended" +msgstr " empregar CTRL-F nin CTRL-G," + +#: engines/scumm/help.cpp:109 +msgid " since they may cause crashes" +msgstr " xa que poden provocar bloqueos" + +#: engines/scumm/help.cpp:110 +msgid " or incorrect game behavior." +msgstr " ou outros erros no xogo." + +#: engines/scumm/help.cpp:114 +msgid "Spinning drafts on the keyboard:" +msgstr "Tecer feitizos co teclado:" + +#: engines/scumm/help.cpp:116 +msgid "Main game controls:" +msgstr "Controis principais de xogo:" + +#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136 +#: engines/scumm/help.cpp:161 +msgid "Push" +msgstr "Empuxar" + +#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137 +#: engines/scumm/help.cpp:162 +msgid "Pull" +msgstr "Tirar de" + +#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138 +#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197 +#: engines/scumm/help.cpp:207 +msgid "Give" +msgstr "Dar" + +#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139 +#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190 +#: engines/scumm/help.cpp:208 +msgid "Open" +msgstr "Abrir" + +#: engines/scumm/help.cpp:126 +msgid "Go to" +msgstr "Ir a" + +#: engines/scumm/help.cpp:127 +msgid "Get" +msgstr "Coller" + +#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152 +#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198 +#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224 +#: engines/scumm/help.cpp:250 +msgid "Use" +msgstr "Usar" + +#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141 +msgid "Read" +msgstr "Ler" + +#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147 +msgid "New kid" +msgstr "Rapaz" + +#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153 +#: engines/scumm/help.cpp:171 +msgid "Turn on" +msgstr "Acender" + +#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154 +#: engines/scumm/help.cpp:172 +msgid "Turn off" +msgstr "Apagar" + +#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167 +#: engines/scumm/help.cpp:194 +msgid "Walk to" +msgstr "Ir a" + +#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168 +#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210 +#: engines/scumm/help.cpp:227 +msgid "Pick up" +msgstr "Coller" + +#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169 +msgid "What is" +msgstr "Que é" + +#: engines/scumm/help.cpp:146 +msgid "Unlock" +msgstr "Despechar" + +#: engines/scumm/help.cpp:149 +msgid "Put on" +msgstr "Poñer" + +#: engines/scumm/help.cpp:150 +msgid "Take off" +msgstr "Quitar" + +#: engines/scumm/help.cpp:156 +msgid "Fix" +msgstr "Reparar" + +#: engines/scumm/help.cpp:158 +msgid "Switch" +msgstr "Cambiar" + +#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228 +msgid "Look" +msgstr "Mirar" + +#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223 +msgid "Talk" +msgstr "Falar" + +#: engines/scumm/help.cpp:174 +msgid "Travel" +msgstr "Viaxar" + +#: engines/scumm/help.cpp:175 +msgid "To Henry / To Indy" +msgstr "A Henry / A Indy" + +#. I18N: These are different musical notes +#: engines/scumm/help.cpp:179 +msgid "play C minor on distaff" +msgstr "tocar do menor no bastón" + +#: engines/scumm/help.cpp:180 +msgid "play D on distaff" +msgstr "tocar re no bastón" + +#: engines/scumm/help.cpp:181 +msgid "play E on distaff" +msgstr "tocar mi no bastón" + +#: engines/scumm/help.cpp:182 +msgid "play F on distaff" +msgstr "tocar fa no bastón" + +#: engines/scumm/help.cpp:183 +msgid "play G on distaff" +msgstr "tocar sol no bastón" + +#: engines/scumm/help.cpp:184 +msgid "play A on distaff" +msgstr "tocar la no bastón" + +#: engines/scumm/help.cpp:185 +msgid "play B on distaff" +msgstr "tocar si no bastón" + +#: engines/scumm/help.cpp:186 +msgid "play C major on distaff" +msgstr "tocar do maior no bastón" + +#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214 +msgid "puSh" +msgstr "Empurrar" + +#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215 +msgid "pull (Yank)" +msgstr "Tirar de" + +#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212 +#: engines/scumm/help.cpp:248 +msgid "Talk to" +msgstr "Falar con" + +#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211 +msgid "Look at" +msgstr "Mirar" + +#: engines/scumm/help.cpp:200 +msgid "turn oN" +msgstr "Acender" + +#: engines/scumm/help.cpp:201 +msgid "turn oFf" +msgstr "Apagar" + +#: engines/scumm/help.cpp:217 +msgid "KeyUp" +msgstr "Arriba" + +#: engines/scumm/help.cpp:217 +msgid "Highlight prev dialogue" +msgstr "Destacar diálogo anterior" + +#: engines/scumm/help.cpp:218 +msgid "KeyDown" +msgstr "Abaixo" + +#: engines/scumm/help.cpp:218 +msgid "Highlight next dialogue" +msgstr "Destacar diálogo seguinte" + +#: engines/scumm/help.cpp:222 +msgid "Walk" +msgstr "Ir a" + +#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234 +#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249 +msgid "Inventory" +msgstr "Inventario" + +#: engines/scumm/help.cpp:226 +msgid "Object" +msgstr "Obxecto" + +#: engines/scumm/help.cpp:229 +msgid "Black and White / Color" +msgstr "Branco e negro/cor" + +#: engines/scumm/help.cpp:232 +msgid "Eyes" +msgstr "Ollos" + +#: engines/scumm/help.cpp:233 +msgid "Tongue" +msgstr "Lingua" + +#: engines/scumm/help.cpp:235 +msgid "Punch" +msgstr "Bater a" + +#: engines/scumm/help.cpp:236 +msgid "Kick" +msgstr "Patear a" + +#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247 +msgid "Examine" +msgstr "Examinar" + +#: engines/scumm/help.cpp:240 +msgid "Regular cursor" +msgstr "Cursor normal" + +#. I18N: Comm is a communication device +#: engines/scumm/help.cpp:243 +msgid "Comm" +msgstr "Comunicador" + +#: engines/scumm/help.cpp:246 +msgid "Save / Load / Options" +msgstr "Gardar/cargar/opcións" + +#: engines/scumm/help.cpp:255 +msgid "Other game controls:" +msgstr "Outros controis de xogo:" + +#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267 +msgid "Inventory:" +msgstr "Inventario:" + +#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274 +msgid "Scroll list up" +msgstr "Subir lista" + +#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275 +msgid "Scroll list down" +msgstr "Baixar lista" + +#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268 +msgid "Upper left item" +msgstr "Obxecto esquerdo arriba" + +#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270 +msgid "Lower left item" +msgstr "Obxecto esquerdo abaixo" + +#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271 +msgid "Upper right item" +msgstr "Obxecto dereito arriba" + +#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273 +msgid "Lower right item" +msgstr "Obxecto dereito abaixo" + +#: engines/scumm/help.cpp:269 +msgid "Middle left item" +msgstr "Obxecto esquerdo medio" + +#: engines/scumm/help.cpp:272 +msgid "Middle right item" +msgstr "Obxecto dereito medio" + +#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284 +msgid "Switching characters:" +msgstr "Cambiar caracteres:" + +#: engines/scumm/help.cpp:281 +msgid "Second kid" +msgstr "Rapaz 2" + +#: engines/scumm/help.cpp:282 +msgid "Third kid" +msgstr "Rapaz 3" + +#: engines/scumm/help.cpp:294 +msgid "Fighting controls (numpad):" +msgstr "Controis de combate (teclado numérico):" + +#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296 +#: engines/scumm/help.cpp:297 +msgid "Step back" +msgstr "Paso atrás" + +#: engines/scumm/help.cpp:298 +msgid "Block high" +msgstr "Bloqueo alto" + +#: engines/scumm/help.cpp:299 +msgid "Block middle" +msgstr "Bloqueo medio" + +#: engines/scumm/help.cpp:300 +msgid "Block low" +msgstr "Bloqueo baixo" + +#: engines/scumm/help.cpp:301 +msgid "Punch high" +msgstr "Puñazo alto" + +#: engines/scumm/help.cpp:302 +msgid "Punch middle" +msgstr "Puñazo medio" + +#: engines/scumm/help.cpp:303 +msgid "Punch low" +msgstr "Puñazo baixo" + +#: engines/scumm/help.cpp:306 +msgid "These are for Indy on left." +msgstr "Son para Indy na esquerda." + +#: engines/scumm/help.cpp:307 +msgid "When Indy is on the right," +msgstr "Se está na dereita," + +#: engines/scumm/help.cpp:308 +msgid "7, 4, and 1 are switched with" +msgstr "7, 4 e 1 cámbianse por" + +#: engines/scumm/help.cpp:309 +msgid "9, 6, and 3, respectively." +msgstr "9, 6 e 3 respectivamente." + +#: engines/scumm/help.cpp:316 +msgid "Biplane controls (numpad):" +msgstr "Controis de biplano (teclado numérico):" + +#: engines/scumm/help.cpp:317 +msgid "Fly to upper left" +msgstr "Voar á esquerda arriba" + +#: engines/scumm/help.cpp:318 +msgid "Fly to left" +msgstr "Voar á esquerda" + +#: engines/scumm/help.cpp:319 +msgid "Fly to lower left" +msgstr "Voar á esquerda abaixo" + +#: engines/scumm/help.cpp:320 +msgid "Fly upwards" +msgstr "Voar arriba" + +#: engines/scumm/help.cpp:321 +msgid "Fly straight" +msgstr "Voar recto" + +#: engines/scumm/help.cpp:322 +msgid "Fly down" +msgstr "Voar abaixo" + +#: engines/scumm/help.cpp:323 +msgid "Fly to upper right" +msgstr "Voar á dereita arriba" + +#: engines/scumm/help.cpp:324 +msgid "Fly to right" +msgstr "Voar á dereita" + +#: engines/scumm/help.cpp:325 +msgid "Fly to lower right" +msgstr "Voar á dereita abaixo" + +#: engines/scumm/scumm.cpp:1773 +#, c-format +msgid "" +"Native MIDI support requires the Roland Upgrade from LucasArts,\n" +"but %s is missing. Using AdLib instead." +msgstr "" +"A compatibilidade nativa con MIDI precisa a actualización de Roland\n" +"de LucasArts, mais falla %s. Empregarase AdLib." + +#: engines/scumm/scumm.cpp:2278 engines/agos/saveload.cpp:220 +#, c-format +msgid "" +"Failed to save game state to file:\n" +"\n" +"%s" +msgstr "" +"Erro ao gardar a partida no ficheiro:\n" +"\n" +"%s" + +#: engines/scumm/scumm.cpp:2285 engines/agos/saveload.cpp:185 +#, c-format +msgid "" +"Failed to load game state from file:\n" +"\n" +"%s" +msgstr "" +"Erro ao cargar a partida do ficheiro:\n" +"\n" +"%s" + +#: engines/scumm/scumm.cpp:2297 engines/agos/saveload.cpp:228 +#, c-format +msgid "" +"Successfully saved game state in file:\n" +"\n" +"%s" +msgstr "" +"Partida gardada con éxito no ficheiro:\n" +"\n" +"%s" + +#: engines/scumm/scumm.cpp:2512 +msgid "" +"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To " +"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' " +"directory inside the Tentacle game directory." +msgstr "" +"Maniac Mansion tería que empezar agora. Porén, ScummVM aínda non é quen de " +"facelo. Para xogar, vai a Engadir xogo no menú de inicio de ScummVM e " +"selecciona o directorio Maniac que está dentro do directorio Tentacle." + +#. I18N: Option for fast scene switching +#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:171 +msgid "~Z~ip Mode Activated" +msgstr "Modo ~c~omprimido activado" + +#: engines/mohawk/dialogs.cpp:93 +msgid "~T~ransitions Enabled" +msgstr "~T~ransicións activadas" + +#. I18N: Drop book page +#: engines/mohawk/dialogs.cpp:95 +msgid "~D~rop Page" +msgstr "~D~eixar folla" + +#: engines/mohawk/dialogs.cpp:99 +msgid "~S~how Map" +msgstr "Mo~s~trar mapa" + +#: engines/mohawk/dialogs.cpp:105 +msgid "~M~ain Menu" +msgstr "~M~enú principal" + +#: engines/mohawk/dialogs.cpp:172 +msgid "~W~ater Effect Enabled" +msgstr "Efecto de ~a~uga activado" + +#: engines/agos/animation.cpp:560 +#, c-format +msgid "Cutscene file '%s' not found!" +msgstr "Non se atopou o ficheiro de secuencia %s!" + +#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1287 +#: engines/tinsel/saveload.cpp:532 +msgid "Failed to load game state from file." +msgstr "Erro ao cargar a partida do ficheiro." + +#: engines/gob/inter_v2.cpp:1357 engines/tinsel/saveload.cpp:545 +msgid "Failed to save game state to file." +msgstr "Erro ao gardar a partida no ficheiro." + +#: engines/gob/inter_v5.cpp:107 +msgid "Failed to delete file." +msgstr "Erro ao eliminar o ficheiro." + +#: engines/groovie/script.cpp:420 +msgid "Failed to save game" +msgstr "Erro ao gardar a partida" + +#. I18N: Studio audience adds an applause and cheering sounds whenever +#. Malcolm makes a joke. +#: engines/kyra/detection.cpp:62 +msgid "Studio audience" +msgstr "Público do estudio" + +#: engines/kyra/detection.cpp:63 +msgid "Enable studio audience" +msgstr "Activar o público do estudio" + +#. I18N: This option allows the user to skip text and cutscenes. +#: engines/kyra/detection.cpp:73 +msgid "Skip support" +msgstr "Omisións" + +#: engines/kyra/detection.cpp:74 +msgid "Allow text and cutscenes to be skipped" +msgstr "Permitir a omisión do texto e das secuencias" + +#. I18N: Helium mode makes people sound like they've inhaled Helium. +#: engines/kyra/detection.cpp:84 +msgid "Helium mode" +msgstr "Modo helio" + +#: engines/kyra/detection.cpp:85 +msgid "Enable helium mode" +msgstr "Activar o modo helio" + +#. I18N: When enabled, this option makes scrolling smoother when +#. changing from one screen to another. +#: engines/kyra/detection.cpp:99 +msgid "Smooth scrolling" +msgstr "Desprazamento suave" + +#: engines/kyra/detection.cpp:100 +msgid "Enable smooth scrolling when walking" +msgstr "Activar o desprazamento suave ao camiñar" + +#. I18N: When enabled, this option changes the cursor when it floats to the +#. edge of the screen to a directional arrow. The player can then click to +#. walk towards that direction. +#: engines/kyra/detection.cpp:112 +msgid "Floating cursors" +msgstr "Cursores flotantes" + +#: engines/kyra/detection.cpp:113 +msgid "Enable floating cursors" +msgstr "Activar cursores flotantes" + +#. I18N: HP stands for Hit Points +#: engines/kyra/detection.cpp:127 +msgid "HP bar graphs" +msgstr "Barras de vida" + +#: engines/kyra/detection.cpp:128 +msgid "Enable hit point bar graphs" +msgstr "Activar barras de vida" + +#: engines/kyra/lol.cpp:478 +msgid "Attack 1" +msgstr "Ataque 1" + +#: engines/kyra/lol.cpp:479 +msgid "Attack 2" +msgstr "Ataque 2" + +#: engines/kyra/lol.cpp:480 +msgid "Attack 3" +msgstr "Ataque 3" + +#: engines/kyra/lol.cpp:481 +msgid "Move Forward" +msgstr "Mover cara diante" + +#: engines/kyra/lol.cpp:482 +msgid "Move Back" +msgstr "Mover cara atrás" + +#: engines/kyra/lol.cpp:483 +msgid "Slide Left" +msgstr "Esvarar á esquerda" + +#: engines/kyra/lol.cpp:484 +msgid "Slide Right" +msgstr "Esvarar á dereita" + +#: engines/kyra/lol.cpp:485 +msgid "Turn Left" +msgstr "Xirar á esquerda" + +#: engines/kyra/lol.cpp:486 +msgid "Turn Right" +msgstr "Xirar á dereita" + +#: engines/kyra/lol.cpp:487 +msgid "Rest" +msgstr "Parar" + +#: engines/kyra/lol.cpp:488 +msgid "Options" +msgstr "Opcións" + +#: engines/kyra/lol.cpp:489 +msgid "Choose Spell" +msgstr "Elixir feitizo" + +#: engines/kyra/sound_midi.cpp:475 +msgid "" +"You appear to be using a General MIDI device,\n" +"but your game only supports Roland MT32 MIDI.\n" +"We try to map the Roland MT32 instruments to\n" +"General MIDI ones. It is still possible that\n" +"some tracks sound incorrect." +msgstr "" +"Semella que estás a empregar un dispositivo,\n" +"de General MIDI, maix o xogo só e compatible con\n" +"Roland MT32 MIDI. Tentamos asignar os instrumentos\n" +"aos de General MIDI. No entanto, existe a posibilidade\n" +"de que algunhas pistas non soen correctamente." + +#: engines/queen/queen.cpp:59 +msgid "Alternative intro" +msgstr "Intro alternativa" + +#: engines/queen/queen.cpp:60 +msgid "Use an alternative game intro (CD version only)" +msgstr "Empregar unha introdución alternativa para o xogo (só versión en CD)" + +#: engines/sky/compact.cpp:130 +msgid "" +"Unable to find \"sky.cpt\" file!\n" +"Please download it from www.scummvm.org" +msgstr "" +"O ficheiro sky.cpt non se atopa!\n" +"Descárgao dende www.scummvm.org" + +#: engines/sky/compact.cpp:141 +msgid "" +"The \"sky.cpt\" file has an incorrect size.\n" +"Please (re)download it from www.scummvm.org" +msgstr "" +"O ficheiro sky.cpt ten un tamaño incorrecto.\n" +"Descárgao (de novo) dende www.scummvm.org" + +#: engines/sky/detection.cpp:44 +msgid "Floppy intro" +msgstr "Intro de disquete" + +#: engines/sky/detection.cpp:45 +msgid "Use the floppy version's intro (CD version only)" +msgstr "Empregar a introdución da versión en disquete (só versión en CD)" + +#: engines/sword1/animation.cpp:539 +#, c-format +msgid "PSX stream cutscene '%s' cannot be played in paletted mode" +msgstr "Non se pode reproducir a secuencia %s de PSX neste modo gráfico" + +#: engines/sword1/animation.cpp:560 engines/sword2/animation.cpp:455 +msgid "DXA cutscenes found but ScummVM has been built without zlib support" +msgstr "" +"Atopáronse secuencias de DXA. No entanto, esta versión de ScummVM non é " +"compatible con zlib" + +#: engines/sword1/animation.cpp:570 engines/sword2/animation.cpp:465 +msgid "MPEG2 cutscenes are no longer supported" +msgstr "Xa non hai compatibilidade coas secuencias en MPEG2" + +#: engines/sword1/animation.cpp:576 engines/sword2/animation.cpp:473 +#, c-format +msgid "Cutscene '%s' not found" +msgstr "Non se atopou a secuencia %s" + +#: engines/sword1/control.cpp:863 +msgid "" +"ScummVM found that you have old savefiles for Broken Sword 1 that should be " +"converted.\n" +"The old save game format is no longer supported, so you will not be able to " +"load your games if you don't convert them.\n" +"\n" +"Press OK to convert them now, otherwise you will be asked again the next " +"time you start the game.\n" +msgstr "" +"ScummVM atopou ficheiros de gardado vellos de Broken Sword 1 que deberían " +"ser convertidos.\n" +"O formato vello xa non é compatible, de xeito que non poderás cargar as " +"partidas se non os convertes.\n" +"\n" +"Preme Aceptar para convertilos. Se non, volverás ver esta mensaxe a próxima " +"vez que inicies o xogo.\n" + +#: engines/sword1/control.cpp:1232 +#, c-format +msgid "" +"Target new save game already exists!\n" +"Would you like to keep the old save game (%s) or the new one (%s)?\n" +msgstr "" +"Xa existe unha partida con ese nome!\n" +"Queres conservar a vella (%s) ou a nova (%s)?\n" + +#: engines/sword1/control.cpp:1235 +msgid "Keep the old one" +msgstr "Conservar a vella" + +#: engines/sword1/control.cpp:1235 +msgid "Keep the new one" +msgstr "Conservar a nova" + +#: engines/sword1/logic.cpp:1633 +msgid "This is the end of the Broken Sword 1 Demo" +msgstr "Aquí remata a demo de Broken Sword 1" + +#: engines/sword2/animation.cpp:435 +msgid "" +"PSX cutscenes found but ScummVM has been built without RGB color support" +msgstr "" +"Atopáronse secuencias de PSX. No entanto, a versión de ScummVM non é " +"compatible con cores RGB" + +#: engines/sword2/sword2.cpp:79 +msgid "Show object labels" +msgstr "Mostrar etiquetas" + +#: engines/sword2/sword2.cpp:80 +msgid "Show labels for objects on mouse hover" +msgstr "Mostrar as etiquetas dos obxectos ao apuntar co rato" + +#: engines/teenagent/resources.cpp:68 +msgid "" +"You're missing the 'teenagent.dat' file. Get it from the ScummVM website" +msgstr "" +"Falta o ficheiro teenagent.dat. Descárgao dende o sitio web de ScummVM." + +#: engines/teenagent/resources.cpp:89 +msgid "" +"The teenagent.dat file is compressed and zlib hasn't been included in this " +"executable. Please decompress it" +msgstr "" +"O ficheiro teenagent.dat está comprimido e zlib non foi incluído neste " +"executable. Descomprime o ficheiro" + +#: engines/parallaction/saveload.cpp:133 +#, c-format +msgid "" +"Can't save game in slot %i\n" +"\n" +msgstr "" +"Non se pode gardar a partida no espazo %i\n" +"\n" + +#: engines/parallaction/saveload.cpp:204 +msgid "Loading game..." +msgstr "Cargando..." + +#: engines/parallaction/saveload.cpp:219 +msgid "Saving game..." +msgstr "Gardando..." + +#: engines/parallaction/saveload.cpp:272 +msgid "" +"ScummVM found that you have old savefiles for Nippon Safes that should be " +"renamed.\n" +"The old names are no longer supported, so you will not be able to load your " +"games if you don't convert them.\n" +"\n" +"Press OK to convert them now, otherwise you will be asked next time.\n" +msgstr "" +"ScummVM atopou ficheiros de gardado vellos de Nippon Safes que deberían ser " +"renomeados.\n" +"Os nomes vellos xa non son compatibles, de xeito que non poderás cargar as " +"partidas se non os cambias.\n" +"\n" +"Preme Aceptar para cambialos. Se non, volverás ver esta mensaxe a próxima " +"vez que inicies o xogo.\n" + +#: engines/parallaction/saveload.cpp:319 +msgid "ScummVM successfully converted all your savefiles." +msgstr "ScummVM converteu correctamente todos os ficheiros de gardado." + +#: engines/parallaction/saveload.cpp:321 +msgid "" +"ScummVM printed some warnings in your console window and can't guarantee all " +"your files have been converted.\n" +"\n" +"Please report to the team." +msgstr "" +"ScummVM imprimiu avisos na ventá da consola. Non se pode garantir a " +"conversión de todos os ficheiros.\n" +"\n" +"Contacta co equipo de ScummVM." + +#: audio/fmopl.cpp:49 +msgid "MAME OPL emulator" +msgstr "Emulador de OPL de MAME" + +#: audio/fmopl.cpp:51 +msgid "DOSBox OPL emulator" +msgstr "Emulador de OPL de DOSBox" + +#: audio/mididrv.cpp:209 +#, c-format +msgid "" +"The selected audio device '%s' was not found (e.g. might be turned off or " +"disconnected)." +msgstr "" +"Non se atopou o dispositivo de son seleccionado (%s). Talvez estea apagado " +"ou desconectado." + +#: audio/mididrv.cpp:209 audio/mididrv.cpp:221 audio/mididrv.cpp:257 +#: audio/mididrv.cpp:272 +msgid "Attempting to fall back to the next available device..." +msgstr "Intentando pasar ao seguinte dispositivo dispoñible..." + +#: audio/mididrv.cpp:221 +#, c-format +msgid "" +"The selected audio device '%s' cannot be used. See log file for more " +"information." +msgstr "" +"Non se pode empregar o dispositivo de son seleccionado (%s). Consulta o " +"rexistro para obter máis información." + +#: audio/mididrv.cpp:257 +#, c-format +msgid "" +"The preferred audio device '%s' was not found (e.g. might be turned off or " +"disconnected)." +msgstr "" +"Non se atopou o dispositivo de son preferido (%s). Talvez estea apagado ou " +"desconectado." + +#: audio/mididrv.cpp:272 +#, c-format +msgid "" +"The preferred audio device '%s' cannot be used. See log file for more " +"information." +msgstr "" +"Non se pode empregar o dispositivo de son preferido (%s). Consulta o " +"rexistro para obter máis información." + +#: audio/null.h:43 +msgid "No music" +msgstr "Sen música" + +#: audio/mods/paula.cpp:189 +msgid "Amiga Audio Emulator" +msgstr "Emulador de Amiga Audio" + +#: audio/softsynth/adlib.cpp:1593 +msgid "AdLib Emulator" +msgstr "Emulador de AdLib" + +#: audio/softsynth/appleiigs.cpp:33 +msgid "Apple II GS Emulator (NOT IMPLEMENTED)" +msgstr "Emulador de Apple II GS (non implementado)" + +#: audio/softsynth/sid.cpp:1430 +msgid "C64 Audio Emulator" +msgstr "Emulador de C64 Audio" + +#: audio/softsynth/mt32.cpp:293 +msgid "Initializing MT-32 Emulator" +msgstr "Iniciando emulador de MT-32" + +#: audio/softsynth/mt32.cpp:512 +msgid "MT-32 Emulator" +msgstr "Emulador de MT-32" + +#: audio/softsynth/pcspk.cpp:139 +msgid "PC Speaker Emulator" +msgstr "Emulador de altofalante de PC" + +#: audio/softsynth/pcspk.cpp:158 +msgid "IBM PCjr Emulator" +msgstr "Emulador de IBM PCjr" + +#: backends/keymapper/remap-dialog.cpp:47 +msgid "Keymap:" +msgstr "Asignación de teclas:" + +#: backends/keymapper/remap-dialog.cpp:66 +msgid " (Effective)" +msgstr " (Efectiva)" + +#: backends/keymapper/remap-dialog.cpp:106 +msgid " (Active)" +msgstr " (Activa)" + +#: backends/keymapper/remap-dialog.cpp:106 +msgid " (Blocked)" +msgstr " (Bloqueada)" + +#: backends/keymapper/remap-dialog.cpp:119 +msgid " (Global)" +msgstr " (Global)" + +#: backends/keymapper/remap-dialog.cpp:127 +msgid " (Game)" +msgstr " (Xogo)" + +#: backends/midi/windows.cpp:164 +msgid "Windows MIDI" +msgstr "Windows MIDI" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:57 +msgid "ScummVM Main Menu" +msgstr "Menú principal de ScummVM" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:63 +msgid "~L~eft handed mode" +msgstr "Modo para ~z~urdos" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:64 +msgid "~I~ndy fight controls" +msgstr "Controis de combate de ~I~ndy" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:65 +msgid "Show mouse cursor" +msgstr "Mostrar cursor do rato" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:66 +msgid "Snap to edges" +msgstr "Axustar ás marxes" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:68 +msgid "Touch X Offset" +msgstr "Corrección táctil X" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:75 +msgid "Touch Y Offset" +msgstr "Corrección táctil Y" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:87 +msgid "Use laptop trackpad-style cursor control" +msgstr "Empregar control de cursor por trackpad" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:88 +msgid "Tap for left click, double tap right click" +msgstr "Tocar unha vez, premer co botón primario; dúas veces, botón secundario" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:90 +msgid "Sensitivity" +msgstr "Sensibilidade" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:99 +msgid "Initial top screen scale:" +msgstr "Escala da pantalla inicial:" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:105 +msgid "Main screen scaling:" +msgstr "Escala da pantalla principal:" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:107 +msgid "Hardware scale (fast, but low quality)" +msgstr "Escala por hardware (rápida, mais baixa calidade)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:108 +msgid "Software scale (good quality, but slower)" +msgstr "Escala por software (boa calidade, mais lenta)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:109 +msgid "Unscaled (you must scroll left and right)" +msgstr "Sen escala (deberás desprazar á esquerda e á dereita)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:111 +msgid "Brightness:" +msgstr "Luminosidade:" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:121 +msgid "High quality audio (slower) (reboot)" +msgstr "Son de alta calidade (máis lento) (reiniciar)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:122 +msgid "Disable power off" +msgstr "Desactivar apagado" + +#: backends/platform/iphone/osys_events.cpp:300 +msgid "Mouse-click-and-drag mode enabled." +msgstr "Modo premer e arrastrar activado." + +#: backends/platform/iphone/osys_events.cpp:302 +msgid "Mouse-click-and-drag mode disabled." +msgstr "Modo premer e arrastrar desactivado." + +#: backends/platform/iphone/osys_events.cpp:313 +msgid "Touchpad mode enabled." +msgstr "Modo panel táctil activado." + +#: backends/platform/iphone/osys_events.cpp:315 +msgid "Touchpad mode disabled." +msgstr "Modo panel táctil desactivado." + +#: backends/platform/maemo/maemo.cpp:209 +msgid "Click Mode" +msgstr "Modo rato" + +#: backends/platform/maemo/maemo.cpp:215 +#: backends/platform/symbian/src/SymbianActions.cpp:42 +#: backends/platform/wince/CEActionsPocket.cpp:60 +#: backends/platform/wince/CEActionsSmartphone.cpp:43 +#: backends/platform/bada/form.cpp:281 +msgid "Left Click" +msgstr "Botón primario" + +#: backends/platform/maemo/maemo.cpp:218 +msgid "Middle Click" +msgstr "Botón central" + +#: backends/platform/maemo/maemo.cpp:221 +#: backends/platform/symbian/src/SymbianActions.cpp:43 +#: backends/platform/wince/CEActionsSmartphone.cpp:44 +#: backends/platform/bada/form.cpp:273 +msgid "Right Click" +msgstr "Botón secundario" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:78 +msgid "Hide ScummVM" +msgstr "Ocultar ScummVM" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:83 +msgid "Hide Others" +msgstr "Ocultar outros" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:88 +msgid "Show All" +msgstr "Mostrar todo" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:110 +#: backends/platform/sdl/macosx/appmenu_osx.mm:121 +msgid "Window" +msgstr "Ventá" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:115 +msgid "Minimize" +msgstr "Minimizar" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:45 +msgid "Normal (no scaling)" +msgstr "Normal (sen escala)" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:64 +msgctxt "lowres" +msgid "Normal (no scaling)" +msgstr "Normal (sen escala)" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2135 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:533 +msgid "Enabled aspect ratio correction" +msgstr "Corrección de proporción activada" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2141 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:538 +msgid "Disabled aspect ratio correction" +msgstr "Corrección de proporción desactivada" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2196 +msgid "Active graphics filter:" +msgstr "Filtro de gráficos activo:" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2238 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:477 +msgid "Windowed mode" +msgstr "Modo en ventá" + +#: backends/graphics/opengl/opengl-graphics.cpp:135 +msgid "OpenGL Normal" +msgstr "OpenGL Normal" + +#: backends/graphics/opengl/opengl-graphics.cpp:136 +msgid "OpenGL Conserve" +msgstr "OpenGL Conserve" + +#: backends/graphics/opengl/opengl-graphics.cpp:137 +msgid "OpenGL Original" +msgstr "OpenGL Original" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:415 +msgid "Current display mode" +msgstr "Modo de visualización actual" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:428 +msgid "Current scale" +msgstr "Escala actual" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:558 +msgid "Active filter mode: Linear" +msgstr "Modo de filtro activo: lineal" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:560 +msgid "Active filter mode: Nearest" +msgstr "Modo de filtro activo: máis próximo" + +#: backends/platform/symbian/src/SymbianActions.cpp:38 +#: backends/platform/wince/CEActionsSmartphone.cpp:39 +msgid "Up" +msgstr "Arriba" + +#: backends/platform/symbian/src/SymbianActions.cpp:39 +#: backends/platform/wince/CEActionsSmartphone.cpp:40 +msgid "Down" +msgstr "Abaixo" + +#: backends/platform/symbian/src/SymbianActions.cpp:40 +#: backends/platform/wince/CEActionsSmartphone.cpp:41 +msgid "Left" +msgstr "Esquerda" + +#: backends/platform/symbian/src/SymbianActions.cpp:41 +#: backends/platform/wince/CEActionsSmartphone.cpp:42 +msgid "Right" +msgstr "Dereita" + +#: backends/platform/symbian/src/SymbianActions.cpp:46 +#: backends/platform/wince/CEActionsSmartphone.cpp:47 +msgid "Zone" +msgstr "Zona" + +#: backends/platform/symbian/src/SymbianActions.cpp:47 +#: backends/platform/wince/CEActionsPocket.cpp:54 +#: backends/platform/wince/CEActionsSmartphone.cpp:48 +msgid "Multi Function" +msgstr "Multifunción" + +#: backends/platform/symbian/src/SymbianActions.cpp:48 +msgid "Swap character" +msgstr "Cambiar carácter" + +#: backends/platform/symbian/src/SymbianActions.cpp:49 +msgid "Skip text" +msgstr "Omitir texto" + +#: backends/platform/symbian/src/SymbianActions.cpp:51 +msgid "Fast mode" +msgstr "Modo rápido" + +#: backends/platform/symbian/src/SymbianActions.cpp:53 +msgid "Debugger" +msgstr "Depurador" + +#: backends/platform/symbian/src/SymbianActions.cpp:54 +msgid "Global menu" +msgstr "Menú global" + +#: backends/platform/symbian/src/SymbianActions.cpp:55 +msgid "Virtual keyboard" +msgstr "Teclado virtual" + +#: backends/platform/symbian/src/SymbianActions.cpp:56 +msgid "Key mapper" +msgstr "Asignador de teclas" + +#: backends/events/symbiansdl/symbiansdl-events.cpp:184 +msgid "Do you want to quit ?" +msgstr "Queres saír?" + +#: backends/platform/wii/options.cpp:51 +msgid "Video" +msgstr "Vídeo" + +#: backends/platform/wii/options.cpp:54 +msgid "Current video mode:" +msgstr "Modo de vídeo actual:" + +#: backends/platform/wii/options.cpp:56 +msgid "Double-strike" +msgstr "Dobre" + +#: backends/platform/wii/options.cpp:60 +msgid "Horizontal underscan:" +msgstr "Marxe horizontal:" + +#: backends/platform/wii/options.cpp:66 +msgid "Vertical underscan:" +msgstr "Marxe vertical:" + +#: backends/platform/wii/options.cpp:71 +msgid "Input" +msgstr "Entrada" + +#: backends/platform/wii/options.cpp:74 +msgid "GC Pad sensitivity:" +msgstr "Sensibilidade do mando de GC:" + +#: backends/platform/wii/options.cpp:80 +msgid "GC Pad acceleration:" +msgstr "Aceleración do mando de GC:" + +#: backends/platform/wii/options.cpp:86 +msgid "DVD" +msgstr "DVD" + +#: backends/platform/wii/options.cpp:89 backends/platform/wii/options.cpp:101 +msgid "Status:" +msgstr "Estado:" + +#: backends/platform/wii/options.cpp:90 backends/platform/wii/options.cpp:102 +msgid "Unknown" +msgstr "Descoñecido" + +#: backends/platform/wii/options.cpp:93 +msgid "Mount DVD" +msgstr "Montar DVD" + +#: backends/platform/wii/options.cpp:94 +msgid "Unmount DVD" +msgstr "Desmontar DVD" + +#: backends/platform/wii/options.cpp:98 +msgid "SMB" +msgstr "SMB" + +#: backends/platform/wii/options.cpp:106 +msgid "Server:" +msgstr "Servidor:" + +#: backends/platform/wii/options.cpp:110 +msgid "Share:" +msgstr "Disco compartido:" + +#: backends/platform/wii/options.cpp:114 +msgid "Username:" +msgstr "Nome de usuario:" + +#: backends/platform/wii/options.cpp:118 +msgid "Password:" +msgstr "Contrasinal:" + +#: backends/platform/wii/options.cpp:121 +msgid "Init network" +msgstr "Conectar á rede" + +#: backends/platform/wii/options.cpp:123 +msgid "Mount SMB" +msgstr "Montar SMB" + +#: backends/platform/wii/options.cpp:124 +msgid "Unmount SMB" +msgstr "Desmontar SMB" + +#: backends/platform/wii/options.cpp:143 +msgid "DVD Mounted successfully" +msgstr "DVD montado con éxito" + +#: backends/platform/wii/options.cpp:146 +msgid "Error while mounting the DVD" +msgstr "Erro ao montar o DVD" + +#: backends/platform/wii/options.cpp:148 +msgid "DVD not mounted" +msgstr "DVD non montado" + +#: backends/platform/wii/options.cpp:161 +msgid "Network up, share mounted" +msgstr "Conexión á rede, disco montado" + +#: backends/platform/wii/options.cpp:163 +msgid "Network up" +msgstr "Conexión á rede" + +#: backends/platform/wii/options.cpp:166 +msgid ", error while mounting the share" +msgstr ", erro ao montar o disco" + +#: backends/platform/wii/options.cpp:168 +msgid ", share not mounted" +msgstr ", disco non montado" + +#: backends/platform/wii/options.cpp:174 +msgid "Network down" +msgstr "Non hai conexión á rede" + +#: backends/platform/wii/options.cpp:178 +msgid "Initializing network" +msgstr "Conectando á rede" + +#: backends/platform/wii/options.cpp:182 +msgid "Timeout while initializing network" +msgstr "Tempo de espera esgotado" + +#: backends/platform/wii/options.cpp:186 +#, c-format +msgid "Network not initialized (%d)" +msgstr "Erro de conexión á rede (%d)" + +#: backends/platform/wince/CEActionsPocket.cpp:46 +msgid "Hide Toolbar" +msgstr "Ocultar barra de ferramentas" + +#: backends/platform/wince/CEActionsPocket.cpp:47 +msgid "Show Keyboard" +msgstr "Mostrar teclado" + +#: backends/platform/wince/CEActionsPocket.cpp:48 +msgid "Sound on/off" +msgstr "Son si/non" + +#: backends/platform/wince/CEActionsPocket.cpp:49 +msgid "Right click" +msgstr "Botón secundario" + +#: backends/platform/wince/CEActionsPocket.cpp:50 +msgid "Show/Hide Cursor" +msgstr "Mostrar/ocultar cursor" + +#: backends/platform/wince/CEActionsPocket.cpp:51 +msgid "Free look" +msgstr "Vista libre" + +#: backends/platform/wince/CEActionsPocket.cpp:52 +msgid "Zoom up" +msgstr "Ampliar" + +#: backends/platform/wince/CEActionsPocket.cpp:53 +msgid "Zoom down" +msgstr "Reducir" + +#: backends/platform/wince/CEActionsPocket.cpp:55 +#: backends/platform/wince/CEActionsSmartphone.cpp:49 +msgid "Bind Keys" +msgstr "Vincular teclas" + +#: backends/platform/wince/CEActionsPocket.cpp:56 +msgid "Cursor Up" +msgstr "Arriba" + +#: backends/platform/wince/CEActionsPocket.cpp:57 +msgid "Cursor Down" +msgstr "Abaixo" + +#: backends/platform/wince/CEActionsPocket.cpp:58 +msgid "Cursor Left" +msgstr "Esquerda" + +#: backends/platform/wince/CEActionsPocket.cpp:59 +msgid "Cursor Right" +msgstr "Dereita" + +#: backends/platform/wince/CEActionsPocket.cpp:267 +#: backends/platform/wince/CEActionsSmartphone.cpp:231 +msgid "Do you want to load or save the game?" +msgstr "Queres cargar ou gardar a partida?" + +#: backends/platform/wince/CEActionsPocket.cpp:326 +#: backends/platform/wince/CEActionsSmartphone.cpp:287 +msgid " Are you sure you want to quit ? " +msgstr " Seguro que queres saír?" + +#: backends/platform/wince/CEActionsSmartphone.cpp:50 +msgid "Keyboard" +msgstr "Teclado" + +#: backends/platform/wince/CEActionsSmartphone.cpp:51 +msgid "Rotate" +msgstr "Rotar" + +#: backends/platform/wince/CELauncherDialog.cpp:56 +msgid "Using SDL driver " +msgstr "Empregando driver de SDL" + +#: backends/platform/wince/CELauncherDialog.cpp:60 +msgid "Display " +msgstr "Pantalla" + +#: backends/platform/wince/CELauncherDialog.cpp:83 +msgid "Do you want to perform an automatic scan ?" +msgstr "Queres realizar unha análise automática?" + +#: backends/platform/wince/wince-sdl.cpp:515 +msgid "Map right click action" +msgstr "Asignar acción de botón secundario" + +#: backends/platform/wince/wince-sdl.cpp:519 +msgid "You must map a key to the 'Right Click' action to play this game" +msgstr "" +"Debes asignar unha tecla á acción do botón secundario do rato para xogar" + +#: backends/platform/wince/wince-sdl.cpp:528 +msgid "Map hide toolbar action" +msgstr "Asignar acción Ocultar barra de ferramentas" + +#: backends/platform/wince/wince-sdl.cpp:532 +msgid "You must map a key to the 'Hide toolbar' action to play this game" +msgstr "" +"Debes asignar unha tecla á acción Ocultar barra de ferramentas para xogar" + +#: backends/platform/wince/wince-sdl.cpp:541 +msgid "Map Zoom Up action (optional)" +msgstr "Asignar acción de Ampliar (opcional)" + +#: backends/platform/wince/wince-sdl.cpp:544 +msgid "Map Zoom Down action (optional)" +msgstr "Asignar acción de Reducir (opcional)" + +#: backends/platform/wince/wince-sdl.cpp:552 +msgid "" +"Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory" +msgstr "" +"Non esquezas asignar unha tecla á acción Ocultar barra de ferramentas para " +"ver o inventario completo" + +#: backends/events/default/default-events.cpp:191 +msgid "Do you really want to return to the Launcher?" +msgstr "Seguro que queres volver ao Iniciador?" + +#: backends/events/default/default-events.cpp:191 +msgid "Launcher" +msgstr "Iniciador" + +#: backends/events/default/default-events.cpp:213 +msgid "Do you really want to quit?" +msgstr "Seguro que queres saír?" + +#: backends/events/gph/gph-events.cpp:386 +#: backends/events/gph/gph-events.cpp:429 +#: backends/events/openpandora/op-events.cpp:139 +msgid "Touchscreen 'Tap Mode' - Left Click" +msgstr "Modo pantalla táctil: premer botón primario" + +#: backends/events/gph/gph-events.cpp:388 +#: backends/events/gph/gph-events.cpp:431 +#: backends/events/openpandora/op-events.cpp:141 +msgid "Touchscreen 'Tap Mode' - Right Click" +msgstr "Modo pantalla táctil: premer botón secundario" + +#: backends/events/gph/gph-events.cpp:390 +#: backends/events/gph/gph-events.cpp:433 +#: backends/events/openpandora/op-events.cpp:143 +msgid "Touchscreen 'Tap Mode' - Hover (No Click)" +msgstr "Modo pantalla táctil: apuntar co rato" + +#: backends/events/gph/gph-events.cpp:410 +msgid "Maximum Volume" +msgstr "Volume máximo" + +#: backends/events/gph/gph-events.cpp:412 +msgid "Increasing Volume" +msgstr "Subindo volume" + +#: backends/events/gph/gph-events.cpp:418 +msgid "Minimal Volume" +msgstr "Volume mínimo" + +#: backends/events/gph/gph-events.cpp:420 +msgid "Decreasing Volume" +msgstr "Baixando volume" + +#: backends/updates/macosx/macosx-updates.mm:65 +msgid "Check for Updates..." +msgstr "Buscar actualizacións..." + +#: backends/platform/bada/form.cpp:269 +msgid "Right Click Once" +msgstr "Botón secundario unha vez" + +#: backends/platform/bada/form.cpp:277 +msgid "Move Only" +msgstr "Mover unicamente" + +#: backends/platform/bada/form.cpp:291 +msgid "Escape Key" +msgstr "ESC" + +#: backends/platform/bada/form.cpp:296 +msgid "Game Menu" +msgstr "Menú do xogo" + +#: backends/platform/bada/form.cpp:301 +msgid "Show Keypad" +msgstr "Mostrar teclado numérico" + +#: backends/platform/bada/form.cpp:309 +msgid "Control Mouse" +msgstr "Rato" + +#: backends/events/maemosdl/maemosdl-events.cpp:192 +msgid "Clicking Enabled" +msgstr "Premer activado" + +#: backends/events/maemosdl/maemosdl-events.cpp:192 +msgid "Clicking Disabled" +msgstr "Premer desactivado" -- cgit v1.2.3 From 333a05c5b1643c3021929b83eca0686a559f1ceb Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Mon, 27 Aug 2012 11:42:29 +0100 Subject: CREDITS: Add credits for Galician translation --- AUTHORS | 3 +++ devtools/credits.pl | 3 +++ gui/credits.h | 3 +++ 3 files changed, 9 insertions(+) diff --git a/AUTHORS b/AUTHORS index 02c805b833..fe806c4490 100644 --- a/AUTHORS +++ b/AUTHORS @@ -408,6 +408,9 @@ Other contributions French: Thierry Crozat + Galician: + Santiago G. Sanz + German: Simon Sawatzki Lothar Serra Mari diff --git a/devtools/credits.pl b/devtools/credits.pl index 6a4b97b89d..7ce17a9df6 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -935,6 +935,9 @@ begin_credits("Credits"); begin_section("French"); add_person("Thierry Crozat", "criezy", ""); end_section(); + begin_section("Galician"); + add_person("Santiago G. Sanz", "sgsanz", ""); + end_section(); begin_section("German"); add_person("Simon Sawatzki", "SimSaw", ""); add_person("Lothar Serra Mari", "Lothar93", ""); diff --git a/gui/credits.h b/gui/credits.h index 34c6f21026..fdde2da821 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -476,6 +476,9 @@ static const char *credits[] = { "C1""French", "C0""Thierry Crozat", "", +"C1""Galician", +"C0""Santiago G. Sanz", +"", "C1""German", "C0""Simon Sawatzki", "C0""Lothar Serra Mari", -- cgit v1.2.3 From b8e10e478572f535a845de37fc005a54375e6bcd Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Mon, 27 Aug 2012 11:42:50 +0100 Subject: I18N: Update translation data file --- gui/themes/translations.dat | Bin 345659 -> 367742 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat index d81c1a0475..613afc0e4a 100644 Binary files a/gui/themes/translations.dat and b/gui/themes/translations.dat differ -- cgit v1.2.3 From ad15f21676fd27b407317c3a164b9a9973f1c349 Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Mon, 27 Aug 2012 11:44:46 +0100 Subject: NEWS: Mention new Galician translation --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index fc5ad8a67e..1f736aa74f 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ For a more comprehensive changelog of the latest experimental code, see: available and used for games without thumbnail support. It is possible to select the old one as default too. - Rewrote VideoDecoder subsystem. + - Added Galician translation. 1.5.0 (2012-07-27) New Games: -- cgit v1.2.3 From 8abba435bffc9b1168ec4d518f4da3b979da64d2 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Mon, 27 Aug 2012 15:56:29 +0200 Subject: I18N: Updated Catalan translation. --- po/ca_ES.po | 234 ++++++++++++++++++++++++++---------------------------------- 1 file changed, 103 insertions(+), 131 deletions(-) diff --git a/po/ca_ES.po b/po/ca_ES.po index 3e8ade3923..da2586a2af 100644 --- a/po/ca_ES.po +++ b/po/ca_ES.po @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: ScummVM 1.3.0svn\n" +"Project-Id-Version: ScummVM 1.6.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2012-08-12 14:57+0200\n" -"PO-Revision-Date: 2011-10-04 20:51+0100\n" +"POT-Creation-Date: 2012-08-27 15:46+0200\n" +"PO-Revision-Date: 2012-08-26 20:32+0100\n" "Last-Translator: Jordi Vilalta Prat \n" "Language-Team: Catalan \n" "Language: Catalan\n" @@ -45,7 +45,7 @@ msgstr "Amunt" #: gui/browser.cpp:69 gui/chooser.cpp:45 gui/KeysDialog.cpp:43 #: gui/launcher.cpp:345 gui/massadd.cpp:94 gui/options.cpp:1228 #: gui/saveload-dialog.cpp:207 gui/saveload-dialog.cpp:267 -#: gui/saveload-dialog.cpp:516 gui/saveload-dialog.cpp:843 +#: gui/saveload-dialog.cpp:516 gui/saveload-dialog.cpp:847 #: gui/themebrowser.cpp:54 engines/engine.cpp:442 #: engines/scumm/dialogs.cpp:190 engines/sword1/control.cpp:865 #: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:48 @@ -78,7 +78,6 @@ msgid "Remap keys" msgstr "Assigna les tecles" #: gui/gui-manager.cpp:129 base/main.cpp:307 -#, fuzzy msgid "Toggle FullScreen" msgstr "Commuta la pantalla completa" @@ -92,15 +91,15 @@ msgstr "Assigna" #: gui/KeysDialog.cpp:42 gui/launcher.cpp:346 gui/launcher.cpp:1001 #: gui/launcher.cpp:1005 gui/massadd.cpp:91 gui/options.cpp:1229 -#: gui/saveload-dialog.cpp:844 engines/engine.cpp:361 engines/engine.cpp:372 +#: gui/saveload-dialog.cpp:848 engines/engine.cpp:361 engines/engine.cpp:372 #: engines/scumm/dialogs.cpp:192 engines/scumm/scumm.cpp:1775 -#: engines/agos/animation.cpp:561 engines/groovie/script.cpp:420 +#: engines/agos/animation.cpp:558 engines/groovie/script.cpp:420 #: engines/sky/compact.cpp:131 engines/sky/compact.cpp:141 -#: engines/sword1/animation.cpp:539 engines/sword1/animation.cpp:560 -#: engines/sword1/animation.cpp:570 engines/sword1/animation.cpp:577 +#: engines/sword1/animation.cpp:519 engines/sword1/animation.cpp:540 +#: engines/sword1/animation.cpp:550 engines/sword1/animation.cpp:557 #: engines/sword1/control.cpp:865 engines/sword1/logic.cpp:1633 -#: engines/sword2/animation.cpp:435 engines/sword2/animation.cpp:455 -#: engines/sword2/animation.cpp:465 engines/sword2/animation.cpp:474 +#: engines/sword2/animation.cpp:419 engines/sword2/animation.cpp:439 +#: engines/sword2/animation.cpp:449 engines/sword2/animation.cpp:458 #: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:47 #: backends/platform/wince/CELauncherDialog.cpp:54 msgid "OK" @@ -194,9 +193,8 @@ msgid "Platform:" msgstr "Platafor.:" #: gui/launcher.cpp:231 -#, fuzzy msgid "Engine" -msgstr "Examina" +msgstr "Motor" #: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 msgid "Graphics" @@ -934,11 +932,11 @@ msgstr "" #: gui/saveload-dialog.cpp:158 msgid "List view" -msgstr "" +msgstr "Vista de llistat" #: gui/saveload-dialog.cpp:159 msgid "Grid view" -msgstr "" +msgstr "Vista de quadrícula" #: gui/saveload-dialog.cpp:202 gui/saveload-dialog.cpp:350 msgid "No date saved" @@ -960,15 +958,15 @@ msgstr "Suprimeix" msgid "Do you really want to delete this savegame?" msgstr "Realment voleu suprimir aquesta partida?" -#: gui/saveload-dialog.cpp:375 gui/saveload-dialog.cpp:796 +#: gui/saveload-dialog.cpp:375 gui/saveload-dialog.cpp:800 msgid "Date: " msgstr "Data: " -#: gui/saveload-dialog.cpp:379 gui/saveload-dialog.cpp:802 +#: gui/saveload-dialog.cpp:379 gui/saveload-dialog.cpp:806 msgid "Time: " msgstr "Hora: " -#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:810 +#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:814 msgid "Playtime: " msgstr "Temps de joc: " @@ -978,31 +976,28 @@ msgstr "Partida sense t #: gui/saveload-dialog.cpp:517 msgid "Next" -msgstr "" +msgstr "Següent" #: gui/saveload-dialog.cpp:520 msgid "Prev" -msgstr "" +msgstr "Anterior" -#: gui/saveload-dialog.cpp:684 -#, fuzzy +#: gui/saveload-dialog.cpp:688 msgid "New Save" -msgstr "Desa" +msgstr "Nova partida desada" -#: gui/saveload-dialog.cpp:684 -#, fuzzy +#: gui/saveload-dialog.cpp:688 msgid "Create a new save game" -msgstr "No s'ha pogut desar l'estat del joc" +msgstr "Crea una nova partida desada" -#: gui/saveload-dialog.cpp:789 -#, fuzzy +#: gui/saveload-dialog.cpp:793 msgid "Name: " -msgstr "Nom:" +msgstr "Nom: " -#: gui/saveload-dialog.cpp:861 +#: gui/saveload-dialog.cpp:865 #, c-format msgid "Enter a description for slot %d:" -msgstr "" +msgstr "Entreu la descripció per l'espai %d:" #: gui/themebrowser.cpp:44 msgid "Select a Theme" @@ -1206,13 +1201,13 @@ msgstr "" "la informació bàsica i les instruccions sobre com obtenir més assistència." #: engines/dialogs.cpp:228 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate save failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Aquest motor no ofereix ajuda dins el joc. Consulteu el fitxer README per a " -"la informació bàsica i les instruccions sobre com obtenir més assistència." +"No s'ha pogut desar la partida (%s)! Consulteu el fitxer README per a la " +"informació bàsica i les instruccions sobre com obtenir més assistència." #: engines/dialogs.cpp:301 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:174 @@ -1273,13 +1268,13 @@ msgstr "" "Consulteu el fitxer README per a més detalls." #: engines/engine.cpp:426 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate load failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Aquest motor no ofereix ajuda dins el joc. Consulteu el fitxer README per a " -"la informació bàsica i les instruccions sobre com obtenir més assistència." +"No s'ha pogut carregar la partida (%s)! Consulteu el fitxer README per a la " +"informació bàsica i les instruccions sobre com obtenir més assistència." #: engines/engine.cpp:439 msgid "" @@ -1295,15 +1290,16 @@ msgstr "" msgid "Start anyway" msgstr "Inicia de totes maneres" -#: engines/agi/detection.cpp:145 engines/dreamweb/detection.cpp:47 +#: engines/agi/detection.cpp:142 engines/dreamweb/detection.cpp:47 #: engines/sci/detection.cpp:390 msgid "Use original save/load screens" -msgstr "" +msgstr "Utilitza les pantalles originals de desat/càrrega" -#: engines/agi/detection.cpp:146 engines/dreamweb/detection.cpp:48 +#: engines/agi/detection.cpp:143 engines/dreamweb/detection.cpp:48 #: engines/sci/detection.cpp:391 msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "" +"Utilitza les pantalles originals de desat/càrrega, en lloc de les de ScummVM" #: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 msgid "Restore game:" @@ -1314,68 +1310,71 @@ msgid "Restore" msgstr "Restaura" #: engines/dreamweb/detection.cpp:57 -#, fuzzy msgid "Use bright palette mode" -msgstr "Element superior dret" +msgstr "Utilitza el mode de paleta brillant" #: engines/dreamweb/detection.cpp:58 msgid "Display graphics using the game's bright palette" -msgstr "" +msgstr "Mostra els gràfics utilitzant la paleta brillant del joc" #: engines/sci/detection.cpp:370 msgid "EGA undithering" msgstr "Elimina el tramat d'EGA" #: engines/sci/detection.cpp:371 -#, fuzzy msgid "Enable undithering in EGA games" -msgstr "Activa l'eliminació del tramat en els jocs EGA que ho suportin" +msgstr "Activa l'eliminació del tramat en els jocs EGA" #: engines/sci/detection.cpp:380 -#, fuzzy msgid "Prefer digital sound effects" -msgstr "Volum dels sons d'efectes especials" +msgstr "Prefereix efectes de so digitals" #: engines/sci/detection.cpp:381 msgid "Prefer digital sound effects instead of synthesized ones" -msgstr "" +msgstr "Prefereix els efectes de so digitals en lloc dels sintetitzats" #: engines/sci/detection.cpp:400 msgid "Use IMF/Yamaha FB-01 for MIDI output" -msgstr "" +msgstr "Utilitza IMF/Yamaha FB-01 per la sortida MIDI" #: engines/sci/detection.cpp:401 msgid "" "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " "output" msgstr "" +"Utilitza una tarja IBM Music Feature o un mòdul sintetitzador Yamaha FB-01 " +"FM per la sortida MIDI" #: engines/sci/detection.cpp:411 msgid "Use CD audio" -msgstr "" +msgstr "Utilitza l'àudio del CD" #: engines/sci/detection.cpp:412 msgid "Use CD audio instead of in-game audio, if available" msgstr "" +"Utilitza l'àudio del CD en lloc de l'àudio intern del joc, si està disponible" #: engines/sci/detection.cpp:422 msgid "Use Windows cursors" -msgstr "" +msgstr "Utilitza els cursors de Windows" #: engines/sci/detection.cpp:423 msgid "" "Use the Windows cursors (smaller and monochrome) instead of the DOS ones" msgstr "" +"Utilitza els cursors de Windows (més petits i en blanc i negre) en lloc dels " +"de DOS" #: engines/sci/detection.cpp:433 -#, fuzzy msgid "Use silver cursors" -msgstr "Cursor normal" +msgstr "Utilitza cursors platejats" #: engines/sci/detection.cpp:434 msgid "" "Use the alternate set of silver cursors, instead of the normal golden ones" msgstr "" +"Utilitza el conjunt alternatiu de cursors platejats, en lloc dels normals " +"daurats" #: engines/scumm/dialogs.cpp:175 #, c-format @@ -1493,24 +1492,23 @@ msgstr "Veus i sub." #: engines/scumm/dialogs.cpp:653 msgid "Select a Proficiency Level." -msgstr "" +msgstr "Seleccioneu el nivell de competència." #: engines/scumm/dialogs.cpp:655 msgid "Refer to your Loom(TM) manual for help." -msgstr "" +msgstr "Consulteu el manual de Loom(TM) per ajuda." #: engines/scumm/dialogs.cpp:658 -#, fuzzy msgid "Standard" -msgstr "Estàndard (16bpp)" +msgstr "Estàndard" #: engines/scumm/dialogs.cpp:659 msgid "Practice" -msgstr "" +msgstr "Pràctica" #: engines/scumm/dialogs.cpp:660 msgid "Expert" -msgstr "" +msgstr "Expert" #: engines/scumm/help.cpp:73 msgid "Common keyboard commands:" @@ -2103,7 +2101,7 @@ msgstr "~M~en msgid "~W~ater Effect Enabled" msgstr "~E~fecte de l'aigua activat" -#: engines/agos/animation.cpp:560 +#: engines/agos/animation.cpp:557 #, c-format msgid "Cutscene file '%s' not found!" msgstr "No s'ha trobat el fitxer d'escena '%s'!" @@ -2129,118 +2127,109 @@ msgstr "No s'ha pogut desar l'estat del joc" #. Malcolm makes a joke. #: engines/kyra/detection.cpp:62 msgid "Studio audience" -msgstr "" +msgstr "Públic" #: engines/kyra/detection.cpp:63 msgid "Enable studio audience" -msgstr "" +msgstr "Activa el públic" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 msgid "Skip support" -msgstr "" +msgstr "Suport per saltar text i escenes" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" -msgstr "" +msgstr "Permet que se saltin textos i escenes" #. I18N: Helium mode makes people sound like they've inhaled Helium. #: engines/kyra/detection.cpp:84 msgid "Helium mode" -msgstr "" +msgstr "Mode heli" #: engines/kyra/detection.cpp:85 -#, fuzzy msgid "Enable helium mode" -msgstr "Activa el Mode Roland GS" +msgstr "Activa el mode heli" #. I18N: When enabled, this option makes scrolling smoother when #. changing from one screen to another. #: engines/kyra/detection.cpp:99 msgid "Smooth scrolling" -msgstr "" +msgstr "Desplaçament suau" #: engines/kyra/detection.cpp:100 msgid "Enable smooth scrolling when walking" -msgstr "" +msgstr "Activa el desplaçament suau al caminar" #. I18N: When enabled, this option changes the cursor when it floats to the #. edge of the screen to a directional arrow. The player can then click to #. walk towards that direction. #: engines/kyra/detection.cpp:112 -#, fuzzy msgid "Floating cursors" -msgstr "Cursor normal" +msgstr "Cursor flotant" #: engines/kyra/detection.cpp:113 msgid "Enable floating cursors" -msgstr "" +msgstr "Activa els cursors flotants" #. I18N: HP stands for Hit Points #: engines/kyra/detection.cpp:127 msgid "HP bar graphs" -msgstr "" +msgstr "Barra gràfica de PI" #: engines/kyra/detection.cpp:128 msgid "Enable hit point bar graphs" -msgstr "" +msgstr "Activa la barra gràfica dels punts d'impacte" #: engines/kyra/lol.cpp:478 msgid "Attack 1" -msgstr "" +msgstr "Atac 1" #: engines/kyra/lol.cpp:479 msgid "Attack 2" -msgstr "" +msgstr "Atac 2" #: engines/kyra/lol.cpp:480 msgid "Attack 3" -msgstr "" +msgstr "Atac 3" #: engines/kyra/lol.cpp:481 msgid "Move Forward" -msgstr "" +msgstr "Mou endavant" #: engines/kyra/lol.cpp:482 msgid "Move Back" -msgstr "" +msgstr "Mou enrere" #: engines/kyra/lol.cpp:483 msgid "Slide Left" -msgstr "" +msgstr "Mou a l'esquerra" #: engines/kyra/lol.cpp:484 -#, fuzzy msgid "Slide Right" -msgstr "Dreta" +msgstr "Mou a la dreta" #: engines/kyra/lol.cpp:485 -#, fuzzy msgid "Turn Left" -msgstr "Apaga" +msgstr "Gira a l'esquerra" #: engines/kyra/lol.cpp:486 -#, fuzzy msgid "Turn Right" -msgstr "Cursor Dreta" +msgstr "Gira a la dreta" #: engines/kyra/lol.cpp:487 -#, fuzzy msgid "Rest" -msgstr "Restaura" +msgstr "Descansa" #: engines/kyra/lol.cpp:488 -#, fuzzy msgid "Options" -msgstr "~O~pcions" +msgstr "Opcions" #: engines/kyra/lol.cpp:489 -#, fuzzy msgid "Choose Spell" -msgstr "Escull" +msgstr "Escull l'encanteri" #: engines/kyra/sound_midi.cpp:475 -#, fuzzy msgid "" "You appear to be using a General MIDI device,\n" "but your game only supports Roland MT32 MIDI.\n" @@ -2256,11 +2245,11 @@ msgstr "" #: engines/queen/queen.cpp:59 msgid "Alternative intro" -msgstr "" +msgstr "Introducció alternativa" #: engines/queen/queen.cpp:60 msgid "Use an alternative game intro (CD version only)" -msgstr "" +msgstr "Utilitza una introducció del joc alternativa (només per la versió CD)" #: engines/sky/compact.cpp:130 msgid "" @@ -2280,28 +2269,29 @@ msgstr "" #: engines/sky/detection.cpp:44 msgid "Floppy intro" -msgstr "" +msgstr "Introducció de disquets" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" msgstr "" +"Utilitza la introducció de la versió de disquets (només per a la versió CD)" -#: engines/sword1/animation.cpp:539 +#: engines/sword1/animation.cpp:519 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" -msgstr "" +msgstr "L'escena '%s' de PSX no es pot reproduir en mode paleta" -#: engines/sword1/animation.cpp:560 engines/sword2/animation.cpp:455 +#: engines/sword1/animation.cpp:540 engines/sword2/animation.cpp:439 msgid "DXA cutscenes found but ScummVM has been built without zlib support" msgstr "" "S'han trobat escenes en DXA, però s'ha compilat el ScummVM sense suport de " "zlib" -#: engines/sword1/animation.cpp:570 engines/sword2/animation.cpp:465 +#: engines/sword1/animation.cpp:550 engines/sword2/animation.cpp:449 msgid "MPEG2 cutscenes are no longer supported" msgstr "Les escenes MPEG2 ja no estan suportades" -#: engines/sword1/animation.cpp:576 engines/sword2/animation.cpp:473 +#: engines/sword1/animation.cpp:556 engines/sword2/animation.cpp:457 #, c-format msgid "Cutscene '%s' not found" msgstr "No s'ha trobat l'escena '%s'" @@ -2345,32 +2335,33 @@ msgstr "Mantingues el nou" msgid "This is the end of the Broken Sword 1 Demo" msgstr "Aquest és el final de la Demo del Broken Sword 1" -#: engines/sword2/animation.cpp:435 -#, fuzzy +#: engines/sword2/animation.cpp:419 msgid "" "PSX cutscenes found but ScummVM has been built without RGB color support" msgstr "" -"S'han trobat escenes en DXA, però s'ha compilat el ScummVM sense suport de " -"zlib" +"S'han trobat escenes de PSX, però s'ha compilat el ScummVM sense suport de " +"color RGB" #: engines/sword2/sword2.cpp:79 msgid "Show object labels" -msgstr "" +msgstr "Mostra les etiquetes dels objectes" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "" +msgstr "Mostra etiquetes al posar el ratolí sobre els objectes" #: engines/teenagent/resources.cpp:68 msgid "" "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "" +msgstr "Us falta el fitxer 'teenagent.dat'. Obteniu-lo a la pàgina de ScummVM" #: engines/teenagent/resources.cpp:89 msgid "" "The teenagent.dat file is compressed and zlib hasn't been included in this " "executable. Please decompress it" msgstr "" +"El fitxer teenagent.dat està comprimit però aquest executable no conté zlib. " +"Descomprimiu-lo, si us plau." #: engines/parallaction/saveload.cpp:133 #, c-format @@ -2512,9 +2503,8 @@ msgid "Keymap:" msgstr "Assignacions de teclat:" #: backends/keymapper/remap-dialog.cpp:66 -#, fuzzy msgid " (Effective)" -msgstr " (Actiu)" +msgstr " (Efectiu)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Active)" @@ -2522,7 +2512,7 @@ msgstr " (Actiu)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Blocked)" -msgstr "" +msgstr " (Bloquejat)" #: backends/keymapper/remap-dialog.cpp:119 msgid " (Global)" @@ -2626,7 +2616,7 @@ msgstr "Mode Touchpad desactivat." #: backends/platform/maemo/maemo.cpp:209 msgid "Click Mode" -msgstr "" +msgstr "Mode clic" #: backends/platform/maemo/maemo.cpp:215 #: backends/platform/symbian/src/SymbianActions.cpp:42 @@ -2637,9 +2627,8 @@ msgid "Left Click" msgstr "Clic esquerre" #: backends/platform/maemo/maemo.cpp:218 -#, fuzzy msgid "Middle Click" -msgstr "Element mig esquerre" +msgstr "Clic central" #: backends/platform/maemo/maemo.cpp:221 #: backends/platform/symbian/src/SymbianActions.cpp:43 @@ -3114,20 +3103,3 @@ msgstr "Clicat activat" #: backends/events/maemosdl/maemosdl-events.cpp:192 msgid "Clicking Disabled" msgstr "Clicat desactivat" - -#~ msgid "Hercules Green" -#~ msgstr "Hercules Verd" - -#~ msgid "Hercules Amber" -#~ msgstr "Hercules Àmbar" - -#~ msgctxt "lowres" -#~ msgid "Hercules Green" -#~ msgstr "Hercules Verd" - -#~ msgctxt "lowres" -#~ msgid "Hercules Amber" -#~ msgstr "Hercules Àmbar" - -#~ msgid "Save game failed!" -#~ msgstr "No s'ha pogut desar la partida!" -- cgit v1.2.3 From e96249a105b36f79656e4b75cd17fd88a9b69ba9 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Mon, 27 Aug 2012 15:57:29 +0200 Subject: I18N: Update translation data file. --- gui/themes/translations.dat | Bin 367742 -> 370908 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat index 613afc0e4a..1c3abf84a8 100644 Binary files a/gui/themes/translations.dat and b/gui/themes/translations.dat differ -- cgit v1.2.3 From 6f105e62302b01db9b8d0bea14235d6e2c5932ba Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 27 Aug 2012 11:09:38 -0400 Subject: VIDEO: Fix "empty" AVI frames --- video/avi_decoder.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 09b95d38ad..0d51f5b130 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -330,19 +330,25 @@ void AVIDecoder::readNextPacket() { error("Cannot get track from tag '%s'", tag2str(nextTag)); uint32 chunkSize = _fileStream->readUint32LE(); - Common::SeekableReadStream *chunk = _fileStream->readStream(chunkSize); - _fileStream->skip(chunkSize & 1); + Common::SeekableReadStream *chunk = 0; + + if (chunkSize != 0) { + chunk = _fileStream->readStream(chunkSize); + _fileStream->skip(chunkSize & 1); + } if (track->getTrackType() == Track::kTrackTypeAudio) { if (getStreamType(nextTag) != MKTAG16('w', 'b')) error("Invalid audio track tag '%s'", tag2str(nextTag)); + assert(chunk); ((AVIAudioTrack *)track)->queueSound(chunk); } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; if (getStreamType(nextTag) == MKTAG16('p', 'c')) { // Palette Change + assert(chunk); byte firstEntry = chunk->readByte(); uint16 numEntries = chunk->readByte(); chunk->readUint16LE(); // Reserved @@ -387,8 +393,13 @@ AVIDecoder::AVIVideoTrack::~AVIVideoTrack() { } void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) { - if (_videoCodec) - _lastFrame = _videoCodec->decodeImage(stream); + if (stream) { + if (_videoCodec) + _lastFrame = _videoCodec->decodeImage(stream); + } else { + // Empty frame + _lastFrame = 0; + } delete stream; _curFrame++; -- cgit v1.2.3 From 4b05031042387ad9118690a77e1681165296bdec Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Mon, 27 Aug 2012 13:19:53 -0400 Subject: Revert "VIDEO: Rework SVQ1 codebooks so they're endian-safe" This reverts commit 1ca81ee6ecff15c843c04a51c8757be5a685edc2. I was wrong about them not being endian-safe before. Don't stone me. Conflicts: video/codecs/svq1.cpp --- video/codecs/svq1.cpp | 8 +- video/codecs/svq1_cb.h | 2900 ++++++++++++++++++++++++------------------------ 2 files changed, 1454 insertions(+), 1454 deletions(-) diff --git a/video/codecs/svq1.cpp b/video/codecs/svq1.cpp index eba0c90305..14452ab15b 100644 --- a/video/codecs/svq1.cpp +++ b/video/codecs/svq1.cpp @@ -317,7 +317,7 @@ bool SVQ1Decoder::svq1DecodeBlockIntra(Common::BitStream *s, byte *pixels, int p for (uint y = 0; y < height; y++) memset(&dst[y * (pitch / 4)], mean, width); } else { - const uint32 *codebook = s_svq1IntraCodebooks[level]; + const uint32 *codebook = (const uint32 *)s_svq1IntraCodebooks[level]; uint32 bitCache = s->getBits(stages * 4); // calculate codebook entries for this vector @@ -336,7 +336,7 @@ bool SVQ1Decoder::svq1DecodeBlockIntra(Common::BitStream *s, byte *pixels, int p // add codebook entries to vector for (int j = 0; j < stages; j++) { - n3 = codebook[entries[j]] ^ 0x80808080; + n3 = READ_UINT32(&codebook[entries[j]]) ^ 0x80808080; n1 += (n3 & 0xFF00FF00) >> 8; n2 += n3 & 0x00FF00FF; } @@ -409,7 +409,7 @@ bool SVQ1Decoder::svq1DecodeBlockNonIntra(Common::BitStream *s, byte *pixels, in } int mean = _interMean->getSymbol(*s) - 256; - const uint32 *codebook = s_svq1InterCodebooks[level]; + const uint32 *codebook = (const uint32 *)s_svq1InterCodebooks[level]; uint32 bitCache = s->getBits(stages * 4); // calculate codebook entries for this vector @@ -430,7 +430,7 @@ bool SVQ1Decoder::svq1DecodeBlockNonIntra(Common::BitStream *s, byte *pixels, in // add codebook entries to vector for (int j = 0; j < stages; j++) { - n3 = codebook[entries[j]] ^ 0x80808080; + n3 = READ_UINT32(&codebook[entries[j]]) ^ 0x80808080; n1 += (n3 & 0xFF00FF00) >> 8; n2 += n3 & 0x00FF00FF; } diff --git a/video/codecs/svq1_cb.h b/video/codecs/svq1_cb.h index f9a8c54e40..8281b3fc28 100644 --- a/video/codecs/svq1_cb.h +++ b/video/codecs/svq1_cb.h @@ -30,1477 +30,1477 @@ namespace Video { -static const uint32 s_svq1InterCodebook4x2[192] = { - 0xf9fa0207, 0xfcfd0307, 0x0807fef9, 0x0403fcf8, - 0x03091113, 0xf8f4f0f2, 0xfdf8f0ee, 0x080c0e0b, - 0x14f6f007, 0x14f6ef07, 0xeb0812fa, 0xec0912f9, - 0xf2ec0319, 0xf3ee071d, 0x0e15fce3, 0x0e14fae1, - 0xe8e4e6ed, 0x0a16201f, 0x1c1f180f, 0xf3eae0e0, - 0xe6e9f802, 0x231b03f7, 0x15150b03, 0xdee5fc08, - 0x2f0ce1e2, 0x2f0de2e3, 0xd2ef1e26, 0xd2ed1a22, - 0xd5cdced6, 0x30373022, 0x2a333630, 0xd1cbccd4, - 0xfa000504, 0x0100fefe, 0xfefffaf5, 0x01090801, - 0x05fa0100, 0x02f40108, 0x08f9f207, 0x0800f805, - 0x080b0401, 0xfb00f8f4, 0x040001ff, 0x1003f8f1, - 0xfafc0811, 0xf8f3fc09, 0xee010602, 0xf40b0bff, - 0x00020006, 0xebf9060e, 0xecf3ff01, 0x150a0101, - 0x0d07fbea, 0x0c04fff5, 0x130e00f9, 0xedfb03fc, - 0x0f0af2e6, 0xfefa0412, 0xeefb1319, 0x0204f9ec, - 0xfcfffaf3, 0xddfe2519, 0x01010405, 0x2b02dceb, - 0x03fffe02, 0xfffafe08, 0x0c02fdfe, 0xfffefefb, - 0xfbfffffd, 0xfe0807ff, 0xfd050702, 0xf8fd0101, - 0xfefdfffd, 0x0d02fdfe, 0xfaf5000f, 0x00000003, - 0xfcfbf7fa, 0x03010412, 0x0400030c, 0xfd03fdf0, - 0x021203ef, 0xfffffdff, 0x00f810fa, 0x00f90ef7, - 0xfb0ef303, 0xfc0ef303, 0xe90e14f9, 0x04f8f908, - 0x10edf108, 0xfd0b0df6, 0x1a01ff09, 0x02e5f105, - 0xfc1007ec, 0x011f09d8, 0xf9e2f41a, 0x04edfe28, - 0x00000006, 0x0201fefa, 0xfa00ff00, 0xfffe0009, - 0xfd0208f9, 0x02fd02ff, 0x04fefc07, 0xfa000002, - 0x0209fefd, 0xfc00fffe, 0xfd00fdfd, 0x040a02fa, - 0x08f60003, 0x04fc0000, 0x020401ff, 0x07f7f903, - 0xfcf70102, 0x00000cff, 0xfc07ff03, 0x0204f203, - 0x0b01f7f4, 0x00010502, 0x02000103, 0xed060800, - 0xfcf9f6fa, 0x07050709, 0xfd031506, 0xfefbf7f5, - 0xfff0f7fc, 0x2401fbfe, 0x00130b08, 0xd7fc0502, - 0xfffeffff, 0x0601fefe, 0xf8010400, 0x00010101, - 0x0004fdfe, 0xfd03ff02, 0x01fc0301, 0xfb0003ff, - 0x03020403, 0xfffafdfe, 0x02fefdfe, 0x000108fc, - 0x060204f9, 0x0001fff9, 0x01fc02fe, 0xff02fa08, - 0x020002fa, 0xfff80405, 0x0900f5ff, 0x0202fe00, - 0xfffcfb11, 0xfefefcff, 0xfd09f300, 0x02f90cff, - 0x02fbfe00, 0xfd14fbf9, 0xe2ff0707, 0x01080503, - 0xfcff03fa, 0x12f5fe02, 0x0e03f900, 0xf7eefd14, - 0xff00fe07, 0xff0000fe, 0x0001fffc, 0x040002fe, - 0x0102fd01, 0x01fb0103, 0xfeff00fd, 0xfd000107, - 0xfe000502, 0x01fffb02, 0xff04feff, 0x0005fd00, - 0xfeff0300, 0xff0501fc, 0x09ff00ff, 0xfffffeff, - 0xff0505fe, 0xfefd02fe, 0x01f50201, 0x02030102, - 0xfefff602, 0x01040204, 0x01fb0504, 0x01f50600, - 0x06060001, 0xf1010200, 0x09050307, 0x020202e2, - 0x020901de, 0x02080805, 0x06060207, 0x0401e502 +static const int8 s_svq1InterCodebook4x2[768] = { + 7, 2, -6, -7, 7, 3, -3, -4, -7, -2, 7, 8, -8, -4, 3, 4, + 19, 17, 9, 3,-14,-16,-12, -8,-18,-16, -8, -3, 11, 14, 12, 8, + 7,-16,-10, 20, 7,-17,-10, 20, -6, 18, 8,-21, -7, 18, 9,-20, + 25, 3,-20,-14, 29, 7,-18,-13,-29, -4, 21, 14,-31, -6, 20, 14, + -19,-26,-28,-24, 31, 32, 22, 10, 15, 24, 31, 28,-32,-32,-22,-13, + 2, -8,-23,-26, -9, 3, 27, 35, 3, 11, 21, 21, 8, -4,-27,-34, + -30,-31, 12, 47,-29,-30, 13, 47, 38, 30,-17,-46, 34, 26,-19,-46, + -42,-50,-51,-43, 34, 48, 55, 48, 48, 54, 51, 42,-44,-52,-53,-47, + 4, 5, 0, -6, -2, -2, 0, 1,-11, -6, -1, -2, 1, 8, 9, 1, + 0, 1, -6, 5, 8, 1,-12, 2, 7,-14, -7, 8, 5, -8, 0, 8, + 1, 4, 11, 8,-12, -8, 0, -5, -1, 1, 0, 4,-15, -8, 3, 16, + 17, 8, -4, -6, 9, -4,-13, -8, 2, 6, 1,-18, -1, 11, 11,-12, + 6, 0, 2, 0, 14, 6, -7,-21, 1, -1,-13,-20, 1, 1, 10, 21, + -22, -5, 7, 13,-11, -1, 4, 12, -7, 0, 14, 19, -4, 3, -5,-19, + -26,-14, 10, 15, 18, 4, -6, -2, 25, 19, -5,-18,-20, -7, 4, 2, + -13, -6, -1, -4, 25, 37, -2,-35, 5, 4, 1, 1,-21,-36, 2, 43, + 2, -2, -1, 3, 8, -2, -6, -1, -2, -3, 2, 12, -5, -2, -2, -1, + -3, -1, -1, -5, -1, 7, 8, -2, 2, 7, 5, -3, 1, 1, -3, -8, + -3, -1, -3, -2, -2, -3, 2, 13, 15, 0,-11, -6, 3, 0, 0, 0, + -6, -9, -5, -4, 18, 4, 1, 3, 12, 3, 0, 4,-16, -3, 3, -3, + -17, 3, 18, 2, -1, -3, -1, -1, -6, 16, -8, 0, -9, 14, -7, 0, + 3,-13, 14, -5, 3,-13, 14, -4, -7, 20, 14,-23, 8, -7, -8, 4, + 8,-15,-19, 16,-10, 13, 11, -3, 9, -1, 1, 26, 5,-15,-27, 2, + -20, 7, 16, -4,-40, 9, 31, 1, 26,-12,-30, -7, 40, -2,-19, 4, + 6, 0, 0, 0, -6, -2, 1, 2, 0, -1, 0, -6, 9, 0, -2, -1, + -7, 8, 2, -3, -1, 2, -3, 2, 7, -4, -2, 4, 2, 0, 0, -6, + -3, -2, 9, 2, -2, -1, 0, -4, -3, -3, 0, -3, -6, 2, 10, 4, + 3, 0,-10, 8, 0, 0, -4, 4, -1, 1, 4, 2, 3, -7, -9, 7, + 2, 1, -9, -4, -1, 12, 0, 0, 3, -1, 7, -4, 3,-14, 4, 2, + -12, -9, 1, 11, 2, 5, 1, 0, 3, 1, 0, 2, 0, 8, 6,-19, + -6,-10, -7, -4, 9, 7, 5, 7, 6, 21, 3, -3,-11, -9, -5, -2, + -4, -9,-16, -1, -2, -5, 1, 36, 8, 11, 19, 0, 2, 5, -4,-41, + -1, -1, -2, -1, -2, -2, 1, 6, 0, 4, 1, -8, 1, 1, 1, 0, + -2, -3, 4, 0, 2, -1, 3, -3, 1, 3, -4, 1, -1, 3, 0, -5, + 3, 4, 2, 3, -2, -3, -6, -1, -2, -3, -2, 2, -4, 8, 1, 0, + -7, 4, 2, 6, -7, -1, 1, 0, -2, 2, -4, 1, 8, -6, 2, -1, + -6, 2, 0, 2, 5, 4, -8, -1, -1,-11, 0, 9, 0, -2, 2, 2, + 17, -5, -4, -1, -1, -4, -2, -2, 0,-13, 9, -3, -1, 12, -7, 2, + 0, -2, -5, 2, -7, -5, 20, -3, 7, 7, -1,-30, 3, 5, 8, 1, + -6, 3, -1, -4, 2, -2,-11, 18, 0, -7, 3, 14, 20, -3,-18, -9, + 7, -2, 0, -1, -2, 0, 0, -1, -4, -1, 1, 0, -2, 2, 0, 4, + 1, -3, 2, 1, 3, 1, -5, 1, -3, 0, -1, -2, 7, 1, 0, -3, + 2, 5, 0, -2, 2, -5, -1, 1, -1, -2, 4, -1, 0, -3, 5, 0, + 0, 3, -1, -2, -4, 1, 5, -1, -1, 0, -1, 9, -1, -2, -1, -1, + -2, 5, 5, -1, -2, 2, -3, -2, 1, 2,-11, 1, 2, 1, 3, 2, + 2,-10, -1, -2, 4, 2, 4, 1, 4, 5, -5, 1, 0, 6,-11, 1, + 1, 0, 6, 6, 0, 2, 1,-15, 7, 3, 5, 9,-30, 2, 2, 2, + -34, 1, 9, 2, 5, 8, 8, 2, 7, 2, 6, 6, 2,-27, 1, 4 }; -static const uint32 s_svq1InterCodebook4x4[384] = { - 0xf9fa0004, 0xf7f3f8fc, 0x06fff8f8, 0x1b1605fe, - 0x0a0bf9f0, 0x0a0df9ee, 0x080cfcf1, 0x0509fff7, - 0xf00f02fe, 0xed1302fd, 0xed1302fd, 0xf20f03fe, - 0x10161611, 0xfefbf9fa, 0xf4f0f0f4, 0xfdff0101, - 0x0800ef0b, 0x09ffeb0e, 0x08feeb0e, 0x06fef00b, - 0x0bf0fe07, 0x0eebfe09, 0x0eeaff0a, 0x0aeeff08, - 0xf70310f6, 0xf50414f3, 0xf60415f2, 0xf80310f5, - 0xf7f7040b, 0xf2f4060f, 0xf2f40811, 0xf5f90a10, - 0x0d0e0a04, 0x100f07ff, 0x0803f9f4, 0xf6eee9ec, - 0xe7e6eef6, 0xf5fa0104, 0x030b0f0d, 0x080d0f0c, - 0xf5f0edf0, 0x0b0f0c07, 0x0b10100b, 0xf6f5f7fa, - 0x050c1312, 0xfc051012, 0xf1f60006, 0xeae9eff7, - 0x15fff2f6, 0x1d00eff5, 0x1e01f0f5, 0x1700f2f6, - 0xfaf4eff0, 0xf9f2eded, 0x0201fffd, 0x131d231b, - 0x1717f8db, 0x1d1cf7d6, 0x1c1af6d5, 0x1613f5da, - 0xdff01020, 0xdbee1427, 0xdaed1326, 0xdeef0f20, - 0xfcfa0918, 0x03faf6ff, 0x03fff7f8, 0xfa020703, - 0x00fffdff, 0xf90204ff, 0xf0030bfd, 0xee091401, - 0x0c06f8fd, 0x0d07f6fb, 0x0705f7fa, 0xff02fbfb, - 0xfffd0cf8, 0x01fd0ff6, 0x01fc0df5, 0x02fd08f5, - 0xf4fb0609, 0xf3f80003, 0xfffffcfc, 0x120f01fc, - 0x0c0e0d09, 0xfeff0304, 0xfbf8fbfe, 0xfcf7f5f9, - 0xfcf9fb07, 0xfcf9fe0e, 0xfbf80011, 0xfbf9010f, - 0x0406fff6, 0x0402f7f1, 0x00fdff02, 0xf6f80d19, - 0xf0fd0b07, 0xf1fd0b07, 0xf7fe0706, 0xfbfd0204, - 0x00fffff9, 0x0602fef7, 0x0e06fcf4, 0x1308faf3, - 0xfbf5eeee, 0x040300fd, 0x06060806, 0x06060606, - 0xf60d03fb, 0xf70f01fa, 0xfa0ffdfa, 0xfd0afafa, - 0xf7f70109, 0x0506090b, 0x07080300, 0xfbfaf2f1, - 0x130bfaf5, 0xf8f7fbfe, 0xf6f70206, 0x05040506, - 0x0f08fdf9, 0x0f0a03ff, 0xfeff0505, 0xe7ebfe04, - 0x05fafa06, 0x09f9f708, 0x0df9f408, 0x0ef9f204, - 0x0101fdfc, 0xfdfefbfd, 0xfcfe0007, 0xfcfc0714, - 0x0afaecfd, 0x01000006, 0xff050805, 0xfe0000fd, - 0x02ff060d, 0x03020305, 0x000300fd, 0xfbfef8f0, - 0x00faf9fe, 0x01fdfafd, 0xff02fffb, 0x05100cff, - 0x080901f9, 0x0305fef6, 0x030702fa, 0xf9ff00fc, - 0xe8f70403, 0x03060200, 0x0704ffff, 0xfeff0305, - 0x02f70603, 0x01f30601, 0x02f60801, 0x01f90801, - 0x1602fdfd, 0x0cfbfdfe, 0x02f6fdfe, 0x02fcfffd, - 0x02080c0b, 0xf8fbfbfb, 0xfd00fcfa, 0x0303fffe, - 0xfffefa0c, 0xfefef80c, 0xfd00f909, 0xfe02fa04, - 0xfd0c01ed, 0xfc0504fc, 0xfffe0106, 0x07fefc04, - 0xf8f9fcfd, 0x00fefcfc, 0x100e02ff, 0x0404fefc, - 0xfb0207ff, 0x01ff00fe, 0x0dfffd04, 0x08f2f406, - 0xfb0405ff, 0xf70305fe, 0xf40407fe, 0xf70407ff, - 0x0101fdfa, 0xfa000b0b, 0xf9fe0406, 0x0a03f6f4, - 0xfefdfdfe, 0x0a0e0b06, 0xf6f6f5f7, 0x02030202, - 0xfff9fbf9, 0x070002ff, 0x090001ff, 0xfffb0403, - 0xfff1ff0a, 0x02fb0104, 0x01ff01fd, 0x040401fd, - 0x0a04ff02, 0x00ff0206, 0xf4f90202, 0xfd0002fc, - 0xf8fffcff, 0xf702ff03, 0xfb050004, 0x03080002, - 0x01010203, 0x0300fe04, 0x0104ff02, 0xe7ff0600, - 0xfcfefeff, 0xfcff00fd, 0x02fcffff, 0x1902fa00, - 0x0005fff5, 0x02fe0007, 0x04fdff0a, 0xfffefbfb, - 0xff030600, 0x01fffffe, 0xfbf4f9ff, 0x04020608, - 0xfaff0602, 0xfcff0a09, 0x00fc0001, 0xfbf7fe03, - 0x000403fc, 0x000303fc, 0x020300f5, 0x020703f5, - 0x0307fc02, 0x0107f801, 0x0104f4ff, 0x0202f703, - 0x09fefe02, 0x0103fdef, 0xfa0107fc, 0x03ff0405, - 0xfc0002ff, 0xff0c08f9, 0xfb0405fe, 0xfef8fb03, - 0xfefb0000, 0x1b03f8fe, 0x06fdfcff, 0xf9fe01fd, - 0xff010404, 0xfdf9f6f9, 0x03050a0a, 0xfdfcfefe, - 0x07050100, 0xecf0fe04, 0x08070400, 0xfffe0002, - 0x110301fe, 0xfffe01fd, 0xfefffeff, 0x00fffbff, - 0x0001fd05, 0x0000fe06, 0xfd00feff, 0xff0801f5, - 0x00000003, 0x01040200, 0x01060002, 0x02fdeefe, - 0x010600f2, 0x01fffefb, 0x010001ff, 0x00040701, - 0xfc0100ff, 0xfc030801, 0x030104fd, 0x01fc01fa, - 0x0303f401, 0xff00f6ff, 0x01020002, 0x04020203, - 0x03000003, 0x01fe0002, 0x00fb0205, 0xfff2ff06, - 0xfdfdfafe, 0x0504ff02, 0x00feff06, 0xfbff0404, - 0x00f501fc, 0x01fc02ff, 0xff03fd02, 0x000ffe01, - 0xfe00ff01, 0x01f9fc01, 0x15fffafe, 0x01ff02fe, - 0x00feff15, 0xfe01fdff, 0xff02fef7, 0xfffc0102, - 0xfa020801, 0x0004fff6, 0x0303fdfc, 0xffff0005, - 0xfe010203, 0x0304fefe, 0xeffc0205, 0x0304fe00, - 0x0300fcf9, 0xff020909, 0xff00faf5, 0x01000105, - 0xf5051100, 0x00fafe03, 0x01fcfe02, 0xff0201fc, - 0xfdfbfffb, 0xfefd05fd, 0xfb021004, 0xffff05fe, - 0x01fc0000, 0x0b0502ff, 0x01feffff, 0xfffdfefc, - 0x000afffb, 0xfd000106, 0x0001fc00, 0xff03fcfe, - 0x00030906, 0x00fe01fe, 0xfefefdfe, 0xfa010001, - 0x01020001, 0x01fe03ff, 0x00f1ff00, 0x060205ff, - 0x02020002, 0x06fcf400, 0xff040100, 0xfc010201, - 0x00f9fe01, 0xff000000, 0x030b02fb, 0xfa000301, - 0xfcf7fd00, 0x00ff0301, 0x00fe0104, 0x06fffd07, - 0x0206fe01, 0xfe03ff00, 0x020004fe, 0x02f202ff, - 0xff000202, 0xf2fd03fe, 0xfd030200, 0x02030105, - 0xf204fd01, 0xff0bfe01, 0x0003ff00, 0x020001ff, - 0x02fd03fe, 0x03fcfffc, 0x030102ff, 0x0702fefa, - 0x000201fe, 0xff0000fe, 0x02ff050c, 0xf901fff8, - 0x02fcfe02, 0xfef5000b, 0xfffd0103, 0xff010300, - 0xfe000300, 0xfdfffa00, 0x00fef90c, 0x0101fe07, - 0x02020201, 0x020002ff, 0x000400e9, 0x03010203, - 0x05fffbfc, 0xff0a05fd, 0xfc030000, 0xfb02ff01 +static const int8 s_svq1InterCodebook4x4[1536] = { + 4, 0, -6, -7, -4, -8,-13, -9, -8, -8, -1, 6, -2, 5, 22, 27, + -16, -7, 11, 10,-18, -7, 13, 10,-15, -4, 12, 8, -9, -1, 9, 5, + -2, 2, 15,-16, -3, 2, 19,-19, -3, 2, 19,-19, -2, 3, 15,-14, + 17, 22, 22, 16, -6, -7, -5, -2,-12,-16,-16,-12, 1, 1, -1, -3, + 11,-17, 0, 8, 14,-21, -1, 9, 14,-21, -2, 8, 11,-16, -2, 6, + 7, -2,-16, 11, 9, -2,-21, 14, 10, -1,-22, 14, 8, -1,-18, 10, + -10, 16, 3, -9,-13, 20, 4,-11,-14, 21, 4,-10,-11, 16, 3, -8, + 11, 4, -9, -9, 15, 6,-12,-14, 17, 8,-12,-14, 16, 10, -7,-11, + 4, 10, 14, 13, -1, 7, 15, 16,-12, -7, 3, 8,-20,-23,-18,-10, + -10,-18,-26,-25, 4, 1, -6,-11, 13, 15, 11, 3, 12, 15, 13, 8, + -16,-19,-16,-11, 7, 12, 15, 11, 11, 16, 16, 11, -6, -9,-11,-10, + 18, 19, 12, 5, 18, 16, 5, -4, 6, 0,-10,-15, -9,-17,-23,-22, + -10,-14, -1, 21,-11,-17, 0, 29,-11,-16, 1, 30,-10,-14, 0, 23, + -16,-17,-12, -6,-19,-19,-14, -7, -3, -1, 1, 2, 27, 35, 29, 19, + -37, -8, 23, 23,-42, -9, 28, 29,-43,-10, 26, 28,-38,-11, 19, 22, + 32, 16,-16,-33, 39, 20,-18,-37, 38, 19,-19,-38, 32, 15,-17,-34, + 24, 9, -6, -4, -1,-10, -6, 3, -8, -9, -1, 3, 3, 7, 2, -6, + -1, -3, -1, 0, -1, 4, 2, -7, -3, 11, 3,-16, 1, 20, 9,-18, + -3, -8, 6, 12, -5,-10, 7, 13, -6, -9, 5, 7, -5, -5, 2, -1, + -8, 12, -3, -1,-10, 15, -3, 1,-11, 13, -4, 1,-11, 8, -3, 2, + 9, 6, -5,-12, 3, 0, -8,-13, -4, -4, -1, -1, -4, 1, 15, 18, + 9, 13, 14, 12, 4, 3, -1, -2, -2, -5, -8, -5, -7,-11, -9, -4, + 7, -5, -7, -4, 14, -2, -7, -4, 17, 0, -8, -5, 15, 1, -7, -5, + -10, -1, 6, 4,-15, -9, 2, 4, 2, -1, -3, 0, 25, 13, -8,-10, + 7, 11, -3,-16, 7, 11, -3,-15, 6, 7, -2, -9, 4, 2, -3, -5, + -7, -1, -1, 0, -9, -2, 2, 6,-12, -4, 6, 14,-13, -6, 8, 19, + -18,-18,-11, -5, -3, 0, 3, 4, 6, 8, 6, 6, 6, 6, 6, 6, + -5, 3, 13,-10, -6, 1, 15, -9, -6, -3, 15, -6, -6, -6, 10, -3, + 9, 1, -9, -9, 11, 9, 6, 5, 0, 3, 8, 7,-15,-14, -6, -5, + -11, -6, 11, 19, -2, -5, -9, -8, 6, 2, -9,-10, 6, 5, 4, 5, + -7, -3, 8, 15, -1, 3, 10, 15, 5, 5, -1, -2, 4, -2,-21,-25, + 6, -6, -6, 5, 8, -9, -7, 9, 8,-12, -7, 13, 4,-14, -7, 14, + -4, -3, 1, 1, -3, -5, -2, -3, 7, 0, -2, -4, 20, 7, -4, -4, + -3,-20, -6, 10, 6, 0, 0, 1, 5, 8, 5, -1, -3, 0, 0, -2, + 13, 6, -1, 2, 5, 3, 2, 3, -3, 0, 3, 0,-16, -8, -2, -5, + -2, -7, -6, 0, -3, -6, -3, 1, -5, -1, 2, -1, -1, 12, 16, 5, + -7, 1, 9, 8,-10, -2, 5, 3, -6, 2, 7, 3, -4, 0, -1, -7, + 3, 4, -9,-24, 0, 2, 6, 3, -1, -1, 4, 7, 5, 3, -1, -2, + 3, 6, -9, 2, 1, 6,-13, 1, 1, 8,-10, 2, 1, 8, -7, 1, + -3, -3, 2, 22, -2, -3, -5, 12, -2, -3,-10, 2, -3, -1, -4, 2, + 11, 12, 8, 2, -5, -5, -5, -8, -6, -4, 0, -3, -2, -1, 3, 3, + 12, -6, -2, -1, 12, -8, -2, -2, 9, -7, 0, -3, 4, -6, 2, -2, + -19, 1, 12, -3, -4, 4, 5, -4, 6, 1, -2, -1, 4, -4, -2, 7, + -3, -4, -7, -8, -4, -4, -2, 0, -1, 2, 14, 16, -4, -2, 4, 4, + -1, 7, 2, -5, -2, 0, -1, 1, 4, -3, -1, 13, 6,-12,-14, 8, + -1, 5, 4, -5, -2, 5, 3, -9, -2, 7, 4,-12, -1, 7, 4, -9, + -6, -3, 1, 1, 11, 11, 0, -6, 6, 4, -2, -7,-12,-10, 3, 10, + -2, -3, -3, -2, 6, 11, 14, 10, -9,-11,-10,-10, 2, 2, 3, 2, + -7, -5, -7, -1, -1, 2, 0, 7, -1, 1, 0, 9, 3, 4, -5, -1, + 10, -1,-15, -1, 4, 1, -5, 2, -3, 1, -1, 1, -3, 1, 4, 4, + 2, -1, 4, 10, 6, 2, -1, 0, 2, 2, -7,-12, -4, 2, 0, -3, + -1, -4, -1, -8, 3, -1, 2, -9, 4, 0, 5, -5, 2, 0, 8, 3, + 3, 2, 1, 1, 4, -2, 0, 3, 2, -1, 4, 1, 0, 6, -1,-25, + -1, -2, -2, -4, -3, 0, -1, -4, -1, -1, -4, 2, 0, -6, 2, 25, + -11, -1, 5, 0, 7, 0, -2, 2, 10, -1, -3, 4, -5, -5, -2, -1, + 0, 6, 3, -1, -2, -1, -1, 1, -1, -7,-12, -5, 8, 6, 2, 4, + 2, 6, -1, -6, 9, 10, -1, -4, 1, 0, -4, 0, 3, -2, -9, -5, + -4, 3, 4, 0, -4, 3, 3, 0,-11, 0, 3, 2,-11, 3, 7, 2, + 2, -4, 7, 3, 1, -8, 7, 1, -1,-12, 4, 1, 3, -9, 2, 2, + 2, -2, -2, 9,-17, -3, 3, 1, -4, 7, 1, -6, 5, 4, -1, 3, + -1, 2, 0, -4, -7, 8, 12, -1, -2, 5, 4, -5, 3, -5, -8, -2, + 0, 0, -5, -2, -2, -8, 3, 27, -1, -4, -3, 6, -3, 1, -2, -7, + 4, 4, 1, -1, -7,-10, -7, -3, 10, 10, 5, 3, -2, -2, -4, -3, + 0, 1, 5, 7, 4, -2,-16,-20, 0, 4, 7, 8, 2, 0, -2, -1, + -2, 1, 3, 17, -3, 1, -2, -1, -1, -2, -1, -2, -1, -5, -1, 0, + 5, -3, 1, 0, 6, -2, 0, 0, -1, -2, 0, -3,-11, 1, 8, -1, + 3, 0, 0, 0, 0, 2, 4, 1, 2, 0, 6, 1, -2,-18, -3, 2, + -14, 0, 6, 1, -5, -2, -1, 1, -1, 1, 0, 1, 1, 7, 4, 0, + -1, 0, 1, -4, 1, 8, 3, -4, -3, 4, 1, 3, -6, 1, -4, 1, + 1,-12, 3, 3, -1,-10, 0, -1, 2, 0, 2, 1, 3, 2, 2, 4, + 3, 0, 0, 3, 2, 0, -2, 1, 5, 2, -5, 0, 6, -1,-14, -1, + -2, -6, -3, -3, 2, -1, 4, 5, 6, -1, -2, 0, 4, 4, -1, -5, + -4, 1,-11, 0, -1, 2, -4, 1, 2, -3, 3, -1, 1, -2, 15, 0, + 1, -1, 0, -2, 1, -4, -7, 1, -2, -6, -1, 21, -2, 2, -1, 1, + 21, -1, -2, 0, -1, -3, 1, -2, -9, -2, 2, -1, 2, 1, -4, -1, + 1, 8, 2, -6,-10, -1, 4, 0, -4, -3, 3, 3, 5, 0, -1, -1, + 3, 2, 1, -2, -2, -2, 4, 3, 5, 2, -4,-17, 0, -2, 4, 3, + -7, -4, 0, 3, 9, 9, 2, -1,-11, -6, 0, -1, 5, 1, 0, 1, + 0, 17, 5,-11, 3, -2, -6, 0, 2, -2, -4, 1, -4, 1, 2, -1, + -5, -1, -5, -3, -3, 5, -3, -2, 4, 16, 2, -5, -2, 5, -1, -1, + 0, 0, -4, 1, -1, 2, 5, 11, -1, -1, -2, 1, -4, -2, -3, -1, + -5, -1, 10, 0, 6, 1, 0, -3, 0, -4, 1, 0, -2, -4, 3, -1, + 6, 9, 3, 0, -2, 1, -2, 0, -2, -3, -2, -2, 1, 0, 1, -6, + 1, 0, 2, 1, -1, 3, -2, 1, 0, -1,-15, 0, -1, 5, 2, 6, + 2, 0, 2, 2, 0,-12, -4, 6, 0, 1, 4, -1, 1, 2, 1, -4, + 1, -2, -7, 0, 0, 0, 0, -1, -5, 2, 11, 3, 1, 3, 0, -6, + 0, -3, -9, -4, 1, 3, -1, 0, 4, 1, -2, 0, 7, -3, -1, 6, + 1, -2, 6, 2, 0, -1, 3, -2, -2, 4, 0, 2, -1, 2,-14, 2, + 2, 2, 0, -1, -2, 3, -3,-14, 0, 2, 3, -3, 5, 1, 3, 2, + 1, -3, 4,-14, 1, -2, 11, -1, 0, -1, 3, 0, -1, 1, 0, 2, + -2, 3, -3, 2, -4, -1, -4, 3, -1, 2, 1, 3, -6, -2, 2, 7, + -2, 1, 2, 0, -2, 0, 0, -1, 12, 5, -1, 2, -8, -1, 1, -7, + 2, -2, -4, 2, 11, 0,-11, -2, 3, 1, -3, -1, 0, 3, 1, -1, + 0, 3, 0, -2, 0, -6, -1, -3, 12, -7, -2, 0, 7, -2, 1, 1, + 1, 2, 2, 2, -1, 2, 0, 2,-23, 0, 4, 0, 3, 2, 1, 3, + -4, -5, -1, 5, -3, 5, 10, -1, 0, 0, 3, -4, 1, -1, 2, -5 }; -static const uint32 s_svq1InterCodebook8x4[768] = { - 0x00040809, 0xfdfcfcfd, 0xff040809, 0xfdfbfbfc, - 0xfe030708, 0xfcfbfbfb, 0xfe010406, 0xfdfcfbfc, - 0xfcf5f2f4, 0x06060501, 0xfbf9f6f8, 0x010101fe, - 0x01030405, 0xffff0000, 0x06090d0d, 0xfeff0003, - 0xfffdfcfc, 0x0b080401, 0xfefcfafb, 0x0c080300, - 0xfcfaf9f9, 0x0a0702fe, 0xfcfbf9f9, 0x080501fe, - 0x01fffefd, 0x06070603, 0x07050302, 0x04060808, - 0x03040504, 0xf9fafe01, 0xf9fe0001, 0xf0eff2f6, - 0x0801fcfb, 0xf9fd0309, 0x0b01faf9, 0xf8fd050c, - 0x0900f9f8, 0xf9fd050b, 0x05fffaf8, 0xfafe0408, - 0xf8f9fbfc, 0xfaf8f7f7, 0xf9fafbfc, 0xfefcfaf9, - 0x03020100, 0x090a0805, 0x06030201, 0x0d0e0c09, - 0x05060605, 0x01020304, 0x07070605, 0x04060606, - 0x010100ff, 0x05050503, 0xefeff0f3, 0xfcfaf6f2, - 0x100d0b09, 0x0a0c0d0f, 0xf9fafbfc, 0xfbfaf9f9, - 0xf9f9fafa, 0xfbfaf9f9, 0x0000fffe, 0xff000000, - 0xf0f1f3f5, 0xf6f4f2f0, 0x05040302, 0x03030304, - 0x08080706, 0x05060708, 0x03030403, 0x03030303, - 0x01040403, 0xeff3f9fe, 0x05070705, 0xedf3fb01, - 0x08090806, 0xf0f7ff05, 0x0a0a0806, 0xf5fc0207, - 0xf6ff0912, 0x00fcf7f3, 0xf4ff0c16, 0x02fcf6f1, - 0xf6000d17, 0x02fdf7f3, 0xfa020c14, 0x02fefaf7, - 0xf9fafafa, 0xfaf9f9f9, 0xf8f8f9fa, 0xf8f7f7f7, - 0xfdfdfdfd, 0xfdfdfdfd, 0x15120f0c, 0x0e111315, - 0x1212100e, 0x0d0f1012, 0x05060605, 0x03040405, - 0xf6f7f9fa, 0xf9f7f6f6, 0xf2f3f5f6, 0xf6f4f3f2, - 0x05fcefe5, 0x070a0a09, 0x07fdede0, 0x080b0c0b, - 0x08fef0e2, 0x070a0c0c, 0x0700f4e9, 0x06090b0a, - 0x0c101110, 0xf4f8ff06, 0x0a0f1211, 0xeef1f801, - 0x040a0e0f, 0xe9ecf2fb, 0xff04080a, 0xeaebf0f7, - 0xf5f4f4f6, 0x140e04fb, 0xf4f1f3f5, 0x1b1307fc, - 0xf5f2f3f5, 0x1c1508fd, 0xf7f4f5f6, 0x191208fe, - 0x01ffffff, 0x05060604, 0x02000000, 0xfe010304, - 0x04020000, 0xf6f9ff04, 0x05030000, 0xf1f5fd03, - 0xfff8f3f2, 0xfcff0303, 0x04fffcfb, 0x00030808, - 0x03020203, 0x01030504, 0xfe000305, 0xfffffffe, - 0xfafa0109, 0xfffefdfb, 0xfafa010c, 0x00fffefc, - 0xfcfc040e, 0xfffffefe, 0xffff060e, 0xffffffff, - 0x0a080604, 0x0507090b, 0x00ffffff, 0xfeffff00, - 0xfbfcfcfe, 0xfcfbfbfb, 0xfcfdfdfe, 0xfffefdfc, - 0x04040302, 0x00000103, 0x050401ff, 0x03040506, - 0x02fefaf8, 0x03040403, 0xfbf7f3f2, 0x0000fffe, - 0xfcfbfcfd, 0x0d0c0700, 0xfbfbfcfd, 0x0a0904fe, - 0xfbfcfdfe, 0x0403fffc, 0xfdfeffff, 0x0100fefd, - 0xf8fe0509, 0xfcf9f6f5, 0x02060a0c, 0x0000ff00, - 0x04030202, 0x01010103, 0x00fcf8f7, 0x00010201, - 0x05080806, 0xf3f5fb01, 0x02020100, 0xf5f8fcff, - 0x0301fefd, 0xfcff0103, 0x0502fffe, 0x01040606, - 0x05050403, 0xfafd0104, 0x02040605, 0xfd000202, - 0xfb000506, 0xfefffefb, 0xf5fd0407, 0xfefdf9f4, - 0xffff0001, 0x000000ff, 0x04040302, 0x03040505, - 0xf6f7f7f9, 0xfaf9f7f6, 0x06050403, 0x05050505, - 0xf9f9f9f9, 0xfcfbfafa, 0xfffdfcfb, 0x0000ffff, - 0x0401fefd, 0x05050505, 0x0603fffe, 0x090a0a09, - 0x030a01f2, 0x010100fe, 0x030d02f0, 0x0001fffd, - 0x030c02f1, 0x0101fefc, 0x020a03f6, 0x0101fffd, - 0x02040100, 0x0bfdf6fb, 0x020401ff, 0x0ffef3fa, - 0x010300ff, 0x0ffff4fa, 0x010201ff, 0x0b00f8fc, - 0xfefe050a, 0xfc010502, 0xfaf80007, 0xfc020501, - 0xf9f4fb02, 0xff040702, 0xfcf6f9ff, 0x02070904, - 0xfafcfbfb, 0xfdfbfbfa, 0xfcfefeff, 0xfcfbfafb, - 0x04070706, 0xfdfdfe00, 0x0a0d0e0d, 0xfeff0105, - 0x02020101, 0x02020202, 0xf7f8fafb, 0xfaf9f8f7, - 0x0b0a0907, 0x0507090b, 0xfdfdfeff, 0xfdfcfcfc, - 0x0000ffff, 0xffff0000, 0xfbfcfdfd, 0xfefdfdfc, - 0xfdff0102, 0x00fffefd, 0x03080c0c, 0x01000001, - 0xfaf8f8fa, 0x080602fe, 0xfeff0101, 0x07050300, - 0xff010303, 0x020000ff, 0xff000100, 0xfffeffff, - 0x00000001, 0x04020000, 0x04030102, 0x02000103, - 0x00000102, 0x0300ffff, 0xf4fa0105, 0x04fff8f3, - 0xfeff00fe, 0x030200ff, 0x00fefdfa, 0x01010101, - 0x0400fbf7, 0x00010305, 0x0703fdf8, 0x00010408, - 0x03020201, 0xfdff0103, 0x06050504, 0x00020506, - 0x00000000, 0xfcfe0001, 0xfdfcfdfd, 0xf8f9fcfd, - 0xff060c0e, 0x0000fdfd, 0xfd010507, 0xfffefcfb, - 0xfefefefe, 0xfffffefe, 0x01fffcfa, 0xff000101, - 0xfd010202, 0xfdfaf9fa, 0xfdff0001, 0x060401fe, - 0x02010000, 0x07080704, 0x00000000, 0xf8f9fcff, - 0xfe010200, 0xfffefdfd, 0xfd0001ff, 0x0200fefb, - 0xfbfefffe, 0x090601fc, 0xfcfdfefd, 0x0d0b05fe, - 0x0602fefc, 0xf2f6fd04, 0x0401fffe, 0xfeff0104, - 0xfeff0000, 0x060400fe, 0xfd000202, 0x090500fd, - 0x01fefcfc, 0xf9030906, 0xfffefefe, 0xf5000804, - 0x00000101, 0xf6ff0602, 0x00010202, 0xf9000402, - 0xfafdfeff, 0xf8f8f8f9, 0x01030302, 0xfcfdfeff, - 0x04050505, 0xff000203, 0x03030303, 0x01010202, - 0xfe020303, 0x0a0700fd, 0xfe020201, 0x0300fcfb, - 0x02040300, 0xfcfafbfd, 0x04040200, 0xf9f9fc01, - 0x05050402, 0x06060505, 0xfbfdfcfc, 0xfefdfdfb, - 0xfbfcfcfd, 0xfefefefc, 0x00000101, 0x04050402, - 0x040300fe, 0x02020304, 0x00fcf9f7, 0x06060603, - 0xfefdfbfb, 0x04030100, 0xfe020505, 0xfdfbfafc, - 0x07fcfa01, 0x01fefe05, 0x06fcfb05, 0x01fcfb04, - 0x06fcfb05, 0x01fdfb04, 0x08fdf901, 0x01fdff07, - 0x00fcf9f8, 0x05050402, 0x02050605, 0xf9f9fbff, - 0x01040605, 0xfbfafbfd, 0xfefbf9f9, 0x0a090601, - 0x01000306, 0xf2f80003, 0x01ff0003, 0xfc000304, - 0x01000001, 0x01010102, 0x0201ffff, 0x00ffff01, - 0x01010101, 0x00fdfe00, 0x00010201, 0xfcf7f8fe, - 0x02030301, 0x01fdfd01, 0x01010100, 0x08040101, - 0x07090502, 0x01ffff02, 0x0001fffc, 0x02fffcfd, - 0x030300fd, 0x0200ff00, 0x0101fffc, 0xfcfbfcfe, - 0xfefeff01, 0x050402ff, 0x00010102, 0x0000ffff, - 0x05040302, 0x00010204, 0xfdfaf7f7, 0xffffffff, - 0x0704fafa, 0xfefffe00, 0x0605feff, 0xff00feff, - 0x0001ff04, 0xfe00fefc, 0xfeff0107, 0x010301fd, - 0x03010204, 0x02010103, 0x00fcfe02, 0x00000103, - 0xfcf8fc01, 0x00010201, 0xfaf7fd02, 0x02030300, - 0xff00ffff, 0x020100ff, 0xf8fc0103, 0x0201fdf9, - 0xfefdff02, 0x000100ff, 0x0b0500ff, 0xfdff0309, - 0xfffefeff, 0x01010101, 0x0300ff00, 0x05050606, - 0xffff0102, 0xfcfafbfe, 0x01020202, 0xfbfbfcff, - 0xf9fafdff, 0x01fffcfa, 0x04030505, 0x05040304, - 0xfefdfeff, 0x0100fefe, 0x00000000, 0x03020100, - 0xfffcfafa, 0x02020202, 0xfefbf9fa, 0x00ffff00, - 0x04020202, 0x04030304, 0xff000102, 0x04020000, - 0xf8fb050c, 0x020200fb, 0xfdfafd02, 0xfeff0000, - 0x03fffdfe, 0xfdfe0104, 0x04030202, 0xffff0103, - 0x00010203, 0x00030401, 0xfb000304, 0x030300fa, - 0xf9010302, 0x0301faf4, 0xff040301, 0x0100fcfa, - 0x0602fcf7, 0x00010407, 0x0604fff9, 0xfdfd0004, - 0x040400fa, 0xfefdfe01, 0x020301fc, 0x00fffe00, - 0xfb020500, 0xfc0103fd, 0xfa0204fe, 0xfd0406fd, - 0xfb0305ff, 0xfc0307ff, 0xfa0002ff, 0xfd0305fd, - 0x0503fdf8, 0xfefe0103, 0xfe040402, 0x0301fdfc, - 0xfbfd0102, 0x030403fd, 0x03fbfafb, 0xfbff080a, - 0xfc020300, 0x0600f9f7, 0x0705fffb, 0xfdfdff04, - 0x03fefbfb, 0xfcff0506, 0xfc000609, 0xff0101fe, - 0x01ffffff, 0x00ff0001, 0x000000ff, 0x00ffff00, - 0xfffe0102, 0x00000101, 0xff02080c, 0xf9f9fcff, - 0x06030102, 0x00020407, 0x00ff0001, 0xf8f9fcff, - 0x00ff0000, 0xfdff0000, 0x00000000, 0xfe000101, - 0x010100ff, 0xfeff0000, 0xfdff0000, 0x01fffdfc, - 0x000000ff, 0x0c0a0401, 0xfefe00ff, 0x01fffdfd, - 0xfcfefffd, 0x07090902, 0xfdff00fd, 0x01ff0200, - 0xfdfe01ff, 0x00fdff00, 0xfefd0000, 0x01ffff00, - 0xfffffeff, 0xfefffffe, 0xfffeff02, 0xfe000100, - 0x02feff03, 0xfdff0305, 0x01fbfb01, 0x00020606, - 0xff000201, 0xfe000100, 0x00fffdfb, 0xfe010201, - 0xfefefbf9, 0x0100fefe, 0x010100ff, 0x0c090300, - 0x01050600, 0x0300fdfe, 0x01050600, 0x03020101, - 0xfdfefefb, 0x00000000, 0xfefdfdfa, 0xfeff0000, - 0x01020404, 0x00ffff00, 0x0100fefe, 0x00010102, - 0xff010202, 0xf6f7fbfd, 0xffff0102, 0x01040401, - 0xfefe0004, 0x00fffefe, 0xfdfc0107, 0x010100fe, - 0xfeff050a, 0x00010100, 0xfcfd0105, 0xfefffffd, - 0xfdff0102, 0xff0101fd, 0x0003fffe, 0x000101ff, - 0x020701fd, 0x00fffefd, 0xff0804fe, 0x0200fbf8, - 0x0201fffc, 0xfefcfd01, 0x01fefdfb, 0x06040404, - 0xfdfcfefd, 0x02010100, 0x01020202, 0xffff0102, - 0xff00fffc, 0xfffffdfd, 0x02040401, 0xfdfeff00, - 0x03050604, 0xfcfe0102, 0x01010100, 0xfafcff01, - 0xff020201, 0x02fffbfa, 0x0101fefd, 0x0502fdfc, - 0x0202fffe, 0x0300fcfd, 0x0602fefe, 0x02010205, - 0x00fdfd02, 0x01030200, 0x0301ff03, 0xfbff0201, - 0xfefcf9fb, 0x01080801, 0x000200ff, 0xfd0100fd, - 0xfefbfbfe, 0xfe00fffd, 0x0400fcff, 0x00040200, - 0x0a080000, 0xff030102, 0x0302fdfc, 0xff01fdfd, - 0x02fcfe01, 0xfffe0307, 0xfffe0406, 0x03ff0002, - 0xfefe0101, 0x04fdfbfe, 0x0101fefa, 0x04fefcff, - 0xfefefffe, 0xfe000100, 0xff0001ff, 0xfdff0000, - 0xfcfe0100, 0x0000fffd, 0x00050806, 0x03020100, - 0x0502fefe, 0x01000002, 0xfffefe02, 0x040201ff, - 0x0100ff02, 0x01000000, 0x01fff9f8, 0x0301ffff, - 0x02060300, 0x000201fe, 0x00fff9f6, 0x0102fffd, - 0x02020000, 0xff010101, 0xfefe0003, 0x00010200, - 0x00000108, 0x00fffdfe, 0x0502fe02, 0x01fffe01, - 0xfffdfafd, 0x02fffdfd, 0x02010002, 0x00000102, - 0xfeffff01, 0x000100ff, 0xff02090f, 0xfdfdfdfe, - 0x00fefd00, 0xffffff00, 0x00010001, 0xffffff00, - 0xfe020200, 0xf8f9fdfd, 0x00020200, 0x01010201, - 0x02020201, 0x03000103, 0xfeff0001, 0x0500feff, - 0x01fffaf5, 0xfd010302, 0xff030401, 0xff0201fe, - 0xff010202, 0xff0100fe, 0xffff0000, 0x02030200, - 0x01020101, 0xfc0001ff, 0xfe000000, 0xfe0402fe, - 0x0000fdfe, 0xfa0102ff, 0x05050200, 0xf9ff0203, - 0x00000204, 0xff010303, 0x03ffff00, 0xff010406, - 0x0200fefe, 0xfefe0002, 0xfbff00ff, 0x01fffbf9, - 0x00feff05, 0xfb020402, 0x02fefb00, 0xfa000201, - 0x01000106, 0x0204fffe, 0x00fdfd02, 0x0000feff, - 0x0200ff01, 0x0b060000, 0x00ffff02, 0x0503fefd, - 0x00fffe00, 0xfd0000ff, 0xffffff01, 0xf9fdfffe, - 0xfefe0101, 0xfe010301, 0xff0002ff, 0x000001ff, - 0xff0302fc, 0x0100fefe, 0x0504fef5, 0xfeff0206, - 0xff01fefa, 0x0901fcfd, 0x030300fd, 0x03fdfd02, - 0x00000101, 0x03feff01, 0xfdfd0002, 0x03ffff00, - 0x01fdff01, 0x06fcfa02, 0xfefbfe00, 0x03fefd00, - 0xfe010202, 0xff0201fe, 0xfe0101ff, 0xff0706ff, - 0xfefc0001, 0x01fdfe01, 0xfefd00fc, 0x00fd0002, - 0x010304fd, 0xff000708, 0xfc0104fd, 0xfdfe0302, - 0xfc0106fd, 0xffff0101, 0xfdfd04fe, 0xffff0003, - 0x02fc0201, 0x02fffd04, 0x05fcff03, 0x02fdfa04 +static const int8 s_svq1InterCodebook8x4[3072] = { + 9, 8, 4, 0, -3, -4, -4, -3, 9, 8, 4, -1, -4, -5, -5, -3, + 8, 7, 3, -2, -5, -5, -5, -4, 6, 4, 1, -2, -4, -5, -4, -3, + -12,-14,-11, -4, 1, 5, 6, 6, -8,-10, -7, -5, -2, 1, 1, 1, + 5, 4, 3, 1, 0, 0, -1, -1, 13, 13, 9, 6, 3, 0, -1, -2, + -4, -4, -3, -1, 1, 4, 8, 11, -5, -6, -4, -2, 0, 3, 8, 12, + -7, -7, -6, -4, -2, 2, 7, 10, -7, -7, -5, -4, -2, 1, 5, 8, + -3, -2, -1, 1, 3, 6, 7, 6, 2, 3, 5, 7, 8, 8, 6, 4, + 4, 5, 4, 3, 1, -2, -6, -7, 1, 0, -2, -7,-10,-14,-17,-16, + -5, -4, 1, 8, 9, 3, -3, -7, -7, -6, 1, 11, 12, 5, -3, -8, + -8, -7, 0, 9, 11, 5, -3, -7, -8, -6, -1, 5, 8, 4, -2, -6, + -4, -5, -7, -8, -9, -9, -8, -6, -4, -5, -6, -7, -7, -6, -4, -2, + 0, 1, 2, 3, 5, 8, 10, 9, 1, 2, 3, 6, 9, 12, 14, 13, + 5, 6, 6, 5, 4, 3, 2, 1, 5, 6, 7, 7, 6, 6, 6, 4, + -1, 0, 1, 1, 3, 5, 5, 5,-13,-16,-17,-17,-14,-10, -6, -4, + 9, 11, 13, 16, 15, 13, 12, 10, -4, -5, -6, -7, -7, -7, -6, -5, + -6, -6, -7, -7, -7, -7, -6, -5, -2, -1, 0, 0, 0, 0, 0, -1, + -11,-13,-15,-16,-16,-14,-12,-10, 2, 3, 4, 5, 4, 3, 3, 3, + 6, 7, 8, 8, 8, 7, 6, 5, 3, 4, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 1, -2, -7,-13,-17, 5, 7, 7, 5, 1, -5,-13,-19, + 6, 8, 9, 8, 5, -1, -9,-16, 6, 8, 10, 10, 7, 2, -4,-11, + 18, 9, -1,-10,-13, -9, -4, 0, 22, 12, -1,-12,-15,-10, -4, 2, + 23, 13, 0,-10,-13, -9, -3, 2, 20, 12, 2, -6, -9, -6, -2, 2, + -6, -6, -6, -7, -7, -7, -7, -6, -6, -7, -8, -8, -9, -9, -9, -8, + -3, -3, -3, -3, -3, -3, -3, -3, 12, 15, 18, 21, 21, 19, 17, 14, + 14, 16, 18, 18, 18, 16, 15, 13, 5, 6, 6, 5, 5, 4, 4, 3, + -6, -7, -9,-10,-10,-10, -9, -7,-10,-11,-13,-14,-14,-13,-12,-10, + -27,-17, -4, 5, 9, 10, 10, 7,-32,-19, -3, 7, 11, 12, 11, 8, + -30,-16, -2, 8, 12, 12, 10, 7,-23,-12, 0, 7, 10, 11, 9, 6, + 16, 17, 16, 12, 6, -1, -8,-12, 17, 18, 15, 10, 1, -8,-15,-18, + 15, 14, 10, 4, -5,-14,-20,-23, 10, 8, 4, -1, -9,-16,-21,-22, + -10,-12,-12,-11, -5, 4, 14, 20,-11,-13,-15,-12, -4, 7, 19, 27, + -11,-13,-14,-11, -3, 8, 21, 28,-10,-11,-12, -9, -2, 8, 18, 25, + -1, -1, -1, 1, 4, 6, 6, 5, 0, 0, 0, 2, 4, 3, 1, -2, + 0, 0, 2, 4, 4, -1, -7,-10, 0, 0, 3, 5, 3, -3,-11,-15, + -14,-13, -8, -1, 3, 3, -1, -4, -5, -4, -1, 4, 8, 8, 3, 0, + 3, 2, 2, 3, 4, 5, 3, 1, 5, 3, 0, -2, -2, -1, -1, -1, + 9, 1, -6, -6, -5, -3, -2, -1, 12, 1, -6, -6, -4, -2, -1, 0, + 14, 4, -4, -4, -2, -2, -1, -1, 14, 6, -1, -1, -1, -1, -1, -1, + 4, 6, 8, 10, 11, 9, 7, 5, -1, -1, -1, 0, 0, -1, -1, -2, + -2, -4, -4, -5, -5, -5, -5, -4, -2, -3, -3, -4, -4, -3, -2, -1, + 2, 3, 4, 4, 3, 1, 0, 0, -1, 1, 4, 5, 6, 5, 4, 3, + -8, -6, -2, 2, 3, 4, 4, 3,-14,-13, -9, -5, -2, -1, 0, 0, + -3, -4, -5, -4, 0, 7, 12, 13, -3, -4, -5, -5, -2, 4, 9, 10, + -2, -3, -4, -5, -4, -1, 3, 4, -1, -1, -2, -3, -3, -2, 0, 1, + 9, 5, -2, -8,-11,-10, -7, -4, 12, 10, 6, 2, 0, -1, 0, 0, + 2, 2, 3, 4, 3, 1, 1, 1, -9, -8, -4, 0, 1, 2, 1, 0, + 6, 8, 8, 5, 1, -5,-11,-13, 0, 1, 2, 2, -1, -4, -8,-11, + -3, -2, 1, 3, 3, 1, -1, -4, -2, -1, 2, 5, 6, 6, 4, 1, + 3, 4, 5, 5, 4, 1, -3, -6, 5, 6, 4, 2, 2, 2, 0, -3, + 6, 5, 0, -5, -5, -2, -1, -2, 7, 4, -3,-11,-12, -7, -3, -2, + 1, 0, -1, -1, -1, 0, 0, 0, 2, 3, 4, 4, 5, 5, 4, 3, + -7, -9, -9,-10,-10, -9, -7, -6, 3, 4, 5, 6, 5, 5, 5, 5, + -7, -7, -7, -7, -6, -6, -5, -4, -5, -4, -3, -1, -1, -1, 0, 0, + -3, -2, 1, 4, 5, 5, 5, 5, -2, -1, 3, 6, 9, 10, 10, 9, + -14, 1, 10, 3, -2, 0, 1, 1,-16, 2, 13, 3, -3, -1, 1, 0, + -15, 2, 12, 3, -4, -2, 1, 1,-10, 3, 10, 2, -3, -1, 1, 1, + 0, 1, 4, 2, -5,-10, -3, 11, -1, 1, 4, 2, -6,-13, -2, 15, + -1, 0, 3, 1, -6,-12, -1, 15, -1, 1, 2, 1, -4, -8, 0, 11, + 10, 5, -2, -2, 2, 5, 1, -4, 7, 0, -8, -6, 1, 5, 2, -4, + 2, -5,-12, -7, 2, 7, 4, -1, -1, -7,-10, -4, 4, 9, 7, 2, + -5, -5, -4, -6, -6, -5, -5, -3, -1, -2, -2, -4, -5, -6, -5, -4, + 6, 7, 7, 4, 0, -2, -3, -3, 13, 14, 13, 10, 5, 1, -1, -2, + 1, 1, 2, 2, 2, 2, 2, 2, -5, -6, -8, -9, -9, -8, -7, -6, + 7, 9, 10, 11, 11, 9, 7, 5, -1, -2, -3, -3, -4, -4, -4, -3, + -1, -1, 0, 0, 0, 0, -1, -1, -3, -3, -4, -5, -4, -3, -3, -2, + 2, 1, -1, -3, -3, -2, -1, 0, 12, 12, 8, 3, 1, 0, 0, 1, + -6, -8, -8, -6, -2, 2, 6, 8, 1, 1, -1, -2, 0, 3, 5, 7, + 3, 3, 1, -1, -1, 0, 0, 2, 0, 1, 0, -1, -1, -1, -2, -1, + 1, 0, 0, 0, 0, 0, 2, 4, 2, 1, 3, 4, 3, 1, 0, 2, + 2, 1, 0, 0, -1, -1, 0, 3, 5, 1, -6,-12,-13, -8, -1, 4, + -2, 0, -1, -2, -1, 0, 2, 3, -6, -3, -2, 0, 1, 1, 1, 1, + -9, -5, 0, 4, 5, 3, 1, 0, -8, -3, 3, 7, 8, 4, 1, 0, + 1, 2, 2, 3, 3, 1, -1, -3, 4, 5, 5, 6, 6, 5, 2, 0, + 0, 0, 0, 0, 1, 0, -2, -4, -3, -3, -4, -3, -3, -4, -7, -8, + 14, 12, 6, -1, -3, -3, 0, 0, 7, 5, 1, -3, -5, -4, -2, -1, + -2, -2, -2, -2, -2, -2, -1, -1, -6, -4, -1, 1, 1, 1, 0, -1, + 2, 2, 1, -3, -6, -7, -6, -3, 1, 0, -1, -3, -2, 1, 4, 6, + 0, 0, 1, 2, 4, 7, 8, 7, 0, 0, 0, 0, -1, -4, -7, -8, + 0, 2, 1, -2, -3, -3, -2, -1, -1, 1, 0, -3, -5, -2, 0, 2, + -2, -1, -2, -5, -4, 1, 6, 9, -3, -2, -3, -4, -2, 5, 11, 13, + -4, -2, 2, 6, 4, -3,-10,-14, -2, -1, 1, 4, 4, 1, -1, -2, + 0, 0, -1, -2, -2, 0, 4, 6, 2, 2, 0, -3, -3, 0, 5, 9, + -4, -4, -2, 1, 6, 9, 3, -7, -2, -2, -2, -1, 4, 8, 0,-11, + 1, 1, 0, 0, 2, 6, -1,-10, 2, 2, 1, 0, 2, 4, 0, -7, + -1, -2, -3, -6, -7, -8, -8, -8, 2, 3, 3, 1, -1, -2, -3, -4, + 5, 5, 5, 4, 3, 2, 0, -1, 3, 3, 3, 3, 2, 2, 1, 1, + 3, 3, 2, -2, -3, 0, 7, 10, 1, 2, 2, -2, -5, -4, 0, 3, + 0, 3, 4, 2, -3, -5, -6, -4, 0, 2, 4, 4, 1, -4, -7, -7, + 2, 4, 5, 5, 5, 5, 6, 6, -4, -4, -3, -5, -5, -3, -3, -2, + -3, -4, -4, -5, -4, -2, -2, -2, 1, 1, 0, 0, 2, 4, 5, 4, + -2, 0, 3, 4, 4, 3, 2, 2, -9, -7, -4, 0, 3, 6, 6, 6, + -5, -5, -3, -2, 0, 1, 3, 4, 5, 5, 2, -2, -4, -6, -5, -3, + 1, -6, -4, 7, 5, -2, -2, 1, 5, -5, -4, 6, 4, -5, -4, 1, + 5, -5, -4, 6, 4, -5, -3, 1, 1, -7, -3, 8, 7, -1, -3, 1, + -8, -7, -4, 0, 2, 4, 5, 5, 5, 6, 5, 2, -1, -5, -7, -7, + 5, 6, 4, 1, -3, -5, -6, -5, -7, -7, -5, -2, 1, 6, 9, 10, + 6, 3, 0, 1, 3, 0, -8,-14, 3, 0, -1, 1, 4, 3, 0, -4, + 1, 0, 0, 1, 2, 1, 1, 1, -1, -1, 1, 2, 1, -1, -1, 0, + 1, 1, 1, 1, 0, -2, -3, 0, 1, 2, 1, 0, -2, -8, -9, -4, + 1, 3, 3, 2, 1, -3, -3, 1, 0, 1, 1, 1, 1, 1, 4, 8, + 2, 5, 9, 7, 2, -1, -1, 1, -4, -1, 1, 0, -3, -4, -1, 2, + -3, 0, 3, 3, 0, -1, 0, 2, -4, -1, 1, 1, -2, -4, -5, -4, + 1, -1, -2, -2, -1, 2, 4, 5, 2, 1, 1, 0, -1, -1, 0, 0, + 2, 3, 4, 5, 4, 2, 1, 0, -9, -9, -6, -3, -1, -1, -1, -1, + -6, -6, 4, 7, 0, -2, -1, -2, -1, -2, 5, 6, -1, -2, 0, -1, + 4, -1, 1, 0, -4, -2, 0, -2, 7, 1, -1, -2, -3, 1, 3, 1, + 4, 2, 1, 3, 3, 1, 1, 2, 2, -2, -4, 0, 3, 1, 0, 0, + 1, -4, -8, -4, 1, 2, 1, 0, 2, -3, -9, -6, 0, 3, 3, 2, + -1, -1, 0, -1, -1, 0, 1, 2, 3, 1, -4, -8, -7, -3, 1, 2, + 2, -1, -3, -2, -1, 0, 1, 0, -1, 0, 5, 11, 9, 3, -1, -3, + -1, -2, -2, -1, 1, 1, 1, 1, 0, -1, 0, 3, 6, 6, 5, 5, + 2, 1, -1, -1, -2, -5, -6, -4, 2, 2, 2, 1, -1, -4, -5, -5, + -1, -3, -6, -7, -6, -4, -1, 1, 5, 5, 3, 4, 4, 3, 4, 5, + -1, -2, -3, -2, -2, -2, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, + -6, -6, -4, -1, 2, 2, 2, 2, -6, -7, -5, -2, 0, -1, -1, 0, + 2, 2, 2, 4, 4, 3, 3, 4, 2, 1, 0, -1, 0, 0, 2, 4, + 12, 5, -5, -8, -5, 0, 2, 2, 2, -3, -6, -3, 0, 0, -1, -2, + -2, -3, -1, 3, 4, 1, -2, -3, 2, 2, 3, 4, 3, 1, -1, -1, + 3, 2, 1, 0, 1, 4, 3, 0, 4, 3, 0, -5, -6, 0, 3, 3, + 2, 3, 1, -7,-12, -6, 1, 3, 1, 3, 4, -1, -6, -4, 0, 1, + -9, -4, 2, 6, 7, 4, 1, 0, -7, -1, 4, 6, 4, 0, -3, -3, + -6, 0, 4, 4, 1, -2, -3, -2, -4, 1, 3, 2, 0, -2, -1, 0, + 0, 5, 2, -5, -3, 3, 1, -4, -2, 4, 2, -6, -3, 6, 4, -3, + -1, 5, 3, -5, -1, 7, 3, -4, -1, 2, 0, -6, -3, 5, 3, -3, + -8, -3, 3, 5, 3, 1, -2, -2, 2, 4, 4, -2, -4, -3, 1, 3, + 2, 1, -3, -5, -3, 3, 4, 3, -5, -6, -5, 3, 10, 8, -1, -5, + 0, 3, 2, -4, -9, -7, 0, 6, -5, -1, 5, 7, 4, -1, -3, -3, + -5, -5, -2, 3, 6, 5, -1, -4, 9, 6, 0, -4, -2, 1, 1, -1, + -1, -1, -1, 1, 1, 0, -1, 0, -1, 0, 0, 0, 0, -1, -1, 0, + 2, 1, -2, -1, 1, 1, 0, 0, 12, 8, 2, -1, -1, -4, -7, -7, + 2, 1, 3, 6, 7, 4, 2, 0, 1, 0, -1, 0, -1, -4, -7, -8, + 0, 0, -1, 0, 0, 0, -1, -3, 0, 0, 0, 0, 1, 1, 0, -2, + -1, 0, 1, 1, 0, 0, -1, -2, 0, 0, -1, -3, -4, -3, -1, 1, + -1, 0, 0, 0, 1, 4, 10, 12, -1, 0, -2, -2, -3, -3, -1, 1, + -3, -1, -2, -4, 2, 9, 9, 7, -3, 0, -1, -3, 0, 2, -1, 1, + -1, 1, -2, -3, 0, -1, -3, 0, 0, 0, -3, -2, 0, -1, -1, 1, + -1, -2, -1, -1, -2, -1, -1, -2, 2, -1, -2, -1, 0, 1, 0, -2, + 3, -1, -2, 2, 5, 3, -1, -3, 1, -5, -5, 1, 6, 6, 2, 0, + 1, 2, 0, -1, 0, 1, 0, -2, -5, -3, -1, 0, 1, 2, 1, -2, + -7, -5, -2, -2, -2, -2, 0, 1, -1, 0, 1, 1, 0, 3, 9, 12, + 0, 6, 5, 1, -2, -3, 0, 3, 0, 6, 5, 1, 1, 1, 2, 3, + -5, -2, -2, -3, 0, 0, 0, 0, -6, -3, -3, -2, 0, 0, -1, -2, + 4, 4, 2, 1, 0, -1, -1, 0, -2, -2, 0, 1, 2, 1, 1, 0, + 2, 2, 1, -1, -3, -5, -9,-10, 2, 1, -1, -1, 1, 4, 4, 1, + 4, 0, -2, -2, -2, -2, -1, 0, 7, 1, -4, -3, -2, 0, 1, 1, + 10, 5, -1, -2, 0, 1, 1, 0, 5, 1, -3, -4, -3, -1, -1, -2, + 2, 1, -1, -3, -3, 1, 1, -1, -2, -1, 3, 0, -1, 1, 1, 0, + -3, 1, 7, 2, -3, -2, -1, 0, -2, 4, 8, -1, -8, -5, 0, 2, + -4, -1, 1, 2, 1, -3, -4, -2, -5, -3, -2, 1, 4, 4, 4, 6, + -3, -2, -4, -3, 0, 1, 1, 2, 2, 2, 2, 1, 2, 1, -1, -1, + -4, -1, 0, -1, -3, -3, -1, -1, 1, 4, 4, 2, 0, -1, -2, -3, + 4, 6, 5, 3, 2, 1, -2, -4, 0, 1, 1, 1, 1, -1, -4, -6, + 1, 2, 2, -1, -6, -5, -1, 2, -3, -2, 1, 1, -4, -3, 2, 5, + -2, -1, 2, 2, -3, -4, 0, 3, -2, -2, 2, 6, 5, 2, 1, 2, + 2, -3, -3, 0, 0, 2, 3, 1, 3, -1, 1, 3, 1, 2, -1, -5, + -5, -7, -4, -2, 1, 8, 8, 1, -1, 0, 2, 0, -3, 0, 1, -3, + -2, -5, -5, -2, -3, -1, 0, -2, -1, -4, 0, 4, 0, 2, 4, 0, + 0, 0, 8, 10, 2, 1, 3, -1, -4, -3, 2, 3, -3, -3, 1, -1, + 1, -2, -4, 2, 7, 3, -2, -1, 6, 4, -2, -1, 2, 0, -1, 3, + 1, 1, -2, -2, -2, -5, -3, 4, -6, -2, 1, 1, -1, -4, -2, 4, + -2, -1, -2, -2, 0, 1, 0, -2, -1, 1, 0, -1, 0, 0, -1, -3, + 0, 1, -2, -4, -3, -1, 0, 0, 6, 8, 5, 0, 0, 1, 2, 3, + -2, -2, 2, 5, 2, 0, 0, 1, 2, -2, -2, -1, -1, 1, 2, 4, + 2, -1, 0, 1, 0, 0, 0, 1, -8, -7, -1, 1, -1, -1, 1, 3, + 0, 3, 6, 2, -2, 1, 2, 0,-10, -7, -1, 0, -3, -1, 2, 1, + 0, 0, 2, 2, 1, 1, 1, -1, 3, 0, -2, -2, 0, 2, 1, 0, + 8, 1, 0, 0, -2, -3, -1, 0, 2, -2, 2, 5, 1, -2, -1, 1, + -3, -6, -3, -1, -3, -3, -1, 2, 2, 0, 1, 2, 2, 1, 0, 0, + 1, -1, -1, -2, -1, 0, 1, 0, 15, 9, 2, -1, -2, -3, -3, -3, + 0, -3, -2, 0, 0, -1, -1, -1, 1, 0, 1, 0, 0, -1, -1, -1, + 0, 2, 2, -2, -3, -3, -7, -8, 0, 2, 2, 0, 1, 2, 1, 1, + 1, 2, 2, 2, 3, 1, 0, 3, 1, 0, -1, -2, -1, -2, 0, 5, + -11, -6, -1, 1, 2, 3, 1, -3, 1, 4, 3, -1, -2, 1, 2, -1, + 2, 2, 1, -1, -2, 0, 1, -1, 0, 0, -1, -1, 0, 2, 3, 2, + 1, 1, 2, 1, -1, 1, 0, -4, 0, 0, 0, -2, -2, 2, 4, -2, + -2, -3, 0, 0, -1, 2, 1, -6, 0, 2, 5, 5, 3, 2, -1, -7, + 4, 2, 0, 0, 3, 3, 1, -1, 0, -1, -1, 3, 6, 4, 1, -1, + -2, -2, 0, 2, 2, 0, -2, -2, -1, 0, -1, -5, -7, -5, -1, 1, + 5, -1, -2, 0, 2, 4, 2, -5, 0, -5, -2, 2, 1, 2, 0, -6, + 6, 1, 0, 1, -2, -1, 4, 2, 2, -3, -3, 0, -1, -2, 0, 0, + 1, -1, 0, 2, 0, 0, 6, 11, 2, -1, -1, 0, -3, -2, 3, 5, + 0, -2, -1, 0, -1, 0, 0, -3, 1, -1, -1, -1, -2, -1, -3, -7, + 1, 1, -2, -2, 1, 3, 1, -2, -1, 2, 0, -1, -1, 1, 0, 0, + -4, 2, 3, -1, -2, -2, 0, 1,-11, -2, 4, 5, 6, 2, -1, -2, + -6, -2, 1, -1, -3, -4, 1, 9, -3, 0, 3, 3, 2, -3, -3, 3, + 1, 1, 0, 0, 1, -1, -2, 3, 2, 0, -3, -3, 0, -1, -1, 3, + 1, -1, -3, 1, 2, -6, -4, 6, 0, -2, -5, -2, 0, -3, -2, 3, + 2, 2, 1, -2, -2, 1, 2, -1, -1, 1, 1, -2, -1, 6, 7, -1, + 1, 0, -4, -2, 1, -2, -3, 1, -4, 0, -3, -2, 2, 0, -3, 0, + -3, 4, 3, 1, 8, 7, 0, -1, -3, 4, 1, -4, 2, 3, -2, -3, + -3, 6, 1, -4, 1, 1, -1, -1, -2, 4, -3, -3, 3, 0, -1, -1, + 1, 2, -4, 2, 4, -3, -1, 2, 3, -1, -4, 5, 4, -6, -3, 2 }; -static const uint32 s_svq1InterCodebook8x8[1536] = { - 0x0504fdfc, 0x00010102, 0x0505fdfb, 0x00000102, - 0x0505fcfa, 0x00000102, 0x0504fcf9, 0x00000102, - 0x0403fbf8, 0x00000102, 0x0403faf8, 0x00010101, - 0x0402faf8, 0x00010102, 0x0402faf8, 0x01010101, - 0xffffffff, 0xffffffff, 0xfefefeff, 0xfefefefe, - 0xfdfdfdfe, 0xfdfdfdfd, 0xfdfdfdfe, 0xfdfcfdfd, - 0xfefefefe, 0xfefdfdfe, 0x01010101, 0xffff0001, - 0x05050504, 0x02030304, 0x08080707, 0x05060708, - 0x04020102, 0xfafc0004, 0x05020101, 0xf9fb0105, - 0x04010201, 0xf8fb0105, 0x05010101, 0xf8fa0005, - 0x05010100, 0xf7fa0106, 0x04010000, 0xf8fb0005, - 0x04010000, 0xf9fb0005, 0x04010000, 0xf9fc0104, - 0x00030201, 0xfffdfcfd, 0x00040301, 0xfffdfcfd, - 0x01050402, 0xfefdfcfd, 0x01060502, 0xfefcfbfd, - 0x01060603, 0xfefcfbfd, 0x01060603, 0xfefcfbfd, - 0x01060603, 0xfefcfbfd, 0x01050503, 0xfefcfcfd, - 0x02020202, 0xff000001, 0x03040404, 0x00010102, - 0x04040504, 0x01020303, 0x04040404, 0x02020304, - 0x03030302, 0x01020303, 0xffffffff, 0x00000000, - 0xfbfafafb, 0xfdfdfcfb, 0xf8f7f7f9, 0xfbfafaf9, - 0x06060606, 0x04050506, 0x03040404, 0x02030303, - 0xffffff00, 0xfffffefe, 0xfafafbfd, 0xfcfbfafa, - 0xf9fafbfd, 0xfcfbfafa, 0xfefefeff, 0xfffffefe, - 0x01010100, 0x01010101, 0x03030303, 0x03030303, - 0xfbfe0102, 0x050200fc, 0xfafe0102, 0x050300fb, - 0xfafe0102, 0x0603fffa, 0xf9fe0203, 0x070400fa, - 0xf9fe0102, 0x070500fb, 0xfafe0102, 0x070400fb, - 0xfafe0102, 0x060400fc, 0xfbfe0101, 0x060300fc, - 0xfcfaf7f6, 0x020302ff, 0xfdfbf7f6, 0x03040400, - 0xfffdf9f7, 0x03050502, 0x00fefbf9, 0x03050503, - 0x0100fdfa, 0x03050604, 0x0201fefc, 0x02040503, - 0x020100fe, 0x01030402, 0x020201ff, 0x01030302, - 0xfafbfbfc, 0xfbfafafa, 0xfcfcfdfd, 0xfcfcfcfc, - 0x00000000, 0xffffffff, 0x05060505, 0x02030405, - 0x07070605, 0x04050607, 0x04040303, 0x02030404, - 0x0000ff00, 0xff00ffff, 0xfcfcfdfd, 0xfdfdfcfc, - 0x01fbfe01, 0x00020405, 0x01fafd01, 0x00020506, - 0x00f9fc00, 0x01020606, 0xfff7fbff, 0x01030606, - 0xfef6faff, 0x01030606, 0xfef7faff, 0x01030605, - 0xfef7fafe, 0x01030505, 0xfef9fafe, 0x01020404, - 0xf7f8f9fb, 0xfaf9f8f7, 0xf9fafafb, 0xfbfafaf9, - 0xfcfdfdfd, 0xfcfcfbfb, 0xff0000ff, 0xffffffff, - 0x02020100, 0x01020202, 0x05040302, 0x04050505, - 0x06050403, 0x07080808, 0x06050403, 0x06070707, - 0x08070605, 0x090a0a09, 0x07060403, 0x08090908, - 0x03020100, 0x05050504, 0xfffffeff, 0x02020100, - 0xfdfdfdfe, 0x00fffefd, 0xfbfbfcfd, 0xfcfbfbfb, - 0xfafbfbfc, 0xfbfaf9f9, 0xfafbfcfd, 0xfafaf9f9, - 0xfd00070d, 0xfbfcfcfd, 0xfd00070e, 0xfcfcfcfd, - 0xfcff080f, 0xfcfbfcfc, 0xfcff080f, 0xfdfcfbfc, - 0xfcff070f, 0xfcfbfbfb, 0xfcff070e, 0xfdfcfcfc, - 0xfcff060c, 0xfdfcfcfc, 0xfcff050b, 0xfdfcfcfc, - 0x0405fcef, 0x03030404, 0x0405fbee, 0x03030404, - 0x0406fbed, 0x02030404, 0x0406fbec, 0x03030404, - 0x0406fcec, 0x03030504, 0x0406fbed, 0x03030504, - 0x0405fcee, 0x02030404, 0x0304fbef, 0x03030404, - 0xfcfafafa, 0x0b0601fe, 0xfcf9f9fa, 0x0d0802fe, - 0xfcf9f8f8, 0x0e0903fe, 0xfbf9f8f8, 0x100a04ff, - 0xfbf9f8f8, 0x110a04ff, 0xfcf9f8f8, 0x100a0500, - 0xfdfaf8f8, 0x0f090400, 0xfdfbf9f9, 0x0c080400, - 0x05070708, 0xf2f8fe02, 0x05070808, 0xf1f8fe02, - 0x05070808, 0xf0f7fd01, 0x05070808, 0xeff6fd01, - 0x05080908, 0xeff6fd01, 0x04070808, 0xf0f6fc01, - 0x04070707, 0xf2f7fd01, 0x03060706, 0xf3f7fd00, - 0xfcfc0105, 0x0000fffd, 0xfdfd0207, 0x0001fffe, - 0xfdfd0107, 0x010100ff, 0xfefd0106, 0x000101ff, - 0xfefc0006, 0x000100ff, 0xfdfc0005, 0xff0000ff, - 0xfffd0005, 0xfe000000, 0xfffe0104, 0xff000100, - 0x01010202, 0xf8f8fafe, 0x01010101, 0xf8f8fbfe, - 0x00010101, 0xfbfbfdff, 0x00000000, 0xfeffffff, - 0x0000ff00, 0x00010000, 0x00000001, 0x02030201, - 0x01010102, 0x03040302, 0x03030303, 0x04050404, - 0xfefdfcfc, 0x01010000, 0xfefdfcfc, 0x010000ff, - 0xfffefefe, 0x0000ffff, 0x00000100, 0xff000000, - 0x02020202, 0x01010202, 0x04040403, 0x03040404, - 0x03010101, 0x03030403, 0xfcfbfafb, 0xfefefdfd, - 0xfffffefc, 0x0100ffff, 0xfffffefc, 0x0100ffff, - 0xfffffefd, 0x020100ff, 0xfffefdfc, 0x030301ff, - 0xfffdfdfc, 0x050401ff, 0xfefefdfc, 0x070401ff, - 0xfffffefe, 0x08060200, 0x010000ff, 0x08070401, - 0xfefdfdfd, 0x00fffffe, 0x0100ffff, 0x03030202, - 0x04020100, 0x05060605, 0x030200ff, 0x03050605, - 0x0200ffff, 0x01020303, 0x00fffefe, 0xfcfcfdff, - 0xffff0000, 0xf9f8fcfe, 0x00010201, 0xf9fafcff, - 0xfa0104fe, 0x00000300, 0xf90105fe, 0x00000300, - 0xf80105fd, 0xffff0300, 0xf70106fe, 0xff000300, - 0xf80206fe, 0xff000400, 0xf90105fd, 0x00000401, - 0xf90104fe, 0x00010400, 0xfa0104ff, 0x00010300, - 0x03000000, 0x01040504, 0x02010101, 0x00020303, - 0x02010202, 0xfeff0102, 0x01010304, 0xfbfdff00, - 0xff010305, 0xfafcfdfe, 0xfe000305, 0xf9fafbfd, - 0xfe000304, 0xfbfbfcfd, 0xff000304, 0xfdfdfefe, - 0x00000000, 0x06fefbff, 0x01000000, 0x08fefaff, - 0x02000000, 0x09fdfa00, 0x0200ff00, 0x0afef900, - 0x0200ff00, 0x0afdf8ff, 0x02ffff00, 0x09fdf9ff, - 0x0100ff00, 0x08fdfaff, 0x01000000, 0x07fefb00, - 0x02030302, 0xffff0001, 0x02030403, 0xfeff0001, - 0x02040403, 0xfdfeff01, 0x02030302, 0xfdfeff00, - 0x010100ff, 0xfefeff00, 0xfffdfcfb, 0x01010100, - 0xfffbf8f8, 0x03040301, 0x00fbf7f6, 0x05060503, - 0x0504fffb, 0x00000103, 0x0504fffa, 0xfeff0002, - 0x0405fffa, 0xfefeff02, 0x0404fff9, 0xfdfdfe01, - 0x0405fffa, 0xfdfdfe01, 0x040400fb, 0xfefeff01, - 0x040500fc, 0xfeffff01, 0x030401fd, 0xfeffff01, - 0x01fefdfe, 0x03050604, 0x00fcfcfd, 0x02040503, - 0xfffbfbfd, 0x01030402, 0xfffcfafc, 0xff020402, - 0x01fdfcfe, 0xff020402, 0x01fefcfe, 0xfe010303, - 0x01fefdfe, 0xfe010303, 0x01fffefe, 0xfe000303, - 0xfefdfcfc, 0x070502ff, 0xfdfdfcfc, 0x070501fe, - 0xfdfefdfe, 0x0503fffd, 0xfe00ffff, 0x0402fefd, - 0xff010101, 0x0301fdfc, 0xff020304, 0x01fffdfc, - 0x00030406, 0x00fefdfd, 0x01030506, 0xfffefdfe, - 0x04080b0c, 0xfffefe00, 0x0206090a, 0x00fffeff, - 0x00020304, 0x0100ffff, 0xffffffff, 0x020100fe, - 0xfefcfbfd, 0x030200fe, 0xfefcfbfb, 0x020100ff, - 0xfefcfbfb, 0x010100ff, 0xfefdfcfc, 0x0000fffe, - 0xff020303, 0xfefdfcfd, 0xfe000203, 0xfefdfcfc, - 0xff010202, 0xfdfcfbfd, 0x01030303, 0xfdfdfdfe, - 0x03040404, 0xfefefe00, 0x03050505, 0xfefeff00, - 0x02040505, 0xfefdfeff, 0x00030303, 0xfcfcfcfe, - 0xfe04ffff, 0xfb0206fe, 0xfe0400ff, 0xfa0206fd, - 0xfe0400ff, 0xf90307fd, 0xfd04ffff, 0xf90308fc, - 0xfd04ff00, 0xfa0307fc, 0xfd04ffff, 0xfa0307fc, - 0xfd03ffff, 0xfa0306fc, 0xfe0300ff, 0xfb0306fd, - 0x02f9fe01, 0x01fffe05, 0x03f8fe01, 0x02fffd06, - 0x04f7fe02, 0x02fefc07, 0x05f7ff03, 0x03fffc07, - 0x04f7ff03, 0x02fefc07, 0x04f9ff03, 0x01fefc06, - 0x04fa0002, 0x01fffc06, 0x03fb0002, 0x01fffd04, - 0x000202fe, 0xfcfdff00, 0x010202fe, 0xfcfe0001, - 0x020202fe, 0xfeff0102, 0x030302fd, 0xfe000204, - 0x020302fd, 0xfd000204, 0x010201fc, 0xfdff0102, - 0x000100fb, 0xfdfe0101, 0x000000fc, 0xfdfe0001, - 0xfeff0000, 0x080702fe, 0xfdff0000, 0x070601fe, - 0xfdff0100, 0x050400fd, 0xff000100, 0x030100ff, - 0x01010200, 0x0100ff00, 0x020100fe, 0xffff0001, - 0x0100fefb, 0xfdfd0001, 0x01fffcfa, 0xfcfdff01, - 0x0502fefc, 0x02030406, 0x0401fdfb, 0x00000204, - 0x0200fefc, 0xfefeff01, 0x0100fffe, 0xfefdfe00, - 0x000000fe, 0xfffeffff, 0x00fffffe, 0x02010000, - 0xfffffefe, 0x04030100, 0xfffefdfe, 0x05040200, - 0xfefe0102, 0x000100ff, 0xfdfd0001, 0x000100ff, - 0xfdfdff00, 0x010101ff, 0xfffd0000, 0x03030201, - 0xfffdff00, 0x03030301, 0xfefcfefe, 0x04040301, - 0xfefcfdfd, 0x04030301, 0xfefbfdfe, 0x03030201, - 0x04030504, 0x05040404, 0x00010303, 0x01000000, - 0xfeff0101, 0xfefdfcfd, 0xfe000202, 0xfefdfcfe, - 0xff010302, 0xfefdfdff, 0x00000201, 0xfffefeff, - 0xff000100, 0xfffefdff, 0xff000101, 0xfefefeff, - 0x00fffffe, 0x00010201, 0x05030201, 0x03050506, - 0x04030201, 0x03040505, 0xfdfdfefe, 0x0000fffe, - 0xfbfcfdfd, 0xfffefdfc, 0xfefeffff, 0x0000fffe, - 0xff000100, 0x010000ff, 0xfeff00ff, 0xfffefefd, - 0x05060707, 0xfeff0204, 0x02020303, 0xfdfe0001, - 0xffffff00, 0xfefeff00, 0xfffefdff, 0x01000000, - 0xfffefe00, 0x020201ff, 0xffff0103, 0x020201ff, - 0xfdfe0103, 0x0201fffe, 0xfafbfe01, 0x00fefdfb, - 0xfdfeff00, 0xfefe00ff, 0xffff0000, 0xfeff0100, - 0xfffe0000, 0xfe000000, 0xfdfdfeff, 0xfdfdfffe, - 0xfdfdfeff, 0xfcfdfefe, 0x00000202, 0xfeff0000, - 0x02030505, 0xff000202, 0x05060808, 0x01020404, - 0xfdfaf8f9, 0xfffeffff, 0x00fdfbfb, 0x00000102, - 0x0300ffff, 0x01010304, 0x03010102, 0x02020304, - 0x02000203, 0x02010203, 0xffff0204, 0x01010100, - 0xfdfe0203, 0x0100fffe, 0xfcfd0103, 0x0100fefd, - 0x02fffefc, 0x00010303, 0xfefcfbf9, 0xfeff0000, - 0xfcfbfbfa, 0xfdfefefe, 0xffff00ff, 0xff000000, - 0x02020302, 0x00010202, 0x03040503, 0x00010001, - 0x02030403, 0xffffff00, 0x01030505, 0xffffff00, - 0xff000101, 0xfcfafbfd, 0x00000101, 0xfffdfd00, - 0x00ffff00, 0x03010001, 0xfffdfefe, 0x07040202, - 0x00fefefe, 0x06030202, 0x010000ff, 0x03000001, - 0x03030300, 0xfffdfe01, 0x03040301, 0xfcfbfd00, - 0xff000200, 0xfefefcfd, 0x00020401, 0xfffefdfe, - 0x01030603, 0xff00fefe, 0x01040704, 0x00fffdfe, - 0x00030603, 0x00fffdfd, 0xff000301, 0x0101fefd, - 0xfeff0100, 0x0202fffd, 0xfdfdfffe, 0x0201fffd, - 0x00ff0103, 0x00000001, 0xfffeff02, 0xffff0001, - 0x00feff01, 0xfdfe0001, 0x01fffe00, 0xfbfd0103, - 0x02fffe00, 0xfbfd0205, 0x04fffe00, 0xfbfe0306, - 0x0400fe00, 0xfcfe0407, 0x0400fe00, 0xfcfe0406, - 0xfcfdfefe, 0x00fffefd, 0xff000101, 0x0100ffff, - 0x02020303, 0x01010101, 0x02020202, 0x01000001, - 0x00000000, 0xffffffff, 0xfcfcfcfc, 0xfdfcfcfc, - 0xfdfefdfd, 0x00fffffe, 0x05040403, 0x07060605, - 0xfe07feff, 0x00fffffc, 0xff09feff, 0x00fffffc, - 0xff0afdff, 0x01fffffc, 0xfe0afdff, 0x02fffffd, - 0xfe0afeff, 0x02fffffc, 0xfe09feff, 0x02fffffc, - 0xfe08feff, 0x01ff00fc, 0xfe07fe00, 0x0200fffd, - 0x0301fc03, 0x0001fefd, 0x0401fb03, 0x0001fefd, - 0x0502fa03, 0x0003fffd, 0x0502fa03, 0x0002fffd, - 0x0501fa03, 0x0003fefc, 0x0501fa03, 0x0002fefd, - 0x0401fa02, 0x0001fffd, 0x0401fa02, 0x0001fffe, - 0x01010000, 0x02000001, 0x0101ff00, 0x02000001, - 0x0000ff00, 0x02000000, 0x0000ff00, 0x00ff0000, - 0x00010001, 0xfffeff00, 0x00010103, 0xfdfcfe00, - 0x01020305, 0xfcfbfd00, 0x00020405, 0xfbfbfcff, - 0xfeff0001, 0xf7fafdfe, 0xffff0002, 0xfafd0000, - 0xff000001, 0xfbfe0000, 0x01010102, 0xfdff0201, - 0x01020101, 0xff010202, 0x01020101, 0x01010101, - 0x01020000, 0x02020000, 0x02020100, 0x02020000, - 0x0100fdfc, 0x03040604, 0x0000fefd, 0x00010402, - 0x0000ffff, 0xfdfe0101, 0x00010101, 0xfbfd0101, - 0x00010101, 0xfbfd0101, 0xff0000ff, 0xfcfe0101, - 0xff0000ff, 0xfe000201, 0x000000ff, 0x00010302, - 0x040300ff, 0xfbfbfc00, 0x05040000, 0xfefdfe02, - 0x0402ff00, 0x00ffff02, 0x01fffe00, 0x0100fe00, - 0x00fefe01, 0x01ffff00, 0x00fdfe01, 0x00ff0001, - 0x01fefe01, 0x00000103, 0x02fffe01, 0x00000204, - 0x02030201, 0x01020200, 0x000100ff, 0x010101fd, - 0xfe0000ff, 0x010200fc, 0xff0202ff, 0x010200fb, - 0xff0403ff, 0x010200fb, 0x000402fe, 0x0000fffc, - 0x000200fc, 0x0000fefc, 0x0102fffb, 0x020301fe, - 0x00010001, 0xfeff0201, 0xfeff0002, 0xff000301, - 0xfcfe0003, 0x00010300, 0xfbfd0105, 0x010102fe, - 0xfbfe0106, 0x010001fe, 0xfbff0105, 0x00ff00fe, - 0xfcfe0003, 0x00ff00fe, 0xfe00ff01, 0x01000100, - 0x03020101, 0x02010102, 0x0100ffff, 0x01010001, - 0x0000fdfc, 0x02010101, 0x0200fdfc, 0x02030202, - 0x0100fcfb, 0x02010101, 0xfffffcfb, 0x00fffefe, - 0x0000fefd, 0xfffefdfe, 0x04040302, 0x00000002, - 0x0100fefc, 0x00000000, 0x0101fffd, 0x00000000, - 0x020200fe, 0x02000000, 0x010201ff, 0x050300ff, - 0xff010200, 0x060500fe, 0xfd000100, 0x060400fd, - 0xfcfe0101, 0x0201fdfc, 0xfcfe0001, 0x00fefcfb, - 0xfdfdfdff, 0xfffffefd, 0x00010203, 0x01010100, - 0x02030405, 0x02020101, 0xfe000102, 0xfffffefe, - 0xff000000, 0xfefefefe, 0x03030100, 0xffff0102, - 0x04030100, 0xff010203, 0x01fffdfc, 0xfdfdfe00, - 0xf8f9fcfd, 0x02fffcf9, 0xfcfdff00, 0x0200fefc, - 0xff000001, 0x0200fefd, 0x00010102, 0x0200ffff, - 0x01010101, 0x01000000, 0x01010101, 0x01010101, - 0x02010000, 0x02020303, 0x03010000, 0x02030404, - 0x00030303, 0x020100ff, 0xff010101, 0x01fffffe, - 0xfdfffefe, 0x00fefefd, 0xfefefcfc, 0x00fdfefe, - 0x01fffcfc, 0x02ff0001, 0x0302fffd, 0x05030304, - 0x030200fe, 0x03030303, 0x0000fefe, 0x01000000, - 0xff010200, 0xfe03fffd, 0xffff00ff, 0xfe0400fd, - 0xfefefefe, 0xfe0501fe, 0xfffdfefd, 0xfd0401fe, - 0x00ff00fe, 0xfb0300ff, 0x02010201, 0xfb020000, - 0x03020402, 0xfd030101, 0x01010201, 0xfe040100, - 0xfffcfd04, 0x03010303, 0xfffcfc04, 0x02000203, - 0x00fcfd04, 0x01ff0202, 0x01fefd04, 0x00fe0102, - 0x01fefc02, 0x00fd0002, 0x00fefd02, 0x02fe0001, - 0x00ffff03, 0x03000000, 0xfefefe02, 0x02ffffff, - 0x04030202, 0xff000103, 0x02010001, 0xfefeff01, - 0x01020102, 0xffff0001, 0x03040304, 0x01010102, - 0x02020203, 0x01010101, 0x00fffeff, 0xffffffff, - 0xfffefdfd, 0xfefefefe, 0xfdfdfcfc, 0xfdfdfcfc, - 0xfdff0102, 0x0403fefc, 0xff010202, 0x0201fefd, - 0x03030201, 0xfefffe00, 0x040200ff, 0xfdff0002, - 0x0300fefe, 0xfd000203, 0xfffdfe00, 0xff020201, - 0xfbfcff03, 0x000200fd, 0xfafe0306, 0x010300fb, - 0x00fe03fe, 0x01fefe03, 0x00fd04fd, 0x02fffe03, - 0x00fd05fd, 0x02fffe04, 0xfffc04fe, 0x02fefd03, - 0x00fd04fd, 0x02fffd03, 0x00fe05fe, 0x02fffd03, - 0x01fd04fe, 0x02fffe03, 0x01fe03fe, 0x0200fe03, - 0xff000001, 0xfffc0201, 0xff000002, 0xfefc0201, - 0xff010101, 0x00fe0402, 0xff01ff00, 0x01ff0502, - 0xfe00ff00, 0x01ff0501, 0xfeffff00, 0xfffd0300, - 0xfe000101, 0xfffd0300, 0xfd000101, 0x00fe0300, - 0x01ff0001, 0x05040201, 0x01ff0001, 0x07050101, - 0xfffe0000, 0x050300ff, 0xfffeff00, 0x0302ffff, - 0xfffdff00, 0x0201ffff, 0xfefcfeff, 0x0000fefe, - 0xfffefeff, 0x0000fefe, 0x00ffff00, 0x0000ffff, - 0xff000303, 0x040401ff, 0xfe000302, 0x010100fe, - 0xff010302, 0x000100ff, 0xff000201, 0xfe00ffff, - 0xff000100, 0xfe00fffe, 0xff000100, 0x0001fffe, - 0xfdff0101, 0x0301fdfc, 0xfdff0201, 0x0301fcfb, - 0x0100fefd, 0xfe000101, 0x01010100, 0xfdff0000, - 0x01010201, 0xfeffff00, 0xfffdff00, 0xff00ffff, - 0xfdfafd00, 0x0101fffe, 0xfdfcff02, 0x020200fe, - 0x01010405, 0x02030100, 0x01020405, 0x0100ff00, - 0xfbfe00fe, 0x0000fdfa, 0x000100fe, 0x020201ff, - 0x030100fe, 0x01020202, 0x040200fe, 0x01010203, - 0x030200fe, 0x00ff0002, 0x0101fffd, 0x01ffff00, - 0x0001fffc, 0x0200feff, 0xff00fffc, 0x0401feff, - 0xff0000fd, 0x00010101, 0xff0001fd, 0xffff0000, - 0x000303ff, 0x01000001, 0xfe0202fd, 0x010000ff, - 0xfe0000fb, 0x020001ff, 0x0001fef9, 0x02020201, - 0x020300fb, 0x02020303, 0x010402fd, 0xfdfe0000, - 0xfefe0205, 0xffffff00, 0xfdfcff02, 0xfffffeff, - 0x01fefe00, 0x0100ff02, 0x03fffeff, 0x0200ff03, - 0x03000001, 0x02fffe03, 0x03010102, 0x00fefe02, - 0x01ff0001, 0xfefdfd01, 0x02010001, 0x00000003, - 0x00fdfbfc, 0xfffeff01, 0x01fffdfe, 0x00000002, - 0x01020101, 0x01010102, 0x01030403, 0xfffffe00, - 0x00020303, 0xfefdfdfe, 0xff000101, 0xfefefcfe, - 0x00000102, 0x0100ff00, 0x01010102, 0x03010101, - 0xff000000, 0x0001fffe, 0xfefffffe, 0x0000fefd, - 0xff0000ff, 0x010100fe, 0xff000101, 0x010301ff, - 0xfe000202, 0x000302ff, 0xffff0103, 0xfe020401, - 0xfffd0002, 0xfb000503, 0x00feff01, 0xfaff0303, - 0x040300ff, 0x02010002, 0x0100fffe, 0x0100feff, - 0xfdfefdfe, 0xfdfaf9fa, 0x01030202, 0xfefdfeff, - 0x01030202, 0x00000000, 0x00010102, 0x01000101, - 0x00000001, 0x02010100, 0x00ff0001, 0x01020200, - 0x01030101, 0x01ffffff, 0x0000fffe, 0x02fffefe, - 0x0101fefe, 0x03010001, 0xff00fefe, 0x0200ff00, - 0x00010000, 0x01feffff, 0x01020203, 0x01fefe00, - 0x02030305, 0x04010101, 0xfbfcfd00, 0x01fffdfc, - 0x02fffcfa, 0xff000002, 0x0301fefc, 0x00020203, - 0x02fffefd, 0x00020303, 0x01fefefd, 0xff010102, - 0x00fefefe, 0xff010202, 0x01ffffff, 0x00020302, - 0x01feffff, 0xff020202, 0x00feff00, 0xff000102, - 0x01020406, 0x01000000, 0xfeff0204, 0xfffffefe, - 0xfeff0102, 0xfffefefe, 0xfe000202, 0x00fffefe, - 0xfeff0000, 0x0100fffe, 0xfffefdfd, 0x00fffeff, - 0x0302fefd, 0xfeff0002, 0x050400fe, 0xff000205, - 0x00020405, 0xfffffeff, 0x01020304, 0xff00ff00, - 0x01000101, 0xff010001, 0x00fffffe, 0xfdfefe00, - 0x000000ff, 0xfbfdfdff, 0xff010100, 0xfdfefeff, - 0xfeffffff, 0x010301ff, 0xfffefeff, 0x05060502, - 0x01fefdfd, 0xfffffe01, 0x04030201, 0xfdfffd01, - 0x01000203, 0xfdfffdff, 0x00ff0001, 0x0001ffff, - 0x01000101, 0x03050202, 0x02010101, 0x00030202, - 0xfefefffd, 0xfdfffdfd, 0x000101ff, 0xfe00ffff, - 0xfefe0002, 0xfe010402, 0xfffe0001, 0xff020503, - 0xfefdfeff, 0xfe010301, 0xfffffeff, 0xff010200, - 0x01010000, 0x00020201, 0x04040100, 0x01030202, - 0x0102fffe, 0xfdfefdfe, 0x000100ff, 0xfbfcfcfd, - 0xfcfd0004, 0xfffefcfc, 0x00ff0005, 0xfffefdff, - 0x01000004, 0x00000001, 0xfffefd00, 0x00010000, - 0x0000fe00, 0x01020101, 0x00000002, 0x00010101, - 0xffff0002, 0x00010101, 0xfefeff01, 0x02020200, - 0x00fefbfd, 0x00fdfdff, 0x0200fe00, 0x03000002, - 0x00feff02, 0x02ffff00, 0xffff0205, 0x02ffffff, - 0xff000205, 0x02ff00ff, 0x00000102, 0x02000100, - 0x0101ffff, 0x02010202, 0x0000fefd, 0xfffe0000, - 0x00020300, 0xfdfdfdfe, 0x01030300, 0x02010000, - 0xfeff00ff, 0x0301ffff, 0xfeff00ff, 0x0200ffff, - 0xfeff00ff, 0x02ff0000, 0xfeff00ff, 0x01feffff, - 0xfd000100, 0x02ffffff, 0xff020505, 0x0301ffff, - 0xff010000, 0x0200fefd, 0x00030101, 0x0100fefe, - 0x01030101, 0xffff0000, 0x0102ff00, 0xfdff0001, - 0x0101feff, 0xfcfe0001, 0x010200ff, 0xfdff0001, - 0x02030101, 0xfdfe0001, 0x02040202, 0xfcfeff01, - 0x02020201, 0x0200fe00, 0xfdfeffff, 0x01fdfbfc, - 0x00010100, 0x01ffffff, 0x01010100, 0x02000000, - 0x02010100, 0x02010101, 0x0200ffff, 0x03020202, - 0xfffcfcfe, 0x00fefefe, 0x01000001, 0x01000000, - 0xfefdff00, 0x01020200, 0xfdfeff00, 0x02010100, - 0xfdfe0001, 0x010000ff, 0xfeff00ff, 0x00ff0000, - 0x000101ff, 0x00000202, 0x01030200, 0x02030503, - 0xfe0101ff, 0x01010300, 0xfc0000ff, 0xfffffffc, - 0x000101ff, 0x02010201, 0x000100fd, 0x02000101, - 0xfffffdfb, 0x01000100, 0xfdfefdfc, 0x00fffffe, - 0xfeff0000, 0x00fefefe, 0x00020403, 0x01000000, - 0x00000102, 0x00ff0000, 0x03020100, 0x02030404, - 0x040704ff, 0x00000000, 0x030604ff, 0x01010100, - 0x00040300, 0x010000ff, 0xfe010100, 0xffff00ff, - 0xffff00ff, 0x000000ff, 0x00ffffff, 0x00000000, - 0x00fdfdff, 0xfffeff01, 0xfefcfcfd, 0xfffefeff, - 0x00010202, 0xfd000101, 0x0000fffe, 0xfd000101, - 0x0100fffe, 0xfe010102, 0x02020201, 0xff020303, - 0x00010201, 0xff020101, 0xfcfe0100, 0xff0100fe, - 0xfdff0101, 0xfdff00fe, 0xff000201, 0xfcff0100, - 0xfefeffff, 0x03040300, 0xfdff0101, 0x000000fe, - 0x02020202, 0xffff0102, 0x03010101, 0xfefe0003, - 0xffffff00, 0xfffffe00, 0xfdfcfdff, 0x0200fefe, - 0x0100ffff, 0x05030202, 0x00fffffe, 0x01000000, - 0x0002fdfe, 0xff010100, 0xfe01fcff, 0x000202ff, - 0xfe00fc01, 0xff0101fe, 0xff01fd02, 0xff0101ff, - 0x0103fe03, 0xff010100, 0x0102fd01, 0xff000100, - 0x0001fbff, 0x010100ff, 0x0303fd00, 0x03030201, - 0x01feff00, 0xff020505, 0xfffeff01, 0xfbfe0101, - 0xfeff0101, 0xfdffffff, 0xffff0101, 0x030402ff, - 0xffffffff, 0x030400ff, 0x0100ffff, 0xfffffdff, - 0x02000000, 0xff000002, 0x00fdfe00, 0x02030101, - 0x01020302, 0xfefe0000, 0x01000302, 0x02030301, - 0xfffd0000, 0x030202ff, 0x01fdfefe, 0x01010201, - 0x02fefffe, 0xfeff0101, 0x02000100, 0xfefe0000, - 0x02000100, 0xfefe0000, 0x00fefefd, 0xfdfefeff, - 0x03ff0100, 0xff0301ff, 0x03ff0100, 0xfd02ffff, - 0x03fe0101, 0xfd00fdff, 0x03fe0202, 0xfe01fe00, - 0x03fd0101, 0xfd01feff, 0x03fd0101, 0xfe01ff00, - 0x04ff0201, 0xfe01ff00, 0x03ff0100, 0xfd00fdff, - 0x01fffdfd, 0xfeff0102, 0x0200fefe, 0xfefe0001, - 0x0201fefd, 0xfffeff01, 0x0402fefd, 0x01fefe00, - 0x0402fffd, 0x02fefe00, 0x030401ff, 0x02fefdff, - 0x02040200, 0x02fffeff, 0x00020100, 0x030100ff, - 0x01fb0003, 0x01000004, 0x02fbfe01, 0x01feff05, - 0x030000ff, 0xff000103, 0xfe0403fe, 0xfe00fffd, - 0xfd0503fd, 0xfe0000fd, 0xfe0203ff, 0xff0202fe, - 0xff000002, 0x00000000, 0x01fefd00, 0xfefe0003 +static const int8 s_svq1InterCodebook8x8[6144] = { + -4, -3, 4, 5, 2, 1, 1, 0, -5, -3, 5, 5, 2, 1, 0, 0, + -6, -4, 5, 5, 2, 1, 0, 0, -7, -4, 4, 5, 2, 1, 0, 0, + -8, -5, 3, 4, 2, 1, 0, 0, -8, -6, 3, 4, 1, 1, 1, 0, + -8, -6, 2, 4, 2, 1, 1, 0, -8, -6, 2, 4, 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, + -2, -3, -3, -3, -3, -3, -3, -3, -2, -3, -3, -3, -3, -3, -4, -3, + -2, -2, -2, -2, -2, -3, -3, -2, 1, 1, 1, 1, 1, 0, -1, -1, + 4, 5, 5, 5, 4, 3, 3, 2, 7, 7, 8, 8, 8, 7, 6, 5, + 2, 1, 2, 4, 4, 0, -4, -6, 1, 1, 2, 5, 5, 1, -5, -7, + 1, 2, 1, 4, 5, 1, -5, -8, 1, 1, 1, 5, 5, 0, -6, -8, + 0, 1, 1, 5, 6, 1, -6, -9, 0, 0, 1, 4, 5, 0, -5, -8, + 0, 0, 1, 4, 5, 0, -5, -7, 0, 0, 1, 4, 4, 1, -4, -7, + 1, 2, 3, 0, -3, -4, -3, -1, 1, 3, 4, 0, -3, -4, -3, -1, + 2, 4, 5, 1, -3, -4, -3, -2, 2, 5, 6, 1, -3, -5, -4, -2, + 3, 6, 6, 1, -3, -5, -4, -2, 3, 6, 6, 1, -3, -5, -4, -2, + 3, 6, 6, 1, -3, -5, -4, -2, 3, 5, 5, 1, -3, -4, -4, -2, + 2, 2, 2, 2, 1, 0, 0, -1, 4, 4, 4, 3, 2, 1, 1, 0, + 4, 5, 4, 4, 3, 3, 2, 1, 4, 4, 4, 4, 4, 3, 2, 2, + 2, 3, 3, 3, 3, 3, 2, 1, -1, -1, -1, -1, 0, 0, 0, 0, + -5, -6, -6, -5, -5, -4, -3, -3, -7, -9, -9, -8, -7, -6, -6, -5, + 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, + 0, -1, -1, -1, -2, -2, -1, -1, -3, -5, -6, -6, -6, -6, -5, -4, + -3, -5, -6, -7, -6, -6, -5, -4, -1, -2, -2, -2, -2, -2, -1, -1, + 0, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 1, -2, -5, -4, 0, 2, 5, 2, 1, -2, -6, -5, 0, 3, 5, + 2, 1, -2, -6, -6, -1, 3, 6, 3, 2, -2, -7, -6, 0, 4, 7, + 2, 1, -2, -7, -5, 0, 5, 7, 2, 1, -2, -6, -5, 0, 4, 7, + 2, 1, -2, -6, -4, 0, 4, 6, 1, 1, -2, -5, -4, 0, 3, 6, + -10, -9, -6, -4, -1, 2, 3, 2,-10, -9, -5, -3, 0, 4, 4, 3, + -9, -7, -3, -1, 2, 5, 5, 3, -7, -5, -2, 0, 3, 5, 5, 3, + -6, -3, 0, 1, 4, 6, 5, 3, -4, -2, 1, 2, 3, 5, 4, 2, + -2, 0, 1, 2, 2, 4, 3, 1, -1, 1, 2, 2, 2, 3, 3, 1, + -4, -5, -5, -6, -6, -6, -6, -5, -3, -3, -4, -4, -4, -4, -4, -4, + 0, 0, 0, 0, -1, -1, -1, -1, 5, 5, 6, 5, 5, 4, 3, 2, + 5, 6, 7, 7, 7, 6, 5, 4, 3, 3, 4, 4, 4, 4, 3, 2, + 0, -1, 0, 0, -1, -1, 0, -1, -3, -3, -4, -4, -4, -4, -3, -3, + 1, -2, -5, 1, 5, 4, 2, 0, 1, -3, -6, 1, 6, 5, 2, 0, + 0, -4, -7, 0, 6, 6, 2, 1, -1, -5, -9, -1, 6, 6, 3, 1, + -1, -6,-10, -2, 6, 6, 3, 1, -1, -6, -9, -2, 5, 6, 3, 1, + -2, -6, -9, -2, 5, 5, 3, 1, -2, -6, -7, -2, 4, 4, 2, 1, + -5, -7, -8, -9, -9, -8, -7, -6, -5, -6, -6, -7, -7, -6, -6, -5, + -3, -3, -3, -4, -5, -5, -4, -4, -1, 0, 0, -1, -1, -1, -1, -1, + 0, 1, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 5, 5, 5, 4, + 3, 4, 5, 6, 8, 8, 8, 7, 3, 4, 5, 6, 7, 7, 7, 6, + 5, 6, 7, 8, 9, 10, 10, 9, 3, 4, 6, 7, 8, 9, 9, 8, + 0, 1, 2, 3, 4, 5, 5, 5, -1, -2, -1, -1, 0, 1, 2, 2, + -2, -3, -3, -3, -3, -2, -1, 0, -3, -4, -5, -5, -5, -5, -5, -4, + -4, -5, -5, -6, -7, -7, -6, -5, -3, -4, -5, -6, -7, -7, -6, -6, + 13, 7, 0, -3, -3, -4, -4, -5, 14, 7, 0, -3, -3, -4, -4, -4, + 15, 8, -1, -4, -4, -4, -5, -4, 15, 8, -1, -4, -4, -5, -4, -3, + 15, 7, -1, -4, -5, -5, -5, -4, 14, 7, -1, -4, -4, -4, -4, -3, + 12, 6, -1, -4, -4, -4, -4, -3, 11, 5, -1, -4, -4, -4, -4, -3, + -17, -4, 5, 4, 4, 4, 3, 3,-18, -5, 5, 4, 4, 4, 3, 3, + -19, -5, 6, 4, 4, 4, 3, 2,-20, -5, 6, 4, 4, 4, 3, 3, + -20, -4, 6, 4, 4, 5, 3, 3,-19, -5, 6, 4, 4, 5, 3, 3, + -18, -4, 5, 4, 4, 4, 3, 2,-17, -5, 4, 3, 4, 4, 3, 3, + -6, -6, -6, -4, -2, 1, 6, 11, -6, -7, -7, -4, -2, 2, 8, 13, + -8, -8, -7, -4, -2, 3, 9, 14, -8, -8, -7, -5, -1, 4, 10, 16, + -8, -8, -7, -5, -1, 4, 10, 17, -8, -8, -7, -4, 0, 5, 10, 16, + -8, -8, -6, -3, 0, 4, 9, 15, -7, -7, -5, -3, 0, 4, 8, 12, + 8, 7, 7, 5, 2, -2, -8,-14, 8, 8, 7, 5, 2, -2, -8,-15, + 8, 8, 7, 5, 1, -3, -9,-16, 8, 8, 7, 5, 1, -3,-10,-17, + 8, 9, 8, 5, 1, -3,-10,-17, 8, 8, 7, 4, 1, -4,-10,-16, + 7, 7, 7, 4, 1, -3, -9,-14, 6, 7, 6, 3, 0, -3, -9,-13, + 5, 1, -4, -4, -3, -1, 0, 0, 7, 2, -3, -3, -2, -1, 1, 0, + 7, 1, -3, -3, -1, 0, 1, 1, 6, 1, -3, -2, -1, 1, 1, 0, + 6, 0, -4, -2, -1, 0, 1, 0, 5, 0, -4, -3, -1, 0, 0, -1, + 5, 0, -3, -1, 0, 0, 0, -2, 4, 1, -2, -1, 0, 1, 0, -1, + 2, 2, 1, 1, -2, -6, -8, -8, 1, 1, 1, 1, -2, -5, -8, -8, + 1, 1, 1, 0, -1, -3, -5, -5, 0, 0, 0, 0, -1, -1, -1, -2, + 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 2, 3, 2, + 2, 1, 1, 1, 2, 3, 4, 3, 3, 3, 3, 3, 4, 4, 5, 4, + -4, -4, -3, -2, 0, 0, 1, 1, -4, -4, -3, -2, -1, 0, 0, 1, + -2, -2, -2, -1, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, + 2, 2, 2, 2, 2, 2, 1, 1, 3, 4, 4, 4, 4, 4, 4, 3, + 1, 1, 1, 3, 3, 4, 3, 3, -5, -6, -5, -4, -3, -3, -2, -2, + -4, -2, -1, -1, -1, -1, 0, 1, -4, -2, -1, -1, -1, -1, 0, 1, + -3, -2, -1, -1, -1, 0, 1, 2, -4, -3, -2, -1, -1, 1, 3, 3, + -4, -3, -3, -1, -1, 1, 4, 5, -4, -3, -2, -2, -1, 1, 4, 7, + -2, -2, -1, -1, 0, 2, 6, 8, -1, 0, 0, 1, 1, 4, 7, 8, + -3, -3, -3, -2, -2, -1, -1, 0, -1, -1, 0, 1, 2, 2, 3, 3, + 0, 1, 2, 4, 5, 6, 6, 5, -1, 0, 2, 3, 5, 6, 5, 3, + -1, -1, 0, 2, 3, 3, 2, 1, -2, -2, -1, 0, -1, -3, -4, -4, + 0, 0, -1, -1, -2, -4, -8, -7, 1, 2, 1, 0, -1, -4, -6, -7, + -2, 4, 1, -6, 0, 3, 0, 0, -2, 5, 1, -7, 0, 3, 0, 0, + -3, 5, 1, -8, 0, 3, -1, -1, -2, 6, 1, -9, 0, 3, 0, -1, + -2, 6, 2, -8, 0, 4, 0, -1, -3, 5, 1, -7, 1, 4, 0, 0, + -2, 4, 1, -7, 0, 4, 1, 0, -1, 4, 1, -6, 0, 3, 1, 0, + 0, 0, 0, 3, 4, 5, 4, 1, 1, 1, 1, 2, 3, 3, 2, 0, + 2, 2, 1, 2, 2, 1, -1, -2, 4, 3, 1, 1, 0, -1, -3, -5, + 5, 3, 1, -1, -2, -3, -4, -6, 5, 3, 0, -2, -3, -5, -6, -7, + 4, 3, 0, -2, -3, -4, -5, -5, 4, 3, 0, -1, -2, -2, -3, -3, + 0, 0, 0, 0, -1, -5, -2, 6, 0, 0, 0, 1, -1, -6, -2, 8, + 0, 0, 0, 2, 0, -6, -3, 9, 0, -1, 0, 2, 0, -7, -2, 10, + 0, -1, 0, 2, -1, -8, -3, 10, 0, -1, -1, 2, -1, -7, -3, 9, + 0, -1, 0, 1, -1, -6, -3, 8, 0, 0, 0, 1, 0, -5, -2, 7, + 2, 3, 3, 2, 1, 0, -1, -1, 3, 4, 3, 2, 1, 0, -1, -2, + 3, 4, 4, 2, 1, -1, -2, -3, 2, 3, 3, 2, 0, -1, -2, -3, + -1, 0, 1, 1, 0, -1, -2, -2, -5, -4, -3, -1, 0, 1, 1, 1, + -8, -8, -5, -1, 1, 3, 4, 3,-10, -9, -5, 0, 3, 5, 6, 5, + -5, -1, 4, 5, 3, 1, 0, 0, -6, -1, 4, 5, 2, 0, -1, -2, + -6, -1, 5, 4, 2, -1, -2, -2, -7, -1, 4, 4, 1, -2, -3, -3, + -6, -1, 5, 4, 1, -2, -3, -3, -5, 0, 4, 4, 1, -1, -2, -2, + -4, 0, 5, 4, 1, -1, -1, -2, -3, 1, 4, 3, 1, -1, -1, -2, + -2, -3, -2, 1, 4, 6, 5, 3, -3, -4, -4, 0, 3, 5, 4, 2, + -3, -5, -5, -1, 2, 4, 3, 1, -4, -6, -4, -1, 2, 4, 2, -1, + -2, -4, -3, 1, 2, 4, 2, -1, -2, -4, -2, 1, 3, 3, 1, -2, + -2, -3, -2, 1, 3, 3, 1, -2, -2, -2, -1, 1, 3, 3, 0, -2, + -4, -4, -3, -2, -1, 2, 5, 7, -4, -4, -3, -3, -2, 1, 5, 7, + -2, -3, -2, -3, -3, -1, 3, 5, -1, -1, 0, -2, -3, -2, 2, 4, + 1, 1, 1, -1, -4, -3, 1, 3, 4, 3, 2, -1, -4, -3, -1, 1, + 6, 4, 3, 0, -3, -3, -2, 0, 6, 5, 3, 1, -2, -3, -2, -1, + 12, 11, 8, 4, 0, -2, -2, -1, 10, 9, 6, 2, -1, -2, -1, 0, + 4, 3, 2, 0, -1, -1, 0, 1, -1, -1, -1, -1, -2, 0, 1, 2, + -3, -5, -4, -2, -2, 0, 2, 3, -5, -5, -4, -2, -1, 0, 1, 2, + -5, -5, -4, -2, -1, 0, 1, 1, -4, -4, -3, -2, -2, -1, 0, 0, + 3, 3, 2, -1, -3, -4, -3, -2, 3, 2, 0, -2, -4, -4, -3, -2, + 2, 2, 1, -1, -3, -5, -4, -3, 3, 3, 3, 1, -2, -3, -3, -3, + 4, 4, 4, 3, 0, -2, -2, -2, 5, 5, 5, 3, 0, -1, -2, -2, + 5, 5, 4, 2, -1, -2, -3, -2, 3, 3, 3, 0, -2, -4, -4, -4, + -1, -1, 4, -2, -2, 6, 2, -5, -1, 0, 4, -2, -3, 6, 2, -6, + -1, 0, 4, -2, -3, 7, 3, -7, -1, -1, 4, -3, -4, 8, 3, -7, + 0, -1, 4, -3, -4, 7, 3, -6, -1, -1, 4, -3, -4, 7, 3, -6, + -1, -1, 3, -3, -4, 6, 3, -6, -1, 0, 3, -2, -3, 6, 3, -5, + 1, -2, -7, 2, 5, -2, -1, 1, 1, -2, -8, 3, 6, -3, -1, 2, + 2, -2, -9, 4, 7, -4, -2, 2, 3, -1, -9, 5, 7, -4, -1, 3, + 3, -1, -9, 4, 7, -4, -2, 2, 3, -1, -7, 4, 6, -4, -2, 1, + 2, 0, -6, 4, 6, -4, -1, 1, 2, 0, -5, 3, 4, -3, -1, 1, + -2, 2, 2, 0, 0, -1, -3, -4, -2, 2, 2, 1, 1, 0, -2, -4, + -2, 2, 2, 2, 2, 1, -1, -2, -3, 2, 3, 3, 4, 2, 0, -2, + -3, 2, 3, 2, 4, 2, 0, -3, -4, 1, 2, 1, 2, 1, -1, -3, + -5, 0, 1, 0, 1, 1, -2, -3, -4, 0, 0, 0, 1, 0, -2, -3, + 0, 0, -1, -2, -2, 2, 7, 8, 0, 0, -1, -3, -2, 1, 6, 7, + 0, 1, -1, -3, -3, 0, 4, 5, 0, 1, 0, -1, -1, 0, 1, 3, + 0, 2, 1, 1, 0, -1, 0, 1, -2, 0, 1, 2, 1, 0, -1, -1, + -5, -2, 0, 1, 1, 0, -3, -3, -6, -4, -1, 1, 1, -1, -3, -4, + -4, -2, 2, 5, 6, 4, 3, 2, -5, -3, 1, 4, 4, 2, 0, 0, + -4, -2, 0, 2, 1, -1, -2, -2, -2, -1, 0, 1, 0, -2, -3, -2, + -2, 0, 0, 0, -1, -1, -2, -1, -2, -1, -1, 0, 0, 0, 1, 2, + -2, -2, -1, -1, 0, 1, 3, 4, -2, -3, -2, -1, 0, 2, 4, 5, + 2, 1, -2, -2, -1, 0, 1, 0, 1, 0, -3, -3, -1, 0, 1, 0, + 0, -1, -3, -3, -1, 1, 1, 1, 0, 0, -3, -1, 1, 2, 3, 3, + 0, -1, -3, -1, 1, 3, 3, 3, -2, -2, -4, -2, 1, 3, 4, 4, + -3, -3, -4, -2, 1, 3, 3, 4, -2, -3, -5, -2, 1, 2, 3, 3, + 4, 5, 3, 4, 4, 4, 4, 5, 3, 3, 1, 0, 0, 0, 0, 1, + 1, 1, -1, -2, -3, -4, -3, -2, 2, 2, 0, -2, -2, -4, -3, -2, + 2, 3, 1, -1, -1, -3, -3, -2, 1, 2, 0, 0, -1, -2, -2, -1, + 0, 1, 0, -1, -1, -3, -2, -1, 1, 1, 0, -1, -1, -2, -2, -2, + -2, -1, -1, 0, 1, 2, 1, 0, 1, 2, 3, 5, 6, 5, 5, 3, + 1, 2, 3, 4, 5, 5, 4, 3, -2, -2, -3, -3, -2, -1, 0, 0, + -3, -3, -4, -5, -4, -3, -2, -1, -1, -1, -2, -2, -2, -1, 0, 0, + 0, 1, 0, -1, -1, 0, 0, 1, -1, 0, -1, -2, -3, -2, -2, -1, + 7, 7, 6, 5, 4, 2, -1, -2, 3, 3, 2, 2, 1, 0, -2, -3, + 0, -1, -1, -1, 0, -1, -2, -2, -1, -3, -2, -1, 0, 0, 0, 1, + 0, -2, -2, -1, -1, 1, 2, 2, 3, 1, -1, -1, -1, 1, 2, 2, + 3, 1, -2, -3, -2, -1, 1, 2, 1, -2, -5, -6, -5, -3, -2, 0, + 0, -1, -2, -3, -1, 0, -2, -2, 0, 0, -1, -1, 0, 1, -1, -2, + 0, 0, -2, -1, 0, 0, 0, -2, -1, -2, -3, -3, -2, -1, -3, -3, + -1, -2, -3, -3, -2, -2, -3, -4, 2, 2, 0, 0, 0, 0, -1, -2, + 5, 5, 3, 2, 2, 2, 0, -1, 8, 8, 6, 5, 4, 4, 2, 1, + -7, -8, -6, -3, -1, -1, -2, -1, -5, -5, -3, 0, 2, 1, 0, 0, + -1, -1, 0, 3, 4, 3, 1, 1, 2, 1, 1, 3, 4, 3, 2, 2, + 3, 2, 0, 2, 3, 2, 1, 2, 4, 2, -1, -1, 0, 1, 1, 1, + 3, 2, -2, -3, -2, -1, 0, 1, 3, 1, -3, -4, -3, -2, 0, 1, + -4, -2, -1, 2, 3, 3, 1, 0, -7, -5, -4, -2, 0, 0, -1, -2, + -6, -5, -5, -4, -2, -2, -2, -3, -1, 0, -1, -1, 0, 0, 0, -1, + 2, 3, 2, 2, 2, 2, 1, 0, 3, 5, 4, 3, 1, 0, 1, 0, + 3, 4, 3, 2, 0, -1, -1, -1, 5, 5, 3, 1, 0, -1, -1, -1, + 1, 1, 0, -1, -3, -5, -6, -4, 1, 1, 0, 0, 0, -3, -3, -1, + 0, -1, -1, 0, 1, 0, 1, 3, -2, -2, -3, -1, 2, 2, 4, 7, + -2, -2, -2, 0, 2, 2, 3, 6, -1, 0, 0, 1, 1, 0, 0, 3, + 0, 3, 3, 3, 1, -2, -3, -1, 1, 3, 4, 3, 0, -3, -5, -4, + 0, 2, 0, -1, -3, -4, -2, -2, 1, 4, 2, 0, -2, -3, -2, -1, + 3, 6, 3, 1, -2, -2, 0, -1, 4, 7, 4, 1, -2, -3, -1, 0, + 3, 6, 3, 0, -3, -3, -1, 0, 1, 3, 0, -1, -3, -2, 1, 1, + 0, 1, -1, -2, -3, -1, 2, 2, -2, -1, -3, -3, -3, -1, 1, 2, + 3, 1, -1, 0, 1, 0, 0, 0, 2, -1, -2, -1, 1, 0, -1, -1, + 1, -1, -2, 0, 1, 0, -2, -3, 0, -2, -1, 1, 3, 1, -3, -5, + 0, -2, -1, 2, 5, 2, -3, -5, 0, -2, -1, 4, 6, 3, -2, -5, + 0, -2, 0, 4, 7, 4, -2, -4, 0, -2, 0, 4, 6, 4, -2, -4, + -2, -2, -3, -4, -3, -2, -1, 0, 1, 1, 0, -1, -1, -1, 0, 1, + 3, 3, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 1, + 0, 0, 0, 0, -1, -1, -1, -1, -4, -4, -4, -4, -4, -4, -4, -3, + -3, -3, -2, -3, -2, -1, -1, 0, 3, 4, 4, 5, 5, 6, 6, 7, + -1, -2, 7, -2, -4, -1, -1, 0, -1, -2, 9, -1, -4, -1, -1, 0, + -1, -3, 10, -1, -4, -1, -1, 1, -1, -3, 10, -2, -3, -1, -1, 2, + -1, -2, 10, -2, -4, -1, -1, 2, -1, -2, 9, -2, -4, -1, -1, 2, + -1, -2, 8, -2, -4, 0, -1, 1, 0, -2, 7, -2, -3, -1, 0, 2, + 3, -4, 1, 3, -3, -2, 1, 0, 3, -5, 1, 4, -3, -2, 1, 0, + 3, -6, 2, 5, -3, -1, 3, 0, 3, -6, 2, 5, -3, -1, 2, 0, + 3, -6, 1, 5, -4, -2, 3, 0, 3, -6, 1, 5, -3, -2, 2, 0, + 2, -6, 1, 4, -3, -1, 1, 0, 2, -6, 1, 4, -2, -1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 2, 0, -1, 1, 1, 1, 0, 0, 2, + 0, -1, 0, 0, 0, 0, 0, 2, 0, -1, 0, 0, 0, 0, -1, 0, + 1, 0, 1, 0, 0, -1, -2, -1, 3, 1, 1, 0, 0, -2, -4, -3, + 5, 3, 2, 1, 0, -3, -5, -4, 5, 4, 2, 0, -1, -4, -5, -5, + 1, 0, -1, -2, -2, -3, -6, -9, 2, 0, -1, -1, 0, 0, -3, -6, + 1, 0, 0, -1, 0, 0, -2, -5, 2, 1, 1, 1, 1, 2, -1, -3, + 1, 1, 2, 1, 2, 2, 1, -1, 1, 1, 2, 1, 1, 1, 1, 1, + 0, 0, 2, 1, 0, 0, 2, 2, 0, 1, 2, 2, 0, 0, 2, 2, + -4, -3, 0, 1, 4, 6, 4, 3, -3, -2, 0, 0, 2, 4, 1, 0, + -1, -1, 0, 0, 1, 1, -2, -3, 1, 1, 1, 0, 1, 1, -3, -5, + 1, 1, 1, 0, 1, 1, -3, -5, -1, 0, 0, -1, 1, 1, -2, -4, + -1, 0, 0, -1, 1, 2, 0, -2, -1, 0, 0, 0, 2, 3, 1, 0, + -1, 0, 3, 4, 0, -4, -5, -5, 0, 0, 4, 5, 2, -2, -3, -2, + 0, -1, 2, 4, 2, -1, -1, 0, 0, -2, -1, 1, 0, -2, 0, 1, + 1, -2, -2, 0, 0, -1, -1, 1, 1, -2, -3, 0, 1, 0, -1, 0, + 1, -2, -2, 1, 3, 1, 0, 0, 1, -2, -1, 2, 4, 2, 0, 0, + 1, 2, 3, 2, 0, 2, 2, 1, -1, 0, 1, 0, -3, 1, 1, 1, + -1, 0, 0, -2, -4, 0, 2, 1, -1, 2, 2, -1, -5, 0, 2, 1, + -1, 3, 4, -1, -5, 0, 2, 1, -2, 2, 4, 0, -4, -1, 0, 0, + -4, 0, 2, 0, -4, -2, 0, 0, -5, -1, 2, 1, -2, 1, 3, 2, + 1, 0, 1, 0, 1, 2, -1, -2, 2, 0, -1, -2, 1, 3, 0, -1, + 3, 0, -2, -4, 0, 3, 1, 0, 5, 1, -3, -5, -2, 2, 1, 1, + 6, 1, -2, -5, -2, 1, 0, 1, 5, 1, -1, -5, -2, 0, -1, 0, + 3, 0, -2, -4, -2, 0, -1, 0, 1, -1, 0, -2, 0, 1, 0, 1, + 1, 1, 2, 3, 2, 1, 1, 2, -1, -1, 0, 1, 1, 0, 1, 1, + -4, -3, 0, 0, 1, 1, 1, 2, -4, -3, 0, 2, 2, 2, 3, 2, + -5, -4, 0, 1, 1, 1, 1, 2, -5, -4, -1, -1, -2, -2, -1, 0, + -3, -2, 0, 0, -2, -3, -2, -1, 2, 3, 4, 4, 2, 0, 0, 0, + -4, -2, 0, 1, 0, 0, 0, 0, -3, -1, 1, 1, 0, 0, 0, 0, + -2, 0, 2, 2, 0, 0, 0, 2, -1, 1, 2, 1, -1, 0, 3, 5, + 0, 2, 1, -1, -2, 0, 5, 6, 0, 1, 0, -3, -3, 0, 4, 6, + 1, 1, -2, -4, -4, -3, 1, 2, 1, 0, -2, -4, -5, -4, -2, 0, + -1, -3, -3, -3, -3, -2, -1, -1, 3, 2, 1, 0, 0, 1, 1, 1, + 5, 4, 3, 2, 1, 1, 2, 2, 2, 1, 0, -2, -2, -2, -1, -1, + 0, 0, 0, -1, -2, -2, -2, -2, 0, 1, 3, 3, 2, 1, -1, -1, + 0, 1, 3, 4, 3, 2, 1, -1, -4, -3, -1, 1, 0, -2, -3, -3, + -3, -4, -7, -8, -7, -4, -1, 2, 0, -1, -3, -4, -4, -2, 0, 2, + 1, 0, 0, -1, -3, -2, 0, 2, 2, 1, 1, 0, -1, -1, 0, 2, + 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 2, 3, 3, 2, 2, 0, 0, 1, 3, 4, 4, 3, 2, + 3, 3, 3, 0, -1, 0, 1, 2, 1, 1, 1, -1, -2, -1, -1, 1, + -2, -2, -1, -3, -3, -2, -2, 0, -4, -4, -2, -2, -2, -2, -3, 0, + -4, -4, -1, 1, 1, 0, -1, 2, -3, -1, 2, 3, 4, 3, 3, 5, + -2, 0, 2, 3, 3, 3, 3, 3, -2, -2, 0, 0, 0, 0, 0, 1, + 0, 2, 1, -1, -3, -1, 3, -2, -1, 0, -1, -1, -3, 0, 4, -2, + -2, -2, -2, -2, -2, 1, 5, -2, -3, -2, -3, -1, -2, 1, 4, -3, + -2, 0, -1, 0, -1, 0, 3, -5, 1, 2, 1, 2, 0, 0, 2, -5, + 2, 4, 2, 3, 1, 1, 3, -3, 1, 2, 1, 1, 0, 1, 4, -2, + 4, -3, -4, -1, 3, 3, 1, 3, 4, -4, -4, -1, 3, 2, 0, 2, + 4, -3, -4, 0, 2, 2, -1, 1, 4, -3, -2, 1, 2, 1, -2, 0, + 2, -4, -2, 1, 2, 0, -3, 0, 2, -3, -2, 0, 1, 0, -2, 2, + 3, -1, -1, 0, 0, 0, 0, 3, 2, -2, -2, -2, -1, -1, -1, 2, + 2, 2, 3, 4, 3, 1, 0, -1, 1, 0, 1, 2, 1, -1, -2, -2, + 2, 1, 2, 1, 1, 0, -1, -1, 4, 3, 4, 3, 2, 1, 1, 1, + 3, 2, 2, 2, 1, 1, 1, 1, -1, -2, -1, 0, -1, -1, -1, -1, + -3, -3, -2, -1, -2, -2, -2, -2, -4, -4, -3, -3, -4, -4, -3, -3, + 2, 1, -1, -3, -4, -2, 3, 4, 2, 2, 1, -1, -3, -2, 1, 2, + 1, 2, 3, 3, 0, -2, -1, -2, -1, 0, 2, 4, 2, 0, -1, -3, + -2, -2, 0, 3, 3, 2, 0, -3, 0, -2, -3, -1, 1, 2, 2, -1, + 3, -1, -4, -5, -3, 0, 2, 0, 6, 3, -2, -6, -5, 0, 3, 1, + -2, 3, -2, 0, 3, -2, -2, 1, -3, 4, -3, 0, 3, -2, -1, 2, + -3, 5, -3, 0, 4, -2, -1, 2, -2, 4, -4, -1, 3, -3, -2, 2, + -3, 4, -3, 0, 3, -3, -1, 2, -2, 5, -2, 0, 3, -3, -1, 2, + -2, 4, -3, 1, 3, -2, -1, 2, -2, 3, -2, 1, 3, -2, 0, 2, + 1, 0, 0, -1, 1, 2, -4, -1, 2, 0, 0, -1, 1, 2, -4, -2, + 1, 1, 1, -1, 2, 4, -2, 0, 0, -1, 1, -1, 2, 5, -1, 1, + 0, -1, 0, -2, 1, 5, -1, 1, 0, -1, -1, -2, 0, 3, -3, -1, + 1, 1, 0, -2, 0, 3, -3, -1, 1, 1, 0, -3, 0, 3, -2, 0, + 1, 0, -1, 1, 1, 2, 4, 5, 1, 0, -1, 1, 1, 1, 5, 7, + 0, 0, -2, -1, -1, 0, 3, 5, 0, -1, -2, -1, -1, -1, 2, 3, + 0, -1, -3, -1, -1, -1, 1, 2, -1, -2, -4, -2, -2, -2, 0, 0, + -1, -2, -2, -1, -2, -2, 0, 0, 0, -1, -1, 0, -1, -1, 0, 0, + 3, 3, 0, -1, -1, 1, 4, 4, 2, 3, 0, -2, -2, 0, 1, 1, + 2, 3, 1, -1, -1, 0, 1, 0, 1, 2, 0, -1, -1, -1, 0, -2, + 0, 1, 0, -1, -2, -1, 0, -2, 0, 1, 0, -1, -2, -1, 1, 0, + 1, 1, -1, -3, -4, -3, 1, 3, 1, 2, -1, -3, -5, -4, 1, 3, + -3, -2, 0, 1, 1, 1, 0, -2, 0, 1, 1, 1, 0, 0, -1, -3, + 1, 2, 1, 1, 0, -1, -1, -2, 0, -1, -3, -1, -1, -1, 0, -1, + 0, -3, -6, -3, -2, -1, 1, 1, 2, -1, -4, -3, -2, 0, 2, 2, + 5, 4, 1, 1, 0, 1, 3, 2, 5, 4, 2, 1, 0, -1, 0, 1, + -2, 0, -2, -5, -6, -3, 0, 0, -2, 0, 1, 0, -1, 1, 2, 2, + -2, 0, 1, 3, 2, 2, 2, 1, -2, 0, 2, 4, 3, 2, 1, 1, + -2, 0, 2, 3, 2, 0, -1, 0, -3, -1, 1, 1, 0, -1, -1, 1, + -4, -1, 1, 0, -1, -2, 0, 2, -4, -1, 0, -1, -1, -2, 1, 4, + -3, 0, 0, -1, 1, 1, 1, 0, -3, 1, 0, -1, 0, 0, -1, -1, + -1, 3, 3, 0, 1, 0, 0, 1, -3, 2, 2, -2, -1, 0, 0, 1, + -5, 0, 0, -2, -1, 1, 0, 2, -7, -2, 1, 0, 1, 2, 2, 2, + -5, 0, 3, 2, 3, 3, 2, 2, -3, 2, 4, 1, 0, 0, -2, -3, + 5, 2, -2, -2, 0, -1, -1, -1, 2, -1, -4, -3, -1, -2, -1, -1, + 0, -2, -2, 1, 2, -1, 0, 1, -1, -2, -1, 3, 3, -1, 0, 2, + 1, 0, 0, 3, 3, -2, -1, 2, 2, 1, 1, 3, 2, -2, -2, 0, + 1, 0, -1, 1, 1, -3, -3, -2, 1, 0, 1, 2, 3, 0, 0, 0, + -4, -5, -3, 0, 1, -1, -2, -1, -2, -3, -1, 1, 2, 0, 0, 0, + 1, 1, 2, 1, 2, 1, 1, 1, 3, 4, 3, 1, 0, -2, -1, -1, + 3, 3, 2, 0, -2, -3, -3, -2, 1, 1, 0, -1, -2, -4, -2, -2, + 2, 1, 0, 0, 0, -1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 3, + 0, 0, 0, -1, -2, -1, 1, 0, -2, -1, -1, -2, -3, -2, 0, 0, + -1, 0, 0, -1, -2, 0, 1, 1, 1, 1, 0, -1, -1, 1, 3, 1, + 2, 2, 0, -2, -1, 2, 3, 0, 3, 1, -1, -1, 1, 4, 2, -2, + 2, 0, -3, -1, 3, 5, 0, -5, 1, -1, -2, 0, 3, 3, -1, -6, + -1, 0, 3, 4, 2, 0, 1, 2, -2, -1, 0, 1, -1, -2, 0, 1, + -2, -3, -2, -3, -6, -7, -6, -3, 2, 2, 3, 1, -1, -2, -3, -2, + 2, 2, 3, 1, 0, 0, 0, 0, 2, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 0, 0, 0, 1, 1, 2, 1, 0, -1, 0, 0, 2, 2, 1, + 1, 1, 3, 1, -1, -1, -1, 1, -2, -1, 0, 0, -2, -2, -1, 2, + -2, -2, 1, 1, 1, 0, 1, 3, -2, -2, 0, -1, 0, -1, 0, 2, + 0, 0, 1, 0, -1, -1, -2, 1, 3, 2, 2, 1, 0, -2, -2, 1, + 5, 3, 3, 2, 1, 1, 1, 4, 0, -3, -4, -5, -4, -3, -1, 1, + -6, -4, -1, 2, 2, 0, 0, -1, -4, -2, 1, 3, 3, 2, 2, 0, + -3, -2, -1, 2, 3, 3, 2, 0, -3, -2, -2, 1, 2, 1, 1, -1, + -2, -2, -2, 0, 2, 2, 1, -1, -1, -1, -1, 1, 2, 3, 2, 0, + -1, -1, -2, 1, 2, 2, 2, -1, 0, -1, -2, 0, 2, 1, 0, -1, + 6, 4, 2, 1, 0, 0, 0, 1, 4, 2, -1, -2, -2, -2, -1, -1, + 2, 1, -1, -2, -2, -2, -2, -1, 2, 2, 0, -2, -2, -2, -1, 0, + 0, 0, -1, -2, -2, -1, 0, 1, -3, -3, -2, -1, -1, -2, -1, 0, + -3, -2, 2, 3, 2, 0, -1, -2, -2, 0, 4, 5, 5, 2, 0, -1, + 5, 4, 2, 0, -1, -2, -1, -1, 4, 3, 2, 1, 0, -1, 0, -1, + 1, 1, 0, 1, 1, 0, 1, -1, -2, -1, -1, 0, 0, -2, -2, -3, + -1, 0, 0, 0, -1, -3, -3, -5, 0, 1, 1, -1, -1, -2, -2, -3, + -1, -1, -1, -2, -1, 1, 3, 1, -1, -2, -2, -1, 2, 5, 6, 5, + -3, -3, -2, 1, 1, -2, -1, -1, 1, 2, 3, 4, 1, -3, -1, -3, + 3, 2, 0, 1, -1, -3, -1, -3, 1, 0, -1, 0, -1, -1, 1, 0, + 1, 1, 0, 1, 2, 2, 5, 3, 1, 1, 1, 2, 2, 2, 3, 0, + -3, -1, -2, -2, -3, -3, -1, -3, -1, 1, 1, 0, -1, -1, 0, -2, + 2, 0, -2, -2, 2, 4, 1, -2, 1, 0, -2, -1, 3, 5, 2, -1, + -1, -2, -3, -2, 1, 3, 1, -2, -1, -2, -1, -1, 0, 2, 1, -1, + 0, 0, 1, 1, 1, 2, 2, 0, 0, 1, 4, 4, 2, 2, 3, 1, + -2, -1, 2, 1, -2, -3, -2, -3, -1, 0, 1, 0, -3, -4, -4, -5, + 4, 0, -3, -4, -4, -4, -2, -1, 5, 0, -1, 0, -1, -3, -2, -1, + 4, 0, 0, 1, 1, 0, 0, 0, 0, -3, -2, -1, 0, 0, 1, 0, + 0, -2, 0, 0, 1, 1, 2, 1, 2, 0, 0, 0, 1, 1, 1, 0, + 2, 0, -1, -1, 1, 1, 1, 0, 1, -1, -2, -2, 0, 2, 2, 2, + -3, -5, -2, 0, -1, -3, -3, 0, 0, -2, 0, 2, 2, 0, 0, 3, + 2, -1, -2, 0, 0, -1, -1, 2, 5, 2, -1, -1, -1, -1, -1, 2, + 5, 2, 0, -1, -1, 0, -1, 2, 2, 1, 0, 0, 0, 1, 0, 2, + -1, -1, 1, 1, 2, 2, 1, 2, -3, -2, 0, 0, 0, 0, -2, -1, + 0, 3, 2, 0, -2, -3, -3, -3, 0, 3, 3, 1, 0, 0, 1, 2, + -1, 0, -1, -2, -1, -1, 1, 3, -1, 0, -1, -2, -1, -1, 0, 2, + -1, 0, -1, -2, 0, 0, -1, 2, -1, 0, -1, -2, -1, -1, -2, 1, + 0, 1, 0, -3, -1, -1, -1, 2, 5, 5, 2, -1, -1, -1, 1, 3, + 0, 0, 1, -1, -3, -2, 0, 2, 1, 1, 3, 0, -2, -2, 0, 1, + 1, 1, 3, 1, 0, 0, -1, -1, 0, -1, 2, 1, 1, 0, -1, -3, + -1, -2, 1, 1, 1, 0, -2, -4, -1, 0, 2, 1, 1, 0, -1, -3, + 1, 1, 3, 2, 1, 0, -2, -3, 2, 2, 4, 2, 1, -1, -2, -4, + 1, 2, 2, 2, 0, -2, 0, 2, -1, -1, -2, -3, -4, -5, -3, 1, + 0, 1, 1, 0, -1, -1, -1, 1, 0, 1, 1, 1, 0, 0, 0, 2, + 0, 1, 1, 2, 1, 1, 1, 2, -1, -1, 0, 2, 2, 2, 2, 3, + -2, -4, -4, -1, -2, -2, -2, 0, 1, 0, 0, 1, 0, 0, 0, 1, + 0, -1, -3, -2, 0, 2, 2, 1, 0, -1, -2, -3, 0, 1, 1, 2, + 1, 0, -2, -3, -1, 0, 0, 1, -1, 0, -1, -2, 0, 0, -1, 0, + -1, 1, 1, 0, 2, 2, 0, 0, 0, 2, 3, 1, 3, 5, 3, 2, + -1, 1, 1, -2, 0, 3, 1, 1, -1, 0, 0, -4, -4, -1, -1, -1, + -1, 1, 1, 0, 1, 2, 1, 2, -3, 0, 1, 0, 1, 1, 0, 2, + -5, -3, -1, -1, 0, 1, 0, 1, -4, -3, -2, -3, -2, -1, -1, 0, + 0, 0, -1, -2, -2, -2, -2, 0, 3, 4, 2, 0, 0, 0, 0, 1, + 2, 1, 0, 0, 0, 0, -1, 0, 0, 1, 2, 3, 4, 4, 3, 2, + -1, 4, 7, 4, 0, 0, 0, 0, -1, 4, 6, 3, 0, 1, 1, 1, + 0, 3, 4, 0, -1, 0, 0, 1, 0, 1, 1, -2, -1, 0, -1, -1, + -1, 0, -1, -1, -1, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, + -1, -3, -3, 0, 1, -1, -2, -1, -3, -4, -4, -2, -1, -2, -2, -1, + 2, 2, 1, 0, 1, 1, 0, -3, -2, -1, 0, 0, 1, 1, 0, -3, + -2, -1, 0, 1, 2, 1, 1, -2, 1, 2, 2, 2, 3, 3, 2, -1, + 1, 2, 1, 0, 1, 1, 2, -1, 0, 1, -2, -4, -2, 0, 1, -1, + 1, 1, -1, -3, -2, 0, -1, -3, 1, 2, 0, -1, 0, 1, -1, -4, + -1, -1, -2, -2, 0, 3, 4, 3, 1, 1, -1, -3, -2, 0, 0, 0, + 2, 2, 2, 2, 2, 1, -1, -1, 1, 1, 1, 3, 3, 0, -2, -2, + 0, -1, -1, -1, 0, -2, -1, -1, -1, -3, -4, -3, -2, -2, 0, 2, + -1, -1, 0, 1, 2, 2, 3, 5, -2, -1, -1, 0, 0, 0, 0, 1, + -2, -3, 2, 0, 0, 1, 1, -1, -1, -4, 1, -2, -1, 2, 2, 0, + 1, -4, 0, -2, -2, 1, 1, -1, 2, -3, 1, -1, -1, 1, 1, -1, + 3, -2, 3, 1, 0, 1, 1, -1, 1, -3, 2, 1, 0, 1, 0, -1, + -1, -5, 1, 0, -1, 0, 1, 1, 0, -3, 3, 3, 1, 2, 3, 3, + 0, -1, -2, 1, 5, 5, 2, -1, 1, -1, -2, -1, 1, 1, -2, -5, + 1, 1, -1, -2, -1, -1, -1, -3, 1, 1, -1, -1, -1, 2, 4, 3, + -1, -1, -1, -1, -1, 0, 4, 3, -1, -1, 0, 1, -1, -3, -1, -1, + 0, 0, 0, 2, 2, 0, 0, -1, 0, -2, -3, 0, 1, 1, 3, 2, + 2, 3, 2, 1, 0, 0, -2, -2, 2, 3, 0, 1, 1, 3, 3, 2, + 0, 0, -3, -1, -1, 2, 2, 3, -2, -2, -3, 1, 1, 2, 1, 1, + -2, -1, -2, 2, 1, 1, -1, -2, 0, 1, 0, 2, 0, 0, -2, -2, + 0, 1, 0, 2, 0, 0, -2, -2, -3, -2, -2, 0, -1, -2, -2, -3, + 0, 1, -1, 3, -1, 1, 3, -1, 0, 1, -1, 3, -1, -1, 2, -3, + 1, 1, -2, 3, -1, -3, 0, -3, 2, 2, -2, 3, 0, -2, 1, -2, + 1, 1, -3, 3, -1, -2, 1, -3, 1, 1, -3, 3, 0, -1, 1, -2, + 1, 2, -1, 4, 0, -1, 1, -2, 0, 1, -1, 3, -1, -3, 0, -3, + -3, -3, -1, 1, 2, 1, -1, -2, -2, -2, 0, 2, 1, 0, -2, -2, + -3, -2, 1, 2, 1, -1, -2, -1, -3, -2, 2, 4, 0, -2, -2, 1, + -3, -1, 2, 4, 0, -2, -2, 2, -1, 1, 4, 3, -1, -3, -2, 2, + 0, 2, 4, 2, -1, -2, -1, 2, 0, 1, 2, 0, -1, 0, 1, 3, + 3, 0, -5, 1, 4, 0, 0, 1, 1, -2, -5, 2, 5, -1, -2, 1, + -1, 0, 0, 3, 3, 1, 0, -1, -2, 3, 4, -2, -3, -1, 0, -2, + -3, 3, 5, -3, -3, 0, 0, -2, -1, 3, 2, -2, -2, 2, 2, -1, + 2, 0, 0, -1, 0, 0, 0, 0, 0, -3, -2, 1, 3, 0, -2, -2 }; -const uint32 *const s_svq1InterCodebooks[6] = { +static const int8 *const s_svq1InterCodebooks[6] = { s_svq1InterCodebook4x2, s_svq1InterCodebook4x4, s_svq1InterCodebook8x4, s_svq1InterCodebook8x8, 0, 0 }; -static const uint32 s_svq1IntraCodebook4x2[192] = { - 0x0b0d0d0c, 0xeff1f6f9, 0xf6f4f1f0, 0x0c0f0f0b, - 0x0f141102, 0x0d02e8d3, 0xdcfa1415, 0xe5ff100c, - 0x2d0aebee, 0x15f9ecf5, 0x00e4f82b, 0x03e4f021, - 0xfaeeeef4, 0x371cf6ec, 0xeeebeefb, 0xecfa1e38, - 0xea1d1bde, 0xe71a1de2, 0x1a21221e, 0xdfdde1e7, - 0xe0dcdde1, 0x1f25241d, 0x2226f4b9, 0x212affc1, - 0xc4e1253a, 0xc3df2237, 0x5d16c7c7, 0x5d15c6c7, - 0x3e46453b, 0xc4bcbcc1, 0xc0b9b9c0, 0x3e48493f, - 0x0f0700fe, 0x05fdf6f5, 0xf6f6f8fb, 0x090e0901, - 0xf5fc080f, 0xf4f5020c, 0x1c1300f8, 0xe6f1ff04, - 0xf2021bf1, 0xf70116f2, 0xf6f3fafc, 0x2f06f2fa, - 0x1706ecdd, 0x04060906, 0xea1702fa, 0xeb1c04f9, - 0x06feea14, 0x08fbe416, 0xf4f0eef6, 0xff021324, - 0x080400fd, 0x1717f6d3, 0xddec0f28, 0x0104fffc, - 0x18dffb09, 0x13e60308, 0xfd0604ff, 0xcff31920, - 0x070f1818, 0xf9ede5ef, 0x182700d1, 0x0407faeb, - 0xf3f600ff, 0x10050101, 0xf7fd0514, 0xfafefcff, - 0x0401f9ef, 0x0000070c, 0x0b0c0003, 0xe90001fd, - 0x00fa1104, 0x00e70306, 0x05080aef, 0x040104f2, - 0x02040a0d, 0x0201f7e9, 0x0701fd03, 0x14f9e901, - 0x0c02eef9, 0x090afcfb, 0xe8070a04, 0xf6040306, - 0x06eaf216, 0xff050500, 0xfcf503fc, 0xf2071ff9, - 0x2afff0fb, 0xfbf7fefc, 0xfdfaf805, 0xfbebfc2a, - 0xf4140cee, 0x07f6f30d, 0xeefef7f8, 0x082806f0, - 0x0400ff0a, 0xf3ff04fd, 0xf10106fe, 0x02010305, - 0x0301fefc, 0xfcf7000f, 0xfcfcfcfd, 0xfd1005fd, - 0x04030d02, 0x00f6f8fd, 0xfffcfefa, 0x17fafdfe, - 0x0107fa06, 0x0105ee04, 0x0ef101ff, 0x04fc06fb, - 0x06020202, 0x030702e8, 0x030300e6, 0x06010705, - 0xfdeefe0e, 0x02fc0507, 0x012003fa, 0xf4fafafa, - 0x0607dc05, 0x000bff09, 0x03050404, 0xda030f04, - 0xd6fb170a, 0x04040400, 0xf3fa1117, 0x1d01dbf3, - 0x01fff205, 0x01030005, 0x02fb0400, 0xf6000008, - 0xfdfe0704, 0x010103f6, 0x030dfff4, 0xfd01ff00, - 0x0103ff00, 0x0903f7fa, 0xfafc01fa, 0x0800ff08, - 0x1200fdfd, 0xfffcfffb, 0xfc03fef8, 0xfbff1100, - 0xf609fe05, 0xfb06fb01, 0x03020204, 0x01f8f20a, - 0xffeefeff, 0x020114ff, 0x01f701ff, 0xfc16f7ff, - 0xfd08fc06, 0x05ed07ff, 0xfcfc1ff9, 0xfbfb00fa, - 0xfcedf8f9, 0x20040101, 0x04f8ff26, 0xf4faf8f9, - 0x01f900ff, 0x00ff09ff, 0x00ffff09, 0xfd01fa02, - 0x010200f4, 0x00080101, 0x02000109, 0x00f501fe, - 0xf6020800, 0x00ff02ff, 0xfb00fcfe, 0x0efffffe, - 0x05ff07fd, 0x0101f600, 0xff0efbff, 0xfefd01fe, - 0x060000fa, 0x04f70302, 0xfffffb04, 0xff0803f9, - 0xf5fffc02, 0x0001020b, 0x090302ff, 0xf1000200, - 0x03ec0503, 0x0303ff03, 0x0110ff01, 0x0209e302, - 0xfdfffaf3, 0xfdf8ff24, 0x02040502, 0x030b09db +static const int8 s_svq1IntraCodebook4x2[768] = { + 12, 13, 13, 11, -7,-10,-15,-17,-16,-15,-12,-10, 11, 15, 15, 12, + 2, 17, 20, 15,-45,-24, 2, 13, 21, 20, -6,-36, 12, 16, -1,-27, + -18,-21, 10, 45,-11,-20, -7, 21, 43, -8,-28, 0, 33,-16,-28, 3, + -12,-18,-18, -6,-20,-10, 28, 55, -5,-18,-21,-18, 56, 30, -6,-20, + -34, 27, 29,-22,-30, 29, 26,-25, 30, 34, 33, 26,-25,-31,-35,-33, + -31,-35,-36,-32, 29, 36, 37, 31,-71,-12, 38, 34,-63, -1, 42, 33, + 58, 37,-31,-60, 55, 34,-33,-61,-57,-57, 22, 93,-57,-58, 21, 93, + 59, 69, 70, 62,-63,-68,-68,-60,-64,-71,-71,-64, 63, 73, 72, 62, + -2, 0, 7, 15,-11,-10, -3, 5, -5, -8,-10,-10, 1, 9, 14, 9, + 15, 8, -4,-11, 12, 2,-11,-12, -8, 0, 19, 28, 4, -1,-15,-26, + -15, 27, 2,-14,-14, 22, 1, -9, -4, -6,-13,-10, -6,-14, 6, 47, + -35,-20, 6, 23, 6, 9, 6, 4, -6, 2, 23,-22, -7, 4, 28,-21, + 20,-22, -2, 6, 22,-28, -5, 8,-10,-18,-16,-12, 36, 19, 2, -1, + -3, 0, 4, 8,-45,-10, 23, 23, 40, 15,-20,-35, -4, -1, 4, 1, + 9, -5,-33, 24, 8, 3,-26, 19, -1, 4, 6, -3, 32, 25,-13,-49, + 24, 24, 15, 7,-17,-27,-19, -7,-47, 0, 39, 24,-21, -6, 7, 4, + -1, 0,-10,-13, 1, 1, 5, 16, 20, 5, -3, -9, -1, -4, -2, -6, + -17, -7, 1, 4, 12, 7, 0, 0, 3, 0, 12, 11, -3, 1, 0,-23, + 4, 17, -6, 0, 6, 3,-25, 0,-17, 10, 8, 5,-14, 4, 1, 4, + 13, 10, 4, 2,-23, -9, 1, 2, 3, -3, 1, 7, 1,-23, -7, 20, + -7,-18, 2, 12, -5, -4, 10, 9, 4, 10, 7,-24, 6, 3, 4,-10, + 22,-14,-22, 6, 0, 5, 5, -1, -4, 3,-11, -4, -7, 31, 7,-14, + -5,-16, -1, 42, -4, -2, -9, -5, 5, -8, -6, -3, 42, -4,-21, -5, + -18, 12, 20,-12, 13,-13,-10, 7, -8, -9, -2,-18,-16, 6, 40, 8, + 10, -1, 0, 4, -3, 4, -1,-13, -2, 6, 1,-15, 5, 3, 1, 2, + -4, -2, 1, 3, 15, 0, -9, -4, -3, -4, -4, -4, -3, 5, 16, -3, + 2, 13, 3, 4, -3, -8,-10, 0, -6, -2, -4, -1, -2, -3, -6, 23, + 6, -6, 7, 1, 4,-18, 5, 1, -1, 1,-15, 14, -5, 6, -4, 4, + 2, 2, 2, 6,-24, 2, 7, 3,-26, 0, 3, 3, 5, 7, 1, 6, + 14, -2,-18, -3, 7, 5, -4, 2, -6, 3, 32, 1, -6, -6, -6,-12, + 5,-36, 7, 6, 9, -1, 11, 0, 4, 4, 5, 3, 4, 15, 3,-38, + 10, 23, -5,-42, 0, 4, 4, 4, 23, 17, -6,-13,-13,-37, 1, 29, + 5,-14, -1, 1, 5, 0, 3, 1, 0, 4, -5, 2, 8, 0, 0,-10, + 4, 7, -2, -3,-10, 3, 1, 1,-12, -1, 13, 3, 0, -1, 1, -3, + 0, -1, 3, 1, -6, -9, 3, 9, -6, 1, -4, -6, 8, -1, 0, 8, + -3, -3, 0, 18, -5, -1, -4, -1, -8, -2, 3, -4, 0, 17, -1, -5, + 5, -2, 9,-10, 1, -5, 6, -5, 4, 2, 2, 3, 10,-14, -8, 1, + -1, -2,-18, -1, -1, 20, 1, 2, -1, 1, -9, 1, -1, -9, 22, -4, + 6, -4, 8, -3, -1, 7,-19, 5, -7, 31, -4, -4, -6, 0, -5, -5, + -7, -8,-19, -4, 1, 1, 4, 32, 38, -1, -8, 4, -7, -8, -6,-12, + -1, 0, -7, 1, -1, 9, -1, 0, 9, -1, -1, 0, 2, -6, 1, -3, + -12, 0, 2, 1, 1, 1, 8, 0, 9, 1, 0, 2, -2, 1,-11, 0, + 0, 8, 2,-10, -1, 2, -1, 0, -2, -4, 0, -5, -2, -1, -1, 14, + -3, 7, -1, 5, 0,-10, 1, 1, -1, -5, 14, -1, -2, 1, -3, -2, + -6, 0, 0, 6, 2, 3, -9, 4, 4, -5, -1, -1, -7, 3, 8, -1, + 2, -4, -1,-11, 11, 2, 1, 0, -1, 2, 3, 9, 0, 2, 0,-15, + 3, 5,-20, 3, 3, -1, 3, 3, 1, -1, 16, 1, 2,-29, 9, 2, + -13, -6, -1, -3, 36, -1, -8, -3, 2, 5, 4, 2,-37, 9, 11, 3 }; -static const uint32 s_svq1IntraCodebook4x4[384] = { - 0x0603fdf5, 0x0705fff6, 0x0706fff7, 0x0604fff7, - 0xf2000705, 0xf1020906, 0xf1020906, 0xf2000604, - 0xfafb0310, 0xf8f80110, 0xf7f7ff0e, 0xf8f8000c, - 0x11100c08, 0x090602fe, 0x00fcf8f6, 0xf9f5f2f1, - 0x10fef6f9, 0x12fdf5f9, 0x14fff5f9, 0x1301f8fa, - 0xeff0f3f7, 0xf7f9fe02, 0xff04080b, 0x070b0f10, - 0x0f0dfeea, 0x100efee8, 0x0f0dfce7, 0x0d0afae7, - 0x10161a1a, 0x03090f11, 0xf2f5fafe, 0xe4e4e7ec, - 0xebe7e5e5, 0xf9f5f1f0, 0x0d0c0803, 0x1e1f1c17, - 0xdff91014, 0xddfa1316, 0xdefa1316, 0xe0fa1114, - 0x2602ecec, 0x2802eaeb, 0x2802eaeb, 0x2603ecec, - 0x1a18fcd1, 0x1b1afdce, 0x1b1afdce, 0x1a18fcd1, - 0xe5e9062d, 0xe4e70530, 0xe4e60530, 0xe5e8062c, - 0x4cf6dce2, 0x4ef5dbe1, 0x4ef5dbe1, 0x4df6dce1, - 0x3423e0cb, 0x3424deca, 0x3424deca, 0x3322dfcb, - 0x413edea3, 0x423edea3, 0x413edea3, 0x403cdea3, - 0x020200f9, 0x0303fff8, 0x050400f8, 0x050501fa, - 0x0b0b0703, 0x03030202, 0xf9fafe01, 0xf3f5fb01, - 0xfdfcfe03, 0xfbfb0007, 0xf9fb040c, 0xf9fc060e, - 0xfe030e12, 0xfd000406, 0x00fefbf8, 0x02fef5f0, - 0x1207faf8, 0x0d02f8f9, 0x06fefafc, 0x01fdfc00, - 0xeef3fd01, 0xf9fbff00, 0x070601ff, 0x110f04fe, - 0xfef9f2f1, 0x00fffbfa, 0x01030606, 0x01060d0f, - 0x0af5fe02, 0x0bf4ff02, 0x0bf4ff03, 0x0bf5fe02, - 0xfbff0ef7, 0xfbfe0ff7, 0xfbfe10f8, 0xfcff0ff9, - 0x08080602, 0x0c0903fe, 0x0a04fbf5, 0x00f8f0ed, - 0xf1f9080e, 0xf2f9070c, 0xf7fc0508, 0xfcff0305, - 0x02fef20c, 0x03fff10d, 0x03fff10e, 0x03fff20d, - 0xf30a0600, 0xf10a0600, 0xef090700, 0xf0080601, - 0xfe0ffbf8, 0xfe11faf8, 0xfd10faf8, 0xfe0ffbf8, - 0xf6f5f5f7, 0x08090a09, 0x090a0a08, 0xf9f8f7f8, - 0x07090a09, 0xf6f6f6f8, 0xf5f5f6f9, 0x080b0c0b, - 0x00070a00, 0xfa000700, 0xfafb0200, 0xfffcfffe, - 0xf7fa0005, 0x01020202, 0x070500fe, 0x0401fbfa, - 0xff02f803, 0x0003f704, 0x0003f905, 0x0003fb07, - 0x0902fdfb, 0x0801fdfa, 0x0701fdfa, 0x0400fefb, - 0x0103080d, 0xfffcfbfd, 0x00fdf9f8, 0x020301ff, - 0xf4fb0203, 0xf7fe0304, 0xfc010403, 0xff040503, - 0x00fcf8f7, 0x00020608, 0x0003080a, 0xfffdfbfa, - 0xfbf4f7fd, 0x00fbfd00, 0x04020302, 0x06070805, - 0x0c05feff, 0x0905ffff, 0xfeff0102, 0xeff5ff02, - 0xff0303f9, 0xff0403f7, 0xff0604f6, 0x000705f7, - 0x0202f9ee, 0x030501f8, 0x00010403, 0xfdfe0509, - 0x080600fe, 0xfdfbfbfc, 0xf8fafe01, 0xff03090a, - 0x00fefe00, 0x00fbfc00, 0x08fcf8fe, 0x1806f9fb, - 0x01f90109, 0x01f80109, 0x01f60008, 0xfff5ff08, - 0x03060808, 0x02030405, 0x00fffdfe, 0xfcf8f3f6, - 0xfd020400, 0xfb030600, 0xf4020a03, 0xeafc0a05, - 0x03fffc00, 0x05fffc01, 0x0800fb01, 0x07fefaff, - 0xfcfeffff, 0xfafcfeff, 0xfeffffff, 0x090a0501, - 0xfe00030a, 0xfbfeff06, 0xfafeff03, 0xfb000002, - 0x00000306, 0x01010306, 0x01fefe04, 0xfef7f700, - 0x0201fdf5, 0x050402fa, 0x040302fd, 0x020101fe, - 0xfefffcfa, 0xfeffff02, 0xfefe020a, 0xfffc020b, - 0x02fe0006, 0x00000303, 0x000303fa, 0x0005ffef, - 0x0b0a04ff, 0x0100fefd, 0xfdfbfcfd, 0xfffefeff, - 0xf4f7fd02, 0x02030303, 0x04040202, 0xfeff0102, - 0xf60509fe, 0xfb0505fd, 0x000201fe, 0x01fefeff, - 0xfe07fdfe, 0xfd07fdff, 0xfc08feff, 0xfd07fefe, - 0x0cfdf801, 0x04fefe02, 0xfb000301, 0xf90205ff, - 0xfb0103ff, 0x0103fef9, 0x02fef9fe, 0xfffb0314, - 0xfefd0005, 0x0600f9f9, 0x060700fa, 0xf9000602, - 0x01f906fe, 0x03f807fe, 0x03f907fe, 0x02fa07ff, - 0x0705fefb, 0xf8fc0104, 0xfbfe0306, 0x0703fbf9, - 0x0506ffff, 0xfc01ff00, 0xf9000102, 0xfc000001, - 0x010300f8, 0xffff01fe, 0x01fdff01, 0x0901fe01, - 0xfcfd0205, 0xfdff00ff, 0x010301fd, 0x020400fc, - 0x0cfefe02, 0x03fbfe00, 0x01fd00ff, 0x01fefffd, - 0x00030501, 0x01fefcfa, 0x02fefe00, 0xfffc0106, - 0xfffbfbfd, 0x04050503, 0xff010300, 0xfdfe01fe, - 0xfdfbfc02, 0xfefdfe04, 0xffff0006, 0x00000107, - 0x00fefefd, 0xfffbfdfe, 0xff0002fe, 0xff090bff, - 0xf6ff0100, 0xfa0001ff, 0x04010001, 0x0dfffb02, - 0x000504fe, 0x030601fb, 0x0203fefa, 0xfe00fefb, - 0xfe0101ff, 0x0200feff, 0x07050505, 0xf9f8fc00, - 0xfbff0200, 0xfd0202ff, 0xfb030500, 0xf4020803, - 0xfe000408, 0xfffcff0a, 0x00fdfa03, 0x0000fbfc, - 0x02fcf600, 0x0503faff, 0x0406fdff, 0x0204fe00, - 0xff010800, 0xfd010b00, 0xfcfe06ff, 0xfcf9fefd, - 0xffffff00, 0x05060504, 0xfbf8f7fb, 0x02030202, - 0x01060200, 0x00030002, 0xfefffe01, 0xfafdff00, - 0x00020000, 0x01020004, 0x0000fe05, 0x02fff7fe, - 0xf6000100, 0x000801ff, 0x0004feff, 0xff02ff01, - 0xff02fefd, 0xfd02fffd, 0x0001ff00, 0x03ff0108, - 0x02010100, 0x00fefc00, 0xff01fbff, 0x020bfffe, - 0xfefe0501, 0x00fc0200, 0x01fb01fe, 0x01000500, - 0x0600fdfb, 0x000002fc, 0x000105fd, 0x000003fd, - 0x01fdfe03, 0x0800fc01, 0x03fefdfe, 0xffff0201, - 0x02000101, 0x06010002, 0x0102ff01, 0xed000300, - 0x02fefd01, 0xf9fe0506, 0x010301fd, 0x0200ffff, - 0xfcfffff8, 0x02ff0101, 0x03020304, 0x000301fb, - 0x01ff0200, 0x050000fd, 0x0800fefb, 0x06fcfcfc, - 0x02010201, 0x02fd0202, 0x00f70004, 0x01f50007, - 0xfe000000, 0xfaff0303, 0xf6fd0304, 0x020602ff, - 0x05fdfe07, 0xff0300fc, 0xf90102fc, 0x03ffff02, - 0x02020203, 0xfbf9f9fb, 0x02040605, 0x0100fffe +static const int8 s_svq1IntraCodebook4x4[1536] = { + -11, -3, 3, 6,-10, -1, 5, 7, -9, -1, 6, 7, -9, -1, 4, 6, + 5, 7, 0,-14, 6, 9, 2,-15, 6, 9, 2,-15, 4, 6, 0,-14, + 16, 3, -5, -6, 16, 1, -8, -8, 14, -1, -9, -9, 12, 0, -8, -8, + 8, 12, 16, 17, -2, 2, 6, 9,-10, -8, -4, 0,-15,-14,-11, -7, + -7,-10, -2, 16, -7,-11, -3, 18, -7,-11, -1, 20, -6, -8, 1, 19, + -9,-13,-16,-17, 2, -2, -7, -9, 11, 8, 4, -1, 16, 15, 11, 7, + -22, -2, 13, 15,-24, -2, 14, 16,-25, -4, 13, 15,-25, -6, 10, 13, + 26, 26, 22, 16, 17, 15, 9, 3, -2, -6,-11,-14,-20,-25,-28,-28, + -27,-27,-25,-21,-16,-15,-11, -7, 3, 8, 12, 13, 23, 28, 31, 30, + 20, 16, -7,-33, 22, 19, -6,-35, 22, 19, -6,-34, 20, 17, -6,-32, + -20,-20, 2, 38,-21,-22, 2, 40,-21,-22, 2, 40,-20,-20, 3, 38, + -47, -4, 24, 26,-50, -3, 26, 27,-50, -3, 26, 27,-47, -4, 24, 26, + 45, 6,-23,-27, 48, 5,-25,-28, 48, 5,-26,-28, 44, 6,-24,-27, + -30,-36,-10, 76,-31,-37,-11, 78,-31,-37,-11, 78,-31,-36,-10, 77, + -53,-32, 35, 52,-54,-34, 36, 52,-54,-34, 36, 52,-53,-33, 34, 51, + -93,-34, 62, 65,-93,-34, 62, 66,-93,-34, 62, 65,-93,-34, 60, 64, + -7, 0, 2, 2, -8, -1, 3, 3, -8, 0, 4, 5, -6, 1, 5, 5, + 3, 7, 11, 11, 2, 2, 3, 3, 1, -2, -6, -7, 1, -5,-11,-13, + 3, -2, -4, -3, 7, 0, -5, -5, 12, 4, -5, -7, 14, 6, -4, -7, + 18, 14, 3, -2, 6, 4, 0, -3, -8, -5, -2, 0,-16,-11, -2, 2, + -8, -6, 7, 18, -7, -8, 2, 13, -4, -6, -2, 6, 0, -4, -3, 1, + 1, -3,-13,-18, 0, -1, -5, -7, -1, 1, 6, 7, -2, 4, 15, 17, + -15,-14, -7, -2, -6, -5, -1, 0, 6, 6, 3, 1, 15, 13, 6, 1, + 2, -2,-11, 10, 2, -1,-12, 11, 3, -1,-12, 11, 2, -2,-11, 11, + -9, 14, -1, -5, -9, 15, -2, -5, -8, 16, -2, -5, -7, 15, -1, -4, + 2, 6, 8, 8, -2, 3, 9, 12,-11, -5, 4, 10,-19,-16, -8, 0, + 14, 8, -7,-15, 12, 7, -7,-14, 8, 5, -4, -9, 5, 3, -1, -4, + 12,-14, -2, 2, 13,-15, -1, 3, 14,-15, -1, 3, 13,-14, -1, 3, + 0, 6, 10,-13, 0, 6, 10,-15, 0, 7, 9,-17, 1, 6, 8,-16, + -8, -5, 15, -2, -8, -6, 17, -2, -8, -6, 16, -3, -8, -5, 15, -2, + -9,-11,-11,-10, 9, 10, 9, 8, 8, 10, 10, 9, -8, -9, -8, -7, + 9, 10, 9, 7, -8,-10,-10,-10, -7,-10,-11,-11, 11, 12, 11, 8, + 0, 10, 7, 0, 0, 7, 0, -6, 0, 2, -5, -6, -2, -1, -4, -1, + 5, 0, -6, -9, 2, 2, 2, 1, -2, 0, 5, 7, -6, -5, 1, 4, + 3, -8, 2, -1, 4, -9, 3, 0, 5, -7, 3, 0, 7, -5, 3, 0, + -5, -3, 2, 9, -6, -3, 1, 8, -6, -3, 1, 7, -5, -2, 0, 4, + 13, 8, 3, 1, -3, -5, -4, -1, -8, -7, -3, 0, -1, 1, 3, 2, + 3, 2, -5,-12, 4, 3, -2, -9, 3, 4, 1, -4, 3, 5, 4, -1, + -9, -8, -4, 0, 8, 6, 2, 0, 10, 8, 3, 0, -6, -5, -3, -1, + -3, -9,-12, -5, 0, -3, -5, 0, 2, 3, 2, 4, 5, 8, 7, 6, + -1, -2, 5, 12, -1, -1, 5, 9, 2, 1, -1, -2, 2, -1,-11,-17, + -7, 3, 3, -1, -9, 3, 4, -1,-10, 4, 6, -1, -9, 5, 7, 0, + -18, -7, 2, 2, -8, 1, 5, 3, 3, 4, 1, 0, 9, 5, -2, -3, + -2, 0, 6, 8, -4, -5, -5, -3, 1, -2, -6, -8, 10, 9, 3, -1, + 0, -2, -2, 0, 0, -4, -5, 0, -2, -8, -4, 8, -5, -7, 6, 24, + 9, 1, -7, 1, 9, 1, -8, 1, 8, 0,-10, 1, 8, -1,-11, -1, + 8, 8, 6, 3, 5, 4, 3, 2, -2, -3, -1, 0,-10,-13, -8, -4, + 0, 4, 2, -3, 0, 6, 3, -5, 3, 10, 2,-12, 5, 10, -4,-22, + 0, -4, -1, 3, 1, -4, -1, 5, 1, -5, 0, 8, -1, -6, -2, 7, + -1, -1, -2, -4, -1, -2, -4, -6, -1, -1, -1, -2, 1, 5, 10, 9, + 10, 3, 0, -2, 6, -1, -2, -5, 3, -1, -2, -6, 2, 0, 0, -5, + 6, 3, 0, 0, 6, 3, 1, 1, 4, -2, -2, 1, 0, -9, -9, -2, + -11, -3, 1, 2, -6, 2, 4, 5, -3, 2, 3, 4, -2, 1, 1, 2, + -6, -4, -1, -2, 2, -1, -1, -2, 10, 2, -2, -2, 11, 2, -4, -1, + 6, 0, -2, 2, 3, 3, 0, 0, -6, 3, 3, 0,-17, -1, 5, 0, + -1, 4, 10, 11, -3, -2, 0, 1, -3, -4, -5, -3, -1, -2, -2, -1, + 2, -3, -9,-12, 3, 3, 3, 2, 2, 2, 4, 4, 2, 1, -1, -2, + -2, 9, 5,-10, -3, 5, 5, -5, -2, 1, 2, 0, -1, -2, -2, 1, + -2, -3, 7, -2, -1, -3, 7, -3, -1, -2, 8, -4, -2, -2, 7, -3, + 1, -8, -3, 12, 2, -2, -2, 4, 1, 3, 0, -5, -1, 5, 2, -7, + -1, 3, 1, -5, -7, -2, 3, 1, -2, -7, -2, 2, 20, 3, -5, -1, + 5, 0, -3, -2, -7, -7, 0, 6, -6, 0, 7, 6, 2, 6, 0, -7, + -2, 6, -7, 1, -2, 7, -8, 3, -2, 7, -7, 3, -1, 7, -6, 2, + -5, -2, 5, 7, 4, 1, -4, -8, 6, 3, -2, -5, -7, -5, 3, 7, + -1, -1, 6, 5, 0, -1, 1, -4, 2, 1, 0, -7, 1, 0, 0, -4, + -8, 0, 3, 1, -2, 1, -1, -1, 1, -1, -3, 1, 1, -2, 1, 9, + 5, 2, -3, -4, -1, 0, -1, -3, -3, 1, 3, 1, -4, 0, 4, 2, + 2, -2, -2, 12, 0, -2, -5, 3, -1, 0, -3, 1, -3, -1, -2, 1, + 1, 5, 3, 0, -6, -4, -2, 1, 0, -2, -2, 2, 6, 1, -4, -1, + -3, -5, -5, -1, 3, 5, 5, 4, 0, 3, 1, -1, -2, 1, -2, -3, + 2, -4, -5, -3, 4, -2, -3, -2, 6, 0, -1, -1, 7, 1, 0, 0, + -3, -2, -2, 0, -2, -3, -5, -1, -2, 2, 0, -1, -1, 11, 9, -1, + 0, 1, -1,-10, -1, 1, 0, -6, 1, 0, 1, 4, 2, -5, -1, 13, + -2, 4, 5, 0, -5, 1, 6, 3, -6, -2, 3, 2, -5, -2, 0, -2, + -1, 1, 1, -2, -1, -2, 0, 2, 5, 5, 5, 7, 0, -4, -8, -7, + 0, 2, -1, -5, -1, 2, 2, -3, 0, 5, 3, -5, 3, 8, 2,-12, + 8, 4, 0, -2, 10, -1, -4, -1, 3, -6, -3, 0, -4, -5, 0, 0, + 0,-10, -4, 2, -1, -6, 3, 5, -1, -3, 6, 4, 0, -2, 4, 2, + 0, 8, 1, -1, 0, 11, 1, -3, -1, 6, -2, -4, -3, -2, -7, -4, + 0, -1, -1, -1, 4, 5, 6, 5, -5, -9, -8, -5, 2, 2, 3, 2, + 0, 2, 6, 1, 2, 0, 3, 0, 1, -2, -1, -2, 0, -1, -3, -6, + 0, 0, 2, 0, 4, 0, 2, 1, 5, -2, 0, 0, -2, -9, -1, 2, + 0, 1, 0,-10, -1, 1, 8, 0, -1, -2, 4, 0, 1, -1, 2, -1, + -3, -2, 2, -1, -3, -1, 2, -3, 0, -1, 1, 0, 8, 1, -1, 3, + 0, 1, 1, 2, 0, -4, -2, 0, -1, -5, 1, -1, -2, -1, 11, 2, + 1, 5, -2, -2, 0, 2, -4, 0, -2, 1, -5, 1, 0, 5, 0, 1, + -5, -3, 0, 6, -4, 2, 0, 0, -3, 5, 1, 0, -3, 3, 0, 0, + 3, -2, -3, 1, 1, -4, 0, 8, -2, -3, -2, 3, 1, 2, -1, -1, + 1, 1, 0, 2, 2, 0, 1, 6, 1, -1, 2, 1, 0, 3, 0,-19, + 1, -3, -2, 2, 6, 5, -2, -7, -3, 1, 3, 1, -1, -1, 0, 2, + -8, -1, -1, -4, 1, 1, -1, 2, 4, 3, 2, 3, -5, 1, 3, 0, + 0, 2, -1, 1, -3, 0, 0, 5, -5, -2, 0, 8, -4, -4, -4, 6, + 1, 2, 1, 2, 2, 2, -3, 2, 4, 0, -9, 0, 7, 0,-11, 1, + 0, 0, 0, -2, 3, 3, -1, -6, 4, 3, -3,-10, -1, 2, 6, 2, + 7, -2, -3, 5, -4, 0, 3, -1, -4, 2, 1, -7, 2, -1, -1, 3, + 3, 2, 2, 2, -5, -7, -7, -5, 5, 6, 4, 2, -2, -1, 0, 1 }; -static const uint32 s_svq1IntraCodebook8x4[768] = { - 0x06060605, 0x08080707, 0x00000000, 0x03020100, - 0xfbfcfcfd, 0xfefdfcfb, 0xfbfcfcfc, 0xfdfdfcfc, - 0x02020201, 0x03030302, 0x04030302, 0x05050504, - 0x010100ff, 0x04040302, 0xf7f7f6f7, 0xfbfaf9f8, - 0xfafbfcfc, 0xf9f9f9fa, 0xfefeff00, 0xfcfcfdfd, - 0x03030404, 0x00010102, 0x06070707, 0x04040506, - 0x06050402, 0xfafd0104, 0x05050403, 0xf8fb0004, - 0x04040302, 0xf6f9fe02, 0x01020202, 0xf4f7fc00, - 0x01fdf9f7, 0x03030404, 0x03fef9f6, 0x03030505, - 0x03fefaf7, 0x03040506, 0x03fffaf8, 0x02030404, - 0xfbfbfbfb, 0x070401fd, 0xfcfbfbfb, 0x080601fe, - 0xfdfcfbfc, 0x0a0803ff, 0xfefdfcfd, 0x0b090501, - 0xfefefefe, 0xfefefefe, 0xfbfbfbfc, 0xfcfbfbfb, - 0xfcfcfcfd, 0xfdfcfcfc, 0x0b0a0a09, 0x0a0a0b0b, - 0xfe010407, 0xf6f7fafc, 0x00030709, 0xf7f8fcfe, - 0x0204080b, 0xf8fafd00, 0x0305090b, 0xf9fbfe01, - 0xf4f3f3f3, 0xf8f8f6f5, 0x03020100, 0x03040404, - 0x06050403, 0x04050606, 0x04040403, 0x02030303, - 0x0a0b0a0a, 0x07080909, 0x06060606, 0x02030405, - 0xff000000, 0xfcfcfdfe, 0xf4f5f6f6, 0xf2f2f2f3, - 0x10111010, 0x0b0c0d0f, 0xfcfdfeff, 0xfdfcfcfc, - 0xfafafbfc, 0xfafafafa, 0xfafafafb, 0xfbfbfafa, - 0xf4f3f3f3, 0xfaf8f6f5, 0xfaf9f8f7, 0x0100fefc, - 0x0301fffe, 0x09080705, 0x0b090705, 0x0f0f0e0d, - 0x070b0e10, 0xf7f9fd02, 0x03080c0e, 0xf5f7faff, - 0x0004090b, 0xf3f5f8fc, 0xfd010508, 0xf2f4f6fa, - 0xfdf7f1ee, 0x0b090601, 0xfff9f3ef, 0x0c0b0703, - 0x01fbf5f1, 0x0d0c0905, 0x02fdf7f3, 0x0d0b0905, - 0x0f131516, 0xf7fc030a, 0x090f1214, 0xeff4fb02, - 0x01080d10, 0xe8ecf2f9, 0xf8ff060a, 0xe5e7ebf1, - 0xf2ece9e7, 0x0e0901f9, 0xf7f0ebe9, 0x15100900, - 0xfff6f0ec, 0x19161008, 0x06fdf5f1, 0x1b19140e, - 0x0100fefc, 0x02020202, 0x0200fefb, 0x03030303, - 0x01fffcfa, 0x03030302, 0x00fefbf9, 0x02020101, - 0x01010102, 0xfdfe0001, 0x01020303, 0xfcfdff00, - 0x01020304, 0xfafcfe00, 0x01030405, 0xfafbfdff, - 0x04060605, 0xfdfe0002, 0x04040403, 0xff000103, - 0xfffffefe, 0xfefeffff, 0xfefdfcfb, 0xfdfdfefe, - 0xffffffff, 0xffffffff, 0xfcfcfcfd, 0xfdfdfdfd, - 0xffffffff, 0xfeffffff, 0x06060605, 0x03040506, - 0x04040404, 0x07060504, 0xffffff00, 0x020100ff, - 0xfdfdfdfe, 0x00fffefd, 0xfcfcfdfd, 0xfffefdfc, - 0xfcfcfe00, 0x030200fe, 0xfdfdfe00, 0x050402ff, - 0xfdfcfeff, 0x06050300, 0xfdfcfdfe, 0x050402ff, - 0xfd000409, 0x0100fffd, 0xfcff0408, 0x0201fffd, - 0xfbfd0206, 0x0100fefc, 0xfcfd0105, 0x0100fefc, - 0xff010305, 0xf6f6f8fc, 0x01020303, 0xfcfdfe00, - 0x02010101, 0x00010203, 0x020100ff, 0x02030403, - 0x02020100, 0xfdfdff01, 0x01010100, 0xfdfcfeff, - 0xfdfdfdfd, 0x02fffdfd, 0x00fdfcfc, 0x0e0c0703, - 0xfafafbfb, 0xfbfafafa, 0x01020202, 0x00000000, - 0x02030404, 0x00000001, 0x04050606, 0x01010202, - 0xfdfaf9f9, 0x08070400, 0xfdfdfeff, 0x0201fffe, - 0xff010303, 0xfffefefe, 0x02040606, 0xfefefe00, - 0x02fefbfa, 0x0c0b0905, 0x00fefcfc, 0x06050402, - 0xfefefefd, 0x0100fffe, 0xfdfefefe, 0xfefdfdfd, - 0x0301fdf9, 0xfbfd0003, 0x0503fefa, 0xfbfd0104, - 0x0604fffb, 0xfcfd0205, 0x070500fc, 0xfdff0306, - 0x00000000, 0x00000000, 0xfdfdfefe, 0xfffefdfd, - 0x09080706, 0x06070809, 0xfbfbfcfc, 0xfcfbfafa, - 0xfcfaf8f7, 0x06060300, 0x03fffcfb, 0x03050605, - 0x06060301, 0xfbfe0104, 0x01050706, 0xf5f6f9fd, - 0x0105090a, 0xfcfafafd, 0xfbff0305, 0x02fefbfa, - 0xfafafcfe, 0x0a0601fc, 0xfcf9f9fa, 0x0c0b0701, - 0x02030506, 0x00000000, 0xfeff0102, 0xfffffefd, - 0xfcfeff00, 0x01fffefc, 0xfeff0000, 0x030200ff, - 0xfefeff00, 0xfffffefe, 0x01020405, 0x00000000, - 0x01030506, 0x00000000, 0xfcfe0002, 0xfefefdfc, - 0x0200fcf9, 0x01020202, 0x0000fdf9, 0x00000000, - 0x0101fffc, 0x01000000, 0x020201ff, 0x03030202, - 0x020200fe, 0x01010101, 0x020201ff, 0xff000001, - 0x02040200, 0xfdfeff00, 0x01030201, 0xfafafcfe, - 0x04020201, 0x01040605, 0xffffff00, 0xfcfe0000, - 0xfeff0000, 0xfafcfefe, 0x00000102, 0xfdff0101, - 0x01010101, 0x03030201, 0x00010000, 0x04040201, - 0xffffffff, 0x03020100, 0xfbfbfcfc, 0x00fffdfb, - 0xfcfbfbfa, 0xfffffefd, 0x010000ff, 0x03030201, - 0x01010100, 0x04030202, 0xffff0000, 0x03020100, - 0x01010100, 0xffff0000, 0x02030301, 0xfefeff01, - 0x020200fe, 0x01010202, 0xfefcf8f7, 0x03030301, - 0xfeffffff, 0xfcfdfdfd, 0xff000000, 0xfdfdfefe, - 0x00020202, 0xffffffff, 0x03040505, 0x02020202, - 0xfcff0306, 0x0101fffd, 0xfcfdff02, 0x000202ff, - 0x01fefeff, 0xfd010404, 0x0401fffe, 0xf8fd0306, - 0x01020303, 0xfefefeff, 0xfffefcfc, 0x04040301, - 0xfcfbfbfc, 0x020200fe, 0x01040707, 0xfefdfeff, - 0x000301ff, 0x0600fafc, 0x010401fe, 0x07fffafc, - 0x020401fd, 0x06fffafd, 0x020300fe, 0x04fffbfe, - 0x01feff01, 0xf9ff0404, 0xfffcff01, 0xfa000605, - 0xfdfc0003, 0xfc020603, 0xfcfb0003, 0xfd010401, - 0x03030202, 0x02020303, 0xf9fafbfc, 0xfaf9f9f9, - 0x03030201, 0x02020303, 0x01010000, 0x01020201, - 0x03fdfd03, 0x02fefe04, 0x04fcfc03, 0x02fcfc04, - 0x04fcfc04, 0x03fdfc04, 0x03fcfd03, 0x03fdfd03, - 0xfefefefe, 0xfffffefe, 0x08080706, 0x05060708, - 0xf9f9fafb, 0xfbfaf9f8, 0x02020101, 0x01010202, - 0x00000000, 0x0000ff00, 0x000000ff, 0x0000ff00, - 0xfefefdfe, 0xfdfdfdfe, 0x06050302, 0x00010204, - 0x00020608, 0x00000000, 0x00000104, 0xffffff00, - 0x0000ff01, 0xfdfeff00, 0x00fffefe, 0xfbfcfe00, - 0xfeff0103, 0xfbfbfcfd, 0x00000102, 0x00000101, - 0x00ffff00, 0x02020202, 0x01fffeff, 0x02020202, - 0xfffeff00, 0x00ffffff, 0xfffefeff, 0x010000ff, - 0x02010102, 0x00010102, 0x01030506, 0xfcfcfe00, - 0x00fffefd, 0xff000101, 0x04030100, 0x01030505, - 0x00ffffff, 0xfeff0001, 0xfffefefe, 0xfdfeff00, - 0xfefeff00, 0x0200ffff, 0xfffeff01, 0x0200ffff, - 0xfefe0001, 0x0501fefe, 0xfefeff01, 0x0a0500fe, - 0x00000000, 0xffffff00, 0x00ffffff, 0x02010000, - 0x03020201, 0x05060404, 0xfefdfdfd, 0xfdfdfdfe, - 0xfefeff01, 0x07050300, 0xfdfe0002, 0x030200fe, - 0xfdfe0103, 0xfffffefd, 0xff000103, 0xffffffff, - 0x04050301, 0xfcfdff02, 0x0201fefd, 0xfeff0001, - 0x0200fdfb, 0x00000102, 0x0201fffd, 0x00000102, - 0xffffff00, 0x04030201, 0xfdfcfcfd, 0x010000ff, - 0xfffefdfe, 0x01010101, 0x0300fefe, 0x02030404, - 0xfefdfcfc, 0x030201ff, 0x01010100, 0xfdfdfeff, - 0x04050403, 0xfdfdff02, 0x0200fefe, 0x00010202, - 0x070500fc, 0xfcfcff04, 0x030402ff, 0xfefdfd00, - 0xff000102, 0x0100fefe, 0xfeff0000, 0x0201fffe, - 0xfffefdfc, 0x02020100, 0x0005090a, 0xfefdfcfd, - 0xfefeff01, 0x000000ff, 0x01fffefe, 0xff000101, - 0x0300fdfb, 0xfe000204, 0x0100fffe, 0xffff0001, - 0xfeff0203, 0x0101fffe, 0xfbff0507, 0x0402fefa, - 0xfd0303fe, 0xfe0201fc, 0xfd0403fd, 0xfe0302fc, - 0xfd0403fd, 0xfe0302fc, 0xfe0402fc, 0xff0201fd, - 0xfdff0304, 0x0201fffd, 0x00fcfafc, 0x01040504, - 0x06050200, 0xfcfbfd02, 0xfdff0101, 0x0402fefb, - 0x020100ff, 0x04030302, 0x010100ff, 0xffffff00, - 0x020100ff, 0xfeff0102, 0x00fffefd, 0xfdfeff00, - 0x01010101, 0x02010000, 0x00ff0001, 0x00010100, - 0xfffcfe01, 0x00010201, 0xfdf9fc01, 0x01020301, - 0x01010101, 0xff000101, 0x00010101, 0x00020201, - 0x00000101, 0xfd000200, 0xff000203, 0xf7fafeff, - 0x01000000, 0x02010000, 0x00000001, 0x0200ffff, - 0x01010100, 0x00fefdff, 0x0601fbf9, 0xffff0206, - 0xfdff0103, 0x0401fefc, 0xfdfe0002, 0x02fffdfc, - 0x01010202, 0x01000001, 0x00000101, 0x01000000, - 0xfe0101ff, 0xfffcfafb, 0x030401ff, 0x02010002, - 0x030200ff, 0x01000001, 0x000100ff, 0x00ffff00, - 0x02020100, 0x01fffe00, 0xfefffffe, 0x080602ff, - 0xfdfeffff, 0x020100fe, 0xff0000ff, 0xffff00ff, - 0x01010102, 0x00000001, 0x01010000, 0x01ffff01, - 0x020200ff, 0x03fefdff, 0x00030200, 0x04fef9fb, - 0x000000ff, 0xfdfdfeff, 0xfeff00ff, 0xfefefefe, - 0x00000101, 0xff000201, 0x02010201, 0x00020605, - 0x00fdfcfe, 0xfd000202, 0x01000103, 0xfdfe0102, - 0x00000103, 0xff000000, 0xfefeff01, 0x030301ff, - 0x02010203, 0xfe010304, 0xfdfcfcfe, 0xfdfe00ff, - 0xffff0001, 0xff000100, 0x00000203, 0x00010100, - 0x00000101, 0x00000000, 0x02030302, 0x01010202, - 0xfdfeff00, 0xfcfbfbfb, 0xff000101, 0x03030100, - 0x00fefaf7, 0x02020101, 0x0201fefa, 0x01000101, - 0x020201fe, 0x01010101, 0x01020200, 0x01010100, - 0x00000001, 0x00ff0000, 0x00000000, 0x00fefdff, - 0xfefdfdfd, 0x090703ff, 0x02020201, 0xfdfcfe00, - 0xfffe0002, 0xfaff0403, 0xfdfe0001, 0x000303ff, - 0x00030300, 0x0101fffe, 0x0203fffa, 0x0100feff, - 0xfe000305, 0x010200fd, 0x02020101, 0xf9fcfe00, - 0x0201fefd, 0xfcff0102, 0xfe000202, 0x020200fe, - 0xfdfe0000, 0x0000fffe, 0x00000000, 0x02020000, - 0x0100fffe, 0x03020100, 0x0000fefc, 0x030200ff, - 0xfffefefe, 0x040200ff, 0x00000000, 0x0100ffff, - 0xffffff00, 0x0000ffff, 0x00020406, 0xfffffeff, - 0x01010100, 0xf6fbff01, 0x01010101, 0xfc000101, - 0x01010001, 0xff010101, 0x01010102, 0x00000000, - 0x030401fd, 0x00ff0103, 0x000100fc, 0x000000ff, - 0x010200fb, 0xff000101, 0xfe0102ff, 0xff00fffe, - 0x03050402, 0x0201ff00, 0x00010000, 0xfffffefe, - 0xfefefefe, 0x00fffefd, 0x00010000, 0x02010000, - 0xfdfefe00, 0xff0202ff, 0x00000001, 0xfe030501, - 0xff00ffff, 0xfb000200, 0x000100ff, 0xfe020200, - 0xffff0103, 0x02010100, 0x01000001, 0x01010101, - 0x01fef8f6, 0x01010102, 0x010201ff, 0x00000000, - 0x0100ffff, 0x01020202, 0x00ffffff, 0xfcfbfdff, - 0x01020101, 0x02000001, 0xfffffeff, 0x040200ff, - 0x00fbf9fd, 0x00000002, 0x01feff03, 0x02010102, - 0x01fffe01, 0x01000102, 0x0300ff00, 0xffffff02, - 0x00010102, 0x00000000, 0x03fef9f7, 0x01010203, - 0xfe000203, 0x0101fffe, 0x0000ff00, 0x00000101, - 0x0101fffe, 0x00000001, 0xfe010201, 0x0201fdfc, - 0xfe010201, 0x010300fd, 0x0000ffff, 0xfc000301, - 0x01ff0002, 0x03fefe02, 0x02ff0002, 0x01fcfe03, - 0x01010100, 0xfefafe02, 0x000000ff, 0xfffe0002, - 0x0201ffff, 0xfefdfe01, 0xfffeff03, 0x020100ff, - 0x0000040a, 0xfffefeff, 0xfffeff03, 0x00ffff00, - 0x010702fb, 0x0001fefc, 0xff0302fe, 0x000200fd, - 0x00000102, 0xfeff0101, 0xfffefe01, 0x0000feff, - 0xf9fe0300, 0x000003ff, 0xfbfd0301, 0x00ff0302, - 0xfefe0200, 0x00fe0204, 0x00ff01ff, 0x01feff02, - 0xfcfd0004, 0x010201fe, 0x05030000, 0xfeff0103, - 0xff010101, 0x0101fffd, 0xfefeff01, 0xfeff0000 +static const int8 s_svq1IntraCodebook8x4[3072] = { + 5, 6, 6, 6, 7, 7, 8, 8, 0, 0, 0, 0, 0, 1, 2, 3, + -3, -4, -4, -5, -5, -4, -3, -2, -4, -4, -4, -5, -4, -4, -3, -3, + 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 4, 4, 5, 5, 5, + -1, 0, 1, 1, 2, 3, 4, 4, -9,-10, -9, -9, -8, -7, -6, -5, + -4, -4, -5, -6, -6, -7, -7, -7, 0, -1, -2, -2, -3, -3, -4, -4, + 4, 4, 3, 3, 2, 1, 1, 0, 7, 7, 7, 6, 6, 5, 4, 4, + 2, 4, 5, 6, 4, 1, -3, -6, 3, 4, 5, 5, 4, 0, -5, -8, + 2, 3, 4, 4, 2, -2, -7,-10, 2, 2, 2, 1, 0, -4, -9,-12, + -9, -7, -3, 1, 4, 4, 3, 3,-10, -7, -2, 3, 5, 5, 3, 3, + -9, -6, -2, 3, 6, 5, 4, 3, -8, -6, -1, 3, 4, 4, 3, 2, + -5, -5, -5, -5, -3, 1, 4, 7, -5, -5, -5, -4, -2, 1, 6, 8, + -4, -5, -4, -3, -1, 3, 8, 10, -3, -4, -3, -2, 1, 5, 9, 11, + -2, -2, -2, -2, -2, -2, -2, -2, -4, -5, -5, -5, -5, -5, -5, -4, + -3, -4, -4, -4, -4, -4, -4, -3, 9, 10, 10, 11, 11, 11, 10, 10, + 7, 4, 1, -2, -4, -6, -9,-10, 9, 7, 3, 0, -2, -4, -8, -9, + 11, 8, 4, 2, 0, -3, -6, -8, 11, 9, 5, 3, 1, -2, -5, -7, + -13,-13,-13,-12,-11,-10, -8, -8, 0, 1, 2, 3, 4, 4, 4, 3, + 3, 4, 5, 6, 6, 6, 5, 4, 3, 4, 4, 4, 3, 3, 3, 2, + 10, 10, 11, 10, 9, 9, 8, 7, 6, 6, 6, 6, 5, 4, 3, 2, + 0, 0, 0, -1, -2, -3, -4, -4,-10,-10,-11,-12,-13,-14,-14,-14, + 16, 16, 17, 16, 15, 13, 12, 11, -1, -2, -3, -4, -4, -4, -4, -3, + -4, -5, -6, -6, -6, -6, -6, -6, -5, -6, -6, -6, -6, -6, -5, -5, + -13,-13,-13,-12,-11,-10, -8, -6, -9, -8, -7, -6, -4, -2, 0, 1, + -2, -1, 1, 3, 5, 7, 8, 9, 5, 7, 9, 11, 13, 14, 15, 15, + 16, 14, 11, 7, 2, -3, -7, -9, 14, 12, 8, 3, -1, -6, -9,-11, + 11, 9, 4, 0, -4, -8,-11,-13, 8, 5, 1, -3, -6,-10,-12,-14, + -18,-15, -9, -3, 1, 6, 9, 11,-17,-13, -7, -1, 3, 7, 11, 12, + -15,-11, -5, 1, 5, 9, 12, 13,-13, -9, -3, 2, 5, 9, 11, 13, + 22, 21, 19, 15, 10, 3, -4, -9, 20, 18, 15, 9, 2, -5,-12,-17, + 16, 13, 8, 1, -7,-14,-20,-24, 10, 6, -1, -8,-15,-21,-25,-27, + -25,-23,-20,-14, -7, 1, 9, 14,-23,-21,-16, -9, 0, 9, 16, 21, + -20,-16,-10, -1, 8, 16, 22, 25,-15,-11, -3, 6, 14, 20, 25, 27, + -4, -2, 0, 1, 2, 2, 2, 2, -5, -2, 0, 2, 3, 3, 3, 3, + -6, -4, -1, 1, 2, 3, 3, 3, -7, -5, -2, 0, 1, 1, 2, 2, + 2, 1, 1, 1, 1, 0, -2, -3, 3, 3, 2, 1, 0, -1, -3, -4, + 4, 3, 2, 1, 0, -2, -4, -6, 5, 4, 3, 1, -1, -3, -5, -6, + 5, 6, 6, 4, 2, 0, -2, -3, 3, 4, 4, 4, 3, 1, 0, -1, + -2, -2, -1, -1, -1, -1, -2, -2, -5, -4, -3, -2, -2, -2, -3, -3, + -1, -1, -1, -1, -1, -1, -1, -1, -3, -4, -4, -4, -3, -3, -3, -3, + -1, -1, -1, -1, -1, -1, -1, -2, 5, 6, 6, 6, 6, 5, 4, 3, + 4, 4, 4, 4, 4, 5, 6, 7, 0, -1, -1, -1, -1, 0, 1, 2, + -2, -3, -3, -3, -3, -2, -1, 0, -3, -3, -4, -4, -4, -3, -2, -1, + 0, -2, -4, -4, -2, 0, 2, 3, 0, -2, -3, -3, -1, 2, 4, 5, + -1, -2, -4, -3, 0, 3, 5, 6, -2, -3, -4, -3, -1, 2, 4, 5, + 9, 4, 0, -3, -3, -1, 0, 1, 8, 4, -1, -4, -3, -1, 1, 2, + 6, 2, -3, -5, -4, -2, 0, 1, 5, 1, -3, -4, -4, -2, 0, 1, + 5, 3, 1, -1, -4, -8,-10,-10, 3, 3, 2, 1, 0, -2, -3, -4, + 1, 1, 1, 2, 3, 2, 1, 0, -1, 0, 1, 2, 3, 4, 3, 2, + 0, 1, 2, 2, 1, -1, -3, -3, 0, 1, 1, 1, -1, -2, -4, -3, + -3, -3, -3, -3, -3, -3, -1, 2, -4, -4, -3, 0, 3, 7, 12, 14, + -5, -5, -6, -6, -6, -6, -6, -5, 2, 2, 2, 1, 0, 0, 0, 0, + 4, 4, 3, 2, 1, 0, 0, 0, 6, 6, 5, 4, 2, 2, 1, 1, + -7, -7, -6, -3, 0, 4, 7, 8, -1, -2, -3, -3, -2, -1, 1, 2, + 3, 3, 1, -1, -2, -2, -2, -1, 6, 6, 4, 2, 0, -2, -2, -2, + -6, -5, -2, 2, 5, 9, 11, 12, -4, -4, -2, 0, 2, 4, 5, 6, + -3, -2, -2, -2, -2, -1, 0, 1, -2, -2, -2, -3, -3, -3, -3, -2, + -7, -3, 1, 3, 3, 0, -3, -5, -6, -2, 3, 5, 4, 1, -3, -5, + -5, -1, 4, 6, 5, 2, -3, -4, -4, 0, 5, 7, 6, 3, -1, -3, + 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -3, -3, -3, -3, -2, -1, + 6, 7, 8, 9, 9, 8, 7, 6, -4, -4, -5, -5, -6, -6, -5, -4, + -9, -8, -6, -4, 0, 3, 6, 6, -5, -4, -1, 3, 5, 6, 5, 3, + 1, 3, 6, 6, 4, 1, -2, -5, 6, 7, 5, 1, -3, -7,-10,-11, + 10, 9, 5, 1, -3, -6, -6, -4, 5, 3, -1, -5, -6, -5, -2, 2, + -2, -4, -6, -6, -4, 1, 6, 10, -6, -7, -7, -4, 1, 7, 11, 12, + 6, 5, 3, 2, 0, 0, 0, 0, 2, 1, -1, -2, -3, -2, -1, -1, + 0, -1, -2, -4, -4, -2, -1, 1, 0, 0, -1, -2, -1, 0, 2, 3, + 0, -1, -2, -2, -2, -2, -1, -1, 5, 4, 2, 1, 0, 0, 0, 0, + 6, 5, 3, 1, 0, 0, 0, 0, 2, 0, -2, -4, -4, -3, -2, -2, + -7, -4, 0, 2, 2, 2, 2, 1, -7, -3, 0, 0, 0, 0, 0, 0, + -4, -1, 1, 1, 0, 0, 0, 1, -1, 1, 2, 2, 2, 2, 3, 3, + -2, 0, 2, 2, 1, 1, 1, 1, -1, 1, 2, 2, 1, 0, 0, -1, + 0, 2, 4, 2, 0, -1, -2, -3, 1, 2, 3, 1, -2, -4, -6, -6, + 1, 2, 2, 4, 5, 6, 4, 1, 0, -1, -1, -1, 0, 0, -2, -4, + 0, 0, -1, -2, -2, -2, -4, -6, 2, 1, 0, 0, 1, 1, -1, -3, + 1, 1, 1, 1, 1, 2, 3, 3, 0, 0, 1, 0, 1, 2, 4, 4, + -1, -1, -1, -1, 0, 1, 2, 3, -4, -4, -5, -5, -5, -3, -1, 0, + -6, -5, -5, -4, -3, -2, -1, -1, -1, 0, 0, 1, 1, 2, 3, 3, + 0, 1, 1, 1, 2, 2, 3, 4, 0, 0, -1, -1, 0, 1, 2, 3, + 0, 1, 1, 1, 0, 0, -1, -1, 1, 3, 3, 2, 1, -1, -2, -2, + -2, 0, 2, 2, 2, 2, 1, 1, -9, -8, -4, -2, 1, 3, 3, 3, + -1, -1, -1, -2, -3, -3, -3, -4, 0, 0, 0, -1, -2, -2, -3, -3, + 2, 2, 2, 0, -1, -1, -1, -1, 5, 5, 4, 3, 2, 2, 2, 2, + 6, 3, -1, -4, -3, -1, 1, 1, 2, -1, -3, -4, -1, 2, 2, 0, + -1, -2, -2, 1, 4, 4, 1, -3, -2, -1, 1, 4, 6, 3, -3, -8, + 3, 3, 2, 1, -1, -2, -2, -2, -4, -4, -2, -1, 1, 3, 4, 4, + -4, -5, -5, -4, -2, 0, 2, 2, 7, 7, 4, 1, -1, -2, -3, -2, + -1, 1, 3, 0, -4, -6, 0, 6, -2, 1, 4, 1, -4, -6, -1, 7, + -3, 1, 4, 2, -3, -6, -1, 6, -2, 0, 3, 2, -2, -5, -1, 4, + 1, -1, -2, 1, 4, 4, -1, -7, 1, -1, -4, -1, 5, 6, 0, -6, + 3, 0, -4, -3, 3, 6, 2, -4, 3, 0, -5, -4, 1, 4, 1, -3, + 2, 2, 3, 3, 3, 3, 2, 2, -4, -5, -6, -7, -7, -7, -7, -6, + 1, 2, 3, 3, 3, 3, 2, 2, 0, 0, 1, 1, 1, 2, 2, 1, + 3, -3, -3, 3, 4, -2, -2, 2, 3, -4, -4, 4, 4, -4, -4, 2, + 4, -4, -4, 4, 4, -4, -3, 3, 3, -3, -4, 3, 3, -3, -3, 3, + -2, -2, -2, -2, -2, -2, -1, -1, 6, 7, 8, 8, 8, 7, 6, 5, + -5, -6, -7, -7, -8, -7, -6, -5, 1, 1, 2, 2, 2, 2, 1, 1, + 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, + -2, -3, -2, -2, -2, -3, -3, -3, 2, 3, 5, 6, 4, 2, 1, 0, + 8, 6, 2, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, -1, -1, -1, + 1, -1, 0, 0, 0, -1, -2, -3, -2, -2, -1, 0, 0, -2, -4, -5, + 3, 1, -1, -2, -3, -4, -5, -5, 2, 1, 0, 0, 1, 1, 0, 0, + 0, -1, -1, 0, 2, 2, 2, 2, -1, -2, -1, 1, 2, 2, 2, 2, + 0, -1, -2, -1, -1, -1, -1, 0, -1, -2, -2, -1, -1, 0, 0, 1, + 2, 1, 1, 2, 2, 1, 1, 0, 6, 5, 3, 1, 0, -2, -4, -4, + -3, -2, -1, 0, 1, 1, 0, -1, 0, 1, 3, 4, 5, 5, 3, 1, + -1, -1, -1, 0, 1, 0, -1, -2, -2, -2, -2, -1, 0, -1, -2, -3, + 0, -1, -2, -2, -1, -1, 0, 2, 1, -1, -2, -1, -1, -1, 0, 2, + 1, 0, -2, -2, -2, -2, 1, 5, 1, -1, -2, -2, -2, 0, 5, 10, + 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 1, 2, + 1, 2, 2, 3, 4, 4, 6, 5, -3, -3, -3, -2, -2, -3, -3, -3, + 1, -1, -2, -2, 0, 3, 5, 7, 2, 0, -2, -3, -2, 0, 2, 3, + 3, 1, -2, -3, -3, -2, -1, -1, 3, 1, 0, -1, -1, -1, -1, -1, + 1, 3, 5, 4, 2, -1, -3, -4, -3, -2, 1, 2, 1, 0, -1, -2, + -5, -3, 0, 2, 2, 1, 0, 0, -3, -1, 1, 2, 2, 1, 0, 0, + 0, -1, -1, -1, 1, 2, 3, 4, -3, -4, -4, -3, -1, 0, 0, 1, + -2, -3, -2, -1, 1, 1, 1, 1, -2, -2, 0, 3, 4, 4, 3, 2, + -4, -4, -3, -2, -1, 1, 2, 3, 0, 1, 1, 1, -1, -2, -3, -3, + 3, 4, 5, 4, 2, -1, -3, -3, -2, -2, 0, 2, 2, 2, 1, 0, + -4, 0, 5, 7, 4, -1, -4, -4, -1, 2, 4, 3, 0, -3, -3, -2, + 2, 1, 0, -1, -2, -2, 0, 1, 0, 0, -1, -2, -2, -1, 1, 2, + -4, -3, -2, -1, 0, 1, 2, 2, 10, 9, 5, 0, -3, -4, -3, -2, + 1, -1, -2, -2, -1, 0, 0, 0, -2, -2, -1, 1, 1, 1, 0, -1, + -5, -3, 0, 3, 4, 2, 0, -2, -2, -1, 0, 1, 1, 0, -1, -1, + 3, 2, -1, -2, -2, -1, 1, 1, 7, 5, -1, -5, -6, -2, 2, 4, + -2, 3, 3, -3, -4, 1, 2, -2, -3, 3, 4, -3, -4, 2, 3, -2, + -3, 3, 4, -3, -4, 2, 3, -2, -4, 2, 4, -2, -3, 1, 2, -1, + 4, 3, -1, -3, -3, -1, 1, 2, -4, -6, -4, 0, 4, 5, 4, 1, + 0, 2, 5, 6, 2, -3, -5, -4, 1, 1, -1, -3, -5, -2, 2, 4, + -1, 0, 1, 2, 2, 3, 3, 4, -1, 0, 1, 1, 0, -1, -1, -1, + -1, 0, 1, 2, 2, 1, -1, -2, -3, -2, -1, 0, 0, -1, -2, -3, + 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, -1, 0, 0, 1, 1, 0, + 1, -2, -4, -1, 1, 2, 1, 0, 1, -4, -7, -3, 1, 3, 2, 1, + 1, 1, 1, 1, 1, 1, 0, -1, 1, 1, 1, 0, 1, 2, 2, 0, + 1, 1, 0, 0, 0, 2, 0, -3, 3, 2, 0, -1, -1, -2, -6, -9, + 0, 0, 0, 1, 0, 0, 1, 2, 1, 0, 0, 0, -1, -1, 0, 2, + 0, 1, 1, 1, -1, -3, -2, 0, -7, -5, 1, 6, 6, 2, -1, -1, + 3, 1, -1, -3, -4, -2, 1, 4, 2, 0, -2, -3, -4, -3, -1, 2, + 2, 2, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, + -1, 1, 1, -2, -5, -6, -4, -1, -1, 1, 4, 3, 2, 0, 1, 2, + -1, 0, 2, 3, 1, 0, 0, 1, -1, 0, 1, 0, 0, -1, -1, 0, + 0, 1, 2, 2, 0, -2, -1, 1, -2, -1, -1, -2, -1, 2, 6, 8, + -1, -1, -2, -3, -2, 0, 1, 2, -1, 0, 0, -1, -1, 0, -1, -1, + 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, -1, -1, 1, + -1, 0, 2, 2, -1, -3, -2, 3, 0, 2, 3, 0, -5, -7, -2, 4, + -1, 0, 0, 0, -1, -2, -3, -3, -1, 0, -1, -2, -2, -2, -2, -2, + 1, 1, 0, 0, 1, 2, 0, -1, 1, 2, 1, 2, 5, 6, 2, 0, + -2, -4, -3, 0, 2, 2, 0, -3, 3, 1, 0, 1, 2, 1, -2, -3, + 3, 1, 0, 0, 0, 0, 0, -1, 1, -1, -2, -2, -1, 1, 3, 3, + 3, 2, 1, 2, 4, 3, 1, -2, -2, -4, -4, -3, -1, 0, -2, -3, + 1, 0, -1, -1, 0, 1, 0, -1, 3, 2, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 2, 3, 3, 2, 2, 2, 1, 1, + 0, -1, -2, -3, -5, -5, -5, -4, 1, 1, 0, -1, 0, 1, 3, 3, + -9, -6, -2, 0, 1, 1, 2, 2, -6, -2, 1, 2, 1, 1, 0, 1, + -2, 1, 2, 2, 1, 1, 1, 1, 0, 2, 2, 1, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, -3, -2, 0, + -3, -3, -3, -2, -1, 3, 7, 9, 1, 2, 2, 2, 0, -2, -4, -3, + 2, 0, -2, -1, 3, 4, -1, -6, 1, 0, -2, -3, -1, 3, 3, 0, + 0, 3, 3, 0, -2, -1, 1, 1, -6, -1, 3, 2, -1, -2, 0, 1, + 5, 3, 0, -2, -3, 0, 2, 1, 1, 1, 2, 2, 0, -2, -4, -7, + -3, -2, 1, 2, 2, 1, -1, -4, 2, 2, 0, -2, -2, 0, 2, 2, + 0, 0, -2, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + -2, -1, 0, 1, 0, 1, 2, 3, -4, -2, 0, 0, -1, 0, 2, 3, + -2, -2, -2, -1, -1, 0, 2, 4, 0, 0, 0, 0, -1, -1, 0, 1, + 0, -1, -1, -1, -1, -1, 0, 0, 6, 4, 2, 0, -1, -2, -1, -1, + 0, 1, 1, 1, 1, -1, -5,-10, 1, 1, 1, 1, 1, 1, 0, -4, + 1, 0, 1, 1, 1, 1, 1, -1, 2, 1, 1, 1, 0, 0, 0, 0, + -3, 1, 4, 3, 3, 1, -1, 0, -4, 0, 1, 0, -1, 0, 0, 0, + -5, 0, 2, 1, 1, 1, 0, -1, -1, 2, 1, -2, -2, -1, 0, -1, + 2, 4, 5, 3, 0, -1, 1, 2, 0, 0, 1, 0, -2, -2, -1, -1, + -2, -2, -2, -2, -3, -2, -1, 0, 0, 0, 1, 0, 0, 0, 1, 2, + 0, -2, -2, -3, -1, 2, 2, -1, 1, 0, 0, 0, 1, 5, 3, -2, + -1, -1, 0, -1, 0, 2, 0, -5, -1, 0, 1, 0, 0, 2, 2, -2, + 3, 1, -1, -1, 0, 1, 1, 2, 1, 0, 0, 1, 1, 1, 1, 1, + -10, -8, -2, 1, 2, 1, 1, 1, -1, 1, 2, 1, 0, 0, 0, 0, + -1, -1, 0, 1, 2, 2, 2, 1, -1, -1, -1, 0, -1, -3, -5, -4, + 1, 1, 2, 1, 1, 0, 0, 2, -1, -2, -1, -1, -1, 0, 2, 4, + -3, -7, -5, 0, 2, 0, 0, 0, 3, -1, -2, 1, 2, 1, 1, 2, + 1, -2, -1, 1, 2, 1, 0, 1, 0, -1, 0, 3, 2, -1, -1, -1, + 2, 1, 1, 0, 0, 0, 0, 0, -9, -7, -2, 3, 3, 2, 1, 1, + 3, 2, 0, -2, -2, -1, 1, 1, 0, -1, 0, 0, 1, 1, 0, 0, + -2, -1, 1, 1, 1, 0, 0, 0, 1, 2, 1, -2, -4, -3, 1, 2, + 1, 2, 1, -2, -3, 0, 3, 1, -1, -1, 0, 0, 1, 3, 0, -4, + 2, 0, -1, 1, 2, -2, -2, 3, 2, 0, -1, 2, 3, -2, -4, 1, + 0, 1, 1, 1, 2, -2, -6, -2, -1, 0, 0, 0, 2, 0, -2, -1, + -1, -1, 1, 2, 1, -2, -3, -2, 3, -1, -2, -1, -1, 0, 1, 2, + 10, 4, 0, 0, -1, -2, -2, -1, 3, -1, -2, -1, 0, -1, -1, 0, + -5, 2, 7, 1, -4, -2, 1, 0, -2, 2, 3, -1, -3, 0, 2, 0, + 2, 1, 0, 0, 1, 1, -1, -2, 1, -2, -2, -1, -1, -2, 0, 0, + 0, 3, -2, -7, -1, 3, 0, 0, 1, 3, -3, -5, 2, 3, -1, 0, + 0, 2, -2, -2, 4, 2, -2, 0, -1, 1, -1, 0, 2, -1, -2, 1, + 4, 0, -3, -4, -2, 1, 2, 1, 0, 0, 3, 5, 3, 1, -1, -2, + 1, 1, 1, -1, -3, -1, 1, 1, 1, -1, -2, -2, 0, 0, -1, -2 }; -static const uint32 s_svq1IntraCodebook8x8[1536] = { - 0x02030404, 0xff000102, 0x02030304, 0xffff0001, - 0x02020303, 0xfeff0001, 0x01020203, 0xfdfeff00, - 0x00010202, 0xfdfeffff, 0x00000102, 0xfcfdfeff, - 0xff000001, 0xfcfcfdfe, 0xfeff0000, 0xfcfcfdfe, - 0x03030302, 0x03030303, 0x02020202, 0x03030202, - 0x02020201, 0x02020202, 0x01010100, 0x01010101, - 0x000000ff, 0x01010000, 0xfffffefe, 0xffffffff, - 0xfdfdfdfd, 0xfefefdfd, 0xfcfcfcfb, 0xfdfcfcfc, - 0x00fffefc, 0x03020201, 0x00fffefc, 0x03030201, - 0x00fffdfc, 0x03030201, 0x00fffdfc, 0x03030201, - 0x00fffdfb, 0x03030201, 0x00fffdfb, 0x03030201, - 0x00fffdfb, 0x03020101, 0xfffefdfb, 0x03020100, - 0x05050404, 0x07070606, 0x03020202, 0x04040403, - 0x00000000, 0x02010101, 0xfefefefe, 0x00ffffff, - 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe, - 0xfefefeff, 0xfefefefe, 0xffffffff, 0xfefefefe, - 0xff010305, 0xfdfdfdfe, 0xff010305, 0xfdfdfdfe, - 0xff010305, 0xfdfdfdfe, 0xff010305, 0xfdfdfdfe, - 0x00010405, 0xfdfdfdfe, 0x00020406, 0xfdfdfefe, - 0x00020406, 0xfdfefeff, 0x01020406, 0xfefefeff, - 0x030301ff, 0xfafd0002, 0x040301ff, 0xfafd0003, - 0x040401ff, 0xfafd0103, 0x040301ff, 0xfafd0103, - 0x040301fe, 0xfafd0103, 0x040301fe, 0xf9fd0103, - 0x030301fe, 0xf9fd0002, 0x030200fe, 0xfafd0002, - 0x0608090a, 0x04040506, 0x03040506, 0x01020202, - 0xff000102, 0xfffefefe, 0xfcfdfeff, 0xfdfcfcfc, - 0xfcfcfdfe, 0xfdfcfcfb, 0xfdfdfefe, 0xfefefdfd, - 0xffffffff, 0x00ffffff, 0x01010101, 0x02010101, - 0x0201fffe, 0x08070504, 0x0100fefd, 0x08070503, - 0x00fffdfc, 0x07060402, 0xfffefcfb, 0x07050301, - 0xfefdfbfa, 0x06040200, 0xfefcfbfa, 0x050301ff, - 0xfdfbfaf9, 0x030200fe, 0xfcfbf9f8, 0x0201fffd, - 0x0507090b, 0xffff0103, 0x0306080a, 0xfefe0001, - 0x02050709, 0xfcfdfe00, 0x01030608, 0xfcfcfdff, - 0xff020406, 0xfbfbfcfd, 0xfe000305, 0xfafafbfc, - 0xfdff0103, 0xf9f9fafb, 0xfcfe0002, 0xf9f9fafa, - 0x07070605, 0x08080807, 0x05050403, 0x06060606, - 0x03020200, 0x05040404, 0x0100fffe, 0x03030202, - 0xfffefdfc, 0x02010100, 0xfdfcfbfa, 0x00fffefe, - 0xfafaf9f8, 0xfdfdfcfb, 0xf8f8f7f6, 0xfbfafaf9, - 0x01030506, 0xf8fafdff, 0x02040506, 0xf8fafdff, - 0x02040506, 0xf8fafd00, 0x02040506, 0xf8fafd00, - 0x02040606, 0xf8fafd00, 0x02040506, 0xf8fafd00, - 0x02040506, 0xf8fafd00, 0x02040506, 0xf8fbfdff, - 0x08090a0b, 0x04050607, 0x06070808, 0x02030405, - 0x04040506, 0x00010202, 0x01020303, 0xfeff0000, - 0xff000101, 0xfdfdfefe, 0xfdfeffff, 0xfbfbfcfc, - 0xfbfcfcfd, 0xf9f9fafa, 0xf9fafbfb, 0xf8f8f8f8, - 0xf5f4f3f2, 0xfcfaf9f7, 0xf7f6f5f4, 0xfffdfbf9, - 0xfaf9f7f6, 0x0200fefd, 0xfefcfaf8, 0x05040200, - 0x0200fdfb, 0x08070504, 0x040200fe, 0x0a090806, - 0x07050300, 0x0c0b0a08, 0x08070503, 0x0c0c0b0a, - 0xeeeeeded, 0xf2f1f0ef, 0xf3f2f1f1, 0xf7f6f5f4, - 0xf8f7f6f5, 0xfdfcfbfa, 0xfefdfbfa, 0x020100ff, - 0x030200ff, 0x06060504, 0x08070604, 0x0a0a0a09, - 0x0c0b0a09, 0x0e0e0e0d, 0x0f0e0e0c, 0x10101010, - 0x11131516, 0x05090b0e, 0x0e111314, 0x0104080b, - 0x0a0d0f11, 0xfc000306, 0x05080b0d, 0xf7fbfe01, - 0xff030609, 0xf3f5f9fc, 0xfafd0004, 0xeff1f4f7, - 0xf5f8fbfe, 0xeceef0f2, 0xf0f3f6f8, 0xeaebedef, - 0x12121211, 0x0e101011, 0x0f0f1010, 0x0b0c0d0e, - 0x0a0b0c0c, 0x05070809, 0x04060607, 0xff010203, - 0xfeff0001, 0xfafbfcfd, 0xf8f9fafb, 0xf4f5f6f7, - 0xf2f3f4f5, 0xeff0f0f1, 0xeeefeff0, 0xecececed, - 0x00000000, 0xfdfeffff, 0x00000001, 0xfdfeff00, - 0x00000101, 0xfefeffff, 0x00010101, 0xfeffff00, - 0x01010102, 0xfeffff00, 0x01010202, 0xfeff0000, - 0x01010202, 0xffff0001, 0x01010202, 0xfe000001, - 0x00ffff00, 0x03020100, 0x00ffff00, 0x02020101, - 0xffffffff, 0x02020100, 0xfffeffff, 0x02010100, - 0xfffefeff, 0x02010000, 0xfefefeff, 0x020100ff, - 0xfffeffff, 0x02010000, 0xffffffff, 0x02010100, - 0x02020203, 0x00000101, 0x02020203, 0x00000102, - 0x01020202, 0x00000101, 0x01010202, 0xff000001, - 0x00010101, 0xffff0000, 0xffff0000, 0xffffffff, - 0xfefefefe, 0xfefefefe, 0xfdfdfdfe, 0xfefefefe, - 0x00000205, 0x000000ff, 0xff000204, 0xff00ffff, - 0xffff0104, 0xfffffffe, 0xffff0104, 0xfffffffe, - 0xfeff0104, 0xfffffffe, 0xfeff0104, 0xfffffffe, - 0xffff0104, 0xffffffff, 0xff000204, 0xff000000, - 0x0100fffe, 0x01010101, 0x0100fffd, 0x01010101, - 0x0100fffd, 0x01010101, 0x0100fffd, 0x01010101, - 0x0100fefd, 0x01010202, 0x0100fefc, 0x02020202, - 0x01fffdfb, 0x02010201, 0x00fefdfb, 0x01010101, - 0x00010303, 0xfbfcfcfe, 0x00020303, 0xfcfdfeff, - 0x01010202, 0xfefeff00, 0x01010101, 0x00000001, - 0x01000000, 0x01010101, 0x00fffffe, 0x02020100, - 0xfffefefd, 0x03020100, 0xfffefdfd, 0x03020100, - 0xfdfdfdfd, 0xfefefefd, 0xfefefdfd, 0xfffffffe, - 0xfffefefe, 0xffffffff, 0x00ffffff, 0x00000000, - 0x00000000, 0x01010101, 0x01010000, 0x02020202, - 0x02010101, 0x03030302, 0x02020202, 0x03030303, - 0xfdfbf9f8, 0xff00fffe, 0x00fffdfc, 0x01010201, - 0x030201ff, 0x01020203, 0x03030201, 0x00010202, - 0x02030302, 0xff000001, 0x00010201, 0xffffffff, - 0xff000101, 0xfffefeff, 0x00000101, 0xff00ffff, - 0x00fefdfc, 0x03030201, 0x00fefdfc, 0x02020201, - 0xfffefdfd, 0x01010100, 0xfffefefe, 0x000000ff, - 0xffffff00, 0xffffffff, 0x00010102, 0xfeffff00, - 0x01030303, 0xfefeff00, 0x02040405, 0xfeff0001, - 0x00000000, 0x03030201, 0x0000ff00, 0x03030201, - 0x0000ff00, 0x02030201, 0x01000000, 0x02020201, - 0x01010102, 0x00010101, 0x01020202, 0xfeff0000, - 0x00000102, 0xfafbfdfe, 0xfdffff00, 0xf7f8fafb, - 0x020100fe, 0xfcff0102, 0x020200fe, 0xfcff0102, - 0x020200fe, 0xfdff0102, 0x020200fe, 0xfdff0102, - 0x0202fffe, 0xfdff0102, 0x0201fffe, 0xfdff0102, - 0x0201fffd, 0xfdff0102, 0x0201fffe, 0xfdff0102, - 0xff0101ff, 0x0400fdfd, 0xff0101ff, 0x0400fdfd, - 0x000101ff, 0x0400fdfd, 0x000201ff, 0x0500fdfd, - 0x00020100, 0x0400fcfd, 0x00020100, 0x0500fcfd, - 0x00020100, 0x0400fdfd, 0xff020100, 0x0400fefe, - 0x06050606, 0x05050505, 0x02020202, 0x02020202, - 0x00000000, 0x00000000, 0xffffffff, 0xfefefefe, - 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe, - 0xfffeffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x02020202, 0x02020202, 0x00010100, 0x00000000, - 0xfefefeff, 0xfffefefe, 0xfdfdfdfd, 0xfefdfdfd, - 0xfdfcfcfd, 0xfefefdfd, 0xfefefefe, 0x0000ffff, - 0x01010100, 0x03030202, 0x05040403, 0x06060605, - 0xfdfe0104, 0x0301fffd, 0xfcfe0104, 0x0301fffd, - 0xfcfe0105, 0x0401fffd, 0xfdfe0105, 0x0402fffd, - 0xfdfe0105, 0x0402fffd, 0xfcfd0004, 0x0402fffd, - 0xfdfd0004, 0x0301fffd, 0xfdfe0003, 0x0301fffe, - 0xfcfcfcfd, 0xfcfcfcfc, 0xffffffff, 0xfefeffff, - 0x02010102, 0x01010102, 0x04030303, 0x03030304, - 0x04030303, 0x03030404, 0x02010201, 0x02020202, - 0xfffefefe, 0x0000ffff, 0xfcfcfcfc, 0xfdfdfdfd, - 0xfdfdfeff, 0x00fffefe, 0xfefeff00, 0x0100fffe, - 0xffff0102, 0x0100ffff, 0xff000103, 0x010000ff, - 0xff000203, 0x01000000, 0xff000103, 0x01000000, - 0xff000103, 0x01000000, 0x00000102, 0x01000000, - 0x01000000, 0x04030201, 0x00ff0000, 0x03020000, - 0xffffff00, 0x0100ffff, 0xffffff00, 0x00ffffff, - 0xffff0000, 0xfffefeff, 0xff000001, 0xfffefeff, - 0x00010202, 0xffffffff, 0x01020303, 0x00ffff00, - 0x00010001, 0xfffeff00, 0x00000000, 0xfffeffff, - 0x0000ff00, 0xffffffff, 0x00ffffff, 0x00000000, - 0x00ffffff, 0x01010000, 0x00ffffff, 0x03020101, - 0x00fffefe, 0x04030201, 0x00fffefe, 0x05040201, - 0x0001fffd, 0x0100ff00, 0x000100fd, 0x0200ffff, - 0x000100fd, 0x0200ffff, 0x000201fe, 0x0200ffff, - 0x000201fe, 0x0200ffff, 0x000201fe, 0x0200ffff, - 0x000202ff, 0x0200ffff, 0x000101ff, 0x01ffffff, - 0x01fffefe, 0x01030403, 0x00fffefe, 0x00020302, - 0x00fffefe, 0xff010201, 0x00ffffff, 0xff010201, - 0x00ffffff, 0xfe000101, 0x00ffff00, 0xff000101, - 0x00ffff00, 0xff010101, 0x00ffff00, 0xff000100, - 0x0100fffe, 0x01010101, 0x0000fffe, 0x00000000, - 0x00fffffe, 0xfefeffff, 0xfffffffe, 0xfdfefeff, - 0x010100ff, 0xfefeff00, 0x03030201, 0x00000102, - 0x03030201, 0x00010203, 0x01010000, 0x00000101, - 0xffffff00, 0x00000000, 0x00000001, 0x01010000, - 0x01010101, 0x01010101, 0x02020101, 0x01010101, - 0x01010101, 0x01010101, 0x010000ff, 0x00000001, - 0xfffffefd, 0xff00ffff, 0xfdfcfbfb, 0xfffefefe, - 0x01010101, 0xff000102, 0x02010101, 0xff000101, - 0x01010101, 0xfe000101, 0x01010102, 0xfe000101, - 0x00000101, 0xfdff0000, 0x00000101, 0xfdfeff00, - 0x00000101, 0xfcfeffff, 0xff000001, 0xfcfdfefe, - 0x03050708, 0x01010102, 0x00000102, 0xfffeffff, - 0xfeffffff, 0xfffefefe, 0xffffffff, 0x00ffff00, - 0x01000000, 0x00000001, 0x01010000, 0x00000001, - 0x000000ff, 0xffff0000, 0xfffffefe, 0xfffefeff, - 0xfe000409, 0xfffffefe, 0xfeff0207, 0x0000fffe, - 0xfefe0004, 0x010100ff, 0xfefefe01, 0x010100ff, - 0xfffefeff, 0x01010100, 0x00fffeff, 0x00010101, - 0x0100ffff, 0xff000101, 0x0100ff00, 0xffff0000, - 0x01010100, 0x00000101, 0x02020201, 0x00000001, - 0x02020202, 0xffff0001, 0x00010101, 0xfefefeff, - 0xff000000, 0xfefefdfe, 0xfeffffff, 0x00fffefe, - 0xffffffff, 0x02010000, 0x00ffffff, 0x04030201, - 0x0000ffff, 0xfdfdfeff, 0x0000ffff, 0xffffff00, - 0x00fffefe, 0x01010101, 0x00fefefe, 0x03030201, - 0x00ffffff, 0x03030301, 0x00000001, 0x02020101, - 0x00010202, 0xffffff00, 0x00010203, 0xfdfdfeff, - 0xfeffffff, 0xfbfcfdfe, 0xff000000, 0xfcfdfdff, - 0x00010101, 0xfdfeff00, 0x01020202, 0xffff0001, - 0x02020202, 0xff000101, 0x02020202, 0x00000102, - 0x01020101, 0x00000101, 0x01010000, 0xff000000, - 0x010302fe, 0xff0101ff, 0x000302fd, 0xff0101ff, - 0x000302fd, 0xff0101ff, 0x000302fc, 0xfe0101ff, - 0x000301fc, 0xfe0101ff, 0xff0301fc, 0xfe0101fe, - 0x000201fd, 0xfe0101ff, 0x000201fd, 0xff0101ff, - 0xfeffffff, 0xfefefefe, 0x01010101, 0x00000000, - 0x02020201, 0x02020202, 0x01010000, 0x02020201, - 0xfffffefe, 0x000000ff, 0xfdfdfdfd, 0xfefdfdfd, - 0xffffffff, 0xfefefefe, 0x04040404, 0x02030304, - 0xfffefdfd, 0x05020100, 0xfefdfdfd, 0x060301ff, - 0xfefefdfd, 0x05030200, 0xfefefefd, 0x05030100, - 0xfffefefe, 0x050301ff, 0xfffffefe, 0x04020100, - 0xffffffff, 0x04010100, 0xffffffff, 0x03020100, - 0x0100ff00, 0xffff0001, 0x01000000, 0xffff0002, - 0x00ff0001, 0x00000001, 0xfffeff01, 0x00000000, - 0xfffdfe01, 0x01000000, 0xfefdff01, 0x02010100, - 0xfffeff01, 0x02010100, 0x00ff0002, 0x02020101, - 0x01010101, 0x02010000, 0xff0000ff, 0x01000000, - 0xfffffefd, 0x010100ff, 0x00fffefc, 0x01010100, - 0x0000fefd, 0x01010101, 0x0100fffd, 0x00000101, - 0x010100ff, 0xff000001, 0x02020100, 0xff000001, - 0xfdfcfcfc, 0xfffffffe, 0xfffefefe, 0x00000000, - 0x000000ff, 0x01010101, 0x01010000, 0x01010101, - 0x01010000, 0x00010202, 0x01010000, 0x00010101, - 0x01000000, 0x00010101, 0x010000ff, 0x00000101, - 0x02020201, 0xfcfeff01, 0x02020101, 0xfcfe0001, - 0x01010100, 0xfdff0001, 0x010100ff, 0xfeff0000, - 0x010100ff, 0xff000001, 0x0000fffe, 0xff000000, - 0x0100ffff, 0x00000001, 0x010100ff, 0x00010101, - 0xff000202, 0xfefffffe, 0xfeff0101, 0xfefffffe, - 0xfeff0101, 0xff0000fe, 0xfe000101, 0x000101ff, - 0xff000101, 0x010201ff, 0xff000101, 0x010201ff, - 0xff000101, 0x010101ff, 0xff000101, 0x01010100, - 0xfeff0000, 0xfcfcfcfc, 0x02030303, 0x00000001, - 0x03030303, 0x02020202, 0x00000000, 0x01000000, - 0xffffffff, 0x00ffffff, 0x0000ff00, 0x000000ff, - 0x00000000, 0x00000000, 0x00000000, 0x00ffff00, - 0xff00ffff, 0xff0201ff, 0x00000101, 0xff030200, - 0xff000101, 0xff0301ff, 0xfe000101, 0xfe0100fe, - 0xfe000001, 0xfd0100fe, 0x00000000, 0xfd0101ff, - 0x00010100, 0xfd010201, 0x010100ff, 0xfc010201, - 0x0100fdfc, 0x00000101, 0x0100fefc, 0xff000101, - 0x0101fffd, 0xffff0001, 0x010101ff, 0x00ff0001, - 0x01020201, 0x0000ff00, 0x00010202, 0x0100ffff, - 0xff000102, 0x0100fffe, 0xff000202, 0x0101fffe, - 0x00000101, 0xffffffff, 0xffffff00, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffff0000, 0xffffffff, - 0xff000001, 0xffffffff, 0x00000102, 0xffffffff, - 0x01020305, 0x00000000, 0x02030506, 0x00000001, - 0x01030404, 0x01000000, 0x01020303, 0x01000000, - 0x00010202, 0x0100ffff, 0xff000000, 0x0100ffff, - 0xffff0000, 0x0200fffe, 0xfeffff00, 0x0100fefe, - 0xfeffff00, 0x00fffefe, 0xfeff0000, 0x00fffefe, - 0xffff0000, 0x030200ff, 0xfefeff00, 0x0201ffff, - 0xffff0001, 0x000000ff, 0x00010101, 0xffff0000, - 0x00010201, 0xffffff00, 0x000000ff, 0xffffffff, - 0xfffffefd, 0x02010100, 0x01fffdfc, 0x05050302, - 0x00000000, 0x00000000, 0x01010101, 0x01010101, - 0xff000000, 0x01000000, 0xfefeffff, 0x00fffffe, - 0x00000000, 0x01010100, 0x02020202, 0x03030302, - 0x01010101, 0x01010202, 0xfcfcfdfc, 0xfdfdfcfc, - 0x020100ff, 0x03030302, 0xffffffff, 0x00000000, - 0xfeff0000, 0xfefdfdfe, 0x00010203, 0xfefefeff, - 0x01020304, 0x00000001, 0x01010202, 0x01010100, - 0xffffff00, 0x010000ff, 0xfefefefe, 0x0000fffe, - 0x0200ff01, 0x01fffe01, 0x0200ff01, 0x01fefe01, - 0x0300ff01, 0x01fffe02, 0x0300fe00, 0x01fefe02, - 0x0300fe00, 0x01fefe02, 0x0300fe00, 0x01fffe01, - 0x0200fe00, 0x01fefe01, 0x0200ff00, 0x01fffe01, - 0x02020100, 0x02020303, 0x02010100, 0x01020303, - 0x02010000, 0x01020202, 0x010000ff, 0x01010101, - 0x0000ffff, 0x00000000, 0xffffffff, 0xffffffff, - 0xfefefefe, 0xfffefefe, 0xfefefefe, 0xfffefefe, - 0xfeff0000, 0x050300ff, 0xffff0000, 0x040200ff, - 0x00000101, 0x0201ffff, 0x01010201, 0x00ffff00, - 0x01020100, 0xfefeff00, 0x020100ff, 0xfdfd0001, - 0x0201fffe, 0xfcfe0002, 0x0200fffe, 0xfdff0102, - 0x00000000, 0xffff0000, 0x00ff0000, 0x00000000, - 0xffffffff, 0x00000000, 0xffffffff, 0x00ffffff, - 0xffffffff, 0x00ffffff, 0x000000ff, 0x00ffff00, - 0x01010000, 0x01000000, 0x04030303, 0x03030303, - 0xfefe0105, 0xff000000, 0xfffdff04, 0xff000000, - 0x00ffff03, 0xff000101, 0x01000002, 0xfe000101, - 0x01000001, 0xfe000101, 0xffffff00, 0xff000000, - 0xffffff00, 0xff0000ff, 0x00000102, 0x00000100, - 0x01010001, 0x00000101, 0x01000001, 0x00000001, - 0x00ffff01, 0x00000000, 0xffff0002, 0x00ffffff, - 0xffff0103, 0xfffefefe, 0x00010204, 0xfffefeff, - 0x00000102, 0x0000ffff, 0xffffff00, 0x010100ff, - 0x02020100, 0xfdff0102, 0x01010000, 0xfeff0001, - 0x00000000, 0xffff0000, 0x00ff0000, 0x00010100, - 0x00ff0000, 0x01010101, 0x00000000, 0x00010101, - 0x01010000, 0xfdff0102, 0x01000000, 0xfbfcff01, - 0xfffefefe, 0x02020200, 0x00000000, 0x00010101, - 0x01010101, 0xfdfe0001, 0x01010000, 0xfcfdff00, - 0x0100ffff, 0xfdfe0000, 0x0100ffff, 0xff000101, - 0x01000000, 0x00010101, 0x01010101, 0x00000000, - 0x00000100, 0x02010101, 0x00000201, 0x01ff0000, - 0xff000200, 0x00ff0001, 0x00000100, 0x01000102, - 0x00ff0100, 0x01000202, 0xffff00ff, 0x02010102, - 0xfefdfefe, 0x01010100, 0xfdfdfefe, 0x00ffffff, - 0x0100fffd, 0x00010102, 0x0100fffd, 0x01010102, - 0x010000fe, 0x01010101, 0x000000ff, 0x00000000, - 0x000000fe, 0x00ffff00, 0x000000fe, 0xffff0000, - 0x010100fd, 0x01000101, 0x0100fefb, 0x02010202, - 0x00fffffe, 0x03020100, 0x01010000, 0x02010000, - 0x00010000, 0x0100ffff, 0xffffffff, 0x00fffefe, - 0xfefefefe, 0x0100fffe, 0xff000000, 0x02020100, - 0x00000102, 0x02020100, 0xff000102, 0x0000ffff, - 0x01010100, 0xfcff0101, 0x0100ffff, 0xfd000101, - 0x0000fffe, 0xfe020201, 0x000000ff, 0xff030200, - 0x000000ff, 0x00020100, 0xfeff0000, 0x000101ff, - 0xfeff0000, 0x010200fe, 0xfeff0000, 0x020201ff, - 0x00000001, 0xfdfefdfe, 0x00010000, 0xfffffefe, - 0x0101ff00, 0x0000ffff, 0x0101ff00, 0x0000ffff, - 0x01020100, 0x0100ffff, 0x02030201, 0x02010000, - 0x010200ff, 0x03020000, 0x0000fffe, 0x020100ff, - 0xff000101, 0x01fffefe, 0xff010101, 0x0200fefe, - 0xff010101, 0x0200ffff, 0x00000000, 0x02010000, - 0x00ffffff, 0x02010000, 0x01fffeff, 0x00000101, - 0x01fffeff, 0xff000202, 0x02fffeff, 0xff000202, - 0xfeffffff, 0x0100ffff, 0xffff0000, 0x020100ff, - 0x00000001, 0x02010100, 0x00000101, 0x01010101, - 0x01000101, 0x01010001, 0x01010101, 0xffffff00, - 0x00010201, 0xfdfefeff, 0x00010202, 0xfcfcfdfe, - 0x0101fefc, 0x00000101, 0x000100fe, 0x00000000, - 0xfe010100, 0x0100fffe, 0xfe010202, 0x0201fffe, - 0xfe010201, 0x0201fffe, 0xff0101ff, 0x0100ffff, - 0x010100fe, 0x00ffff00, 0x020200fe, 0x00ffff01, - 0x00000101, 0x00000100, 0xfefdfdfe, 0x0000fffe, - 0xfefdfcfd, 0x000000ff, 0x0100ffff, 0x01020302, - 0x03020100, 0x01020303, 0x02010101, 0xff000001, - 0x00000000, 0xffffffff, 0x00ffff00, 0x00000000, - 0x00000101, 0x0200ffff, 0x00010000, 0x0101ffff, - 0x0100fffe, 0x01010101, 0x0200fdfd, 0x00010102, - 0x0100fefe, 0x00000101, 0x00000001, 0xffff0000, - 0xfdff0103, 0x0100fffe, 0xfdff0204, 0x0201fffd, - 0xff000000, 0xffffffff, 0x00010201, 0xffff0000, - 0x02030302, 0xffff0001, 0x02040403, 0xfeff0001, - 0x01020303, 0xfefeff00, 0xff000101, 0xfdfefeff, - 0xff000000, 0xfefefeff, 0xffffffff, 0xfffefeff, - 0x02020201, 0x02020102, 0x01010100, 0x00000001, - 0x01000000, 0xfeff0001, 0x00000000, 0xfcff0001, - 0x00000001, 0xfbfe0000, 0x00000001, 0xfcff0000, - 0x00ff0001, 0xfdff0000, 0x00ffff00, 0xff010101, - 0x0000fffe, 0xfeffffff, 0x000000ff, 0xfefeffff, - 0x00010100, 0xfeffffff, 0x00010100, 0xffff0000, - 0x00000100, 0x00010101, 0x00000101, 0x01020201, - 0x00000101, 0x01020201, 0xff000101, 0x00010100, - 0x00010204, 0x01010100, 0x00010204, 0x01000000, - 0x00000103, 0x00ffffff, 0xff000001, 0x00fffeff, - 0x00000000, 0x00ffffff, 0x0000ffff, 0x0100ffff, - 0xff00fffe, 0x010000ff, 0xfefffefe, 0x010000ff, - 0x01010100, 0xff000102, 0x00ffffff, 0xfefeff00, - 0x00ff00ff, 0xfffeff00, 0x00000000, 0x02010000, - 0x00000000, 0x03020000, 0xffff00ff, 0x0300ffff, - 0xff0000ff, 0x0300feff, 0x00000000, 0x0401ffff, - 0x00000202, 0x01000000, 0xfeff0101, 0x01fffeff, - 0xfefeffff, 0x00fefdfe, 0xffff00ff, 0x01fffeff, - 0x00000101, 0x01000001, 0x00000202, 0x01000001, - 0x00000202, 0xffff0000, 0x00000202, 0xffff0001, - 0x010100ff, 0xffffff00, 0x02030201, 0x00000001, - 0x01010100, 0x0000ff00, 0x00fffefe, 0x00000001, - 0x02fffefe, 0x00010202, 0x0100fffe, 0xff000001, - 0x0000ffff, 0xfefffeff, 0x01010100, 0x01010000, - 0xfefdfdfd, 0xfefeffff, 0x0100ffff, 0x00000102, - 0x02010101, 0x00000102, 0x01010101, 0x01ff0001, - 0xffff0001, 0x01ff0000, 0xffffff00, 0x01ffff00, - 0x00ff0001, 0x0200ff00, 0x00ff0002, 0x02000000, - 0xfffe0001, 0x00010100, 0xffff0002, 0x00010100, - 0xfffe0001, 0xff000100, 0xffff0001, 0xff000100, - 0x00010100, 0x00000101, 0x010201fe, 0x01000000, - 0x010200fb, 0x0100ff00, 0x0102fffa, 0x0000ff00, - 0xff000305, 0xfffffffe, 0xff000101, 0xffff00ff, - 0x010100ff, 0x00010202, 0x0100fffe, 0x01010102, - 0xfffffffe, 0x0100ff00, 0x00000100, 0x0000ffff, - 0x01010100, 0x00000001, 0x0100fefd, 0xff000001, - 0x000100ff, 0x030200ff, 0xfe0000ff, 0x00fffefc, - 0x00010100, 0xff00fffe, 0x01030201, 0x00010100, - 0x010100ff, 0x00010101, 0x00fefdfe, 0x00010000, - 0x00fefeff, 0xff000001, 0x00000103, 0xffff0001, - 0x0000fffe, 0x0000ffff, 0x000000ff, 0x01010100, - 0x00ffffff, 0x01010101, 0xfffdfe00, 0x00000001, - 0xfffdff01, 0xff000101, 0x01ff0103, 0xff000202, - 0x01000103, 0x00010102, 0xfffefe00, 0x000000ff, - 0xffff0001, 0x00010201, 0xfffeff00, 0x01020201, - 0x00ffffff, 0x00020100, 0x000000fe, 0xff010000, - 0x000100ff, 0xffffffff, 0x02010100, 0x00fffe00, - 0x02020201, 0x00ffff01, 0x01010100, 0xfffefe00, - 0xffff0000, 0xfefeffff, 0x00ff0000, 0x01020201, - 0xffff0000, 0x02020100, 0xfeff0101, 0xffffffff, - 0x00010202, 0xfefeff00, 0x01020201, 0xfefe0000, - 0x00000000, 0xff000101, 0xffffff00, 0x01020302, - 0x0201fe00, 0x010000ff, 0x0302feff, 0x000000ff, - 0x0302fe00, 0x0000ffff, 0x0203ff00, 0x000100fe, - 0x0103ff00, 0x000100fe, 0x0102ff00, 0xff0001ff, - 0xff010000, 0xff0000fe, 0xfe000001, 0xfffffffe, - 0x01010101, 0xfeffff01, 0x01000000, 0x01010101, - 0x01000000, 0x03020101, 0xff000001, 0x02010000, - 0xfeffff00, 0x020100ff, 0xfefefefe, 0x010100ff, - 0xffffffff, 0xff000000, 0x00020202, 0xfcfeffff, - 0xfffffeff, 0x03020100, 0xffffffff, 0x03020100, - 0x00ff0001, 0x020100ff, 0x00000001, 0x020200ff, - 0xffff0001, 0x020100fe, 0xfefefe00, 0x0100fffd, - 0xfefefe00, 0x0101fffe, 0x00000000, 0x02020100 +static const int8 s_svq1IntraCodebook8x8[6144] = { + 4, 4, 3, 2, 2, 1, 0, -1, 4, 3, 3, 2, 1, 0, -1, -1, + 3, 3, 2, 2, 1, 0, -1, -2, 3, 2, 2, 1, 0, -1, -2, -3, + 2, 2, 1, 0, -1, -1, -2, -3, 2, 1, 0, 0, -1, -2, -3, -4, + 1, 0, 0, -1, -2, -3, -4, -4, 0, 0, -1, -2, -2, -3, -4, -4, + 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, + 1, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1, 1, + -1, 0, 0, 0, 0, 0, 1, 1, -2, -2, -1, -1, -1, -1, -1, -1, + -3, -3, -3, -3, -3, -3, -2, -2, -5, -4, -4, -4, -4, -4, -4, -3, + -4, -2, -1, 0, 1, 2, 2, 3, -4, -2, -1, 0, 1, 2, 3, 3, + -4, -3, -1, 0, 1, 2, 3, 3, -4, -3, -1, 0, 1, 2, 3, 3, + -5, -3, -1, 0, 1, 2, 3, 3, -5, -3, -1, 0, 1, 2, 3, 3, + -5, -3, -1, 0, 1, 1, 2, 3, -5, -3, -2, -1, 0, 1, 2, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 2, 2, 2, 3, 3, 4, 4, 4, + 0, 0, 0, 0, 1, 1, 1, 2, -2, -2, -2, -2, -1, -1, -1, 0, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -1, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -2, -2, -2, -2, + 5, 3, 1, -1, -2, -3, -3, -3, 5, 3, 1, -1, -2, -3, -3, -3, + 5, 3, 1, -1, -2, -3, -3, -3, 5, 3, 1, -1, -2, -3, -3, -3, + 5, 4, 1, 0, -2, -3, -3, -3, 6, 4, 2, 0, -2, -2, -3, -3, + 6, 4, 2, 0, -1, -2, -2, -3, 6, 4, 2, 1, -1, -2, -2, -2, + -1, 1, 3, 3, 2, 0, -3, -6, -1, 1, 3, 4, 3, 0, -3, -6, + -1, 1, 4, 4, 3, 1, -3, -6, -1, 1, 3, 4, 3, 1, -3, -6, + -2, 1, 3, 4, 3, 1, -3, -6, -2, 1, 3, 4, 3, 1, -3, -7, + -2, 1, 3, 3, 2, 0, -3, -7, -2, 0, 2, 3, 2, 0, -3, -6, + 10, 9, 8, 6, 6, 5, 4, 4, 6, 5, 4, 3, 2, 2, 2, 1, + 2, 1, 0, -1, -2, -2, -2, -1, -1, -2, -3, -4, -4, -4, -4, -3, + -2, -3, -4, -4, -5, -4, -4, -3, -2, -2, -3, -3, -3, -3, -2, -2, + -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1, 2, + -2, -1, 1, 2, 4, 5, 7, 8, -3, -2, 0, 1, 3, 5, 7, 8, + -4, -3, -1, 0, 2, 4, 6, 7, -5, -4, -2, -1, 1, 3, 5, 7, + -6, -5, -3, -2, 0, 2, 4, 6, -6, -5, -4, -2, -1, 1, 3, 5, + -7, -6, -5, -3, -2, 0, 2, 3, -8, -7, -5, -4, -3, -1, 1, 2, + 11, 9, 7, 5, 3, 1, -1, -1, 10, 8, 6, 3, 1, 0, -2, -2, + 9, 7, 5, 2, 0, -2, -3, -4, 8, 6, 3, 1, -1, -3, -4, -4, + 6, 4, 2, -1, -3, -4, -5, -5, 5, 3, 0, -2, -4, -5, -6, -6, + 3, 1, -1, -3, -5, -6, -7, -7, 2, 0, -2, -4, -6, -6, -7, -7, + 5, 6, 7, 7, 7, 8, 8, 8, 3, 4, 5, 5, 6, 6, 6, 6, + 0, 2, 2, 3, 4, 4, 4, 5, -2, -1, 0, 1, 2, 2, 3, 3, + -4, -3, -2, -1, 0, 1, 1, 2, -6, -5, -4, -3, -2, -2, -1, 0, + -8, -7, -6, -6, -5, -4, -3, -3,-10, -9, -8, -8, -7, -6, -6, -5, + 6, 5, 3, 1, -1, -3, -6, -8, 6, 5, 4, 2, -1, -3, -6, -8, + 6, 5, 4, 2, 0, -3, -6, -8, 6, 5, 4, 2, 0, -3, -6, -8, + 6, 6, 4, 2, 0, -3, -6, -8, 6, 5, 4, 2, 0, -3, -6, -8, + 6, 5, 4, 2, 0, -3, -6, -8, 6, 5, 4, 2, -1, -3, -5, -8, + 11, 10, 9, 8, 7, 6, 5, 4, 8, 8, 7, 6, 5, 4, 3, 2, + 6, 5, 4, 4, 2, 2, 1, 0, 3, 3, 2, 1, 0, 0, -1, -2, + 1, 1, 0, -1, -2, -2, -3, -3, -1, -1, -2, -3, -4, -4, -5, -5, + -3, -4, -4, -5, -6, -6, -7, -7, -5, -5, -6, -7, -8, -8, -8, -8, + -14,-13,-12,-11, -9, -7, -6, -4,-12,-11,-10, -9, -7, -5, -3, -1, + -10, -9, -7, -6, -3, -2, 0, 2, -8, -6, -4, -2, 0, 2, 4, 5, + -5, -3, 0, 2, 4, 5, 7, 8, -2, 0, 2, 4, 6, 8, 9, 10, + 0, 3, 5, 7, 8, 10, 11, 12, 3, 5, 7, 8, 10, 11, 12, 12, + -19,-19,-18,-18,-17,-16,-15,-14,-15,-15,-14,-13,-12,-11,-10, -9, + -11,-10, -9, -8, -6, -5, -4, -3, -6, -5, -3, -2, -1, 0, 1, 2, + -1, 0, 2, 3, 4, 5, 6, 6, 4, 6, 7, 8, 9, 10, 10, 10, + 9, 10, 11, 12, 13, 14, 14, 14, 12, 14, 14, 15, 16, 16, 16, 16, + 22, 21, 19, 17, 14, 11, 9, 5, 20, 19, 17, 14, 11, 8, 4, 1, + 17, 15, 13, 10, 6, 3, 0, -4, 13, 11, 8, 5, 1, -2, -5, -9, + 9, 6, 3, -1, -4, -7,-11,-13, 4, 0, -3, -6, -9,-12,-15,-17, + -2, -5, -8,-11,-14,-16,-18,-20, -8,-10,-13,-16,-17,-19,-21,-22, + 17, 18, 18, 18, 17, 16, 16, 14, 16, 16, 15, 15, 14, 13, 12, 11, + 12, 12, 11, 10, 9, 8, 7, 5, 7, 6, 6, 4, 3, 2, 1, -1, + 1, 0, -1, -2, -3, -4, -5, -6, -5, -6, -7, -8, -9,-10,-11,-12, + -11,-12,-13,-14,-15,-16,-16,-17,-16,-17,-17,-18,-19,-20,-20,-20, + 0, 0, 0, 0, -1, -1, -2, -3, 1, 0, 0, 0, 0, -1, -2, -3, + 1, 1, 0, 0, -1, -1, -2, -2, 1, 1, 1, 0, 0, -1, -1, -2, + 2, 1, 1, 1, 0, -1, -1, -2, 2, 2, 1, 1, 0, 0, -1, -2, + 2, 2, 1, 1, 1, 0, -1, -1, 2, 2, 1, 1, 1, 0, 0, -2, + 0, -1, -1, 0, 0, 1, 2, 3, 0, -1, -1, 0, 1, 1, 2, 2, + -1, -1, -1, -1, 0, 1, 2, 2, -1, -1, -2, -1, 0, 1, 1, 2, + -1, -2, -2, -1, 0, 0, 1, 2, -1, -2, -2, -2, -1, 0, 1, 2, + -1, -1, -2, -1, 0, 0, 1, 2, -1, -1, -1, -1, 0, 1, 1, 2, + 3, 2, 2, 2, 1, 1, 0, 0, 3, 2, 2, 2, 2, 1, 0, 0, + 2, 2, 2, 1, 1, 1, 0, 0, 2, 2, 1, 1, 1, 0, 0, -1, + 1, 1, 1, 0, 0, 0, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -2, -2, -2, -2, + 5, 2, 0, 0, -1, 0, 0, 0, 4, 2, 0, -1, -1, -1, 0, -1, + 4, 1, -1, -1, -2, -1, -1, -1, 4, 1, -1, -1, -2, -1, -1, -1, + 4, 1, -1, -2, -2, -1, -1, -1, 4, 1, -1, -2, -2, -1, -1, -1, + 4, 1, -1, -1, -1, -1, -1, -1, 4, 2, 0, -1, 0, 0, 0, -1, + -2, -1, 0, 1, 1, 1, 1, 1, -3, -1, 0, 1, 1, 1, 1, 1, + -3, -1, 0, 1, 1, 1, 1, 1, -3, -1, 0, 1, 1, 1, 1, 1, + -3, -2, 0, 1, 2, 2, 1, 1, -4, -2, 0, 1, 2, 2, 2, 2, + -5, -3, -1, 1, 1, 2, 1, 2, -5, -3, -2, 0, 1, 1, 1, 1, + 3, 3, 1, 0, -2, -4, -4, -5, 3, 3, 2, 0, -1, -2, -3, -4, + 2, 2, 1, 1, 0, -1, -2, -2, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, -2, -1, -1, 0, 0, 1, 2, 2, + -3, -2, -2, -1, 0, 1, 2, 3, -3, -3, -2, -1, 0, 1, 2, 3, + -3, -3, -3, -3, -3, -2, -2, -2, -3, -3, -2, -2, -2, -1, -1, -1, + -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 2, 2, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, + -8, -7, -5, -3, -2, -1, 0, -1, -4, -3, -1, 0, 1, 2, 1, 1, + -1, 1, 2, 3, 3, 2, 2, 1, 1, 2, 3, 3, 2, 2, 1, 0, + 2, 3, 3, 2, 1, 0, 0, -1, 1, 2, 1, 0, -1, -1, -1, -1, + 1, 1, 0, -1, -1, -2, -2, -1, 1, 1, 0, 0, -1, -1, 0, -1, + -4, -3, -2, 0, 1, 2, 3, 3, -4, -3, -2, 0, 1, 2, 2, 2, + -3, -3, -2, -1, 0, 1, 1, 1, -2, -2, -2, -1, -1, 0, 0, 0, + 0, -1, -1, -1, -1, -1, -1, -1, 2, 1, 1, 0, 0, -1, -1, -2, + 3, 3, 3, 1, 0, -1, -2, -2, 5, 4, 4, 2, 1, 0, -1, -2, + 0, 0, 0, 0, 1, 2, 3, 3, 0, -1, 0, 0, 1, 2, 3, 3, + 0, -1, 0, 0, 1, 2, 3, 2, 0, 0, 0, 1, 1, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 1, 0, 0, -1, -2, + 2, 1, 0, 0, -2, -3, -5, -6, 0, -1, -1, -3, -5, -6, -8, -9, + -2, 0, 1, 2, 2, 1, -1, -4, -2, 0, 2, 2, 2, 1, -1, -4, + -2, 0, 2, 2, 2, 1, -1, -3, -2, 0, 2, 2, 2, 1, -1, -3, + -2, -1, 2, 2, 2, 1, -1, -3, -2, -1, 1, 2, 2, 1, -1, -3, + -3, -1, 1, 2, 2, 1, -1, -3, -2, -1, 1, 2, 2, 1, -1, -3, + -1, 1, 1, -1, -3, -3, 0, 4, -1, 1, 1, -1, -3, -3, 0, 4, + -1, 1, 1, 0, -3, -3, 0, 4, -1, 1, 2, 0, -3, -3, 0, 5, + 0, 1, 2, 0, -3, -4, 0, 4, 0, 1, 2, 0, -3, -4, 0, 5, + 0, 1, 2, 0, -3, -3, 0, 4, 0, 1, 2, -1, -2, -2, 0, 4, + 6, 6, 5, 6, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 0, 0, 0, 0, 0, + -1, -2, -2, -2, -2, -2, -2, -1, -3, -3, -3, -3, -3, -3, -3, -2, + -3, -4, -4, -3, -3, -3, -2, -2, -2, -2, -2, -2, -1, -1, 0, 0, + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, + 4, 1, -2, -3, -3, -1, 1, 3, 4, 1, -2, -4, -3, -1, 1, 3, + 5, 1, -2, -4, -3, -1, 1, 4, 5, 1, -2, -3, -3, -1, 2, 4, + 5, 1, -2, -3, -3, -1, 2, 4, 4, 0, -3, -4, -3, -1, 2, 4, + 4, 0, -3, -3, -3, -1, 1, 3, 3, 0, -2, -3, -2, -1, 1, 3, + -3, -4, -4, -4, -4, -4, -4, -4, -1, -1, -1, -1, -1, -1, -2, -2, + 2, 1, 1, 2, 2, 1, 1, 1, 3, 3, 3, 4, 4, 3, 3, 3, + 3, 3, 3, 4, 4, 4, 3, 3, 1, 2, 1, 2, 2, 2, 2, 2, + -2, -2, -2, -1, -1, -1, 0, 0, -4, -4, -4, -4, -3, -3, -3, -3, + -1, -2, -3, -3, -2, -2, -1, 0, 0, -1, -2, -2, -2, -1, 0, 1, + 2, 1, -1, -1, -1, -1, 0, 1, 3, 1, 0, -1, -1, 0, 0, 1, + 3, 2, 0, -1, 0, 0, 0, 1, 3, 1, 0, -1, 0, 0, 0, 1, + 3, 1, 0, -1, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 1, 2, 3, 4, 0, 0, -1, 0, 0, 0, 2, 3, + 0, -1, -1, -1, -1, -1, 0, 1, 0, -1, -1, -1, -1, -1, -1, 0, + 0, 0, -1, -1, -1, -2, -2, -1, 1, 0, 0, -1, -1, -2, -2, -1, + 2, 2, 1, 0, -1, -1, -1, -1, 3, 3, 2, 1, 0, -1, -1, 0, + 1, 0, 1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, -2, -1, + 0, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, + -1, -1, -1, 0, 0, 0, 1, 1, -1, -1, -1, 0, 1, 1, 2, 3, + -2, -2, -1, 0, 1, 2, 3, 4, -2, -2, -1, 0, 1, 2, 4, 5, + -3, -1, 1, 0, 0, -1, 0, 1, -3, 0, 1, 0, -1, -1, 0, 2, + -3, 0, 1, 0, -1, -1, 0, 2, -2, 1, 2, 0, -1, -1, 0, 2, + -2, 1, 2, 0, -1, -1, 0, 2, -2, 1, 2, 0, -1, -1, 0, 2, + -1, 2, 2, 0, -1, -1, 0, 2, -1, 1, 1, 0, -1, -1, -1, 1, + -2, -2, -1, 1, 3, 4, 3, 1, -2, -2, -1, 0, 2, 3, 2, 0, + -2, -2, -1, 0, 1, 2, 1, -1, -1, -1, -1, 0, 1, 2, 1, -1, + -1, -1, -1, 0, 1, 1, 0, -2, 0, -1, -1, 0, 1, 1, 0, -1, + 0, -1, -1, 0, 1, 1, 1, -1, 0, -1, -1, 0, 0, 1, 0, -1, + -2, -1, 0, 1, 1, 1, 1, 1, -2, -1, 0, 0, 0, 0, 0, 0, + -2, -1, -1, 0, -1, -1, -2, -2, -2, -1, -1, -1, -1, -2, -2, -3, + -1, 0, 1, 1, 0, -1, -2, -2, 1, 2, 3, 3, 2, 1, 0, 0, + 1, 2, 3, 3, 3, 2, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, + 0, -1, -1, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, 0, 1, 1, 0, 0, 0, + -3, -2, -1, -1, -1, -1, 0, -1, -5, -5, -4, -3, -2, -2, -2, -1, + 1, 1, 1, 1, 2, 1, 0, -1, 1, 1, 1, 2, 1, 1, 0, -1, + 1, 1, 1, 1, 1, 1, 0, -2, 2, 1, 1, 1, 1, 1, 0, -2, + 1, 1, 0, 0, 0, 0, -1, -3, 1, 1, 0, 0, 0, -1, -2, -3, + 1, 1, 0, 0, -1, -1, -2, -4, 1, 0, 0, -1, -2, -2, -3, -4, + 8, 7, 5, 3, 2, 1, 1, 1, 2, 1, 0, 0, -1, -1, -2, -1, + -1, -1, -1, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, -1, -1, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, + -1, 0, 0, 0, 0, 0, -1, -1, -2, -2, -1, -1, -1, -2, -2, -1, + 9, 4, 0, -2, -2, -2, -1, -1, 7, 2, -1, -2, -2, -1, 0, 0, + 4, 0, -2, -2, -1, 0, 1, 1, 1, -2, -2, -2, -1, 0, 1, 1, + -1, -2, -2, -1, 0, 1, 1, 1, -1, -2, -1, 0, 1, 1, 1, 0, + -1, -1, 0, 1, 1, 1, 0, -1, 0, -1, 0, 1, 0, 0, -1, -1, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, + 2, 2, 2, 2, 1, 0, -1, -1, 1, 1, 1, 0, -1, -2, -2, -2, + 0, 0, 0, -1, -2, -3, -2, -2, -1, -1, -1, -2, -2, -2, -1, 0, + -1, -1, -1, -1, 0, 0, 1, 2, -1, -1, -1, 0, 1, 2, 3, 4, + -1, -1, 0, 0, -1, -2, -3, -3, -1, -1, 0, 0, 0, -1, -1, -1, + -2, -2, -1, 0, 1, 1, 1, 1, -2, -2, -2, 0, 1, 2, 3, 3, + -1, -1, -1, 0, 1, 3, 3, 3, 1, 0, 0, 0, 1, 1, 2, 2, + 2, 2, 1, 0, 0, -1, -1, -1, 3, 2, 1, 0, -1, -2, -3, -3, + -1, -1, -1, -2, -2, -3, -4, -5, 0, 0, 0, -1, -1, -3, -3, -4, + 1, 1, 1, 0, 0, -1, -2, -3, 2, 2, 2, 1, 1, 0, -1, -1, + 2, 2, 2, 2, 1, 1, 0, -1, 2, 2, 2, 2, 2, 1, 0, 0, + 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, -1, + -2, 2, 3, 1, -1, 1, 1, -1, -3, 2, 3, 0, -1, 1, 1, -1, + -3, 2, 3, 0, -1, 1, 1, -1, -4, 2, 3, 0, -1, 1, 1, -2, + -4, 1, 3, 0, -1, 1, 1, -2, -4, 1, 3, -1, -2, 1, 1, -2, + -3, 1, 2, 0, -1, 1, 1, -2, -3, 1, 2, 0, -1, 1, 1, -1, + -1, -1, -1, -2, -2, -2, -2, -2, 1, 1, 1, 1, 0, 0, 0, 0, + 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 1, 2, 2, 2, + -2, -2, -1, -1, -1, 0, 0, 0, -3, -3, -3, -3, -3, -3, -3, -2, + -1, -1, -1, -1, -2, -2, -2, -2, 4, 4, 4, 4, 4, 3, 3, 2, + -3, -3, -2, -1, 0, 1, 2, 5, -3, -3, -3, -2, -1, 1, 3, 6, + -3, -3, -2, -2, 0, 2, 3, 5, -3, -2, -2, -2, 0, 1, 3, 5, + -2, -2, -2, -1, -1, 1, 3, 5, -2, -2, -1, -1, 0, 1, 2, 4, + -1, -1, -1, -1, 0, 1, 1, 4, -1, -1, -1, -1, 0, 1, 2, 3, + 0, -1, 0, 1, 1, 0, -1, -1, 0, 0, 0, 1, 2, 0, -1, -1, + 1, 0, -1, 0, 1, 0, 0, 0, 1, -1, -2, -1, 0, 0, 0, 0, + 1, -2, -3, -1, 0, 0, 0, 1, 1, -1, -3, -2, 0, 1, 1, 2, + 1, -1, -2, -1, 0, 1, 1, 2, 2, 0, -1, 0, 1, 1, 2, 2, + 1, 1, 1, 1, 0, 0, 1, 2, -1, 0, 0, -1, 0, 0, 0, 1, + -3, -2, -1, -1, -1, 0, 1, 1, -4, -2, -1, 0, 0, 1, 1, 1, + -3, -2, 0, 0, 1, 1, 1, 1, -3, -1, 0, 1, 1, 1, 0, 0, + -1, 0, 1, 1, 1, 0, 0, -1, 0, 1, 2, 2, 1, 0, 0, -1, + -4, -4, -4, -3, -2, -1, -1, -1, -2, -2, -2, -1, 0, 0, 0, 0, + -1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 2, 2, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 0, -1, 0, 0, 1, 1, 1, 0, 0, + 1, 2, 2, 2, 1, -1, -2, -4, 1, 1, 2, 2, 1, 0, -2, -4, + 0, 1, 1, 1, 1, 0, -1, -3, -1, 0, 1, 1, 0, 0, -1, -2, + -1, 0, 1, 1, 1, 0, 0, -1, -2, -1, 0, 0, 0, 0, 0, -1, + -1, -1, 0, 1, 1, 0, 0, 0, -1, 0, 1, 1, 1, 1, 1, 0, + 2, 2, 0, -1, -2, -1, -1, -2, 1, 1, -1, -2, -2, -1, -1, -2, + 1, 1, -1, -2, -2, 0, 0, -1, 1, 1, 0, -2, -1, 1, 1, 0, + 1, 1, 0, -1, -1, 1, 2, 1, 1, 1, 0, -1, -1, 1, 2, 1, + 1, 1, 0, -1, -1, 1, 1, 1, 1, 1, 0, -1, 0, 1, 1, 1, + 0, 0, -1, -2, -4, -4, -4, -4, 3, 3, 3, 2, 1, 0, 0, 0, + 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, + -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, + -1, -1, 0, -1, -1, 1, 2, -1, 1, 1, 0, 0, 0, 2, 3, -1, + 1, 1, 0, -1, -1, 1, 3, -1, 1, 1, 0, -2, -2, 0, 1, -2, + 1, 0, 0, -2, -2, 0, 1, -3, 0, 0, 0, 0, -1, 1, 1, -3, + 0, 1, 1, 0, 1, 2, 1, -3, -1, 0, 1, 1, 1, 2, 1, -4, + -4, -3, 0, 1, 1, 1, 0, 0, -4, -2, 0, 1, 1, 1, 0, -1, + -3, -1, 1, 1, 1, 0, -1, -1, -1, 1, 1, 1, 1, 0, -1, 0, + 1, 2, 2, 1, 0, -1, 0, 0, 2, 2, 1, 0, -1, -1, 0, 1, + 2, 1, 0, -1, -2, -1, 0, 1, 2, 2, 0, -1, -2, -1, 1, 1, + 1, 1, 0, 0, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, + 1, 0, 0, -1, -1, -1, -1, -1, 2, 1, 0, 0, -1, -1, -1, -1, + 5, 3, 2, 1, 0, 0, 0, 0, 6, 5, 3, 2, 1, 0, 0, 0, + 4, 4, 3, 1, 0, 0, 0, 1, 3, 3, 2, 1, 0, 0, 0, 1, + 2, 2, 1, 0, -1, -1, 0, 1, 0, 0, 0, -1, -1, -1, 0, 1, + 0, 0, -1, -1, -2, -1, 0, 2, 0, -1, -1, -2, -2, -2, 0, 1, + 0, -1, -1, -2, -2, -2, -1, 0, 0, 0, -1, -2, -2, -2, -1, 0, + 0, 0, -1, -1, -1, 0, 2, 3, 0, -1, -2, -2, -1, -1, 1, 2, + 1, 0, -1, -1, -1, 0, 0, 0, 1, 1, 1, 0, 0, 0, -1, -1, + 1, 2, 1, 0, 0, -1, -1, -1, -1, 0, 0, 0, -1, -1, -1, -1, + -3, -2, -1, -1, 0, 1, 1, 2, -4, -3, -1, 1, 2, 3, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, -1, 0, 0, 0, 1, -1, -1, -2, -2, -2, -1, -1, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, + 1, 1, 1, 1, 2, 2, 1, 1, -4, -3, -4, -4, -4, -4, -3, -3, + -1, 0, 1, 2, 2, 3, 3, 3, -1, -1, -1, -1, 0, 0, 0, 0, + 0, 0, -1, -2, -2, -3, -3, -2, 3, 2, 1, 0, -1, -2, -2, -2, + 4, 3, 2, 1, 1, 0, 0, 0, 2, 2, 1, 1, 0, 1, 1, 1, + 0, -1, -1, -1, -1, 0, 0, 1, -2, -2, -2, -2, -2, -1, 0, 0, + 1, -1, 0, 2, 1, -2, -1, 1, 1, -1, 0, 2, 1, -2, -2, 1, + 1, -1, 0, 3, 2, -2, -1, 1, 0, -2, 0, 3, 2, -2, -2, 1, + 0, -2, 0, 3, 2, -2, -2, 1, 0, -2, 0, 3, 1, -2, -1, 1, + 0, -2, 0, 2, 1, -2, -2, 1, 0, -1, 0, 2, 1, -2, -1, 1, + 0, 1, 2, 2, 3, 3, 2, 2, 0, 1, 1, 2, 3, 3, 2, 1, + 0, 0, 1, 2, 2, 2, 2, 1, -1, 0, 0, 1, 1, 1, 1, 1, + -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, + -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -2, -2, -2, -2, -2, -1, + 0, 0, -1, -2, -1, 0, 3, 5, 0, 0, -1, -1, -1, 0, 2, 4, + 1, 1, 0, 0, -1, -1, 1, 2, 1, 2, 1, 1, 0, -1, -1, 0, + 0, 1, 2, 1, 0, -1, -2, -2, -1, 0, 1, 2, 1, 0, -3, -3, + -2, -1, 1, 2, 2, 0, -2, -4, -2, -1, 0, 2, 2, 1, -1, -3, + 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, -1, 0, 0, 0, 0, 0, + -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, + -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, 0, 0, 0, -1, -1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 3, 3, 3, 4, 3, 3, 3, 3, + 5, 1, -2, -2, 0, 0, 0, -1, 4, -1, -3, -1, 0, 0, 0, -1, + 3, -1, -1, 0, 1, 1, 0, -1, 2, 0, 0, 1, 1, 1, 0, -2, + 1, 0, 0, 1, 1, 1, 0, -2, 0, -1, -1, -1, 0, 0, 0, -1, + 0, -1, -1, -1, -1, 0, 0, -1, 2, 1, 0, 0, 0, 1, 0, 0, + 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, + 1, -1, -1, 0, 0, 0, 0, 0, 2, 0, -1, -1, -1, -1, -1, 0, + 3, 1, -1, -1, -2, -2, -2, -1, 4, 2, 1, 0, -1, -2, -2, -1, + 2, 1, 0, 0, -1, -1, 0, 0, 0, -1, -1, -1, -1, 0, 1, 1, + 0, 1, 2, 2, 2, 1, -1, -3, 0, 0, 1, 1, 1, 0, -1, -2, + 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, -1, 0, 0, 1, 1, 0, + 0, 0, -1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 2, 1, -1, -3, 0, 0, 0, 1, 1, -1, -4, -5, + -2, -2, -2, -1, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 0, -2, -3, 0, 0, 1, 1, 0, -1, -3, -4, + -1, -1, 0, 1, 0, 0, -2, -3, -1, -1, 0, 1, 1, 1, 0, -1, + 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 1, 1, 2, 1, 2, 0, 0, 0, 0, -1, 1, + 0, 2, 0, -1, 1, 0, -1, 0, 0, 1, 0, 0, 2, 1, 0, 1, + 0, 1, -1, 0, 2, 2, 0, 1, -1, 0, -1, -1, 2, 1, 1, 2, + -2, -2, -3, -2, 0, 1, 1, 1, -2, -2, -3, -3, -1, -1, -1, 0, + -3, -1, 0, 1, 2, 1, 1, 0, -3, -1, 0, 1, 2, 1, 1, 1, + -2, 0, 0, 1, 1, 1, 1, 1, -1, 0, 0, 0, 0, 0, 0, 0, + -2, 0, 0, 0, 0, -1, -1, 0, -2, 0, 0, 0, 0, 0, -1, -1, + -3, 0, 1, 1, 1, 1, 0, 1, -5, -2, 0, 1, 2, 2, 1, 2, + -2, -1, -1, 0, 0, 1, 2, 3, 0, 0, 1, 1, 0, 0, 1, 2, + 0, 0, 1, 0, -1, -1, 0, 1, -1, -1, -1, -1, -2, -2, -1, 0, + -2, -2, -2, -2, -2, -1, 0, 1, 0, 0, 0, -1, 0, 1, 2, 2, + 2, 1, 0, 0, 0, 1, 2, 2, 2, 1, 0, -1, -1, -1, 0, 0, + 0, 1, 1, 1, 1, 1, -1, -4, -1, -1, 0, 1, 1, 1, 0, -3, + -2, -1, 0, 0, 1, 2, 2, -2, -1, 0, 0, 0, 0, 2, 3, -1, + -1, 0, 0, 0, 0, 1, 2, 0, 0, 0, -1, -2, -1, 1, 1, 0, + 0, 0, -1, -2, -2, 0, 2, 1, 0, 0, -1, -2, -1, 1, 2, 2, + 1, 0, 0, 0, -2, -3, -2, -3, 0, 0, 1, 0, -2, -2, -1, -1, + 0, -1, 1, 1, -1, -1, 0, 0, 0, -1, 1, 1, -1, -1, 0, 0, + 0, 1, 2, 1, -1, -1, 0, 1, 1, 2, 3, 2, 0, 0, 1, 2, + -1, 0, 2, 1, 0, 0, 2, 3, -2, -1, 0, 0, -1, 0, 1, 2, + 1, 1, 0, -1, -2, -2, -1, 1, 1, 1, 1, -1, -2, -2, 0, 2, + 1, 1, 1, -1, -1, -1, 0, 2, 0, 0, 0, 0, 0, 0, 1, 2, + -1, -1, -1, 0, 0, 0, 1, 2, -1, -2, -1, 1, 1, 1, 0, 0, + -1, -2, -1, 1, 2, 2, 0, -1, -1, -2, -1, 2, 2, 2, 0, -1, + -1, -1, -1, -2, -1, -1, 0, 1, 0, 0, -1, -1, -1, 0, 1, 2, + 1, 0, 0, 0, 0, 1, 1, 2, 1, 1, 0, 0, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, + 1, 2, 1, 0, -1, -2, -2, -3, 2, 2, 1, 0, -2, -3, -4, -4, + -4, -2, 1, 1, 1, 1, 0, 0, -2, 0, 1, 0, 0, 0, 0, 0, + 0, 1, 1, -2, -2, -1, 0, 1, 2, 2, 1, -2, -2, -1, 1, 2, + 1, 2, 1, -2, -2, -1, 1, 2, -1, 1, 1, -1, -1, -1, 0, 1, + -2, 0, 1, 1, 0, -1, -1, 0, -2, 0, 2, 2, 1, -1, -1, 0, + 1, 1, 0, 0, 0, 1, 0, 0, -2, -3, -3, -2, -2, -1, 0, 0, + -3, -4, -3, -2, -1, 0, 0, 0, -1, -1, 0, 1, 2, 3, 2, 1, + 0, 1, 2, 3, 3, 3, 2, 1, 1, 1, 1, 2, 1, 0, 0, -1, + 0, 0, 0, 0, -1, -1, -1, -1, 0, -1, -1, 0, 0, 0, 0, 0, + 1, 1, 0, 0, -1, -1, 0, 2, 0, 0, 1, 0, -1, -1, 1, 1, + -2, -1, 0, 1, 1, 1, 1, 1, -3, -3, 0, 2, 2, 1, 1, 0, + -2, -2, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, -1, + 3, 1, -1, -3, -2, -1, 0, 1, 4, 2, -1, -3, -3, -1, 1, 2, + 0, 0, 0, -1, -1, -1, -1, -1, 1, 2, 1, 0, 0, 0, -1, -1, + 2, 3, 3, 2, 1, 0, -1, -1, 3, 4, 4, 2, 1, 0, -1, -2, + 3, 3, 2, 1, 0, -1, -2, -2, 1, 1, 0, -1, -1, -2, -2, -3, + 0, 0, 0, -1, -1, -2, -2, -2, -1, -1, -1, -1, -1, -2, -2, -1, + 1, 2, 2, 2, 2, 1, 2, 2, 0, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, -1, -2, 0, 0, 0, 0, 1, 0, -1, -4, + 1, 0, 0, 0, 0, 0, -2, -5, 1, 0, 0, 0, 0, 0, -1, -4, + 1, 0, -1, 0, 0, 0, -1, -3, 0, -1, -1, 0, 1, 1, 1, -1, + -2, -1, 0, 0, -1, -1, -1, -2, -1, 0, 0, 0, -1, -1, -2, -2, + 0, 1, 1, 0, -1, -1, -1, -2, 0, 1, 1, 0, 0, 0, -1, -1, + 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 2, 2, 1, + 1, 1, 0, 0, 1, 2, 2, 1, 1, 1, 0, -1, 0, 1, 1, 0, + 4, 2, 1, 0, 0, 1, 1, 1, 4, 2, 1, 0, 0, 0, 0, 1, + 3, 1, 0, 0, -1, -1, -1, 0, 1, 0, 0, -1, -1, -2, -1, 0, + 0, 0, 0, 0, -1, -1, -1, 0, -1, -1, 0, 0, -1, -1, 0, 1, + -2, -1, 0, -1, -1, 0, 0, 1, -2, -2, -1, -2, -1, 0, 0, 1, + 0, 1, 1, 1, 2, 1, 0, -1, -1, -1, -1, 0, 0, -1, -2, -2, + -1, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, 0, 0, 1, 2, + 0, 0, 0, 0, 0, 0, 2, 3, -1, 0, -1, -1, -1, -1, 0, 3, + -1, 0, 0, -1, -1, -2, 0, 3, 0, 0, 0, 0, -1, -1, 1, 4, + 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, -1, -2, -1, -2, -1, 1, + -1, -1, -2, -2, -2, -3, -2, 0, -1, 0, -1, -1, -1, -2, -1, 1, + 1, 1, 0, 0, 1, 0, 0, 1, 2, 2, 0, 0, 1, 0, 0, 1, + 2, 2, 0, 0, 0, 0, -1, -1, 2, 2, 0, 0, 1, 0, -1, -1, + -1, 0, 1, 1, 0, -1, -1, -1, 1, 2, 3, 2, 1, 0, 0, 0, + 0, 1, 1, 1, 0, -1, 0, 0, -2, -2, -1, 0, 1, 0, 0, 0, + -2, -2, -1, 2, 2, 2, 1, 0, -2, -1, 0, 1, 1, 0, 0, -1, + -1, -1, 0, 0, -1, -2, -1, -2, 0, 1, 1, 1, 0, 0, 1, 1, + -3, -3, -3, -2, -1, -1, -2, -2, -1, -1, 0, 1, 2, 1, 0, 0, + 1, 1, 1, 2, 2, 1, 0, 0, 1, 1, 1, 1, 1, 0, -1, 1, + 1, 0, -1, -1, 0, 0, -1, 1, 0, -1, -1, -1, 0, -1, -1, 1, + 1, 0, -1, 0, 0, -1, 0, 2, 2, 0, -1, 0, 0, 0, 0, 2, + 1, 0, -2, -1, 0, 1, 1, 0, 2, 0, -1, -1, 0, 1, 1, 0, + 1, 0, -2, -1, 0, 1, 0, -1, 1, 0, -1, -1, 0, 1, 0, -1, + 0, 1, 1, 0, 1, 1, 0, 0, -2, 1, 2, 1, 0, 0, 0, 1, + -5, 0, 2, 1, 0, -1, 0, 1, -6, -1, 2, 1, 0, -1, 0, 0, + 5, 3, 0, -1, -2, -1, -1, -1, 1, 1, 0, -1, -1, 0, -1, -1, + -1, 0, 1, 1, 2, 2, 1, 0, -2, -1, 0, 1, 2, 1, 1, 1, + -2, -1, -1, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, -1, 0, 0, + 0, 1, 1, 1, 1, 0, 0, 0, -3, -2, 0, 1, 1, 0, 0, -1, + -1, 0, 1, 0, -1, 0, 2, 3, -1, 0, 0, -2, -4, -2, -1, 0, + 0, 1, 1, 0, -2, -1, 0, -1, 1, 2, 3, 1, 0, 1, 1, 0, + -1, 0, 1, 1, 1, 1, 1, 0, -2, -3, -2, 0, 0, 0, 1, 0, + -1, -2, -2, 0, 1, 0, 0, -1, 3, 1, 0, 0, 1, 0, -1, -1, + -2, -1, 0, 0, -1, -1, 0, 0, -1, 0, 0, 0, 0, 1, 1, 1, + -1, -1, -1, 0, 1, 1, 1, 1, 0, -2, -3, -1, 1, 0, 0, 0, + 1, -1, -3, -1, 1, 1, 0, -1, 3, 1, -1, 1, 2, 2, 0, -1, + 3, 1, 0, 1, 2, 1, 1, 0, 0, -2, -2, -1, -1, 0, 0, 0, + 1, 0, -1, -1, 1, 2, 1, 0, 0, -1, -2, -1, 1, 2, 2, 1, + -1, -1, -1, 0, 0, 1, 2, 0, -2, 0, 0, 0, 0, 0, 1, -1, + -1, 0, 1, 0, -1, -1, -1, -1, 0, 1, 1, 2, 0, -2, -1, 0, + 1, 2, 2, 2, 1, -1, -1, 0, 0, 1, 1, 1, 0, -2, -2, -1, + 0, 0, -1, -1, -1, -1, -2, -2, 0, 0, -1, 0, 1, 2, 2, 1, + 0, 0, -1, -1, 0, 1, 2, 2, 1, 1, -1, -2, -1, -1, -1, -1, + 2, 2, 1, 0, 0, -1, -2, -2, 1, 2, 2, 1, 0, 0, -2, -2, + 0, 0, 0, 0, 1, 1, 0, -1, 0, -1, -1, -1, 2, 3, 2, 1, + 0, -2, 1, 2, -1, 0, 0, 1, -1, -2, 2, 3, -1, 0, 0, 0, + 0, -2, 2, 3, -1, -1, 0, 0, 0, -1, 3, 2, -2, 0, 1, 0, + 0, -1, 3, 1, -2, 0, 1, 0, 0, -1, 2, 1, -1, 1, 0, -1, + 0, 0, 1, -1, -2, 0, 0, -1, 1, 0, 0, -2, -2, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -2, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 0, 0, 1, 1, 1, 2, 3, 1, 0, 0, -1, 0, 0, 1, 2, + 0, -1, -1, -2, -1, 0, 1, 2, -2, -2, -2, -2, -1, 0, 1, 1, + -1, -1, -1, -1, 0, 0, 0, -1, 2, 2, 2, 0, -1, -1, -2, -4, + -1, -2, -1, -1, 0, 1, 2, 3, -1, -1, -1, -1, 0, 1, 2, 3, + 1, 0, -1, 0, -1, 0, 1, 2, 1, 0, 0, 0, -1, 0, 2, 2, + 1, 0, -1, -1, -2, 0, 1, 2, 0, -2, -2, -2, -3, -1, 0, 1, + 0, -2, -2, -2, -2, -1, 1, 1, 0, 0, 0, 0, 0, 1, 2, 2 }; -const uint32 *const s_svq1IntraCodebooks[6] = { +static const int8 *const s_svq1IntraCodebooks[6] = { s_svq1IntraCodebook4x2, s_svq1IntraCodebook4x4, s_svq1IntraCodebook8x4, s_svq1IntraCodebook8x8, 0, 0 -- cgit v1.2.3 From cd5e750a7fdfa0c2ac7904d24b7d8e5a06eff99a Mon Sep 17 00:00:00 2001 From: Littleboy Date: Mon, 13 Aug 2012 00:05:38 -0400 Subject: LASTEXPRESS: Fix analysis warnings --- engines/lastexpress/data/background.cpp | 1 + engines/lastexpress/debug.cpp | 3 +++ engines/lastexpress/sound/queue.cpp | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/engines/lastexpress/data/background.cpp b/engines/lastexpress/data/background.cpp index 3d866c26f9..60379251a3 100644 --- a/engines/lastexpress/data/background.cpp +++ b/engines/lastexpress/data/background.cpp @@ -107,6 +107,7 @@ byte *Background::decodeComponent(Common::SeekableReadStream *in, uint32 inSize, return NULL; // Initialize the decoding + memset(out, 0, outSize * sizeof(byte)); uint32 inPos = 0; uint32 outPos = 0; diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index f89ad8b80d..55fb469da3 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -139,6 +139,9 @@ void Debugger::copyCommand(int argc, const char **argv) { for (int i = 0; i < _numParams; i++) { _commandParams[i] = (char *)malloc(strlen(argv[i]) + 1); + if (_commandParams[i] == NULL) + error("[Debugger::copyCommand] Cannot allocate memory for command parameters"); + memset(_commandParams[i], 0, strlen(argv[i]) + 1); strcpy(_commandParams[i], argv[i]); } diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp index d72acfd8a0..8904b48930 100644 --- a/engines/lastexpress/sound/queue.cpp +++ b/engines/lastexpress/sound/queue.cpp @@ -67,6 +67,8 @@ void SoundQueue::handleTimer() { for (Common::List::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); + if (entry == NULL) + error("[SoundQueue::handleTimer] Invalid entry found in sound queue"); // When the entry has stopped playing, we remove his buffer if (entry->isFinished()) { @@ -123,6 +125,8 @@ void SoundQueue::updateQueue() { for (Common::List::iterator it = _soundList.begin(); it != _soundList.end(); ++it) { SoundEntry *entry = *it; + if (entry == NULL) + error("[SoundQueue::updateQueue] Invalid entry found in sound queue"); // Original removes the entry data from the cache and sets the archive as not loaded // and if the sound data buffer is not full, loads a new entry to be played based on @@ -179,6 +183,8 @@ void SoundQueue::clearQueue() { for (Common::List::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); + if (entry == NULL) + error("[SoundQueue::clearQueue] Invalid entry found in sound queue"); // Delete entry entry->close(); -- cgit v1.2.3 From 47fa7abbe00fb923be4053ae2a19e41a8d7753b9 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Sun, 19 Aug 2012 19:24:25 -0400 Subject: LASTEXPRESS: Fix playsnd debugger command --- engines/lastexpress/debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index 55fb469da3..fae9ea7ceb 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -523,7 +523,7 @@ bool Debugger::cmdPlaySnd(int argc, const char **argv) { _engine->_system->getMixer()->stopAll(); - _soundStream->load(getArchive(name)); + _soundStream->load(getArchive(name), 16); if (argc == 3) restoreArchive(); -- cgit v1.2.3 From 17c051b58c00cc1424978fc886bcd8b4cd18356c Mon Sep 17 00:00:00 2001 From: Littleboy Date: Sun, 19 Aug 2012 19:41:25 -0400 Subject: LASTEXPRESS: Check for invalid cd number in debugger commands --- engines/lastexpress/debug.cpp | 61 ++++++++++++++++++++++++++++++------------- engines/lastexpress/debug.h | 2 +- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index fae9ea7ceb..21bf0119c4 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -155,9 +155,18 @@ void Debugger::callCommand() { (*_command)(_numParams, const_cast(_commandParams)); } -void Debugger::loadArchive(ArchiveIndex index) const { - _engine->getResourceManager()->loadArchive(index); +bool Debugger::loadArchive(ArchiveIndex index) { + if (index < 1 || index > 3) { + DebugPrintf("Invalid cd number (was: %d, valid: [1-3])\n", index); + return false; + } + + if (!_engine->getResourceManager()->loadArchive(index)) + return false; + getScenes()->loadSceneDataFile(index); + + return true; } // Restore loaded archive @@ -236,8 +245,10 @@ bool Debugger::cmdListFiles(int argc, const char **argv) { Common::String filter(const_cast(argv[1])); // Load the proper archive - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + return true; + } Common::ArchiveMemberList list; int count = _engine->getResourceManager()->listMatchingMembers(list, filter); @@ -320,8 +331,10 @@ bool Debugger::cmdShowFrame(int argc, const char **argv) { Common::String filename(const_cast(argv[1])); filename += ".seq"; - if (argc == 4) - loadArchive((ArchiveIndex)getNumber(argv[3])); + if (argc == 4) { + if (!loadArchive((ArchiveIndex)getNumber(argv[3]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename)) { DebugPrintf("Cannot find file: %s\n", filename.c_str()); @@ -380,8 +393,10 @@ bool Debugger::cmdShowBg(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String filename(const_cast(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename + ".BG")) { DebugPrintf("Cannot find file: %s\n", (filename + ".BG").c_str()); @@ -433,8 +448,10 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { Common::String filename(const_cast(argv[1])); filename += ".seq"; - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename)) { DebugPrintf("Cannot find file: %s\n", filename.c_str()); @@ -508,8 +525,10 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { bool Debugger::cmdPlaySnd(int argc, const char **argv) { if (argc == 2 || argc == 3) { - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + return true; + } // Add .SND at the end of the filename if needed Common::String name(const_cast(argv[1])); @@ -545,8 +564,10 @@ bool Debugger::cmdPlaySbe(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String filename(const_cast(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + return true; + } filename += ".sbe"; @@ -608,8 +629,10 @@ bool Debugger::cmdPlayNis(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String name(const_cast(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + return true; + } // If we got a nis filename, check that the file exists if (name.contains('.') && !_engine->getResourceManager()->hasFile(name)) { @@ -665,8 +688,10 @@ bool Debugger::cmdLoadScene(int argc, const char **argv) { SceneIndex index = (SceneIndex)getNumber(argv[1]); // Check args - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + return true; + } if (index > 2500) { DebugPrintf("Error: invalid index value (0-2500)"); diff --git a/engines/lastexpress/debug.h b/engines/lastexpress/debug.h index d9ba6f47a1..06534f4bc0 100644 --- a/engines/lastexpress/debug.h +++ b/engines/lastexpress/debug.h @@ -87,7 +87,7 @@ private: void copyCommand(int argc, const char **argv); int getNumber(const char *arg) const; - void loadArchive(ArchiveIndex index) const; + bool loadArchive(ArchiveIndex index); void restoreArchive() const; Debuglet *_command; -- cgit v1.2.3 From 6f18ec2104b5cf02ebeb0c928a5c2507c99d820d Mon Sep 17 00:00:00 2001 From: Littleboy Date: Sun, 19 Aug 2012 19:58:30 -0400 Subject: LASTEXPRESS: Identify some Abbot Chapter 3 functions --- engines/lastexpress/entities/abbot.cpp | 24 ++++++++++++------------ engines/lastexpress/entities/abbot.h | 8 ++++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp index e0fe429520..85d0d8948b 100644 --- a/engines/lastexpress/entities/abbot.cpp +++ b/engines/lastexpress/entities/abbot.cpp @@ -58,10 +58,10 @@ Abbot::Abbot(LastExpressEngine *engine) : Entity(engine, kEntityAbbot) { ADD_CALLBACK_FUNCTION(Abbot, chapter2); ADD_CALLBACK_FUNCTION(Abbot, chapter3); ADD_CALLBACK_FUNCTION(Abbot, chapter3Handler); - ADD_CALLBACK_FUNCTION(Abbot, function19); - ADD_CALLBACK_FUNCTION(Abbot, function20); - ADD_CALLBACK_FUNCTION(Abbot, function21); - ADD_CALLBACK_FUNCTION(Abbot, function22); + ADD_CALLBACK_FUNCTION(Abbot, conversationWithBoutarel); + ADD_CALLBACK_FUNCTION(Abbot, readPaper); + ADD_CALLBACK_FUNCTION(Abbot, goToLunch); + ADD_CALLBACK_FUNCTION(Abbot, haveLunch); ADD_CALLBACK_FUNCTION(Abbot, function23); ADD_CALLBACK_FUNCTION(Abbot, function24); ADD_CALLBACK_FUNCTION(Abbot, function25); @@ -259,7 +259,7 @@ IMPLEMENT_FUNCTION(18, Abbot, chapter3Handler) getData()->entityPosition = kPosition_6470; getData()->location = kLocationInsideCompartment; - setup_function19(); + setup_conversationWithBoutarel(); break; } break; @@ -272,7 +272,7 @@ IMPLEMENT_FUNCTION(18, Abbot, chapter3Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(19, Abbot, function19) +IMPLEMENT_FUNCTION(19, Abbot, conversationWithBoutarel) switch (savepoint.action) { default: break; @@ -311,21 +311,21 @@ IMPLEMENT_FUNCTION(19, Abbot, function19) case 3: getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122288808); - setup_function20(); + setup_readPaper(); break; } } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Abbot, function20) +IMPLEMENT_FUNCTION(20, Abbot, readPaper) switch (savepoint.action) { default: break; case kActionNone: if (getState()->time > kTime1966500 && getEntities()->isInRestaurant(kEntityBoutarel)) - setup_function21(); + setup_goToLunch(); break; case kActionDefault: @@ -335,7 +335,7 @@ IMPLEMENT_FUNCTION(20, Abbot, function20) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(21, Abbot, function21) +IMPLEMENT_FUNCTION(21, Abbot, goToLunch) switch (savepoint.action) { default: break; @@ -393,7 +393,7 @@ IMPLEMENT_FUNCTION(21, Abbot, function21) break; case 7: - setup_function22(); + setup_haveLunch(); break; } break; @@ -409,7 +409,7 @@ IMPLEMENT_FUNCTION(21, Abbot, function21) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Abbot, function22) +IMPLEMENT_FUNCTION(22, Abbot, haveLunch) switch (savepoint.action) { default: break; diff --git a/engines/lastexpress/entities/abbot.h b/engines/lastexpress/entities/abbot.h index ce52bb68ce..dc3e86db54 100644 --- a/engines/lastexpress/entities/abbot.h +++ b/engines/lastexpress/entities/abbot.h @@ -156,10 +156,10 @@ public: * Handle Chapter 3 events */ DECLARE_FUNCTION(chapter3Handler) - DECLARE_FUNCTION(function19) - DECLARE_FUNCTION(function20) - DECLARE_FUNCTION(function21) - DECLARE_FUNCTION(function22) + DECLARE_FUNCTION(conversationWithBoutarel) + DECLARE_FUNCTION(readPaper) + DECLARE_FUNCTION(goToLunch) + DECLARE_FUNCTION(haveLunch) DECLARE_FUNCTION(function23) DECLARE_FUNCTION(function24) DECLARE_FUNCTION(function25) -- cgit v1.2.3 From 86febf3d1dfd780c35c505accc55df28c1ac80c3 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Tue, 21 Aug 2012 22:41:55 -0400 Subject: LASTEXPRESS: Check for valid data in Beetle::invertDirection() --- engines/lastexpress/game/beetle.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/engines/lastexpress/game/beetle.cpp b/engines/lastexpress/game/beetle.cpp index 2a72459697..7cdd67caf5 100644 --- a/engines/lastexpress/game/beetle.cpp +++ b/engines/lastexpress/game/beetle.cpp @@ -351,6 +351,9 @@ void Beetle::drawUpdate() { } void Beetle::invertDirection() { + if (!_data) + error("[Beetle::invertDirection] Sequences have not been loaded"); + switch (_data->indexes[_data->offset]) { default: break; -- cgit v1.2.3 From cec57e091834567552658aacfa6561fe80e1a6f8 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Tue, 21 Aug 2012 22:49:38 -0400 Subject: LASTEXPRESS: Reduce header interdependency --- engines/lastexpress/entities/entity.cpp | 11 +++++++++-- engines/lastexpress/entities/entity.h | 5 ----- engines/lastexpress/game/logic.cpp | 1 - 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp index 2deca291f6..552e1a8a82 100644 --- a/engines/lastexpress/entities/entity.cpp +++ b/engines/lastexpress/entities/entity.cpp @@ -26,10 +26,15 @@ #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" +#include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savegame.h" +#include "lastexpress/game/savepoint.h" +#include "lastexpress/game/state.h" #include "lastexpress/game/scenes.h" +#include "lastexpress/lastexpress.h" + namespace LastExpress { ////////////////////////////////////////////////////////////////////////// @@ -49,8 +54,10 @@ void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::Strin char seqName[13]; memset(&seqName, 0, length); - if (s.isSaving()) strcpy((char *)&seqName, string.c_str()); - s.syncBytes((byte *)&seqName, length); + if (s.isSaving()) + strcpy((char *)&seqName, string.c_str()); + + s.syncBytes((byte *)&seqName, length); if (s.isLoading()) string = seqName; diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h index 3601f34f6f..e5c097b50a 100644 --- a/engines/lastexpress/entities/entity.h +++ b/engines/lastexpress/entities/entity.h @@ -25,13 +25,8 @@ #include "lastexpress/shared.h" -#include "lastexpress/game/logic.h" -#include "lastexpress/game/savepoint.h" -#include "lastexpress/game/state.h" - #include "lastexpress/sound/sound.h" -#include "lastexpress/lastexpress.h" #include "lastexpress/helpers.h" #include "common/array.h" diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp index 1696f100ff..09104d1bf9 100644 --- a/engines/lastexpress/game/logic.cpp +++ b/engines/lastexpress/game/logic.cpp @@ -48,7 +48,6 @@ #include "lastexpress/sound/queue.h" -#include "lastexpress/graphics.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" -- cgit v1.2.3 From ab4c47c584b0451a30bc5239a66cc8649aa66682 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Tue, 21 Aug 2012 22:53:33 -0400 Subject: LASTEXPRESS: Update Debug::loadArchive() to reduce casts --- engines/lastexpress/debug.cpp | 22 +++++++++++----------- engines/lastexpress/debug.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index 21bf0119c4..3994cb0bcb 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -155,16 +155,16 @@ void Debugger::callCommand() { (*_command)(_numParams, const_cast(_commandParams)); } -bool Debugger::loadArchive(ArchiveIndex index) { +bool Debugger::loadArchive(int index) { if (index < 1 || index > 3) { DebugPrintf("Invalid cd number (was: %d, valid: [1-3])\n", index); return false; } - if (!_engine->getResourceManager()->loadArchive(index)) + if (!_engine->getResourceManager()->loadArchive((ArchiveIndex)index)) return false; - getScenes()->loadSceneDataFile(index); + getScenes()->loadSceneDataFile((ArchiveIndex)index); return true; } @@ -246,7 +246,7 @@ bool Debugger::cmdListFiles(int argc, const char **argv) { // Load the proper archive if (argc == 3) { - if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + if (!loadArchive(getNumber(argv[2]))) return true; } @@ -332,7 +332,7 @@ bool Debugger::cmdShowFrame(int argc, const char **argv) { filename += ".seq"; if (argc == 4) { - if (!loadArchive((ArchiveIndex)getNumber(argv[3]))) + if (!loadArchive(getNumber(argv[3]))) return true; } @@ -394,7 +394,7 @@ bool Debugger::cmdShowBg(int argc, const char **argv) { Common::String filename(const_cast(argv[1])); if (argc == 3) { - if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + if (!loadArchive(getNumber(argv[2]))) return true; } @@ -449,7 +449,7 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { filename += ".seq"; if (argc == 3) { - if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + if (!loadArchive(getNumber(argv[2]))) return true; } @@ -526,7 +526,7 @@ bool Debugger::cmdPlaySnd(int argc, const char **argv) { if (argc == 2 || argc == 3) { if (argc == 3) { - if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + if (!loadArchive(getNumber(argv[2]))) return true; } @@ -565,7 +565,7 @@ bool Debugger::cmdPlaySbe(int argc, const char **argv) { Common::String filename(const_cast(argv[1])); if (argc == 3) { - if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + if (!loadArchive(getNumber(argv[2]))) return true; } @@ -630,7 +630,7 @@ bool Debugger::cmdPlayNis(int argc, const char **argv) { Common::String name(const_cast(argv[1])); if (argc == 3) { - if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + if (!loadArchive(getNumber(argv[2]))) return true; } @@ -689,7 +689,7 @@ bool Debugger::cmdLoadScene(int argc, const char **argv) { // Check args if (argc == 3) { - if (!loadArchive((ArchiveIndex)getNumber(argv[2]))) + if (!loadArchive(getNumber(argv[2]))) return true; } diff --git a/engines/lastexpress/debug.h b/engines/lastexpress/debug.h index 06534f4bc0..a9f0443af9 100644 --- a/engines/lastexpress/debug.h +++ b/engines/lastexpress/debug.h @@ -87,7 +87,7 @@ private: void copyCommand(int argc, const char **argv); int getNumber(const char *arg) const; - bool loadArchive(ArchiveIndex index); + bool loadArchive(int index); void restoreArchive() const; Debuglet *_command; -- cgit v1.2.3 From 2c0033c7bad5b15c9bcccbce804e244a17a7f891 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Tue, 21 Aug 2012 23:00:29 -0400 Subject: LASTEXPRESS: Add const modifiers --- engines/lastexpress/entities/chapters.cpp | 2 +- engines/lastexpress/entities/chapters.h | 2 +- engines/lastexpress/entities/entity.cpp | 14 +++++++------- engines/lastexpress/entities/entity.h | 14 +++++++------- engines/lastexpress/game/beetle.cpp | 2 +- engines/lastexpress/game/entities.cpp | 2 +- engines/lastexpress/game/entities.h | 2 +- engines/lastexpress/game/scenes.cpp | 2 +- engines/lastexpress/game/scenes.h | 2 +- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/engines/lastexpress/entities/chapters.cpp b/engines/lastexpress/entities/chapters.cpp index a2f3a3d871..d373432710 100644 --- a/engines/lastexpress/entities/chapters.cpp +++ b/engines/lastexpress/entities/chapters.cpp @@ -1851,7 +1851,7 @@ void Chapters::enterExitHelper(bool isEnteringStation) { callbackAction(); } -void Chapters::playSteam() { +void Chapters::playSteam() const { getSoundQueue()->resetState(); getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4)); ENTITY_PARAM(0, 2) = 0; diff --git a/engines/lastexpress/entities/chapters.h b/engines/lastexpress/entities/chapters.h index ddb3de3bea..fb52ea3ee4 100644 --- a/engines/lastexpress/entities/chapters.h +++ b/engines/lastexpress/entities/chapters.h @@ -157,7 +157,7 @@ private: bool timeCheckExitStation(TimeValue timeValue, uint ¶meter, byte callback, const char *sequence); void enterExitStation(const SavePoint &savepoint, bool isEnteringStation); void enterExitHelper(bool isEnteringStation); - void playSteam(); + void playSteam() const; }; } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp index 552e1a8a82..88b2ada185 100644 --- a/engines/lastexpress/entities/entity.cpp +++ b/engines/lastexpress/entities/entity.cpp @@ -50,7 +50,7 @@ EntityData::EntityCallData::~EntityCallData() { SAFE_DELETE(sequence3); } -void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, int length) { +void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, int length) const { char seqName[13]; memset(&seqName, 0, length); @@ -825,7 +825,7 @@ void Entity::setupIISS(const char *name, uint index, uint param1, uint param2, c // Helper functions ////////////////////////////////////////////////////////////////////////// -bool Entity::updateParameter(uint ¶meter, uint timeType, uint delta) { +bool Entity::updateParameter(uint ¶meter, uint timeType, uint delta) const { if (!parameter) parameter = (uint)(timeType + delta); @@ -837,7 +837,7 @@ bool Entity::updateParameter(uint ¶meter, uint timeType, uint delta) { return true; } -bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) { +bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) const { if (getState()->time <= timeValue) { if (check || !parameter) parameter = (uint)(getState()->time + delta); @@ -851,7 +851,7 @@ bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint ¶mete return true; } -bool Entity::updateParameterCheck(uint ¶meter, uint timeType, uint delta) { +bool Entity::updateParameterCheck(uint ¶meter, uint timeType, uint delta) const { if (parameter && parameter >= timeType) return false; @@ -861,7 +861,7 @@ bool Entity::updateParameterCheck(uint ¶meter, uint timeType, uint delta) { return true; } -bool Entity::timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0 *function) { +bool Entity::timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0 *function) const { if (getState()->time > timeValue && !parameter) { parameter = 1; (*function)(); @@ -936,14 +936,14 @@ bool Entity::timeCheckCar(TimeValue timeValue, uint ¶meter, byte callback, C return false; } -void Entity::timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) { +void Entity::timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) const { if (getState()->time > timeValue && !parameter) { parameter = 1; getSavePoints()->push(entity1, entity2, action); } } -void Entity::timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex object, ObjectLocation location) { +void Entity::timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex object, ObjectLocation location) const { if (getState()->time > timeValue && !parameter) { parameter = 1; getObjects()->updateLocation2(object, location); diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h index e5c097b50a..c45367c43c 100644 --- a/engines/lastexpress/entities/entity.h +++ b/engines/lastexpress/entities/entity.h @@ -822,7 +822,7 @@ public: * @param string The string. * @param length Length of the string. */ - void syncString(Common::Serializer &s, Common::String &string, int length); + void syncString(Common::Serializer &s, Common::String &string, int length) const; // Serializable void saveLoadWithSerializer(Common::Serializer &s); @@ -1084,18 +1084,18 @@ protected: // Helper functions ////////////////////////////////////////////////////////////////////////// - bool updateParameter(uint ¶meter, uint timeType, uint delta); - bool updateParameterCheck(uint ¶meter, uint timeType, uint delta); - bool updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta); + bool updateParameter(uint ¶meter, uint timeType, uint delta) const; + bool updateParameterCheck(uint ¶meter, uint timeType, uint delta) const; + bool updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) const; - bool timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0 *function); + bool timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0 *function) const; bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0 *function); bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, const char *str, Common::Functor1 *function); bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, bool check, Common::Functor1 *function); bool timeCheckCallbackInventory(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0 *function); bool timeCheckCar(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0 *function); - void timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action); - void timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex index, ObjectLocation location); + void timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) const; + void timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex index, ObjectLocation location) const; bool timeCheckCallbackAction(TimeValue timeValue, uint ¶meter); bool timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint ¶meter, byte callback, const char* sound, EntityPosition position); diff --git a/engines/lastexpress/game/beetle.cpp b/engines/lastexpress/game/beetle.cpp index 7cdd67caf5..d7a369ba40 100644 --- a/engines/lastexpress/game/beetle.cpp +++ b/engines/lastexpress/game/beetle.cpp @@ -94,7 +94,7 @@ void Beetle::load() { // Check that all sequences are loaded properly _data->isLoaded = true; - for (int i = 0; i < (int)_data->sequences.size(); i++) { + for (uint i = 0; i < _data->sequences.size(); i++) { if (!_data->sequences[i]->isLoaded()) { _data->isLoaded = false; break; diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp index 51db635bed..de30792405 100644 --- a/engines/lastexpress/game/entities.cpp +++ b/engines/lastexpress/game/entities.cpp @@ -669,7 +669,7 @@ void Entities::executeCallbacks() { ////////////////////////////////////////////////////////////////////////// // Processing ////////////////////////////////////////////////////////////////////////// -void Entities::incrementDirectionCounter(EntityData::EntityCallData *data) { +void Entities::incrementDirectionCounter(EntityData::EntityCallData *data) const { data->doProcessEntity = false; if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight)) diff --git a/engines/lastexpress/game/entities.h b/engines/lastexpress/game/entities.h index a9de7931f0..81aed627aa 100644 --- a/engines/lastexpress/game/entities.h +++ b/engines/lastexpress/game/entities.h @@ -344,7 +344,7 @@ private: uint _positions[_positionsCount]; void executeCallbacks(); - void incrementDirectionCounter(EntityData::EntityCallData *data); + void incrementDirectionCounter(EntityData::EntityCallData *data) const; void processEntity(EntityIndex entity); void drawSequence(EntityIndex entity, const char *sequence, EntityDirection direction) const; diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp index 3cda900757..a2c7226b93 100644 --- a/engines/lastexpress/game/scenes.cpp +++ b/engines/lastexpress/game/scenes.cpp @@ -739,7 +739,7 @@ void SceneManager::resetQueue() { _queue.clear(); } -void SceneManager::setCoordinates(Common::Rect rect) { +void SceneManager::setCoordinates(const Common::Rect &rect) { _flagCoordinates = true; if (_coords.right > rect.right) diff --git a/engines/lastexpress/game/scenes.h b/engines/lastexpress/game/scenes.h index a866c65111..1c7ae85f98 100644 --- a/engines/lastexpress/game/scenes.h +++ b/engines/lastexpress/game/scenes.h @@ -79,7 +79,7 @@ public: void removeAndRedraw(SequenceFrame **frame, bool doRedraw); void resetQueue(); void setCoordinates(SequenceFrame *frame); - void setCoordinates(Common::Rect rect); + void setCoordinates(const Common::Rect &rect); // Helpers SceneIndex getSceneIndexFromPosition(CarIndex car, Position position, int param3 = -1); -- cgit v1.2.3 From bc4e10dabca5b76283eb6fb431702ccd92a001c0 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Tue, 21 Aug 2012 23:02:39 -0400 Subject: LASTEXPRESS: Remove some unreachable code --- engines/lastexpress/fight/fight.cpp | 2 -- engines/lastexpress/game/action.cpp | 2 -- engines/lastexpress/game/inventory.cpp | 2 -- engines/lastexpress/game/savegame.cpp | 2 +- engines/lastexpress/sound/entry.cpp | 4 +--- 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/engines/lastexpress/fight/fight.cpp b/engines/lastexpress/fight/fight.cpp index b00c1732e7..49a9b85657 100644 --- a/engines/lastexpress/fight/fight.cpp +++ b/engines/lastexpress/fight/fight.cpp @@ -39,10 +39,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp index 60a309518a..033fdfc2e8 100644 --- a/engines/lastexpress/game/action.cpp +++ b/engines/lastexpress/game/action.cpp @@ -421,8 +421,6 @@ SceneIndex Action::processHotspot(const SceneHotspot &hotspot) { // Action 0 IMPLEMENT_ACTION(dummy) error("[Action::action_dummy] Dummy action function called (hotspot action: %d)", hotspot.action); - - return kSceneInvalid; } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index 52c00ece31..9e0f583c63 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -35,10 +35,8 @@ #include "lastexpress/menu/menu.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 360e99146a..9857ef24cc 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -550,7 +550,7 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { entry.saveLoadWithSerializer(ser); if (!entry.isValid()) { - error("[SaveLoad::saveGame] Invalid entry. This savegame might be corrupted"); + warning("[SaveLoad::saveGame] Invalid entry. This savegame might be corrupted"); _savegame->seek(header.offset); } else if (getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) { // Not ready to save a game, skipping! diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp index f2a063e45f..3d22657124 100644 --- a/engines/lastexpress/sound/entry.cpp +++ b/engines/lastexpress/sound/entry.cpp @@ -116,10 +116,8 @@ void SoundEntry::close() { } void SoundEntry::play() { - if (!_stream) { + if (!_stream) error("[SoundEntry::play] stream has been disposed"); - return; - } // Prepare sound stream if (!_soundStream) -- cgit v1.2.3 From 275aded0b0e485eead8d5bdac48d9c8dc1a6ef9c Mon Sep 17 00:00:00 2001 From: Littleboy Date: Tue, 21 Aug 2012 23:16:52 -0400 Subject: LASTEXPRESS: Remove unnecessary casts --- engines/lastexpress/data/subtitle.cpp | 6 +++--- engines/lastexpress/entities/entity.cpp | 4 ++-- engines/lastexpress/entities/entity.h | 6 +++--- engines/lastexpress/game/action.cpp | 2 +- engines/lastexpress/game/entities.cpp | 2 +- engines/lastexpress/game/inventory.cpp | 4 ++-- engines/lastexpress/game/savepoint.cpp | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/engines/lastexpress/data/subtitle.cpp b/engines/lastexpress/data/subtitle.cpp index a9a8284588..4d19c02aa7 100644 --- a/engines/lastexpress/data/subtitle.cpp +++ b/engines/lastexpress/data/subtitle.cpp @@ -210,10 +210,10 @@ void SubtitleManager::setTime(uint16 time) { _currentIndex = -1; // Find the appropriate line to show - for (int16 i = 0; i < (int16)_subtitles.size(); i++) { + for (uint i = 0; i < _subtitles.size(); i++) { if ((time >= _subtitles[i]->getTimeStart()) && (time <= _subtitles[i]->getTimeStop())) { // Keep the index of the line to show - _currentIndex = i; + _currentIndex = (int16)i; return; } } @@ -237,7 +237,7 @@ Common::Rect SubtitleManager::draw(Graphics::Surface *surface) { // Draw the current line assert(_currentIndex >= 0 && _currentIndex < (int16)_subtitles.size()); - return _subtitles[_currentIndex]->draw(surface, _font); + return _subtitles[(uint16)_currentIndex]->draw(surface, _font); } } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp index 88b2ada185..dad5e67392 100644 --- a/engines/lastexpress/entities/entity.cpp +++ b/engines/lastexpress/entities/entity.cpp @@ -50,7 +50,7 @@ EntityData::EntityCallData::~EntityCallData() { SAFE_DELETE(sequence3); } -void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, int length) const { +void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, uint length) const { char seqName[13]; memset(&seqName, 0, length); @@ -117,7 +117,7 @@ EntityData::EntityParameters *EntityData::getParameters(uint callback, byte inde return _parameters[callback].parameters[index]; } -int EntityData::getCallback(uint callback) const { +byte EntityData::getCallback(uint callback) const { if (callback >= 16) error("[EntityData::getCallback] Invalid callback value (was: %d, max: 16)", callback); diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h index c45367c43c..c67d13db9e 100644 --- a/engines/lastexpress/entities/entity.h +++ b/engines/lastexpress/entities/entity.h @@ -822,7 +822,7 @@ public: * @param string The string. * @param length Length of the string. */ - void syncString(Common::Serializer &s, Common::String &string, int length) const; + void syncString(Common::Serializer &s, Common::String &string, uint length) const; // Serializable void saveLoadWithSerializer(Common::Serializer &s); @@ -845,8 +845,8 @@ public: EntityParameters *getCurrentParameters(byte index = 0) { return getParameters(_data.currentCall, index); } EntityCallParameters *getCurrentCallParameters() { return &_parameters[_data.currentCall]; } - int getCallback(uint callback) const; - int getCurrentCallback() { return getCallback(_data.currentCall); } + byte getCallback(uint callback) const; + byte getCurrentCallback() { return getCallback(_data.currentCall); } void setCallback(uint callback, byte index); void setCurrentCallback(uint index) { setCallback(_data.currentCall, index); } diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp index 033fdfc2e8..796abf2ce7 100644 --- a/engines/lastexpress/game/action.cpp +++ b/engines/lastexpress/game/action.cpp @@ -394,7 +394,7 @@ Action::Action(LastExpressEngine *engine) : _engine(engine) { } Action::~Action() { - for (int i = 0; i < (int)_actions.size(); i++) + for (uint i = 0; i < _actions.size(); i++) SAFE_DELETE(_actions[i]); _actions.clear(); diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp index de30792405..fafbd7cb64 100644 --- a/engines/lastexpress/game/entities.cpp +++ b/engines/lastexpress/game/entities.cpp @@ -181,7 +181,7 @@ Entities::Entities(LastExpressEngine *engine) : _engine(engine) { Entities::~Entities() { SAFE_DELETE(_header); - for (int i = 0; i < (int)_entities.size(); i++) + for (uint i = 0; i < _entities.size(); i++) SAFE_DELETE(_entities[i]); _entities.clear(); diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index 9e0f583c63..11e7369ee1 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -619,7 +619,7 @@ void Inventory::drawEgg() const { // Blinking egg: we need to blink the egg for delta time, with the blinking getting faster until it's always lit. void Inventory::drawBlinkingEgg(uint ticks) { - uint globalTimer = getGlobalTimer(); + uint globalTimer = (uint)getGlobalTimer(); uint timerValue = (getProgress().jacket == kJacketGreen) ? 450 : 225; if (globalTimer == timerValue || globalTimer == 900) { @@ -653,7 +653,7 @@ void Inventory::drawBlinkingEgg(uint ticks) { } void Inventory::blinkEgg() { - drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, (_blinkingBrightness == 0) ? -1 : _blinkingBrightness); + drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, (_blinkingBrightness == 0) ? -1 : (int16)_blinkingBrightness); askForRedraw(); diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp index 6b2dfc5930..8d14ec386b 100644 --- a/engines/lastexpress/game/savepoint.cpp +++ b/engines/lastexpress/game/savepoint.cpp @@ -202,7 +202,7 @@ void SavePoints::callAndProcess() { // Misc ////////////////////////////////////////////////////////////////////////// bool SavePoints::updateEntityFromData(const SavePoint &savepoint) { - for (int i = 0; i < (int)_data.size(); i++) { + for (uint i = 0; i < _data.size(); i++) { // Not a data savepoint! if (!_data[i].entity1) @@ -210,7 +210,7 @@ bool SavePoints::updateEntityFromData(const SavePoint &savepoint) { // Found our data! if (_data[i].entity1 == savepoint.entity1 && _data[i].action == savepoint.action) { - debugC(8, kLastExpressDebugLogic, "Update entity from data: entity1=%s, action=%s, param=%d", ENTITY_NAME(_data[i].entity1), ACTION_NAME(_data[i].action), _data[i].param); + debugC(8, kLastExpressDebugLogic, "Update entity from data: entity1=%s, action=%s, param=%u", ENTITY_NAME(_data[i].entity1), ACTION_NAME(_data[i].action), _data[i].param); // the SavePoint param value is the index of the entity call parameter to update getEntities()->get(_data[i].entity1)->getParamData()->updateParameters(_data[i].param); -- cgit v1.2.3 From 81c6016e8f6c670c1046be12b541b0d63c9fd5fa Mon Sep 17 00:00:00 2001 From: Littleboy Date: Thu, 23 Aug 2012 05:09:01 -0400 Subject: LASTEXPRESS: Identify several Verges functions --- engines/lastexpress/entities/verges.cpp | 102 ++++++++++++++++---------------- engines/lastexpress/entities/verges.h | 8 +-- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/engines/lastexpress/entities/verges.cpp b/engines/lastexpress/entities/verges.cpp index 867f122d8f..94698886bb 100644 --- a/engines/lastexpress/entities/verges.cpp +++ b/engines/lastexpress/entities/verges.cpp @@ -46,13 +46,13 @@ Verges::Verges(LastExpressEngine *engine) : Entity(engine, kEntityVerges) { ADD_CALLBACK_FUNCTION(Verges, callbackActionRestaurantOrSalon); ADD_CALLBACK_FUNCTION(Verges, savegame); ADD_CALLBACK_FUNCTION(Verges, updateEntity); - ADD_CALLBACK_FUNCTION(Verges, function9); - ADD_CALLBACK_FUNCTION(Verges, function10); + ADD_CALLBACK_FUNCTION(Verges, walkBetweenCars); + ADD_CALLBACK_FUNCTION(Verges, makeAnnouncement); ADD_CALLBACK_FUNCTION(Verges, function11); ADD_CALLBACK_FUNCTION(Verges, function12); - ADD_CALLBACK_FUNCTION(Verges, function13); + ADD_CALLBACK_FUNCTION(Verges, baggageCar); ADD_CALLBACK_FUNCTION(Verges, updateFromTime); - ADD_CALLBACK_FUNCTION(Verges, function15); + ADD_CALLBACK_FUNCTION(Verges, dialog); ADD_CALLBACK_FUNCTION(Verges, function16); ADD_CALLBACK_FUNCTION(Verges, function17); ADD_CALLBACK_FUNCTION(Verges, chapter1); @@ -149,7 +149,7 @@ IMPLEMENT_FUNCTION_II(8, Verges, updateEntity, CarIndex, EntityPosition) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(9, Verges, function9) +IMPLEMENT_FUNCTION_S(9, Verges, walkBetweenCars) switch (savepoint.action) { default: break; @@ -201,7 +201,7 @@ switch (savepoint.action) { case 3: setCallback(4); - setup_function10(kCarGreenSleeping, kPosition_540, (char *)¶ms->seq1); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, (char *)¶ms->seq1); break; case 4: @@ -225,7 +225,7 @@ switch (savepoint.action) { IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition) +IMPLEMENT_FUNCTION_IIS(10, Verges, makeAnnouncement, CarIndex, EntityPosition) switch (savepoint.action) { default: break; @@ -404,7 +404,7 @@ IMPLEMENT_FUNCTION(12, Verges, function12) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_I(13, Verges, function13, bool) +IMPLEMENT_FUNCTION_I(13, Verges, baggageCar, bool) switch (savepoint.action) { default: break; @@ -449,7 +449,7 @@ IMPLEMENT_FUNCTION_I(14, Verges, updateFromTime, uint32) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex) +IMPLEMENT_FUNCTION_IS(15, Verges, dialog, EntityIndex) switch (savepoint.action) { default: break; @@ -548,7 +548,7 @@ IMPLEMENT_FUNCTION(17, Verges, function17) case 2: setCallback(3); - setup_function15(kEntityMertens, "TRA1291"); + setup_dialog(kEntityMertens, "TRA1291"); break; case 3: @@ -774,10 +774,10 @@ IMPLEMENT_FUNCTION(25, Verges, function25) if (getData()->car == kCarRedSleeping) { setCallback(6); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA1005"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA1005"); } else { setCallback(7); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA1006"); } break; } @@ -805,7 +805,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25) getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872); setCallback(4); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA1006"); break; case 4: @@ -838,7 +838,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25) getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872); setCallback(10); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA1006"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA1006"); break; case 10: @@ -892,7 +892,7 @@ IMPLEMENT_FUNCTION(26, Verges, chapter1Handler) label_callback1: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(2); - setup_function13(false); + setup_baggageCar(false); break; } @@ -907,7 +907,7 @@ label_callback3: if (params->param6) goto label_callback12; - if (Entity::timeCheckCallback(kTimeChapter1, params->param7, 4, "TRA1001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTimeChapter1, params->param7, 4, "TRA1001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback4: @@ -923,19 +923,19 @@ label_callback4: } label_callback8: - if (Entity::timeCheckCallback(kTime1107000, CURRENT_PARAM(1, 1), 9, "TRA1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1107000, CURRENT_PARAM(1, 1), 9, "TRA1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback9: - if (Entity::timeCheckCallback(kTime1134000, CURRENT_PARAM(1, 2), 10, "TRA1002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1134000, CURRENT_PARAM(1, 2), 10, "TRA1002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback10: - if (Entity::timeCheckCallback(kTime1165500, CURRENT_PARAM(1, 3), 11, "TRA1003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1165500, CURRENT_PARAM(1, 3), 11, "TRA1003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback11: - if (Entity::timeCheckCallback(kTime1225800, CURRENT_PARAM(1, 4), 12, "TRA1004", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1225800, CURRENT_PARAM(1, 4), 12, "TRA1004", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback12: @@ -970,7 +970,7 @@ label_callback15: case kActionOpenDoor: setCallback(17); - setup_function13(savepoint.param.intValue < 106 ? true : false); + setup_baggageCar(savepoint.param.intValue < 106 ? true : false); break; case kActionDefault: @@ -1006,7 +1006,7 @@ label_callback15: case 6: setCallback(7); - setup_function15(kEntityMertens, "TRA1202"); + setup_dialog(kEntityMertens, "TRA1202"); break; case 7: @@ -1084,11 +1084,11 @@ IMPLEMENT_FUNCTION(28, Verges, chapter2Handler) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); } label_callback_1: - if (Entity::timeCheckCallback(kTime1818900, params->param1, 2, "Tra2177", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1818900, params->param1, 2, "Tra2177", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_2: @@ -1130,7 +1130,7 @@ label_callback_6: case kActionOpenDoor: setCallback(8); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionDefault: @@ -1155,7 +1155,7 @@ label_callback_6: case 4: setCallback(5); - setup_function15(kEntityCoudert, "TRA2100"); + setup_dialog(kEntityCoudert, "TRA2100"); break; case 5: @@ -1221,7 +1221,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30) case 2: setCallback(3); - setup_function15(kEntityCoudert, (char *)¶ms->seq1); + setup_dialog(kEntityCoudert, (char *)¶ms->seq1); break; case 3: @@ -1260,7 +1260,7 @@ IMPLEMENT_FUNCTION(31, Verges, function31) case 2: setCallback(3); - setup_function15(kEntityCoudert, "TRA3015"); + setup_dialog(kEntityCoudert, "TRA3015"); break; case 3: @@ -1289,7 +1289,7 @@ IMPLEMENT_FUNCTION(32, Verges, function32) if (getState()->time > kTime2263500 && !params->param1) { params->param1 = 1; setCallback(5); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA3006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA3006"); break; } break; @@ -1341,7 +1341,7 @@ IMPLEMENT_FUNCTION(32, Verges, function32) case 3: setCallback(4); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA3004"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA3004"); break; case 4: @@ -1412,7 +1412,7 @@ IMPLEMENT_FUNCTION(33, Verges, function33) getSavePoints()->push(kEntityVerges, kEntityAbbot, kAction192054567); setCallback(6); - setup_function9("Tra3010"); + setup_walkBetweenCars("Tra3010"); break; case 6: @@ -1432,7 +1432,7 @@ IMPLEMENT_FUNCTION(34, Verges, function34) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); break; } @@ -1451,11 +1451,11 @@ label_callback_2: } label_callback_3: - if (Entity::timeCheckCallback(kTime1971000, params->param1, 4, "Tra3001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1971000, params->param1, 4, "Tra3001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_4: - if (Entity::timeCheckCallback(kTime1998000, params->param2, 5, "Tra3010a", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1998000, params->param2, 5, "Tra3010a", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_5: @@ -1463,11 +1463,11 @@ label_callback_5: break; label_callback_6: - if (Entity::timeCheckCallback(kTime2070000, params->param4, 7, "Tra3002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2070000, params->param4, 7, "Tra3002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_7: - if (Entity::timeCheckCallback(kTime2142000, params->param5, 8, "Tra3003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2142000, params->param5, 8, "Tra3003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_8: @@ -1480,7 +1480,7 @@ label_callback_9: case kActionOpenDoor: setCallback(11); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionCallback: @@ -1542,7 +1542,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35) case 2: setCallback(3); - setup_function15(kEntityMertens, "Tra3011A"); + setup_dialog(kEntityMertens, "Tra3011A"); break; case 3: @@ -1554,7 +1554,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35) case 4: setCallback(5); - setup_function15(kEntityMertens, "Tra3011"); + setup_dialog(kEntityMertens, "Tra3011"); break; case 5: @@ -1609,7 +1609,7 @@ IMPLEMENT_FUNCTION(37, Verges, chapter4Handler) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); break; } @@ -1622,37 +1622,37 @@ label_callback_1: } label_callback_2: - if (Entity::timeCheckCallback(kTime2349000, params->param1, 3, "Tra1001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2349000, params->param1, 3, "Tra1001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_3: - if (Entity::timeCheckCallback(kTime2378700, params->param2, 4, "Tra4001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2378700, params->param2, 4, "Tra4001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_4: - if (Entity::timeCheckCallback(kTime2403000, params->param3, 5, "Tra1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2403000, params->param3, 5, "Tra1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_5: - if (Entity::timeCheckCallback(kTime2414700, params->param4, 6, "Tra4002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2414700, params->param4, 6, "Tra4002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_6: - if (Entity::timeCheckCallback(kTime2484000, params->param5, 7, "Tra4003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2484000, params->param5, 7, "Tra4003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_7: - if (Entity::timeCheckCallback(kTime2511000, params->param6, 8, "Tra4004", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2511000, params->param6, 8, "Tra4004", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; } label_callback_8: - Entity::timeCheckCallback(kTime2538000, params->param7, 9, "Tra4005", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)); + Entity::timeCheckCallback(kTime2538000, params->param7, 9, "Tra4005", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars)); break; case kActionOpenDoor: setCallback(10); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionDefault: @@ -1822,7 +1822,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) getData()->location = kLocationInsideCompartment; setCallback(1); - setup_function10(kCarRedSleeping, kPosition_2000, "Tra5001"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_2000, "Tra5001"); break; case kActionCallback: @@ -1891,7 +1891,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so case 2: setCallback(3); - setup_function15(kEntityCoudert, sound1); + setup_dialog(kEntityCoudert, sound1); break; case 3: @@ -1901,7 +1901,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so case 4: setCallback(5); - setup_function15(kEntityMertens, sound2); + setup_dialog(kEntityMertens, sound2); break; case 5: diff --git a/engines/lastexpress/entities/verges.h b/engines/lastexpress/entities/verges.h index 82381043d3..8932f81fce 100644 --- a/engines/lastexpress/entities/verges.h +++ b/engines/lastexpress/entities/verges.h @@ -87,11 +87,11 @@ public: */ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition) - DECLARE_FUNCTION_1(function9, const char *soundName) - DECLARE_FUNCTION_3(function10, CarIndex car, EntityPosition entityPosition, const char *soundName) + DECLARE_FUNCTION_1(walkBetweenCars, const char *soundName) + DECLARE_FUNCTION_3(makeAnnouncement, CarIndex car, EntityPosition entityPosition, const char *soundName) DECLARE_FUNCTION(function11) DECLARE_FUNCTION(function12) - DECLARE_FUNCTION_1(function13, bool) + DECLARE_FUNCTION_1(baggageCar, bool) /** * Updates parameter 2 using time value @@ -100,7 +100,7 @@ public: */ DECLARE_FUNCTION_1(updateFromTime, uint32 time) - DECLARE_FUNCTION_2(function15, EntityIndex entity, const char *soundName) + DECLARE_FUNCTION_2(dialog, EntityIndex entity, const char *soundName) DECLARE_FUNCTION_3(function16, EntityIndex entityIndex, const char *soundName1, const char *soundName2) DECLARE_FUNCTION(function17) -- cgit v1.2.3 From 8fa617556c080c4af843944e900f055f4e717e44 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Thu, 23 Aug 2012 05:09:25 -0400 Subject: LASTEXPRESS: Fix typo in Verges chapter 3 function --- engines/lastexpress/entities/verges.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/lastexpress/entities/verges.cpp b/engines/lastexpress/entities/verges.cpp index 94698886bb..ed1918d4ed 100644 --- a/engines/lastexpress/entities/verges.cpp +++ b/engines/lastexpress/entities/verges.cpp @@ -1177,7 +1177,7 @@ IMPLEMENT_FUNCTION(29, Verges, chapter3) break; case kActionNone: - setup_function23(); + setup_function33(); break; case kActionDefault: -- cgit v1.2.3 From 6ab3b903d46899d642fb57faad6b445242285033 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Fri, 24 Aug 2012 13:44:17 -0400 Subject: LASTEXPRESS: Identify more Verges functions --- engines/lastexpress/entities/abbot.cpp | 2 +- engines/lastexpress/entities/august.cpp | 2 +- engines/lastexpress/entities/verges.cpp | 60 ++++++++++++++++----------------- engines/lastexpress/entities/verges.h | 18 +++++----- 4 files changed, 41 insertions(+), 41 deletions(-) diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp index 85d0d8948b..406b017d3a 100644 --- a/engines/lastexpress/entities/abbot.cpp +++ b/engines/lastexpress/entities/abbot.cpp @@ -1547,7 +1547,7 @@ IMPLEMENT_FUNCTION(45, Abbot, function45) getData()->car = kCarRedSleeping; getData()->location = kLocationOutsideCompartment; - RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function38); + RESET_ENTITY_STATE(kEntityVerges, Verges, setup_resetState); getEntities()->drawSequenceLeft(kEntityAbbot, "617Ec"); getEntities()->enterCompartment(kEntityAbbot, kObjectCompartmentC, true); diff --git a/engines/lastexpress/entities/august.cpp b/engines/lastexpress/entities/august.cpp index 67d810fde2..dbae7bad20 100644 --- a/engines/lastexpress/entities/august.cpp +++ b/engines/lastexpress/entities/august.cpp @@ -3530,7 +3530,7 @@ IMPLEMENT_FUNCTION(69, August, unhookCars) getScenes()->loadSceneFromPosition(kCarRestaurant, 85, 1); getSavePoints()->pushAll(kEntityAugust, kActionProceedChapter5); - RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function42) + RESET_ENTITY_STATE(kEntityVerges, Verges, setup_end) } break; } diff --git a/engines/lastexpress/entities/verges.cpp b/engines/lastexpress/entities/verges.cpp index ed1918d4ed..d9ddb0a4d1 100644 --- a/engines/lastexpress/entities/verges.cpp +++ b/engines/lastexpress/entities/verges.cpp @@ -53,33 +53,33 @@ Verges::Verges(LastExpressEngine *engine) : Entity(engine, kEntityVerges) { ADD_CALLBACK_FUNCTION(Verges, baggageCar); ADD_CALLBACK_FUNCTION(Verges, updateFromTime); ADD_CALLBACK_FUNCTION(Verges, dialog); - ADD_CALLBACK_FUNCTION(Verges, function16); - ADD_CALLBACK_FUNCTION(Verges, function17); + ADD_CALLBACK_FUNCTION(Verges, dialog2); + ADD_CALLBACK_FUNCTION(Verges, talkAboutPassengerList); ADD_CALLBACK_FUNCTION(Verges, chapter1); ADD_CALLBACK_FUNCTION(Verges, talkHarem); ADD_CALLBACK_FUNCTION(Verges, talkPassengerList); ADD_CALLBACK_FUNCTION(Verges, talkGendarmes); - ADD_CALLBACK_FUNCTION(Verges, function22); + ADD_CALLBACK_FUNCTION(Verges, askMertensToRelayAugustInvitation); ADD_CALLBACK_FUNCTION(Verges, function23); ADD_CALLBACK_FUNCTION(Verges, policeGettingOffTrain); - ADD_CALLBACK_FUNCTION(Verges, function25); + ADD_CALLBACK_FUNCTION(Verges, policeSearch); ADD_CALLBACK_FUNCTION(Verges, chapter1Handler); ADD_CALLBACK_FUNCTION(Verges, chapter2); ADD_CALLBACK_FUNCTION(Verges, chapter2Handler); ADD_CALLBACK_FUNCTION(Verges, chapter3); ADD_CALLBACK_FUNCTION(Verges, function30); - ADD_CALLBACK_FUNCTION(Verges, function31); + ADD_CALLBACK_FUNCTION(Verges, talkAboutMax); ADD_CALLBACK_FUNCTION(Verges, function32); ADD_CALLBACK_FUNCTION(Verges, function33); ADD_CALLBACK_FUNCTION(Verges, function34); - ADD_CALLBACK_FUNCTION(Verges, function35); + ADD_CALLBACK_FUNCTION(Verges, organizeConcertInvitations); ADD_CALLBACK_FUNCTION(Verges, chapter4); ADD_CALLBACK_FUNCTION(Verges, chapter4Handler); - ADD_CALLBACK_FUNCTION(Verges, function38); + ADD_CALLBACK_FUNCTION(Verges, resetState); ADD_CALLBACK_FUNCTION(Verges, chapter5); ADD_CALLBACK_FUNCTION(Verges, chapter5Handler); - ADD_CALLBACK_FUNCTION(Verges, function41); - ADD_CALLBACK_FUNCTION(Verges, function42); + ADD_CALLBACK_FUNCTION(Verges, askPassengersToStayInCompartments); + ADD_CALLBACK_FUNCTION(Verges, end); } ////////////////////////////////////////////////////////////////////////// @@ -486,7 +486,7 @@ IMPLEMENT_FUNCTION_IS(15, Verges, dialog, EntityIndex) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex) +IMPLEMENT_FUNCTION_ISS(16, Verges, dialog2, EntityIndex) switch (savepoint.action) { default: break; @@ -526,7 +526,7 @@ IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Verges, function17) +IMPLEMENT_FUNCTION(17, Verges, talkAboutPassengerList) switch (savepoint.action) { default: break; @@ -611,7 +611,7 @@ IMPLEMENT_FUNCTION(21, Verges, talkGendarmes) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Verges, function22) +IMPLEMENT_FUNCTION(22, Verges, askMertensToRelayAugustInvitation) switch (savepoint.action) { default: break; @@ -634,10 +634,10 @@ IMPLEMENT_FUNCTION(22, Verges, function22) case 2: if (getEvent(kEventMertensAskTylerCompartment) || getEvent(kEventMertensAskTylerCompartmentD) || getEvent(kEventMertensAugustWaiting)) { setCallback(3); - setup_function16(kEntityMertens, "TRA1200", "TRA1201"); + setup_dialog2(kEntityMertens, "TRA1200", "TRA1201"); } else { setCallback(4); - setup_function16(kEntityMertens, "TRA1200A", "TRA1201"); + setup_dialog2(kEntityMertens, "TRA1200A", "TRA1201"); } break; @@ -714,7 +714,7 @@ IMPLEMENT_FUNCTION(24, Verges, policeGettingOffTrain) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(25, Verges, function25) +IMPLEMENT_FUNCTION(25, Verges, policeSearch) switch (savepoint.action) { default: break; @@ -899,7 +899,7 @@ label_callback1: label_callback2: if (ENTITY_PARAM(0, 7)) { setCallback(3); - setup_function25(); + setup_policeSearch(); break; } @@ -955,7 +955,7 @@ label_callback13: label_callback14: if (ENTITY_PARAM(0, 3) && !params->param4 && (getState()->time < kTime1134000 || getState()->time > kTime1156500)) { setCallback(15); - setup_function17(); + setup_talkAboutPassengerList(); break; } @@ -963,7 +963,7 @@ label_callback15: if (ENTITY_PARAM(0, 1) && !params->param5) { if (getState()->time < kTime1134000 || getState()->time > kTime1156500) { setCallback(16); - setup_function22(); + setup_askMertensToRelayAugustInvitation(); } } break; @@ -1117,7 +1117,7 @@ label_callback_6: if (ENTITY_PARAM(0, 3)) { setCallback(7); - setup_function17(); + setup_talkAboutPassengerList(); } break; @@ -1238,7 +1238,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(31, Verges, function31) +IMPLEMENT_FUNCTION(31, Verges, talkAboutMax) switch (savepoint.action) { default: break; @@ -1439,14 +1439,14 @@ IMPLEMENT_FUNCTION(34, Verges, function34) label_callback_1: if (ENTITY_PARAM(0, 4)) { setCallback(2); - setup_function31(); + setup_talkAboutMax(); break; } label_callback_2: if (ENTITY_PARAM(0, 3)) { setCallback(3); - setup_function17(); + setup_talkAboutPassengerList(); break; } @@ -1459,7 +1459,7 @@ label_callback_4: break; label_callback_5: - if (Entity::timeCheckCallback(kTime2016000, params->param3, 6, WRAP_SETUP_FUNCTION(Verges, setup_function35))) + if (Entity::timeCheckCallback(kTime2016000, params->param3, 6, WRAP_SETUP_FUNCTION(Verges, setup_organizeConcertInvitations))) break; label_callback_6: @@ -1520,7 +1520,7 @@ label_callback_9: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(35, Verges, function35) +IMPLEMENT_FUNCTION(35, Verges, organizeConcertInvitations) switch (savepoint.action) { default: break; @@ -1617,7 +1617,7 @@ label_callback_1: if (ENTITY_PARAM(0, 6)) { if (ENTITY_PARAM(0, 3)) { setCallback(2); - setup_function17(); + setup_talkAboutPassengerList(); break; } @@ -1697,7 +1697,7 @@ label_callback_8: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(38, Verges, function38) +IMPLEMENT_FUNCTION(38, Verges, resetState) switch (savepoint.action) { default: break; @@ -1803,14 +1803,14 @@ IMPLEMENT_FUNCTION(40, Verges, chapter5Handler) getAction()->playAnimation(kEventCathFreePassengers); getSavePoints()->pushAll(kEntityVerges, kActionProceedChapter5); getScenes()->loadSceneFromPosition(kCarRedSleeping, 40); - setup_function41(); + setup_askPassengersToStayInCompartments(); } break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(41, Verges, function41) +IMPLEMENT_FUNCTION(41, Verges, askPassengersToStayInCompartments) switch (savepoint.action) { default: break; @@ -1852,7 +1852,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) break; case 4: - setup_function42(); + setup_end(); break; } break; @@ -1860,7 +1860,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(42, Verges, function42) +IMPLEMENT_FUNCTION(42, Verges, end) if (savepoint.action == kActionDefault) getEntities()->clearSequences(kEntityVerges); IMPLEMENT_FUNCTION_END diff --git a/engines/lastexpress/entities/verges.h b/engines/lastexpress/entities/verges.h index 8932f81fce..93cc190d1e 100644 --- a/engines/lastexpress/entities/verges.h +++ b/engines/lastexpress/entities/verges.h @@ -101,8 +101,8 @@ public: DECLARE_FUNCTION_1(updateFromTime, uint32 time) DECLARE_FUNCTION_2(dialog, EntityIndex entity, const char *soundName) - DECLARE_FUNCTION_3(function16, EntityIndex entityIndex, const char *soundName1, const char *soundName2) - DECLARE_FUNCTION(function17) + DECLARE_FUNCTION_3(dialog2, EntityIndex entityIndex, const char *soundName1, const char *soundName2) + DECLARE_FUNCTION(talkAboutPassengerList) /** * Setup Chapter 1 @@ -112,10 +112,10 @@ public: DECLARE_FUNCTION_NOSETUP(talkHarem) DECLARE_FUNCTION(talkPassengerList) DECLARE_FUNCTION(talkGendarmes) - DECLARE_FUNCTION(function22) + DECLARE_FUNCTION(askMertensToRelayAugustInvitation) DECLARE_FUNCTION(function23) DECLARE_FUNCTION(policeGettingOffTrain) - DECLARE_FUNCTION(function25) + DECLARE_FUNCTION(policeSearch) /** * Handle Chapter 1 events @@ -138,11 +138,11 @@ public: DECLARE_FUNCTION(chapter3) DECLARE_FUNCTION_1(function30, const char *soundName) - DECLARE_FUNCTION(function31) + DECLARE_FUNCTION(talkAboutMax) DECLARE_FUNCTION(function32) DECLARE_FUNCTION(function33) DECLARE_FUNCTION(function34) - DECLARE_FUNCTION(function35) + DECLARE_FUNCTION(organizeConcertInvitations) /** * Setup Chapter 4 @@ -154,7 +154,7 @@ public: */ DECLARE_FUNCTION(chapter4Handler) - DECLARE_FUNCTION(function38) + DECLARE_FUNCTION(resetState) /** * Setup Chapter 5 @@ -166,8 +166,8 @@ public: */ DECLARE_FUNCTION(chapter5Handler) - DECLARE_FUNCTION(function41) - DECLARE_FUNCTION(function42) + DECLARE_FUNCTION(askPassengersToStayInCompartments) + DECLARE_FUNCTION(end) private: void talk(const SavePoint &savepoint, const char *sound1, const char *sound2); -- cgit v1.2.3 From ee8581b778b83bc01af0f26bc8b3680ebc266700 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Mon, 27 Aug 2012 21:49:15 -0400 Subject: LASTEXPRESS: Cleanup savegame - Check for valid stream in readValue/writeValue functions - Properly initialize/clear members --- engines/lastexpress/game/savegame.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 9857ef24cc..7efce0007b 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -78,7 +78,7 @@ uint32 SavegameStream::read(void *dataPtr, uint32 dataSize) { uint32 SavegameStream::readUncompressed(void *dataPtr, uint32 dataSize) { if ((int32)dataSize > size() - pos()) { - dataSize = size() - pos(); + dataSize = (uint32)(size() - pos()); _eos = true; } memcpy(dataPtr, getData() + pos(), dataSize); @@ -230,7 +230,7 @@ uint32 SavegameStream::writeCompressed(const void *dataPtr, uint32 dataSize) { if (*data != _previousValue || _repeatCount >= 255) { if (_previousValue) { writeBuffer(0xFF, true); - writeBuffer(_repeatCount, true); + writeBuffer((uint8)_repeatCount, true); writeBuffer(_previousValue, true); _previousValue = *data++; @@ -255,7 +255,7 @@ uint32 SavegameStream::writeCompressed(const void *dataPtr, uint32 dataSize) { } writeBuffer(0xFD, true); - writeBuffer(_repeatCount, true); + writeBuffer((uint8)_repeatCount, true); _previousValue = *data++; _valueCount = 1; @@ -348,11 +348,12 @@ uint32 SavegameStream::readCompressed(void *dataPtr, uint32 dataSize) { // Constructors ////////////////////////////////////////////////////////////////////////// -SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0) { +SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0), _entity(kEntityPlayer) { } SaveLoad::~SaveLoad() { clear(true); + _savegame = NULL; // Zero passed pointers _engine = NULL; @@ -634,6 +635,9 @@ bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *he // Entries ////////////////////////////////////////////////////////////////////////// uint32 SaveLoad::writeValue(Common::Serializer &ser, const char *name, Common::Functor1 *function, uint size) { + if (!_savegame) + error("[SaveLoad::writeValue] Stream not initialized properly"); + debugC(kLastExpressDebugSavegame, "Savegame: Writing %s: %u bytes", name, size); uint32 prevPosition = (uint32)_savegame->pos(); @@ -652,6 +656,9 @@ uint32 SaveLoad::writeValue(Common::Serializer &ser, const char *name, Common::F } uint32 SaveLoad::readValue(Common::Serializer &ser, const char *name, Common::Functor1 *function, uint size) { + if (!_savegame) + error("[SaveLoad::readValue] Stream not initialized properly"); + debugC(kLastExpressDebugSavegame, "Savegame: Reading %s: %u bytes", name, size); uint32 prevPosition = (uint32)_savegame->pos(); -- cgit v1.2.3 From 6ab8db638e4a1d547ee67db067b5d6c3d6c940a4 Mon Sep 17 00:00:00 2001 From: Littleboy Date: Mon, 27 Aug 2012 23:29:09 -0400 Subject: LASTEXPRESS: Implement more savegame loading - Rename existing function to load the last saved game - Remove loadgame debugger command --- engines/lastexpress/debug.cpp | 25 ------------------------- engines/lastexpress/debug.h | 1 - engines/lastexpress/game/savegame.cpp | 30 ++++++++++++++++++++++++++---- engines/lastexpress/game/savegame.h | 4 ++-- engines/lastexpress/menu/menu.cpp | 4 ++-- 5 files changed, 30 insertions(+), 34 deletions(-) diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index 3994cb0bcb..db3a3e3962 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -85,7 +85,6 @@ Debugger::Debugger(LastExpressEngine *engine) : _engine(engine), _command(NULL), DCmd_Register("entity", WRAP_METHOD(Debugger, cmdEntity)); // Misc - DCmd_Register("loadgame", WRAP_METHOD(Debugger, cmdLoadGame)); DCmd_Register("chapter", WRAP_METHOD(Debugger, cmdSwitchChapter)); DCmd_Register("clear", WRAP_METHOD(Debugger, cmdClear)); @@ -1118,30 +1117,6 @@ label_error: return true; } -/** - * Command: loads a game - * - * @param argc The argument count. - * @param argv The values. - * - * @return true if it was handled, false otherwise - */ -bool Debugger::cmdLoadGame(int argc, const char **argv) { - if (argc == 2) { - int id = getNumber(argv[1]); - - if (id == 0 || id > 6) - goto error; - - getSaveLoad()->loadGame((GameId)(id - 1)); - } else { -error: - DebugPrintf("Syntax: loadgame (id=1-6)\n"); - } - - return true; -} - /** * Command: switch to a specific chapter * diff --git a/engines/lastexpress/debug.h b/engines/lastexpress/debug.h index a9f0443af9..532cb83717 100644 --- a/engines/lastexpress/debug.h +++ b/engines/lastexpress/debug.h @@ -79,7 +79,6 @@ private: bool cmdShow(int argc, const char **argv); bool cmdEntity(int argc, const char **argv); - bool cmdLoadGame(int argc, const char **argv); bool cmdSwitchChapter(int argc, const char **argv); bool cmdClear(int argc, const char **argv); diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 7efce0007b..021dc40bb9 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -482,10 +482,10 @@ void SaveLoad::clear(bool clearStream) { // Save & Load ////////////////////////////////////////////////////////////////////////// -// Load game -void SaveLoad::loadGame(GameId id) { +// Load last saved game +void SaveLoad::loadLastGame() { if (!_savegame) - error("[SaveLoad::loadGame] No savegame stream present"); + error("[SaveLoad::loadLastGame] No savegame stream present"); // Rewind current savegame _savegame->seek(0); @@ -522,7 +522,29 @@ void SaveLoad::loadGame(GameId id) { } // Load a specific game entry -void SaveLoad::loadGame(GameId id, uint32 index) { +void SaveLoad::loadGame(uint32 index) { + if (!_savegame) + error("[SaveLoad::loadLastGame] No savegame stream present"); + + // Rewind current savegame + _savegame->seek(0); + + // Write main header (with selected index) + SavegameMainHeader header; + header.count = index; + header.brightness = getState()->brightness; + header.volume = getState()->volume; + + Common::Serializer ser(NULL, _savegame); + header.saveLoadWithSerializer(ser); + + // TODO + // Go to the entry + // Load the entry + // Get offset (main and entry) + // Write main header again with correct entry offset + // Setup game and start + error("[SaveLoad::loadGame] Not implemented! (only loading the last entry is working for now)"); } diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h index 8656b2ee86..361957227e 100644 --- a/engines/lastexpress/game/savegame.h +++ b/engines/lastexpress/game/savegame.h @@ -153,8 +153,8 @@ public: uint32 init(GameId id, bool resetHeaders); // Save & Load - void loadGame(GameId id); - void loadGame(GameId id, uint32 index); + void loadLastGame(); + void loadGame(uint32 index); void saveGame(SavegameType type, EntityIndex entity, uint32 value); void loadVolumeBrightness(); diff --git a/engines/lastexpress/menu/menu.cpp b/engines/lastexpress/menu/menu.cpp index 6a453aee99..c48e55bb55 100644 --- a/engines/lastexpress/menu/menu.cpp +++ b/engines/lastexpress/menu/menu.cpp @@ -916,13 +916,13 @@ void Menu::startGame() { if (_lastIndex == _index) { setGlobalTimer(0); if (_index) { - getSaveLoad()->loadGame(_gameId); + getSaveLoad()->loadLastGame(); } else { getLogic()->resetState(); getEntities()->setup(true, kEntityPlayer); } } else { - getSaveLoad()->loadGame(_gameId, _index); + getSaveLoad()->loadGame(_index); } } -- cgit v1.2.3 From 47a7df2d0f9be2c13648a18c9de7b81e77e5d7fe Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan SømaÌŠen Date: Mon, 13 Aug 2012 00:09:42 +0200 Subject: GRAPHICS: Add in a TGA-decoder --- graphics/decoders/tga.cpp | 419 ++++++++++++++++++++++++++++++++++++++++++++++ graphics/decoders/tga.h | 100 +++++++++++ graphics/module.mk | 3 +- 3 files changed, 521 insertions(+), 1 deletion(-) create mode 100644 graphics/decoders/tga.cpp create mode 100644 graphics/decoders/tga.h diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp new file mode 100644 index 0000000000..7d214a6f24 --- /dev/null +++ b/graphics/decoders/tga.cpp @@ -0,0 +1,419 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* Based on code from xoreos https://github.com/DrMcCoy/xoreos/ + * relicensed under GPLv2+ with permission from DrMcCoy and clone2727 + */ + +#include "common/util.h" +#include "common/stream.h" +#include "common/textconsole.h" +#include "common/error.h" + +#include "graphics/decoders/tga.h" + +namespace Graphics { + +TGADecoder::TGADecoder() { + _colorMapSize = 0; + _colorMapOrigin = 0; + _colorMapLength = 0; + _colorMapEntryLength = 0; + _colorMap = NULL; +} + +TGADecoder::~TGADecoder() { + destroy(); +} + +void TGADecoder::destroy() { + _surface.free(); + delete[] _colorMap; +} + +bool TGADecoder::loadStream(Common::SeekableReadStream &tga) { + byte imageType, pixelDepth; + bool success; + success = readHeader(tga, imageType, pixelDepth); + if (success) { + switch (imageType) { + case TYPE_BW: + case TYPE_TRUECOLOR: + success = readData(tga, imageType, pixelDepth); + break; + case TYPE_RLE_BW: + case TYPE_RLE_TRUECOLOR: + case TYPE_RLE_CMAP: + success = readDataRLE(tga, imageType, pixelDepth); + break; + case TYPE_CMAP: + success = readDataColorMapped(tga, imageType, pixelDepth); + break; + default: + success = false; + break; + } + } + if (tga.err() || !success) { + warning("Failed reading TGA-file"); + return false; + } + return success; +} + +bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth) { + if (!tga.seek(0)) { + warning("Failed reading TGA-file"); + return false; + } + + // TGAs have an optional "id" string in the header + uint32 idLength = tga.readByte(); + + // Number of colors in the color map / palette + int hasColorMap = tga.readByte(); + + // Image type. See header for numeric constants + imageType = tga.readByte(); + + switch (imageType) { + case TYPE_CMAP: + case TYPE_TRUECOLOR: + case TYPE_BW: + case TYPE_RLE_CMAP: + case TYPE_RLE_TRUECOLOR: + case TYPE_RLE_BW: + break; + default: + warning("Unsupported image type: %d", imageType); + return false; + } + + // Color map specifications + if (hasColorMap == 0) { + tga.skip(5); + } else { + _colorMapOrigin = tga.readUint16LE(); + _colorMapLength = tga.readUint16LE(); + _colorMapEntryLength = tga.readByte(); + } + // Origin-defintions + tga.skip(2 + 2); + + // Image dimensions + _surface.w = tga.readUint16LE(); + _surface.h = tga.readUint16LE(); + + // Bits per pixel + pixelDepth = tga.readByte(); + _surface.format.bytesPerPixel = pixelDepth / 8; + + // Image descriptor + byte imgDesc = tga.readByte(); + int attributeBits = imgDesc & 0x0F; + assert((imgDesc & 0x10) == 0); + _originTop = (imgDesc & 0x20); + + // Interleaving is not handled at this point + //int interleave = (imgDesc & 0xC); + if (imageType == TYPE_CMAP || imageType == TYPE_RLE_CMAP) { + if (pixelDepth == 8) { + _format = PixelFormat::createFormatCLUT8(); + } else { + warning("Unsupported index-depth: %d", pixelDepth); + return false; + } + } else if (imageType == TYPE_TRUECOLOR || imageType == TYPE_RLE_TRUECOLOR) { + if (pixelDepth == 24) { + _format = PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0); + } else if (pixelDepth == 32) { + _format = PixelFormat(4, 8, 8, 8, attributeBits, 16, 8, 0, 24); + } else if (pixelDepth == 16 && imageType == TYPE_TRUECOLOR) { + // 16bpp TGA is ARGB1555 + _format = PixelFormat(2, 5, 5, 5, attributeBits, 10, 5, 0, 15); + } else { + warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); + return false; + } + } else if (imageType == TYPE_BW || TYPE_RLE_BW) { + if (pixelDepth == 8) { + _format = PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0); + } else { + warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); + return false; + } + + } else { + warning("Unsupported image type: %d", imageType); + return false; + } + + // Skip the id string + tga.skip(idLength); + + if (hasColorMap) { + return readColorMap(tga, imageType, pixelDepth); + } + return true; +} + +bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + _colorMap = new byte[3 * _colorMapLength]; + for (int i = 0; i < _colorMapLength * 3; i += 3) { + byte r, g, b, a; + if (_colorMapEntryLength == 32) { + PixelFormat format(4, 8, 8, 8, 0, 16, 8, 0, 24); + uint32 color = tga.readUint32LE(); + format.colorToARGB(color, a, r, g, b); + } else if (_colorMapEntryLength == 24) { + r = tga.readByte(); + g = tga.readByte(); + b = tga.readByte(); + } else if (_colorMapEntryLength == 16) { + PixelFormat format(2, 5, 5, 5, 0, 10, 5, 0, 15); + uint16 color = tga.readUint16LE(); + format.colorToARGB(color, a, r, g, b); + } +#ifdef SCUMM_LITTLE_ENDIAN + _colorMap[i] = r; + _colorMap[i + 1] = g; + _colorMap[i + 2] = b; +#else + _colorMap[i] = b; + _colorMap[i + 1] = g; + _colorMap[i + 2] = r; +#endif + } + return true; +} + +// Additional information found from http://paulbourke.net/dataformats/tga/ +// With some details from the link referenced in the header. +bool TGADecoder::readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + // TrueColor + if (imageType == TYPE_TRUECOLOR) { + _surface.create(_surface.w, _surface.h, _format); + + if (pixelDepth == 16) { + for (int i = 0; i < _surface.h; i++) { + uint16 *dst; + if (!_originTop) { + dst = (uint16 *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (uint16 *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + *dst++ = tga.readUint16LE(); + } + } + } else if (pixelDepth == 32) { + for (int i = 0; i < _surface.h; i++) { + uint32 *dst; + if (!_originTop) { + dst = (uint32 *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (uint32 *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + *dst++ = tga.readUint32LE(); + } + } + } else if (pixelDepth == 24) { + for (int i = 0; i < _surface.h; i++) { + byte *dst; + if (!_originTop) { + dst = (byte *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (byte *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); +#ifdef SCUMM_LITTLE_ENDIAN + *dst++ = r; + *dst++ = g; + *dst++ = b; +#else + *dst++ = b; + *dst++ = g; + *dst++ = r; +#endif + } + } + } + // Black/White + } else if (imageType == TYPE_BW) { + _surface.create(_surface.w, _surface.h, _format); + + byte *data = (byte *)_surface.pixels; + uint32 count = _surface.w * _surface.h; + + while (count-- > 0) { + byte g = tga.readByte(); + *data++ = g; + *data++ = g; + *data++ = g; + *data++ = g; + } + } + return true; +} + +bool TGADecoder::readDataColorMapped(Common::SeekableReadStream &tga, byte imageType, byte indexDepth) { + // Color-mapped + if (imageType == TYPE_CMAP) { + _surface.create(_surface.w, _surface.h, _format); + if (indexDepth == 8) { + for (int i = 0; i < _surface.h; i++) { + byte *dst; + if (!_originTop) { + dst = (byte *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (byte *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + byte index = tga.readByte(); + *dst++ = index; + } + } + } else if (indexDepth == 16) { + warning("16 bit indexes not supported"); + return false; + } + } else { + return false; + } + return true; +} + +bool TGADecoder::readDataRLE(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + // RLE-TrueColor / RLE-Black/White + if (imageType == TYPE_RLE_TRUECOLOR || imageType == TYPE_RLE_BW || imageType == TYPE_RLE_CMAP) { + _surface.create(_surface.w, _surface.h, _format); + uint32 count = _surface.w * _surface.h; + byte *data = (byte *)_surface.pixels; + + while (count > 0) { + uint32 header = tga.readByte(); + byte type = (header & 0x80) >> 7; + uint32 rleCount = (header & 0x7F) + 1; + + // RLE-packet + if (type == 1) { + if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { + uint32 color = tga.readUint32LE(); + while (rleCount-- > 0) { + *((uint32 *)data) = color; + data += 4; + count--; + } + } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); + while (rleCount-- > 0) { +#ifdef SCUMM_LITTLE_ENDIAN + *data++ = r; + *data++ = g; + *data++ = b; +#else + *data++ = b; + *data++ = g; + *data++ = r; +#endif + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { + byte color = tga.readByte(); + while (rleCount-- > 0) { + *data++ = color; + *data++ = color; + *data++ = color; + *data++ = color; + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { + byte index = tga.readByte(); + while (rleCount-- > 0) { + *data++ = index; + count--; + } + } else { + warning("Unhandled pixel-depth for image-type 10"); + return false; + } + // Raw-packet + } else if (type == 0) { + if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { + while (rleCount-- > 0) { + uint32 color = tga.readUint32LE(); + *((uint32 *)data) = color; + data += 4; + count--; + } + } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { + while (rleCount-- > 0) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); +#ifdef SCUMM_LITTLE_ENDIAN + *data++ = r; + *data++ = g; + *data++ = b; +#else + *data++ = b; + *data++ = g; + *data++ = r; +#endif + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { + while (rleCount-- > 0) { + byte color = tga.readByte(); + *data++ = color; + *data++ = color; + *data++ = color; + *data++ = color; + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { + while (rleCount-- > 0) { + byte index = tga.readByte(); + *data++ = index; + count--; + } + } else { + warning("Unhandled pixel-depth for image-type 10"); + return false; + } + } else { + warning("Unknown header for RLE-packet %d", type); + return false; + } + } + } else { + return false; + } + return true; +} + +} // End of namespace Graphics diff --git a/graphics/decoders/tga.h b/graphics/decoders/tga.h new file mode 100644 index 0000000000..e8dd2b8411 --- /dev/null +++ b/graphics/decoders/tga.h @@ -0,0 +1,100 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* Based on code from eos https://github.com/DrMcCoy/xoreos/ + * relicensed under GPLv2+ with permission from DrMcCoy and clone2727 + */ + +/* + * TGA decoder used in engines: + * - none + */ + +#ifndef GRAPHICS_DECODERS_TGA_H +#define GRAPHICS_DECODERS_TGA_H + +#include "graphics/surface.h" +#include "graphics/decoders/image_decoder.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { + +/** TarGa image-decoder + * The following variations of TGA are supported: + * - Type 1 - Color-mapped images in 16/24/32 bpp with 8 bit indexes + * - Type 2 - 16/24/32 bpp Top AND Bottom origined. + * - Type 3 - Black/White images, 8bpp. + * - Type 9 - RLE-encoded color-mapped images. (8 bit indexes only) + * - Type 10 - RLE-encoded TrueColor, 24/32bpp. + * - Type 11 - RLE-encoded Black/White, 8bpp. + * + * No images are returned with a palette, instead they are converted + * to 16 bpp for Type 1, or 32 bpp for Black/White-images. + */ +class TGADecoder : public ImageDecoder { +public: + TGADecoder(); + virtual ~TGADecoder(); + virtual void destroy(); + virtual const Surface *getSurface() const { + return &_surface; + }; + virtual const byte *getPalette() const { return _colorMap; } + virtual uint16 getPaletteColorCount() const { return _colorMapLength; } + virtual bool loadStream(Common::SeekableReadStream &stream); +private: + // Format-spec from: + //http://www.ludorg.net/amnesia/TGA_File_Format_Spec.html + enum { + TYPE_CMAP = 1, + TYPE_TRUECOLOR = 2, + TYPE_BW = 3, + TYPE_RLE_CMAP = 9, + TYPE_RLE_TRUECOLOR = 10, + TYPE_RLE_BW = 11 + }; + + // Color-map: + bool _colorMapSize; + byte *_colorMap; + int16 _colorMapOrigin; + int16 _colorMapLength; + byte _colorMapEntryLength; + + // Origin may be at the top, or bottom + bool _originTop; + + PixelFormat _format; + Surface _surface; + // Loading helpers + bool readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth); + bool readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); + bool readDataColorMapped(Common::SeekableReadStream &tga, byte imageType, byte indexDepth); + bool readDataRLE(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); + bool readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); +}; + +} // End of namespace Graphics + +#endif // GRAPHICS_DECODERS_TGA_H diff --git a/graphics/module.mk b/graphics/module.mk index 281f904b38..e67efd2cf5 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -26,7 +26,8 @@ MODULE_OBJS := \ decoders/bmp.o \ decoders/jpeg.o \ decoders/pict.o \ - decoders/png.o + decoders/png.o \ + decoders/tga.o ifdef USE_SCALERS MODULE_OBJS += \ -- cgit v1.2.3 From f189d8a541647506498b19a2b66138b6171000a3 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 29 Aug 2012 15:58:55 +0200 Subject: GRAPHICS: Remove extra semicolon. --- graphics/decoders/tga.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/decoders/tga.h b/graphics/decoders/tga.h index e8dd2b8411..8149014a24 100644 --- a/graphics/decoders/tga.h +++ b/graphics/decoders/tga.h @@ -59,7 +59,7 @@ public: virtual void destroy(); virtual const Surface *getSurface() const { return &_surface; - }; + } virtual const byte *getPalette() const { return _colorMap; } virtual uint16 getPaletteColorCount() const { return _colorMapLength; } virtual bool loadStream(Common::SeekableReadStream &stream); -- cgit v1.2.3 From f87154def8c54722c8068e9ee9130c30ab393537 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 29 Aug 2012 15:59:15 +0200 Subject: GRAPHICS: Slight formatting change for consistency. --- graphics/decoders/tga.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/graphics/decoders/tga.h b/graphics/decoders/tga.h index 8149014a24..dfdc5a4da9 100644 --- a/graphics/decoders/tga.h +++ b/graphics/decoders/tga.h @@ -57,9 +57,7 @@ public: TGADecoder(); virtual ~TGADecoder(); virtual void destroy(); - virtual const Surface *getSurface() const { - return &_surface; - } + virtual const Surface *getSurface() const { return &_surface; } virtual const byte *getPalette() const { return _colorMap; } virtual uint16 getPaletteColorCount() const { return _colorMapLength; } virtual bool loadStream(Common::SeekableReadStream &stream); -- cgit v1.2.3 From 3b4d713ba114a692354f2a9dc68d7b9c3cfe5560 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Thu, 30 Aug 2012 18:13:00 +0200 Subject: GRAPHICS: Undefined behaviour/warnings removal in the TGA decoder --- graphics/decoders/tga.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp index 7d214a6f24..c27cd2b20b 100644 --- a/graphics/decoders/tga.cpp +++ b/graphics/decoders/tga.cpp @@ -191,6 +191,9 @@ bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, b PixelFormat format(2, 5, 5, 5, 0, 10, 5, 0, 15); uint16 color = tga.readUint16LE(); format.colorToARGB(color, a, r, g, b); + } else { + warning("Unsupported image type: %d", imageType); + r = g = b = a = 0; } #ifdef SCUMM_LITTLE_ENDIAN _colorMap[i] = r; -- cgit v1.2.3 From 10a947a0be80ea8c5c88bd3493a5057b1223ce45 Mon Sep 17 00:00:00 2001 From: Bertrand Augereau Date: Thu, 30 Aug 2012 18:32:27 +0200 Subject: GRAPHICS: Scope reduction of the sometimes unused alpha component in TGADecoder::readHeader --- graphics/decoders/tga.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp index c27cd2b20b..0b2318e127 100644 --- a/graphics/decoders/tga.cpp +++ b/graphics/decoders/tga.cpp @@ -178,8 +178,9 @@ bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, by bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { _colorMap = new byte[3 * _colorMapLength]; for (int i = 0; i < _colorMapLength * 3; i += 3) { - byte r, g, b, a; + byte r, g, b; if (_colorMapEntryLength == 32) { + byte a; PixelFormat format(4, 8, 8, 8, 0, 16, 8, 0, 24); uint32 color = tga.readUint32LE(); format.colorToARGB(color, a, r, g, b); @@ -188,12 +189,13 @@ bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, b g = tga.readByte(); b = tga.readByte(); } else if (_colorMapEntryLength == 16) { + byte a; PixelFormat format(2, 5, 5, 5, 0, 10, 5, 0, 15); uint16 color = tga.readUint16LE(); format.colorToARGB(color, a, r, g, b); } else { warning("Unsupported image type: %d", imageType); - r = g = b = a = 0; + r = g = b = 0; } #ifdef SCUMM_LITTLE_ENDIAN _colorMap[i] = r; -- cgit v1.2.3