//	VirtualDub - Video processing and capture application
//	Copyright (C) 1998-2001 Avery Lee
//
//	This program is free software; you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation; either version 2 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program; if not, write to the Free Software
//	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#ifndef f_DUB_H
#define f_DUB_H

#include <windows.h>
#include <mmsystem.h>
#include <vfw.h>

#include "Error.h"
#include "audio.h"
#include "filters.h"

class Histogram;
class AsyncBlitter;
class AVIPipe;
class AVIOutput;
class DubSource;
class AudioSource;
class VideoSource;
class FrameSubset;
class InputFile;
class IDubStatusHandler;

////////////////////////

class DubAudioOptions {
public:
	enum {
		P_NOCHANGE=0,
		P_8BIT=1,
		P_16BIT=2,
		C_NOCHANGE=0,
		C_MONO=1,
		C_STEREO=2,
		C_MONOLEFT=3,
		C_MONORIGHT=4,
		M_NONE			= 0,
		M_FULL			= 1,
	};

	long volume;		// 0, or 8-bit fixed point fraction

	long preload;
	long interval;
	long new_rate;
	long offset;
	bool is_ms;
	bool enabled;
	bool fStartAudio, fEndAudio;
	bool integral_rate;
	bool fHighQuality;
	char newPrecision;
	char newChannels;
	char mode;
};

class DubVideoOptions {
public:
	enum {
		D_16BIT = 0,
		D_24BIT = 1,
		D_32BIT	= 2,
	};
	enum {
		M_NONE		= 0,
		M_FASTREPACK= 1,
		M_SLOWREPACK= 2,
		M_FULL		= 3,
	};
	enum {
		FR_SAMELENGTH = -1
	};

	char	inputDepth, outputDepth;
	char	mode;
	BOOL	fShowInputFrame, fShowOutputFrame, fShowDecompressedFrame;
	BOOL	fHistogram, fSyncToAudio;
	int		frameRateDecimation;
	long	frameRateNewMicroSecs;

	long	lStartOffsetMS;
	long	lEndOffsetMS;

	bool	fInvTelecine;
	bool	fIVTCMode;
	int		nIVTCOffset;
	bool	fIVTCPolarity;

	int		nPreviewFieldMode;
};

class DubPerfOptions {
public:
	long	outputBufferSize;
	long	waveBufferSize;
	long	pipeBufferCount;

	bool	dynamicEnable;
	bool	dynamicShowDisassembly;
	bool	useDirectDraw;
	bool	fDropFrames;
};

class DubOptions {
public:
	DubAudioOptions audio;
	DubAudioOptions audio2;
	DubVideoOptions video;
	DubPerfOptions perf;

	bool	fShowStatus, fMoveSlider;
};

class DubStreamInfo {
public:
	long	start_src;
	long	cur_src;
	long	cur_proc_src;
	long	end_src;
	long	start_dst;
	long	cur_dst;
	long	end_dst;
	__int64	total_size;
};

class DubAudioStreamInfo : public DubStreamInfo {
public:
	AudioFormatConverter formatConverter;
	long	samp_frac;
	bool	converting, resampling;
	bool	is_16bit;
	bool	is_stereo;
	bool	is_right;
	bool	single_channel;
	char	bytesPerSample;

	long	lPreloadSamples;
};

class DubVideoStreamInfo : public DubStreamInfo {
public:
	long	usPerFrame;
	long	usPerFrameIn;
	long	usPerFrameNoTelecine;
	long	processed;
	int		nLag;
	bool	fAudioOnly;
};

class IDubber {
public:
	virtual ~IDubber()					=0;

	virtual void SetAudioCompression(WAVEFORMATEX *wf, LONG cb)	=0;
	virtual void SetAudio2Compression(WAVEFORMATEX *wf, LONG cb)	=0;
	virtual void SetInputFile(InputFile *)=0;
	virtual void SetPhantomVideoMode()=0;
	virtual void SetFrameRectangles(RECT *prInput, RECT *prOutput)=0;
	virtual void EnableSpill(const char *pszPrefix, __int64 size, long lFrameLimit)=0;
//	virtual void InitStreamValues(VideoSource *video, AudioSource *audio, AVIOutput *out)	=0;
	virtual void Init(VideoSource *video, AudioSource *audio, AudioSource *audio2, AVIOutput *out, char *szFile, HDC hDC, COMPVARS *videoCompVars)	=0;
	virtual void Go(int iPriority = 0)	=0;

	virtual void RealizePalette()	=0;
	virtual void Abort()			=0;
	virtual bool isAbortedByUser()	=0;
	virtual void Tag(int x, int y)	=0;
	virtual void SetClientRectOffset(int x, int y) = 0;

