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

	Classes for writing AVIs
	Copyright 2000 Eugene Kuznetsov  (divx@euro.ru)

*********************************************************/
#ifndef AVIFILE_AVISEGWRITE_H
#define AVIFILE_AVISEGWRITE_H

#include <string>
#include <except.h>

#include "AviWrite.h"

class AviSegWriteFile;

class AviSegWriteStream : public IAviWriteStream
{
friend class AviSegWriteFile;

protected:
    IAviWriteStream* m_pStream;
    AviSegWriteFile* m_pFile;

    int _handler;
    int _frame_rate;
    int _samplesize;
    int _quality;
    int _flags;

    char* _format;
    int _format_size;
public:
//    void SetType(StreamType type){return m_pStream->SetType(type);}
    AviSegWriteStream(AviSegWriteFile* file, IAviWriteStream* stream);
//    AviSegWriteStream(AviWriteFile* file, int ckid,
//	enum AviStream::StreamType type,
//	const char* format, unsigned format_size,
//	int handler, int frame_rate,
//	int samplesize=0, int quality=0, int flags=0);

    virtual ~AviSegWriteStream();
    //
    // these two should be called before data insertion begins
    //
    //
    // for video streams, specify time in microsecs per frame in frame_rate
    // for audio streams - count of bytes per second
    //
//    void SetHeader(int handler, int frame_rate, int samplesize=0, int quality=0, int flags=0)
//    {
//	_handler=handler;
//	_frame_rate=frame_rate;
//	_samplesize=samplesize;
//	_quality=quality;
//	_flags=flags;
//	return m_pStream->SetHeader(handler, frame_rate, samplesize, quality, flags);
//    }
//    void SetFormat(const char* format, unsigned format_size)
//    {
//	if(_format)delete _format;
//	_format=new char[format_size];
//	_format_size=format_size;
//	memcpy(_format, format, format_size);
//	return m_pStream->SetFormat(format, format_size);
//    }
    void SetRealStream(IAviWriteStream* pStream);
    StreamType GetType() const {return m_pStream->GetType();}
    HRESULT AddChunk(const void* chunk, size_t size, int flags=0);
    size_t GetLength() const { return m_pStream->GetLength(); }
};

class AviVideoSegWriteStream : public IAviVideoWriteStream
//class AviVideoWriteStream : public IAviVideoWriteStream, public AviWriteStream
{

    IAviVideoWriteStream* m_pStream;
    AviSegWriteFile* m_pFile;
    BITMAPINFOHEADER _srchdr;
    fourcc_t _fourcc;
//    int _frame_rate;
//    int _flags;
    static const int undefined = -256;
    int _quality;
    int _keyfreq;
public:
//    AviVideoSegWriteStream(AviWriteFile* file, int ckid, int fourcc, BITMAPINFOHEADER* srchdr,
//	int frame_rate, int flags=0)

    AviVideoSegWriteStream(AviSegWriteFile* file, IAviVideoWriteStream* stream)
	:m_pStream(stream), m_pFile(file), _quality(undefined), _keyfreq(undefined)
    {
//	_frame_rate=frame_rate;
//	_flags=flags;
    }
    ~AviVideoSegWriteStream() {}
//    void Create(int fourcc, BITMAPINFOHEADER* srchdr)
//    {
//	_srchdr=*srchdr;
//	_fourcc=fourcc;
//	return (AviVideoWriteStream*)m_pStream->Create(fourcc, srchdr);
//    }
//    void SetHeader(int frame_rate,
//            int flags=0)
//    {
//	return m_pStream->SetHeader(frame_rate, flags);
//    }
    virtual HRESULT Start() { return m_pStream->Start(); }
    virtual HRESULT Stop() { return m_pStream->Stop(); }
    HRESULT AddFrame(CImage* chunk, size_t* sz =0, int* kf =0);
    virtual HRESULT SetQuality(int quality)
    {
	_quality = quality;
	return m_pStream->SetQuality(quality);
    }
    HRESULT SetKeyFrame(int frequency)
    {
	_keyfreq = frequency;
	return m_pStream->SetKeyFrame(frequency);
    }
    size_t GetLength() const { return m_pStream->GetLength(); }

    void SetRealStream(IAviVideoWriteStream* realstream)
    {
//	realstream->Create(_fourcc, &_srchdr);
//	realstream->SetHeader(_frame_rate, _flags);
	m_pStream=realstream;
	if(_quality!=undefined)
	    realstream->SetQuality(_quality);
	if(_keyfreq!=undefined)
	    realstream->SetKeyFrame(_keyfreq);
	realstream->Start();
    }
};

