/* 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" #include "graphics/surface.h" #include "image/codecs/codec.h" /* Common structures, macros, and base class shared by both Indeo4 and * Indeo5 decoders, derived from ffmpeg. We don't currently support Indeo5 * decoding, but just in case we eventually need it, this is kept as a separate * file like it is in ffmpeg. * * Original copyright note: * Intel Indeo 4 (IV41, IV42, etc.) video decoder for ffmpeg * written, produced, and directed by Alan Smithee */ #ifndef IMAGE_CODECS_INDEO_INDEO_H #define IMAGE_CODECS_INDEO_INDEO_H #include "image/codecs/indeo/get_bits.h" #include "image/codecs/indeo/vlc.h" namespace Image { namespace Indeo { /** * Indeo 4 frame types. */ enum { IVI4_FRAMETYPE_INTRA = 0, IVI4_FRAMETYPE_INTRA1 = 1, ///< intra frame with slightly different bitstream coding IVI4_FRAMETYPE_INTER = 2, ///< non-droppable P-frame IVI4_FRAMETYPE_BIDIR = 3, ///< bidirectional frame IVI4_FRAMETYPE_INTER_NOREF = 4, ///< droppable P-frame IVI4_FRAMETYPE_NULL_FIRST = 5, ///< empty frame with no data IVI4_FRAMETYPE_NULL_LAST = 6 ///< empty frame with no data }; enum { IVI_MB_HUFF = 0, /// Huffman table is used for coding macroblocks IVI_BLK_HUFF = 1 /// Huffman table is used for coding blocks }; /** * Declare inverse transform function types */ typedef void (InvTransformPtr)(const int32 *in, int16 *out, uint32 pitch, const uint8 *flags); typedef void (DCTransformPtr)(const int32 *in, int16 *out, uint32 pitch, int blkSize); typedef void (*IviMCFunc)(int16 *buf, const int16 *refBuf, uint32 pitch, int mcType); typedef void (*IviMCAvgFunc)(int16 *buf, const int16 *refBuf1, const int16 *refBuf2, uint32 pitch, int mcType, int mcType2); ///< max number of bits of the ivi's huffman codes #define IVI_VLC_BITS 13 #define IVI5_IS_PROTECTED 0x20 /** * convert unsigned values into signed ones (the sign is in the LSB) */ #define IVI_TOSIGNED(val) (-(((val) >> 1) ^ -((val) & 1))) /** * calculate number of macroblocks in a tile */ #define IVI_MBs_PER_TILE(tileWidth, tileHeight, mbSize) \ ((((tileWidth) + (mbSize) - 1) / (mbSize)) * (((tileHeight) + (mbSize) - 1) / (mbSize))) /** * huffman codebook descriptor */ struct IVIHuffDesc { int32 _numRows; uint8 _xBits[16]; /** * Generate a huffman codebook from the given descriptor * and convert it into the FFmpeg VLC table. * * @param[out] vlc Where to place the generated VLC table * @param[in] flag Flag: true - for static or false for dynamic tables * @returns result code: 0 - OK, -1 = error (invalid codebook descriptor) */ int createHuffFromDesc(VLC *vlc, bool flag) const; /** * Compare two huffman codebook descriptors. * * @param[in] desc2 Ptr to the 2nd descriptor to compare * @returns comparison result: 0 - equal, 1 - not equal */ bool huffDescCompare(const IVIHuffDesc *desc2) const; /** * Copy huffman codebook descriptors. * * @param[in] src ptr to the source descriptor */ void huffDescCopy(const IVIHuffDesc *src); }; struct IVI45DecContext; /** * Macroblock/block huffman table descriptor */ struct IVIHuffTab { public: int32 _tabSel; /// index of one of the predefined tables /// or "7" for custom one VLC * _tab; /// pointer to the table associated with tab_sel /// the following are used only when tab_sel == 7 IVIHuffDesc _custDesc; /// custom Huffman codebook descriptor VLC _custTab; /// vlc table for custom codebook /** * Constructor */ IVIHuffTab(); /** * Decode a huffman codebook descriptor from the bitstream * and select specified huffman table. * * @param[in] ctx Decoder context * @param[in] descCoded Flag signalling if table descriptor was coded * @param[in] whichTab Codebook purpose (IVI_MB_HUFF or IVI_BLK_HUFF) * @returns Zero on success, negative value otherwise */ int decodeHuffDesc(IVI45DecContext *ctx, int descCoded, int whichTab); }; /** * run-value (RLE) table descriptor */ struct RVMapDesc { uint8 _eobSym; ///< end of block symbol uint8 _escSym; ///< escape symbol uint8 _runtab[256]; int8 _valtab[256]; }; /** * information for Indeo macroblock (16x16, 8x8 or 4x4) */ struct IVIMbInfo { int16 _xPos; int16 _yPos; uint32 _bufOffs; ///< address in the output buffer for this mb uint8 _type; ///< macroblock type: 0 - INTRA, 1 - INTER uint8 _cbp; ///< coded block pattern int8 _qDelta; ///< quant delta int8 _mvX; ///< motion vector (x component) int8 _mvY; ///< motion vector (y component) int8 _bMvX; ///< second motion vector (x component) int8 _bMvY; ///< second motion vector (y component) IVIMbInfo(); }; /** * information for Indeo tile */ struct IVITile { int _xPos; int _yPos; int _width; int _height; int _mbSize; bool _isEmpty; int _dataSize; ///< size of the data in bytes int _numMBs; ///< number of macroblocks in this tile IVIMbInfo * _mbs; ///< array of macroblock descriptors IVIMbInfo * _refMbs; ///< ptr to the macroblock descriptors of the reference tile IVITile(); }; /** * information for Indeo wavelet band */ struct IVIBandDesc { int _plane; ///< plane number this band belongs to int _bandNum; ///< band number int _width; int _height; int _aHeight; ///< aligned band height const uint8 * _dataPtr; ///< ptr to the first byte of the band data int _dataSize; ///< size of the band data int16 * _buf; ///< pointer to the output buffer for this band int16 * _refBuf; ///< pointer to the reference frame buffer (for motion compensation) int16 * _bRefBuf; ///< pointer to the second reference frame buffer (for motion compensation) int16 * _bufs[4]; ///< array of pointers to the band buffers int _pitch; ///< _pitch associated with the buffers above bool _isEmpty; int _mbSize; ///< macroblock size int _blkSize; ///< block size uint8 _isHalfpel; ///< precision of the motion compensation: 0 - fullpel, 1 - halfpel bool _inheritMv; ///< tells if motion vector is inherited from reference macroblock bool _inheritQDelta; ///< tells if quantiser delta is inherited from reference macroblock bool _qdeltaPresent; ///< tells if Qdelta signal is present in the bitstream (Indeo5 only) int _quantMat; ///< dequant matrix index int _globQuant; ///< quant base for this band const uint8 * _scan; ///< ptr to the scan pattern int _scanSize; ///< size of the scantable IVIHuffTab _blkVlc; ///< vlc table for decoding block data int _numCorr; ///< number of correction entries uint8 _corr[61 * 2]; ///< rvmap correction pairs int _rvmapSel; ///< rvmap table selector RVMapDesc * _rvMap; ///< ptr to the RLE table for this band int _numTiles; ///< number of tiles in this band IVITile * _tiles; ///< array of tile descriptors InvTransformPtr *_invTransform; int _transformSize; DCTransformPtr *_dcTransform; bool _is2dTrans; int32 _checksum; ///< for debug purposes int _checksumPresent; int _bufSize; ///< band buffer size in bytes const uint16 * _intraBase; ///< quantization matrix for intra blocks const uint16 * _interBase; ///< quantization matrix for inter blocks const uint8 * _intraScale; ///< quantization coefficient for intra blocks const uint8 * _interScale; ///< quantization coefficient for inter blocks IVIBandDesc(); int initTiles(IVITile *refTile, int p, int b, int tHeight, int tWidth); }; struct IVIPicConfig { uint16 _picWidth; uint16 _picHeight; uint16 _chromaWidth; uint16 _chromaHeight; uint16 _tileWidth; uint16 _tileHeight; uint8 _lumaBands; uint8 _chromaBands; IVIPicConfig(); /** * Compare some properties of two pictures */ bool ivi_pic_config_cmp(const IVIPicConfig &cfg2); }; /** * color plane (luma or chroma) information */ struct IVIPlaneDesc { uint16 _width; uint16 _height; uint8 _numBands; ///< number of bands this plane subdivided into IVIBandDesc * _bands; ///< array of band descriptors IVIPlaneDesc(); static int initPlanes(IVIPlaneDesc *planes, const IVIPicConfig *cfg, bool isIndeo4); static int initTiles(IVIPlaneDesc *planes, int tileWidth, int tileHeight); /** * Free planes, bands and macroblocks buffers. * * @param[in] planes pointer to the array of the plane descriptors */ static void freeBuffers(IVIPlaneDesc *planes); /** * Check if the given dimension of an image is valid, meaning that all * bytes of the image can be addressed with a signed int. * * @param w the width of the picture * @param h the height of the picture * @param log_offset the offset to sum to the log level for logging with log_ctx * @returns >= 0 if valid, a negative error code otherwise */ static int checkImageSize(unsigned int w, unsigned int h, int logOffset); }; struct AVFrame { /** * Dimensions */ int _width, _height; #define AV_NUM_DATA_POINTERS 3 /** * pointer to the picture/channel planes. * This might be different from the first allocated byte * * Some decoders access areas outside 0,0 - width,height, please * see avcodec_align_dimensions2(). Some filters and swscale can read * up to 16 bytes beyond the planes, if these filters are to be used, * then 16 extra bytes must be allocated. * * NOTE: Except for hwaccel formats, pointers not needed by the format * MUST be set to NULL. */ uint8 *_data[AV_NUM_DATA_POINTERS]; /** * For video, size in bytes of each picture line. * For audio, size in bytes of each plane. * * For audio, only linesize[0] may be set. For planar audio, each channel * plane must be the same size. * * For video the linesizes should be multiples of the CPUs alignment * preference, this is 16 or 32 for modern desktop CPUs. * Some code requires such alignment other code can be slower without * correct alignment, for yet other it makes no difference. * * @note The linesize may be larger than the size of usable data -- there * may be extra padding present for performance reasons. */ int _linesize[AV_NUM_DATA_POINTERS]; /** * Constructor */ AVFrame(); /** * Destructor */ ~AVFrame() { freeFrame(); } /** * Sets the frame dimensions */ int setDimensions(uint16 width, uint16 height); /** * Get a buffer for a frame */ int getBuffer(int flags); /** * Frees any data loaded for the frame */ void freeFrame(); }; struct IVI45DecContext { friend struct IVIHuffTab; private: VLC_TYPE _tableData[8192 * 16][2]; VLC _iviMbVlcTabs[8]; ///< static macroblock Huffman tables VLC _iviBlkVlcTabs[8]; ///< static block Huffman tables public: GetBits * _gb; RVMapDesc _rvmapTabs[9]; ///< local corrected copy of the static rvmap tables uint32 _frameNum; int _frameType; int _prevFrameType; ///< frame type of the previous frame uint32 _dataSize; ///< size of the frame data in bytes from picture header int _isScalable; const uint8 * _frameData; ///< input frame data pointer int _interScal; ///< signals a sequence of scalable inter frames uint32 _frameSize; ///< frame size in bytes uint32 _picHdrSize; ///< picture header size in bytes uint8 _frameFlags; uint16 _checksum; ///< frame _checksum IVIPicConfig _picConf; IVIPlaneDesc _planes[3]; ///< color planes int _bufSwitch; ///< used to switch between three buffers int _dstBuf; ///< buffer index for the currently decoded frame int _refBuf; ///< inter frame reference buffer index int _ref2Buf; ///< temporal storage for switching buffers int _bRefBuf; ///< second reference frame buffer index IVIHuffTab _mbVlc; ///< current macroblock table descriptor IVIHuffTab _blkVlc; ///< current block table descriptor IVIHuffTab _transVlc; ///< current transparency table descriptor uint8 _rvmapSel; bool _inImf; bool _inQ; ///< flag for explicitly stored quantiser delta uint8 _picGlobQuant; uint8 _unknown1; uint16 _gopHdrSize; uint8 _gopFlags; uint32 _lockWord; bool _hasBFrames; bool _hasTransp; ///< transparency mode enabled bool _usesTiling; bool _usesHaar; bool _usesFullpel; bool _gopInvalid; int _bufInvalid[4]; bool _isIndeo4; uint32 _transKeyColor; AVFrame * _pFrame; bool _gotPFrame; IVI45DecContext(); private: /** * Initial Run-value (RLE) tables. */ static const RVMapDesc _ff_ivi_rvmap_tabs[9]; }; class IndeoDecoderBase : public Codec { private: /** * Decode an Indeo 4 or 5 band. * * @param[in,out] band ptr to the band descriptor * @returns result code: 0 = OK, -1 = error */ int decode_band(IVIBandDesc *band); /** * Haar wavelet recomposition filter for Indeo 4 * * @param[in] plane Pointer to the descriptor of the plane being processed * @param[out] dst pointer to the destination buffer * @param[in] dstPitch Pitch of the destination buffer */ void recomposeHaar(const IVIPlaneDesc *plane, uint8 *dst, const int dstPitch); /** * 5/3 wavelet recomposition filter for Indeo5 * * @param[in] plane Pointer to the descriptor of the plane being processed * @param[out] dst Pointer to the destination buffer * @param[in] dstPitch Pitch of the destination buffer */ void recompose53(const IVIPlaneDesc *plane, uint8 *dst, const int dstPitch); /* * Convert and output the current plane. * This conversion is done by adding back the bias value of 128 * (subtracted in the encoder) and clipping the result. * * @param[in] plane Pointer to the descriptor of the plane being processed * @param[out] dst Pointer to the buffer receiving converted pixels * @param[in] dstPitch Pitch for moving to the next y line */ void outputPlane(IVIPlaneDesc *plane, uint8 *dst, int dstPitch); /** * Handle empty tiles by performing data copying and motion * compensation respectively. * * @param[in] band Pointer to the band descriptor * @param[in] tile Pointer to the tile descriptor * @param[in] mvScale Scaling factor for motion vectors */ int processEmptyTile(IVIBandDesc *band, IVITile *tile, int32 mvScale); /* * Decode size of the tile data. * The size is stored as a variable-length field having the following format: * if (tile_data_size < 255) than this field is only one byte long * if (tile_data_size >= 255) than this field four is byte long: 0xFF X1 X2 X3 * where X1-X3 is size of the tile data * * @param[in,out] gb the GetBit context * @returns Size of the tile data in bytes */ int decodeTileDataSize(GetBits *gb); /* * Decode block data: * extract huffman-coded transform coefficients from the bitstream, * dequantize them, apply inverse transform and motion compensation * in order to reconstruct the picture. * * @param[in,out] gb The GetBit context * @param[in] band Pointer to the band descriptor * @param[in] tile Pointer to the tile descriptor * @returns Result code: 0 - OK, -1 = error (corrupted blocks data) */ int decodeBlocks(GetBits *gb, IVIBandDesc *band, IVITile *tile); int iviMc(IVIBandDesc *band, IviMCFunc mc, IviMCAvgFunc mcAvg, int offs, int mvX, int mvY, int mvX2, int mvY2, int mcType, int mcType2); int decodeCodedBlocks(GetBits *gb, IVIBandDesc *band, IviMCFunc mc, IviMCAvgFunc mcAvg, int mvX, int mvY, int mvX2, int mvY2, int32 *prevDc, int isIntra, int mcType, int mcType2, uint32 quant, int offs); int iviDcTransform(IVIBandDesc *band, int32 *prevDc, int bufOffs, int blkSize); protected: IVI45DecContext _ctx; Graphics::PixelFormat _pixelFormat; Graphics::Surface _surface; /** * Scan patterns shared between indeo4 and indeo5 */ static const uint8 _ffIviVerticalScan8x8[64]; static const uint8 _ffIviHorizontalScan8x8[64]; static const uint8 _ffIviDirectScan4x4[16]; protected: /** * Returns the pixel format for the decoder's surface */ virtual Graphics::PixelFormat getPixelFormat() const { return _pixelFormat; } /** * Decode the Indeo picture header. * @returns 0 = Ok, negative number = error */ virtual int decodePictureHeader() = 0; /** * Rearrange decoding and reference buffers. */ virtual void switchBuffers() = 0; virtual bool isNonNullFrame() const = 0; /** * Decode Indeo band header. * * @param[in,out] band Pointer to the band descriptor * @returns Result code: 0 = OK, negative number = error */ virtual int decodeBandHeader(IVIBandDesc *band) = 0; /** * Decode information (block type, _cbp, quant delta, motion vector) * for all macroblocks in the current tile. * * @param[in,out] band Pointer to the band descriptor * @param[in,out] tile Pointer to the tile descriptor * @returns Result code: 0 = OK, negative number = error */ virtual int decodeMbInfo(IVIBandDesc *band, IVITile *tile) = 0; /** * Decodes optional transparency data within Indeo frames */ virtual int decodeTransparency() { return -1; } /** * Decodes the Indeo frame from the bit reader already * loaded into the context */ int decodeIndeoFrame(); /** * scale motion vector */ int scaleMV(int mv, int mvScale); public: IndeoDecoderBase(uint16 width, uint16 height, uint bitsPerPixel); virtual ~IndeoDecoderBase(); }; } // End of namespace Indeo } // End of namespace Image #endif