//---------------------------------------------------------------------------
//	AVFile - library for audio and video files processing
//	2002 - 2007 Stanislav Sumec <sumec@fit.vutbr.cz>
//
//	avfile.h
//	base class
//---------------------------------------------------------------------------

#ifndef _AVFILE_H
#define _AVFILE_H

#include <string>
#include <vector>
#include "types.h"

#ifdef AVFILE_HAVE_CONFIG
#include "avfile_config.h"
#endif

#ifdef AVFILE_WITH_DIGILIB
#include "Image.h"
#endif

#if defined(__BORLANDC__) && !defined(AVFILE_NO_VCL_EXCEPTIONS)
#include <SysUtils.hpp>
#endif

class TAVFile
{
public:
	enum EOpenMode {omClosed = 0x0, omRead = 0x1, omWrite = 0x2};
	enum EOpenType {otNone = 0x0, otVideo = 0x1, otAudio = 0x2, otVideoAudio = 0x3};
	enum ECapability {cNone = 0x0, cDependentStreams = 0x1};

	class TFrameRate
	{
	public:
		unsigned int Rate, Scale;
		friend bool operator == (const TFrameRate& f1, const TFrameRate& f2);
		friend bool operator < (const TFrameRate& f1, const TFrameRate& f2);
	};

	class TFrameInfo
	{
	public:
		int Width, Height;
		TFrameRate FrameRate;
		friend bool operator == (const TFrameInfo& f1, const TFrameInfo& f2);
	};

	class TAudioInfo
	{
	public:
		int Channels, SamplesPerSec;
	};

	class TParameters
	{
	public:
		int BitRate, KeyFrame, AudioBitRate;
		std::string Codec, AudioCodec;
		bool Deinterlace;
	};

	typedef std::string TDescription;

#if defined(__BORLANDC__) && !defined(AVFILE_NO_VCL_EXCEPTIONS)
	class AVFileError: public Exception
	{
	public:
		AVFileError();
		AVFileError(const char *AMessage);
	};
#else
	class AVFileError
	{
	public:
		std::string Message;
		AVFileError();
		AVFileError(const char *AMessage);
	};
#endif
	class AVFileErrorMemory: public AVFileError
	{
	public:
		AVFileErrorMemory();
		AVFileErrorMemory(const char *AMessage);
	};

	class AVFileErrorNotImplemented: public AVFileError
	{
	public:
		AVFileErrorNotImplemented();
		AVFileErrorNotImplemented(const char *AMessage);
	};

	class AVFileErrorOpen: public AVFileError
	{
	public:
		AVFileErrorOpen();
		AVFileErrorOpen(const char *AMessage);
	};

	class AVFileErrorOpenVideo: public AVFileErrorOpen
	{
	public:
		AVFileErrorOpenVideo();
		AVFileErrorOpenVideo(const char *AMessage);
	};

	class AVFileErrorOpenAudio: public AVFileErrorOpen
	{
	public:
		AVFileErrorOpenAudio();
		AVFileErrorOpenAudio(const char *AMessage);
	};

	class AVFileErrorOpenInvalidMode: public AVFileErrorOpen
	{
	public:
		AVFileErrorOpenInvalidMode();
		AVFileErrorOpenInvalidMode(const char *AMessage);
	};

	class AVFileErrorNotOpened: public AVFileError
	{
	public:
		AVFileErrorNotOpened();
		AVFileErrorNotOpened(const char *AMessage);
	};

	class AVFileErrorVideoNotOpened: public AVFileErrorNotOpened
	{
	public:
		AVFileErrorVideoNotOpened();
		AVFileErrorVideoNotOpened(const char *AMessage);
	};

	class AVFileErrorAudioNotOpened: public AVFileErrorNotOpened
	{
	public:
		AVFileErrorAudioNotOpened();
		AVFileErrorAudioNotOpened(const char *AMessage);
	};

	class AVFileErrorRead: public AVFileError
	{
	public:
		AVFileErrorRead(const char *AMessage);
	};

	class AVFileErrorGetVideo: public AVFileErrorRead
	{
	public:
		AVFileErrorGetVideo();
		AVFileErrorGetVideo(const char *AMessage);
	};

	class AVFileErrorGetAudio: public AVFileErrorRead
	{
	public:
		AVFileErrorGetAudio();
		AVFileErrorGetAudio(const char *AMessage);
	};

	class AVFileErrorWrite: public AVFileError
	{
	public:
		AVFileErrorWrite(const char *AMessage);
	};

	class AVFileErrorPutVideo: public AVFileErrorWrite
	{
	public:
		AVFileErrorPutVideo();
		AVFileErrorPutVideo(const char *AMessage);
	};

