#ifndef _HEADER_CAPPROC_H_
#define _HEADER_CAPPROC_H_

#include <default.h>
#include <queue>
#include <string>
#include <strstream>
#include <pthread.h>
#include "v4lxif.h"

class ClosedCaption;
class frame_allocator;
class dsp;

enum Sound_Freqs
{
    NoAudio	=-1,
    F48		=0,
    F44		=1,
    F22		=2,
    F11		=3
};
enum Sample_Sizes
{
    S16		=0,
    S8		=1
};
enum Sound_Chans
{
    Mono	=0,
    Stereo	=1
};
enum Resolutions
{
    WNONE 	=-1,
    W160	=0,
    W192	=1,
    W320	=2,
    W384	=3,
    W400  	=4,
    W512	=5,
    W576	=6,
    W640  	=7,
    W768 	=8,
};

enum Colorspaces
{
    cspRGB24	= 0,
    cspYUY2	= 1,
    cspYV12	= 2
};

struct restable_t
{
    enum Resolutions res;
    int width;
    int height;
};

static struct restable_t restable[] = {
    { W768, 768, 576 },
    { W640, 640, 480 },
    { W576, 576, 432 },
    { W400, 400, 300 },
    { W384, 384, 288 },
    { W320, 320, 240 },
    { W192, 192, 144 },
    { W160, 160, 120 },
    { W512, 512, 384 },
    { WNONE, 0, 0 }
};

struct chunk
{
    char* data;
    double timestamp;
};

struct CaptureProgress
{
    pthread_mutex_t mutex;
    static const int history_size=256;
    int video_frame_len;
    int buffer_len;
    int max_frames;
    
    const char* filename;
    float framerate;
    int xdim;
    int ydim;
    int audio_freq;
    int audio_ssize;
    int audio_channels;
    
    CaptureProgress() 
	: 
	video_frame_len(0),  buffer_len(0),
	enc_time(0), video_time(0), audio_time(0), 
	video_bytes(0), 
	video_frames(0), synch_fix(0),
	audio_bytes(0), file_size(0),
	video_frame_head(0), buffer_head(0),
	max_frames(0),
	dropped_cap(0), dropped_enc(0)
	{ pthread_mutex_init(&mutex, 0); }
    ~CaptureProgress() { pthread_mutex_destroy(&mutex); }
    void lock() { pthread_mutex_lock(&mutex); }
    void unlock() { pthread_mutex_unlock(&mutex); }
    void init(const char* fn, float fps, int xd, int yd, int freq, int ssize, int channels, int frames)
    {
	lock();
	filename=fn;	  
	framerate=fps;
	xdim=xd;
	ydim=yd;
	audio_freq=freq;
	audio_ssize=ssize;
	audio_channels=channels;
	max_frames=frames;
	unlock();
    }
    void update(long long etime, double vidtime, double audtime,
	long long audbytes, long long fsize, int synchfix,
	int vframe, int bufstatus,
	int drop_cap, int drop_enc,
	const char* fn)
    {
	lock();
	enc_time=etime;
	video_time=vidtime;
	audio_time=audtime;
	if(vframe>0)
	    video_bytes+=(vframe & ~0x40000000);
	audio_bytes=audbytes;
	file_size=fsize;
	synch_fix=synchfix;
	if(vframe>=0)
	{
    	    video_frames++;
	    video_frame_sizes[video_frame_head]=vframe;
	    video_frame_head++;
	    video_frame_head%=history_size;
	    if(video_frame_len<history_size)
		video_frame_len++;
	    buffer_occupancies[buffer_head]=bufstatus;
	    buffer_head++;
	    buffer_head%=history_size;
	    if(buffer_len<history_size)
		buffer_len++;
	    dropped_cap=drop_cap;
	    dropped_enc=drop_enc;
	}	
	filename=fn;
	unlock();
    }
    
    long long enc_time;
    double video_time;
    double audio_time;
    long long video_bytes;
    int video_frames;
    int synch_fix;
    long long audio_bytes;
    long long file_size;
    int video_frame_sizes[history_size];
    int video_frame_head;
    int buffer_occupancies[history_size];
    int buffer_head;
    int dropped_cap;
    int dropped_enc;
};

struct CaptureConfig
{
    std::string filename;
    int segment_size;
		   // Segmentation is implicit finishing one
		   // file and starting next one when old file
		   // grows to specified size
		   //Kbytes
		   //-1 for no segmentation
    int compressor;
    int quality;	// 0..10000
		   // compressor-dependent
		   // for IV 5.0 Quick it's ignored
    int keyframes;
    int frequency;
		   // frequency ID
		   //-1 for no audio
    int samplesize;
    int chan;
    int res_w;
    int res_h;
    int timelimit;		//in seconds. -1 if no limit
    int sizelimit;		//in Kbytes. -1 if no limit
    float fps;
    Colorspaces colorspace;    
    void load();    
    void setDimensions(Resolutions res);
    void setChannels(Sound_Chans c);
    void setSamplesize(Sample_Sizes ss);
    void setFrequency(Sound_Freqs freq);
};
class CaptureProcess
{
protected:
    void* vidcap();
    void* audcap();
    void* writer();
    static void* vidcap_starter(void* arg) { return ((CaptureProcess*)arg)->vidcap(); }
    static void* audcap_starter(void* arg) { return ((CaptureProcess*)arg)->audcap(); }
    static void* writer_starter(void* arg) { return ((CaptureProcess*)arg)->writer(); }
    static void capwriter(void*, const char*);
    v4lxif* m_v4l;
    pthread_t m_vidc;
    pthread_t m_audc;
    pthread_t m_writer;
    pthread_t m_sub;
    int m_quit;
    std::queue<chunk> m_vidq;
    std::queue<chunk> m_audq;
    int cnt;
    int cap_drop;
    int comp_drop;
    long long starttime;
    int ccfd;
    long long lastcctime;
    std::string lastccstring;
    
    CaptureProgress* m_pProgress;
    ClosedCaption* m_ccap;
    frame_allocator* m_pAllocator;
    const CaptureConfig m_conf;
    dsp* m_pDsp;
    
    std::string error;    

    int segment_flag;

    int vid_clear;
    int aud_clear;

public:
    CaptureProcess(v4lxif* v4l,		
		    CaptureConfig* conf,
		    ClosedCaption* ccap);
     ~CaptureProcess();

     void getState(int& finished, std::string& e)
     {
	 finished = m_quit;
	 e = error;	 
     }

     void setMessenger(CaptureProgress* pProgress);

     void segment()
     {
	 segment_flag=1;
     }
};

#endif /* _HEADER_CAPPROC_H_ */