	virtual void SetStatusHandler(IDubStatusHandler *pdsh)		=0;
	virtual void SetPriority(int index)=0;
	virtual void UpdateFrames()=0;
};

IDubber *CreateDubber(DubOptions *xopt);
void InitStreamValuesStatic(DubVideoStreamInfo& vInfo, DubAudioStreamInfo& aInfo, DubAudioStreamInfo& a2Info, VideoSource *video, AudioSource *audio, AudioSource *audio2, DubOptions *opt, FrameSubset *pfs=NULL);

#ifndef f_DUB_CPP

extern DubOptions g_dubOpts;
#endif

//==============================//
//=====  MODIFICATION OGM  =====//
//=====    -= Cyrius =-    =====//
//BEGIN ========================//
// Moved Dubber class definition from Dub.cpp to here
// Added the following class definitions so that it can compile :)
class VideoSequenceCompressor;
class IDDrawSurface;
class VideoTelecineRemover;
class OGMDubber;
//////

class Dubber : public IDubber {
//private:
	// Cyrius : changed to protected so that derived class (OGMDubber) can access
	// important fields and functions
	// added also virtual for some functions (to be sure those of the derived classes
	// will be used)
protected:
	static void CALLBACK DubFrameTimerProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
	static int PulseCallbackProc(void *_thisPtr, DWORD framenum);

	void ResizeInputBuffer(long bufsize);
	void ResizeAudioBuffer(long bufsize);
	void ResizeAudio2Buffer(long bufsize);
	void ReadVideoFrame(long stream_frame, long display_frame, BOOL preload);
	void ReadNullVideoFrame(long lVStreamPos);
	virtual long ReadAudio(long& lAStreamPos, long samples);
	virtual long ReadAudio2(long& lAStreamPos, long samples);
	void CheckSpill(long videopt, long audiopt, long audio2pt);
	void NextSegment();
	void MainAddVideoFrame();
	virtual void MainAddAudioFrame(int);
	virtual void MainAddAudio2Frame(int);
	static void MainThreadKickstart(void *thisPtr);
	virtual void MainThread();
	void WriteVideoFrame(void *buffer, int exdata, int droptype, LONG lastSize, long sample_num, long display_num);
	void WriteAudio(void *buffer, long lActualBytes, long lActualSamples);
	void WriteAudio2(void *buffer, long lActualBytes, long lActualSamples);
	static void ProcessingThreadKickstart(void *thisPtr);
	virtual void ProcessingThread();

	MyError				err;
	bool				fError;
	LONG				lStopCount;

	DubOptions			*opt;
	AudioSource			*aSrc;
	AudioSource			*a2Src;
	VideoSource			*vSrc;
	InputFile			*pInput;
	AVIOutput			*AVIout;
	COMPVARS			*compVars;
	COMPVARS			*compVars2;
	HDC					hDCWindow;

	DubAudioStreamInfo	aInfo;
	DubAudioStreamInfo	a2Info;
	DubVideoStreamInfo	vInfo;

	bool				fUseVideoCompression;
	bool				fPreview;
	volatile bool		fAbort;
	volatile bool		fUserAbort;
	bool				fADecompressionOk;
	bool				fA2DecompressionOk;
	bool				fVDecompressionOk;
	BOOL				fFiltersOk;
	BOOL				fNoProcessingPriority;
	UINT				timerInterval;
	MMRESULT			timerID;

	HANDLE				hEventAbortOk;
	volatile LONG		lThreadsActive;
	HANDLE				hThreadMain;
	HANDLE				hThreadProcessor;

	void *				inputBuffer;
	long				inputBufferSize;
	void *				audioBuffer;
	long				audioBufferSize;
	void *				audio2Buffer;
	long				audio2BufferSize;

	VideoSequenceCompressor	*pVideoPacker;

	unsigned char *		frameBuffer;

	AVIPipe *			pipe;
	AsyncBlitter *		blitter;

	HIC					outputDecompressor;
	HIC					hicOutput;
	HDRAWDIB			hDDInput, hDDOutput;
	HDC					hdcCompatInput, hdcCompatOutput;
	HBITMAP				hbmInput, hbmOutput, hbmInputOld, hbmOutputOld;
	BITMAPINFO			biInput, biOutput;
	void				*lpvInput, *lpvOutput;

	int					x_client, y_client;
	RECT				rInputFrame, rOutputFrame, rInputHistogram, rOutputHistogram;
	bool				fShowDecompressedFrame;
	bool				fDisplay565;
	IDDrawSurface		*pdsInput;
	IDDrawSurface		*pdsOutput;

	int					iOutputDepth;
	BITMAPINFOHEADER	*decompressedVideoFormat;
	BITMAPINFO			*compressorVideoFormat;
	BITMAPINFO			compressorVideoDIBFormat;
	BITMAPV4HEADER		bihDisplayFormat;