	class AVFileErrorPutAudio: public AVFileErrorWrite
	{
	public:
		AVFileErrorPutAudio(const char *AMessage);
	};

private:
	std::vector<std::string> FileTypes;
	BITMAPINFO *DIBFrame;
	unsigned int DIBFrameSize;
	BITMAPINFO* Frame2DIB(BYTE *Buffer);
	void Frame2Frame(BYTE *Buffer1, BYTE *Buffer2);
#ifdef AVFILE_WITH_DIGILIB
	ImageStruct *DLFrame;
	ImageStruct* Frame2Image(BYTE *Buffer);
	void Frame2Image(BYTE *Buffer, ImageStruct *Image);
#if defined(_WIN32) || defined(WIN32)
	ImageStruct* DIB2Image(BITMAPINFO *Bitmap);
#endif
#endif

protected:
	enum EImplemented
	{
		iGetFrameA = 0x1,
		iGetFrameB = 0x2,
		iGetFrameA2 = 0x4,
		iGetFrameB2 = 0x8,
		iDIBGetFrameA = 0x10,
		iDIBGetFrameB = 0x20,
		iDLGetFrameA = 0x40,
		iDLGetFrameB = 0x80,
		iDLGetFrameA2 = 0x100,
		iDLGetFrameB2 = 0x200
	};

	int Implemented, Capabilities;
	int OpenMode, OpenType;
	unsigned int AudioPos, VideoPos;
	TFrameInfo VideoInfo;
	TAudioInfo AudioInfo;
	TParameters Parameters;
	TDescription Description; 

	void RegisterFileType(const char *Ext);

	void* GetMem(size_t Size);
	void FreeMem(void *Mem);

	void CheckOpened();
	void CheckRead();
	void CheckWrite();
	void CheckClosed();
	void CheckVideoStream();
	void CheckAudioStream();

	virtual void OpenA(const char *FileName, int Mode, int Type, bool ThrowExceptions);

	virtual BYTE* GetFrameA();
	virtual BYTE* GetFrameB(unsigned int Position);
	virtual void GetFrameA2(BYTE *Buffer);
	virtual void GetFrameB2(BYTE *Buffer, unsigned int Position);

	virtual BITMAPINFO* DIBGetFrameA();
	virtual BITMAPINFO* DIBGetFrameB(unsigned int Position);

#ifdef AVFILE_WITH_DIGILIB
	virtual ImageStruct* DLGetFrameA();
	virtual ImageStruct* DLGetFrameB(unsigned int Position);
	virtual void DLGetFrameA2(ImageStruct *Buffer);
	virtual void DLGetFrameB2(ImageStruct *Buffer, unsigned int Position);
#endif

public:
	TAVFile();
	virtual ~TAVFile();

	virtual unsigned int GetCapabilities();
	void Open(const char *FileName, int Mode, int Type, bool ThrowExceptions = true);
	virtual void Close();
	virtual void Seek(unsigned int Frame);

	virtual int GetOpenMode();
	virtual int GetOpenType();

	BYTE* GetFrame();
	BYTE* GetFrame(unsigned int Position);
	void GetFrame(BYTE *Buffer);
	void GetFrame(BYTE *Buffer, unsigned int Position);

	BITMAPINFO* DIBGetFrame();
	BITMAPINFO* DIBGetFrame(unsigned int Position);

#ifdef AVFILE_WITH_DIGILIB
	ImageStruct* DLGetFrame();
	ImageStruct* DLGetFrame(unsigned int Position);
	void DLGetFrame(ImageStruct *Buffer);
	void DLGetFrame(ImageStruct *Buffer, unsigned int Position);
	virtual void DLPutFrame(ImageStruct *Buffer);
#endif

	virtual void SkipFrames(unsigned int Frames);

	virtual void PutFrame(BYTE *Buffer);
	virtual void DIBPutFrame(BITMAPINFO *Buffer);

	virtual unsigned int GetVideoLength();
	virtual unsigned int GetVideoPos();
	virtual TFrameInfo GetFrameInfo();
	virtual void SetFrameInfo(TFrameInfo Info);
	virtual void SeekVideo(unsigned int Frame);

	virtual BYTE* GetAudio(unsigned int &Size);
	virtual void SkipAudio();
	virtual void PutAudio(BYTE *Buffer, unsigned int Size);
	virtual unsigned int GetAudioLength();
	virtual unsigned int GetAudioPos();
	virtual TAudioInfo GetAudioInfo();
	virtual void SetAudioInfo(TAudioInfo Info);
	virtual void SeekAudio(unsigned int Sample);

	virtual bool FileTypeSupported(const char *Ext);

	virtual TParameters GetParameters();
	virtual void SetParameters(TParameters Parameters);

	virtual TDescription GetDescription();

	virtual int GetAudioSkew();

	static int Round(double v);
};

#endif

