#ifndef AVIFILE_IVIDEODECODER_H
#define AVIFILE_IVIDEODECODER_H

/********************************************************

	Video decoder interface
	Copyright 2000 Eugene Kuznetsov  (divx@euro.ru)

*********************************************************/

#include <default.h>
#include <formats.h>
#include <infotypes.h>
#include <image.h>
#include <Locker.h>

/**
 *
 *  Class for video decompression.
 *
 *  Usage:
 *    
 *  IVideoDecoder::Create() call tries to load video codec
 *  corresponding to your format, and throws FatalError if something goes wrong. 
 *  Start() starts decompression and Stop() stops it.
 *
 * SetDestFmt() sets desired bit depth and color space of output picture. 
 * Returns zero on success, -1 if format is unsupported and 
 * +1 if there was no 'native' support for the depth and library
 * is going to perform internal conversion of format. Most decoders 
 * support depths 15, 16, 24 or 32. Many of them also allow to use
 * YUV formats. You can check if your particular decoder is able to decode
 * into the particular YUV format by calling GetCapabilities(),
 * which returns bitwise OR of supported formats.
 *
 * DecodeFrame() decodes a single frame. Returns zero on success, any
 * other value on failure. Nonzero here is not fatal ( maybe it was
 * just one defective bit in file, after next keyframe everything 
 * will be OK ).
 *
 * SetDirection() allows to 'flip' output picture. By default picture 
 * is flipped ( DestFmt().biHeight<0 ), so that output image can
 * be simply memcpy()'ed to the X screen. It should be turned on
 * if image will be used for recompression, because some video encoders
 * will refuse to encode images with negative biHeight. Call it before
 * Start().
 *
 * Some decoders allow tweaking of their parameters. There are two ways
 * of doing it. 1) Use Get/SetExtendedAttr() to store parameter values
 * in registry. Decoders read these values during Start(), so you should
 * perform Restart() if you need to change parameters in run-time. 
 *
 * There's more convenient way, which is supported by a few DirectShow
 * codecs. If dynamic_cast<IRtConfig*>(decoder) gives you nonzero, you can
 * use IRtConfig methods to adjust picture properties between Start() and
 * Stop(). These adjustments are applied from the first frame following 
 * method call.
 *
 * List of valid parameters is available as GetCodecInfo().decoder_info.
 * See include/infotypes.h for details on accessing it.
 *
 */
class IRtConfig
{
public:
    virtual HRESULT GetValue(const char*, int&)		=0;
    virtual HRESULT SetValue(const char*, int)		=0;
};

class frame;		// internal class
class VideoRenderer;    // for Direct unbuffered rendering

class IVideoDecoder
{
public:
    // defined in the IVideoDecoder implementation file
    // we could probably modify them in runtime
    // for now we remove static
    int VBUFSIZE;
    int QMARKHI;
    int QMARKLO;
    int DMARKHI;
    int DMARKLO;

    enum CAPS
    {
	CAP_NONE = 0,
	CAP_YUY2 = 1,
	CAP_YV12 = 2,
	CAP_IYUV = 4,
	CAP_UYVY = 8,
	CAP_YVYU = 16,
	CAP_I420 = 32,
    };
    enum DecodingMode
    {
	DIRECT = 0,
	REALTIME,
	REALTIME_QUALITY_AUTO,
    };
    enum DecodingState
    {
	STOP = 0,
	START,
    };
    IVideoDecoder(const CodecInfo& info, const BITMAPINFOHEADER& format);
    virtual ~IVideoDecoder();

    /**
     * Passes the data to decoder.
     * 'render' flag signals decoder if the frame will be rendered.
     * If it is 'false', decoder may speed up the decoding process 
     * by not filling CImage object. This feature is available only
     * for a few decoders, such as Indeo Video 5.0.
     */
    virtual int DecodeFrame(void* src, size_t size, framepos_t pos,
			    double time, int is_keyframe, bool render = true);

    virtual CAPS GetCapabilities() const;
    virtual framepos_t GetPos() const;
    virtual double GetTime() const;
    virtual const BITMAPINFOHEADER& DestFmt() const;
    virtual const CodecInfo& GetCodecInfo() const;
    /**
     * Returns pointer to last decoded image. Future calls to DecodeFrame()
     * may overwrite the area contained in this object. Call CImage::release()  
     * when the image is not needed any more.
     * There's a possibility that underlying decoder is not capable of decoding
     * directly into your format, but CImage offers the necessary conversion.
     * In this case, the conversion will take place inside call to GetFrame().
     */
    virtual CImage* GetFrame();
    virtual int GetFreeBuffers() const;

    virtual void Restart();
    virtual void Start();
    virtual void Stop();

    /* Functions which are implemented by each decoder */
    virtual int SetDestFmt(int bits = 24, fourcc_t csp = 0) 		  =0;

    /* Functions which may be reimplemented */
    virtual int SetDirection(int dir);
    /* sets internal variable 'realtime' to rt if decoder supports caching */
    virtual int SetDirectMemoryAccess(VideoRenderer* vr);
    virtual int SetDecodingMode(DecodingMode mode);
    virtual DecodingMode GetDecodingMode();

    // intentionaly wakeup thread which is waiting for free played position
    // and enable/disable decompression for realtime mode
    virtual void SetEnabled(bool enabled);

    /* Functions which probably won't be overloaded */
    virtual int FlushCache();

    // will be removed as it is useless
    virtual int DropFrame() const;
protected:
    virtual void StartInternal() 					= 0;
    virtual void StopInternal() 					= 0;
    /* Performs actual decoding */
    virtual int DecodeInternal(void* src, size_t size,
			       int is_keyframe, CImage* pImage)		= 0;
    const CodecInfo& record;

    DecodingMode m_Mode;	// should we do precaching (or even change Quality on the fly)
    int m_iDecpos;
    int m_iPlaypos;
    float m_fQuality;           // quality for the progress bar 0..1(best)
    bool m_bCapable16b;
    PthreadMutex decoding;
    PthreadMutex reading;

    BITMAPINFOHEADER* m_bh;	// format of input data (might be larger - e.g. huffyuv)
    BitmapInfo m_decoder;	// format of decoder output
    BitmapInfo m_obh;		// format of returned frames
    // mostly private
    frame* m_pFrame;		// used for direct mode and also hold
    				// reference for the last decoded image
    DecodingState m_State;
    bool m_bFilling;
    bool m_bLastNeeded;         // in case codecs updates last frame
    PthreadCond playposcond;	// wait till frame is played
    PthreadCond decposcond;	// wait till new frame is decoded
    mutable PthreadMutex playposmut; // mutable for const locking
    PthreadMutex decposmut;
    bool m_bEnabled;
    frame** vbuf;              // buffer for frames (currently with fixed size)
    CImage* m_pDecoderImage;
    VideoRenderer* m_pVideoRenderer;
};

#endif // AVIFILE_IVIDEODECODER_H
/*
vim: tabstop=8
*/