	AudioStream			*audioStreamSource;
	AudioStream			*audioStreamConverter;
	AudioStream			*audioStreamResampler;
	AudioStream			*audioStreamAmplifier;
	AudioStream			*audioSubsetFilter;
	AudioStream			*audioStream, *audioTimingStream;
	AudioStream			*audioStatusStream;
	AudioL3Corrector	*audioCorrector;
	AudioCompressor		*audioCompressor;

	AudioStream			*audio2StreamSource;
	AudioStream			*audio2StreamConverter;
	AudioStream			*audio2StreamResampler;
	AudioStream			*audio2StreamAmplifier;
	AudioStream			*audio2SubsetFilter;
	AudioStream			*audio2Stream, *audio2TimingStream;
	AudioStream			*audio2StatusStream;
	AudioL3Corrector	*audio2Corrector;
	AudioCompressor		*audio2Compressor;

	FrameSubset				*inputSubsetActive;
	FrameSubset				*inputSubsetAlloc;
	VideoTelecineRemover	*pInvTelecine;
	int					nVideoLag;
	int					nVideoLagNoTelecine;
	int					nVideoLagPreload;

	WAVEFORMATEX		*wfexAudioCompressionFormat;
	long				cbAudioCompressionFormat;
	
	WAVEFORMATEX		*wfexAudio2CompressionFormat;
	long				cbAudio2CompressionFormat;

	Histogram			*inputHisto, *outputHisto;

	volatile int		okToDraw;
	HWND				hwndStatus;

	DWORD				timer_counter, timer_period;
	bool				fSyncToAudioEvenClock;
	bool				mbAudioFrozen;
	bool				mbAudioFrozenValid;

	int					iPriority;
	long				lDropFrames;

	FilterStateInfo		fsi;

	bool				fPhantom;

	IDubStatusHandler	*pStatusHandler;

	__int64				i64SegmentSize;
	volatile __int64	i64SegmentCredit;
	__int64				i64SegmentThreshold;
	long				lVideoSizeEstimate;
	const char *		pszSegmentPrefix;
	bool				fEnableSpill;
	int					nSpillSegment;
	long				lSpillVideoPoint, lSpillAudioPoint, lSpillAudio2Point;
	long				lSpillVideoOk, lSpillAudioOk, lSpillAudio2Ok;
	long				lSegmentFrameLimit;
	long				lSegmentFrameStart;

//	pulco-added
	int					saveAudioInputMode;
	int					saveAudio2InputMode;


	// This is used to keep track of the last video frame when decimating in DSC mode.
	long				mDSCLastVideoFrame;

	volatile int		mFramesDelayedByCodec;
	volatile int		mFramesPushedToFlushCodec;

	///////

public:
	Dubber(DubOptions *);
	~Dubber();

	void SetAudioCompression(WAVEFORMATEX *wf, LONG cb);
	void SetAudio2Compression(WAVEFORMATEX *wf, LONG cb);
	void SetPhantomVideoMode();
	void SetInputFile(InputFile *pInput);
	void SetFrameRectangles(RECT *prInput, RECT *prOutput);
	void SetClientRectOffset(int x, int y);
	void EnableSpill(const char *pszPrefix, __int64 threshold, long framethreshold);

	static void Dubber::SetClientRectOffset2(void *pv);
	static void Dubber::SetFrameRectangles2(void *pv);


	virtual void InitAudioConversionChain();
	virtual void InitAudio2ConversionChain();
	void InitOutputFile(char *pszFile);
	bool AttemptInputOverlay(BITMAPINFOHEADER *pbih);
	void AttemptInputOverlays();
	static void AttemptInputOverlays2(void *pThis);

	bool AttemptOutputOverlay();
	void InitDirectDraw();
	void InitDisplay();
	bool NegotiateFastFormat(BITMAPINFOHEADER *pbih);
	bool NegotiateFastFormat(int depth);
	void InitSelectInputFormat();
	//void Init(VideoSource *video, AudioSource *audio, AVIOutput *out, char *szFile, HDC hDC, COMPVARS *videoCompVars);
	virtual void Init(VideoSource *video, AudioSource *audio, AudioSource *audio2, AVIOutput *out, char *szFile, HDC hDC, COMPVARS *videoCompVars);
	void Go(int iPriority = 0);
	void Stop();

	void RealizePalette();
	void Abort();
	void ForceAbort();
	bool isAbortedByUser();
	void Tag(int x, int y);

	void SetStatusHandler(IDubStatusHandler *pdsh);
	void SetPriority(int index);
	void UpdateFrames();
};
//END ==========================//


#endif