class AviAudioSegWriteStream : public IAviAudioWriteStream
{
    IAviAudioWriteStream* m_pStream;
    AviSegWriteFile* m_pFile;
    static const int undefined=-256;
    int _quality;
public:

    AviAudioSegWriteStream(AviSegWriteFile* file, IAviAudioWriteStream* stream)
	:m_pStream(stream), m_pFile(file), _quality(undefined)
    {
    }
    ~AviAudioSegWriteStream(){}
    virtual HRESULT Start() { return m_pStream->Start(); }
    virtual HRESULT Stop() { return m_pStream->Stop(); }
    HRESULT AddData(void* chunk, size_t size);
    virtual HRESULT SetQuality(int quality)
    {
	_quality = quality;
	return m_pStream->SetQuality(quality);
    }
    size_t GetLength() const { return m_pStream->GetLength(); }

    void SetRealStream(IAviAudioWriteStream* realstream)
    {
	m_pStream=realstream;
	if (_quality != undefined)
	    realstream->SetQuality(_quality);
	realstream->Start();
    }
};

class AviSegWriteFile: public IAviSegWriteFile
{
friend class AviSegWriteStream;
friend class AviVideoSegWriteStream;
friend class AviAudioSegWriteStream;
    struct streaminfo
    {
	enum St {
	    Audio, Video, Common
	};
	St state;
	AviStream::StreamType type;
        AviSegWriteStream* stream;
	uint8_t* format;
        size_t format_size;
	fourcc_t fourcc;
	size_t samplesize;
        int quality;
	int frame_rate;
	int flags;
        BITMAPINFOHEADER hdr;
	AviVideoSegWriteStream* vstream;
	AviAudioSegWriteStream* astream;
    };
    std::vector<streaminfo> m_streams;
    std::string _name;
    int _flags;
    int _mask;
protected:
    AviWriteFile* rf;
    size_t m_lFlimit;
    int64_t _size;
public:
    AviSegWriteFile(const char* name, size_t flimit = 0x7F000000,
		    int flags = 0, int mask = 00777);
    ~AviSegWriteFile();
    IAviAudioWriteStream* AddAudioStream(fourcc_t fourcc,
					 WAVEFORMATEX* fmt,
					 int bitrate, int flags = 0);
    IAviVideoWriteStream* AddVideoStream(fourcc_t fourcc,
					 BITMAPINFOHEADER* srchdr,
					 int frame_rate, int flags = 0);
    IAviWriteStream* AddStream(enum AviStream::StreamType type,
			       const void* format, size_t format_size,
			       fourcc_t handler, int frame_rate,
			       size_t samplesize=0,
			       int quality=0, int flags=0);
    HRESULT Reserve(size_t size){return -1;}
    HRESULT WriteChunk(fourcc_t fourcc, void* data, size_t size){return -1;}
    int64_t FileSize(){return _size+rf->FileSize();}
    void Segment();
    const char* FileName() const { return _name.c_str(); }
//protected:
    //
    //called when data is added to stream
    //
//    void AddChunk(offset_t offset, unsigned size, unsigned id, unsigned flags=0);
};

#endif // AVIFILE_AVISEGWRITE_H
