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

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

*********************************************************/
#ifndef AVIFILE_AVIWRITE_H
#define AVIFILE_AVIWRITE_H


#include <avifmt.h>
#include <avifile.h>
#include <except.h>
#include <videoencoder.h>
#include <creators.h>

#include <unistd.h>
#include <pthread.h>

#include "FileBuffer.h"

#include <vector>
#include <string>
#include <list>

#define __MODULE__ "AviWriteFile"

class Component
{
public:
    virtual ~Component(){}
};

class Registrator: public std::list<Component*>
{
public:
    Registrator():_destroying(false){}
    static Registrator Reg;
    bool _destroying;
    ~Registrator()
    {
	_destroying=true;
	for(std::list<Component*>::iterator it=begin(); it!=end(); it++)
	    delete *it;
    }
};

class AviWriteFile;

class AviWriteStream : public IAviWriteStream
{
friend class AviWriteFile;

protected:
    AviWriteFile* m_file;
    FileBuffer* m_fd;
//    int m_fd;
    StreamType m_type;

    uint8_t* m_format;
    size_t m_forsize;
    int m_ckid;
    AviWriteStream(AviWriteFile* file, int ckid, enum AviStream::StreamType,
		   fourcc_t handler, int frame_rate, int flags=0);
    void SetVideoData(int quality, int width, int height)
    {
    	m_header.dwQuality=quality;
        m_header.rcFrame.right=width;
	m_header.rcFrame.bottom=labs(height);
    }
//    void SetAudioData(
public:
    AviWriteStream(AviWriteFile* file, int ckid,
		   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);

    ~AviWriteStream();
    //
    // 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
    //
    StreamType GetType() const { return m_type; }
    HRESULT AddChunk(const void* chunk, size_t size, int flags=0);

    size_t GetLength() const { return m_header.dwLength; }
};

class AviAudioWriteStream : public IAviAudioWriteStream, public AviWriteStream
{
    IAudioEncoder* m_pIEnc;
    WAVEFORMATEX srcfmt;
    int _status;
    int _bitrate;
public:
    AviAudioWriteStream(AviWriteFile* file, int ckid, fourcc_t fourcc,
			WAVEFORMATEX* fmt, int bitrate, int flags=0);
    virtual ~AviAudioWriteStream();
    virtual HRESULT Start();
    virtual HRESULT AddData(void* data, size_t size);
    virtual HRESULT Stop();
    virtual HRESULT SetQuality(int quality);
    size_t GetLength() const;
};

class AviVideoWriteStream : public IAviVideoWriteStream, public AviWriteStream
{
    IVideoEncoder* m_pIEnc;
    int m_vstatus;
    uint8_t* m_local_buffer;
public:
    AviVideoWriteStream(AviWriteFile* file, int ckid, fourcc_t fourcc,
			BITMAPINFOHEADER* srchdr,
			int frame_rate, int flags=0);
    ~AviVideoWriteStream();
    virtual HRESULT Start();
    virtual HRESULT Stop();
    HRESULT AddFrame(CImage* chunk, size_t* =0, int* =0);
    virtual HRESULT SetQuality(int quality);
    HRESULT SetKeyFrame(int frequency);
    size_t GetLength() const;
};

//
//maintains global file info
//
class AviSegWriteFile;
class AviWriteFile: public IAviWriteFile, public Component
{
friend class AviWriteStream;
friend class AviSegWriteFile;
private:
    std::vector<AviWriteStream*> m_streams;
    int m_strcnt;
    MainAVIHeader m_header;
    int m_status;
    std::vector<AVIINDEXENTRY> m_index;
    std::string m_filename;
protected:
    FileBuffer* m_fd;
//    int m_fd;
    void _destruct();
public:
    AviWriteFile(const char* name, int flags=0, int mask=00777);
    ~AviWriteFile();
    void WriteHeaders();
//    void Create(const char* name, int flags=0, int mask=00777);
    IAviAudioWriteStream* AddAudioStream(fourcc_t fourcc,
					 WAVEFORMATEX* fmt, int bitrate,
					 int flags=0);
    IAviVideoWriteStream* AddVideoStream(fourcc_t fourcc,
					 BITMAPINFOHEADER* srchdr,
					 int frame_rate, int flags);

    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);
    HRESULT WriteChunk(fourcc_t fourcc, void* data, size_t size);
    int64_t FileSize();
    const char* FileName() const { return m_filename.c_str(); }
protected:
    //
    //called when data is added to stream
    //
    void AddChunk(offset_t offset, size_t size, Unsigned id, int flags=0);
};

#endif // AVIFILE_AVIWRITE_H
