/* 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. * */ // Currently, only GOB and SCI32 games play IMDs and VMDs, so skip compiling if GOB and SCI32 is disabled. #if !(defined(ENABLE_GOB) || defined(ENABLE_SCI32) || defined(DYNAMIC_MODULES)) // Do not compile the CoktelDecoder code #else #ifndef VIDEO_COKTELDECODER_H #define VIDEO_COKTELDECODER_H #include "common/list.h" #include "common/array.h" #include "common/rational.h" #include "common/str.h" #include "graphics/surface.h" #include "video/video_decoder.h" #include "audio/mixer.h" namespace Common { struct Rect; class MemoryReadWriteStream; class SeekableReadStream; } namespace Audio { class QueuingAudioStream; } namespace Graphics { struct PixelFormat; } namespace Image { class Codec; } namespace Video { /** * Decoder for Coktel videos. * * Video decoder used in engines: * - gob * - sci */ class CoktelDecoder { public: struct State { /** Set accordingly to what was done. */ uint32 flags; /** The id of the spoken words. */ uint16 speechId; State(); }; CoktelDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); virtual ~CoktelDecoder(); /** Replace the current video stream with this identical one. */ virtual bool reloadStream(Common::SeekableReadStream *stream) = 0; virtual bool seek(int32 frame, int whence = SEEK_SET, bool restart = false) = 0; /** Draw directly onto the specified video memory. */ void setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp); /** Reset the video memory. */ void setSurfaceMemory(); const Graphics::Surface *getSurface() const; /** Draw the video starting at this position within the video memory. */ virtual void setXY(uint16 x, uint16 y); /** Draw the video at the default position. */ void setXY(); /** 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; /** Get the video's default Y position. */ uint16 getDefaultY() const; /** Return a list of rectangles that changed in the last frame. */ const Common::List &getDirtyRects() const; bool hasPalette() const; virtual bool hasVideo() const; bool hasSound() const; bool isSoundEnabled() const; bool isSoundPlaying() const; void enableSound(); void disableSound(); void finishSound(); virtual void colorModeChanged(); /** Return the coordinates of the specified frame. */ virtual bool getFrameCoords(int16 frame, int16 &x, int16 &y, int16 &width, int16 &height); /** Return whether that video has any embedded files. */ virtual bool hasEmbeddedFiles() const; /** Return whether that embedded file exists. */ virtual bool hasEmbeddedFile(const Common::String &fileName) const; /** Return that embedded file. */ virtual Common::SeekableReadStream *getEmbeddedFile(const Common::String &fileName) const; /** Return the current subtitle index. */ virtual int32 getSubtitleIndex() const; /** Is the video paletted or true color? */ virtual bool isPaletted() const; /** * Get the current frame * @see VideoDecoder::getCurFrame() */ int getCurFrame() const; /** * 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(); /** 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; 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. kSoundLoaded = 1, ///< Sound loaded. kSoundPlaying = 2, ///< Sound is playing. kSoundFinished = 3 ///< No more new sound data. }; enum Features { kFeaturesNone = 0x0000, kFeaturesPalette = 0x0008, ///< Has an own palette. kFeaturesDataSize = 0x0020, ///< Suggests a data size. kFeaturesSound = 0x0040, ///< Has sound. kFeaturesFrameCoords = 0x0080, ///< Has specific frame coordinates. kFeaturesStdCoords = 0x0100, ///< Has general standard coordinates. kFeaturesFramePos = 0x0200, ///< Has a frame positions table. kFeaturesVideo = 0x0400 ///< Has video. }; Audio::Mixer *_mixer; Audio::Mixer::SoundType _soundType; uint16 _width; uint16 _height; uint16 _x; uint16 _y; uint16 _defaultX; uint16 _defaultY; uint32 _features; int32 _curFrame; uint32 _frameCount; uint32 _startTime; byte _palette[768]; bool _paletteDirty; bool _ownSurface; Graphics::Surface _surface; Common::List _dirtyRects; Common::Rational _frameRate; // Current sound state bool _hasSound; bool _soundEnabled; SoundStage _soundStage; Audio::QueuingAudioStream *_audioStream; Audio::SoundHandle _audioHandle; bool evaluateSeekFrame(int32 &frame, int whence) const; // Surface management bool hasSurface(); void createSurface(); void freeSurface(); // Decompression uint32 deLZ77(byte *dest, const byte *src, uint32 srcSize, uint32 destSize); void deRLE(byte *&destPtr, const byte *&srcPtr, int16 destLen, int16 srcLen); // Block rendering void renderBlockWhole (Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect); void renderBlockWhole4X (Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect); void renderBlockWhole2Y (Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect); void renderBlockSparse (Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect); void renderBlockSparse2Y(Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect); void renderBlockRLE (Graphics::Surface &dstSurf, const byte *src, Common::Rect &rect); // Sound helper functions inline void unsignedToSigned(byte *buffer, int length); private: uint32 _pauseStartTime; bool _isPaused; }; class PreIMDDecoder : public CoktelDecoder { public: PreIMDDecoder(uint16 width, uint16 height, Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); ~PreIMDDecoder(); bool reloadStream(Common::SeekableReadStream *stream); bool seek(int32 frame, int whence = SEEK_SET, bool restart = false); bool loadStream(Common::SeekableReadStream *stream); void close(); bool isVideoLoaded() const; const Graphics::Surface *decodeNextFrame(); Graphics::PixelFormat getPixelFormat() const; private: Common::SeekableReadStream *_stream; // Buffer for processed frame data byte *_videoBuffer; uint32 _videoBufferSize; // Frame decoding void processFrame(); void renderFrame(); }; class IMDDecoder : public CoktelDecoder { public: IMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); ~IMDDecoder(); bool reloadStream(Common::SeekableReadStream *stream); bool seek(int32 frame, int whence = SEEK_SET, bool restart = false); void setXY(uint16 x, uint16 y); bool loadStream(Common::SeekableReadStream *stream); void close(); bool isVideoLoaded() const; const Graphics::Surface *decodeNextFrame(); Graphics::PixelFormat getPixelFormat() const; private: enum Command { kCommandNextSound = 0xFF00, kCommandStartSound = 0xFF01, kCommandBreak = 0xFFF0, kCommandBreakSkip0 = 0xFFF1, kCommandBreakSkip16 = 0xFFF2, kCommandBreakSkip32 = 0xFFF3, kCommandBreakMask = 0xFFF8, kCommandPalette = 0xFFF4, kCommandVideoData = 0xFFFC, kCommandJump = 0xFFFD }; struct Coord { int16 left; int16 top; int16 right; int16 bottom; }; Common::SeekableReadStream *_stream; byte _version; // Standard coordinates gives by the header int16 _stdX; int16 _stdY; int16 _stdWidth; int16 _stdHeight; uint32 _flags; uint32 _firstFramePos; ///< Position of the first frame's data within the stream. uint32 *_framePos; ///< Positions of all frames. Coord *_frameCoords; ///< Coordinates of all frames. uint32 _videoBufferSize; ///< Size of the video buffers. byte *_videoBuffer[2]; ///< Video buffers. uint32 _videoBufferLen[2]; ///< Size of the video buffers filled. // Sound properties uint16 _soundFlags; int16 _soundFreq; int16 _soundSliceSize; int16 _soundSlicesCount; // Loading helper functions bool loadCoordinates(); bool loadFrameTableOffsets(uint32 &framePosPos, uint32 &frameCoordsPos); bool assessVideoProperties(); bool assessAudioProperties(); bool loadFrameTables(uint32 framePosPos, uint32 frameCoordsPos); // Frame decoding void processFrame(); Common::Rect calcFrameCoords(uint32 frame); // Video bool renderFrame(Common::Rect &rect); // Sound void nextSoundSlice(bool hasNextCmd); bool initialSoundSlice(bool hasNextCmd); void emptySoundSlice(bool hasNextCmd); }; class VMDDecoder : public CoktelDecoder { friend class AdvancedVMDDecoder; public: VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); ~VMDDecoder(); bool reloadStream(Common::SeekableReadStream *stream); bool seek(int32 frame, int whence = SEEK_SET, bool restart = false); void setXY(uint16 x, uint16 y); void colorModeChanged(); bool getFrameCoords(int16 frame, int16 &x, int16 &y, int16 &width, int16 &height); bool hasEmbeddedFiles() const; bool hasEmbeddedFile(const Common::String &fileName) const; Common::SeekableReadStream *getEmbeddedFile(const Common::String &fileName) const; int32 getSubtitleIndex() const; bool hasVideo() const; bool isPaletted() const; bool loadStream(Common::SeekableReadStream *stream); void close(); bool isVideoLoaded() const; const Graphics::Surface *decodeNextFrame(); Graphics::PixelFormat getPixelFormat() const; protected: void setAutoStartSound(bool autoStartSound); private: enum PartType { kPartTypeSeparator = 0, kPartTypeAudio = 1, kPartTypeVideo = 2, kPartTypeFile = 3, kPartType4 = 4, kPartTypeSubtitle = 5 }; enum AudioFormat { kAudioFormat8bitRaw = 0, kAudioFormat16bitDPCM = 1, kAudioFormat16bitADPCM = 2 }; struct File { Common::String name; uint32 offset; uint32 size; uint32 realSize; File(); }; struct Part { PartType type; byte field_1; byte field_E; uint32 size; int16 left; int16 top; int16 right; int16 bottom; uint16 id; byte flags; Part(); }; struct Frame { uint32 offset; Part *parts; Frame(); ~Frame(); }; Common::SeekableReadStream *_stream; byte _version; uint32 _flags; uint32 _frameInfoOffset; uint16 _partsPerFrame; Frame *_frames; Common::Array _files; // Sound properties uint16 _soundFlags; int16 _soundFreq; int16 _soundSliceSize; int16 _soundSlicesCount; byte _soundBytesPerSample; byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo) uint32 _soundHeaderSize; uint32 _soundDataSize; uint32 _soundLastFilledFrame; AudioFormat _audioFormat; bool _autoStartSound; /** * Old stereo format packs a DPCM stream into audio packets without ensuring * that each packet contains an even amount of samples. In order for the * stream to play back correctly, all audio data needs to be pushed into a * single data buffer and read from there. * * This buffer is owned by _audioStream and will be disposed when * _audioStream is disposed. */ Common::MemoryReadWriteStream *_oldStereoBuffer; // Video properties bool _hasVideo; uint32 _videoCodec; byte _blitMode; byte _bytesPerPixel; uint32 _firstFramePos; ///< Position of the first frame's data within the stream. uint32 _videoBufferSize; ///< Size of the video buffers. byte *_videoBuffer[3]; ///< Video buffers. uint32 _videoBufferLen[3]; ///< Size of the video buffers filled. Graphics::Surface _8bppSurface[3]; ///< Fake 8bpp surfaces over the video buffers. bool _externalCodec; Image::Codec *_codec; int32 _subtitle; bool _isPaletted; // Loading helper functions bool assessVideoProperties(); bool assessAudioProperties(); bool openExternalCodec(); bool readFrameTable(int &numFiles); bool readFiles(); // Frame decoding void processFrame(); // Video bool renderFrame(Common::Rect &rect); bool getRenderRects(const Common::Rect &rect, Common::Rect &realRect, Common::Rect &fakeRect); void blit16(const Graphics::Surface &srcSurf, Common::Rect &rect); void blit24(const Graphics::Surface &srcSurf, Common::Rect &rect); // Sound void emptySoundSlice (uint32 size); void filledSoundSlice (uint32 size); void filledSoundSlices(uint32 size, uint32 mask); void createAudioStream(); uint8 evaluateMask(uint32 mask, bool *fillInfo, uint8 &max); // Generating audio streams Audio::AudioStream *create8bitRaw (Common::SeekableReadStream *stream); Audio::AudioStream *create16bitDPCM (Common::SeekableReadStream *stream); Audio::AudioStream *create16bitADPCM(Common::SeekableReadStream *stream); bool getPartCoords(int16 frame, PartType type, int16 &x, int16 &y, int16 &width, int16 &height); }; /** * A wrapper around the VMD code that implements the VideoDecoder * API. */ class AdvancedVMDDecoder : public VideoDecoder { public: AdvancedVMDDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); ~AdvancedVMDDecoder(); bool loadStream(Common::SeekableReadStream *stream); void close(); void setSurfaceMemory(void *mem, uint16 width, uint16 height, uint8 bpp); 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); protected: virtual Audio::AudioStream *getAudioStream() const; private: VMDDecoder *_decoder; }; VMDDecoder *_decoder; VMDVideoTrack *_videoTrack; VMDAudioTrack *_audioTrack; }; } // End of namespace Video #endif // VIDEO_COKTELDECODER_H #endif // Engine and dynamic plugins guard