/*************************************************************
 *   mpgtx an mpeg toolbox                                   *
 *   by Laurent Alacoque <laureck@users.sourceforge.net>     *   
 *   (c) 2001                                                *
 *   You may copy, modify and redistribute this              *
 *   source file under the terms of the GNU Public License   *
 ************************************************************/
#ifndef __mpegOut_hh_
#define __mpegOut_hh_

#include "common.hh"
#include "mpeg.hh"
// required by access()
// FIXME: Still needed, because we have mpgtx_access()?
#include <unistd.h>


class mpeg;


class mpegOut
{
public:
	mpegOut(char *filename);
	mpegOut(FILE *filehandle);
	virtual ~mpegOut();
	const FILE* OutFile() {return MpegOut;}
	int WriteChunk(mpeg* Mpeg, off_t from, off_t to)
			{return WriteChunk(Mpeg, from, false, to, true);};
	virtual void WriteHeader(mpeg* Mpeg) = 0;
	virtual int WriteChunk (mpeg* Mpeg,
		off_t from, bool from_included,
		off_t to, bool to_included) = 0;
	virtual void Finish() {};

protected:
	mpegOut() {};
	virtual void Copy(FILE* file, off_t from, off_t to) = 0;
	int FileType;
	bool HasAudio,HasVideo;
	FILE* MpegOut;
	byte* buffer;
};


class mpegOutWithVideo : public mpegOut
{
protected:
	mpegOutWithVideo(char* filename) : 
		mpegOut(filename) {mpeg_version = 0;};
	mpegOutWithVideo(FILE* filehandle) : 
		mpegOut(filehandle) {mpeg_version = 0;};

	mpegOutWithVideo(){};
	long CorrectTS(long bufferlength);

	void memReadTS(long offset, double* ts, bool mpeg2pack = false, bool pack = false);
	int  memReadPktTS(long* off, double* pts, double* dts, long bufferlength);
	void memWriteTS(long offset, double ts, bool mpeg2pack = false, bool pack = false);

	double currentTS;
	double ts_correction;
	bool first_TS_correction;
	
	int mpeg_version;
};

class mpegVideoOut : public mpegOutWithVideo
{
public:
	mpegVideoOut(char* filename) :
		mpegOutWithVideo(filename) {};
	mpegVideoOut(FILE* filehandle) :
		mpegOutWithVideo(filehandle) {};
		
	void WriteHeader(mpeg* Mpeg);
	int WriteChunk (mpeg* Mpeg,
		off_t from, bool from_included,
		off_t to, bool to_included );
protected:
	mpegVideoOut(){};
	void Copy(FILE* file, off_t from, off_t to);
};


class mpegSystemOut : public mpegOutWithVideo
{
public:
	mpegSystemOut(char* filename) :
		mpegOutWithVideo(filename) {partial_packet = 0;};
	mpegSystemOut(FILE* filehandle) :
		mpegOutWithVideo(filehandle) {partial_packet = 0;};

	void WriteHeader(mpeg* Mpeg);
	int WriteChunk(mpeg* Mpeg,
		off_t from, bool from_included,
		off_t to, bool to_included );
	void Finish(); 
	
protected:
	mpegSystemOut() {};
	void Copy(FILE* file, off_t from, off_t to);

	//size of data from the end of the packet header to the end of file
	off_t partial_packet_length;
	//keep the partial packet in memory (because stdout is not seekable)
	byte* partial_packet;
};

class mpegAudioOut : public mpegOut
{
public:
	mpegAudioOut(char* filename):
		mpegOut(filename){};
	mpegAudioOut(FILE* filehandle):
		mpegOut(filehandle){};

	void WriteHeader(mpeg* Mpeg){};
	int WriteChunk(mpeg* Mpeg,
		off_t from, bool from_included,
		off_t to, bool to_included );

	void Finish();
protected:
	mpegAudioOut(){};
	void Copy(FILE* file, off_t from, off_t to);
};

class mpegOutFactory
{
public:
	mpegOut* NewMpegFrom(mpeg* MpegIn, char* filename);
	mpegOut* NewMpegFrom(mpeg* MpegIn, FILE* filehandle);
};


class demuxer
{
public:
	demuxer(mpeg* _Mpeg, char* _basename, bool _confirm = true);
	~demuxer();
	int Process();
	
protected:
	int ProcessTransportStream();
	int ProcessProgramStream();
	int DemuxTrPkt(FILE* out, off_t start, off_t end);
	FILE* openfile(char* filename);
	off_t Copy(FILE* into, off_t from, off_t to);
	demuxer() {};
	FILE* AudioFile[16];
	int n_audio;
	FILE* VideoFile[16];
	int n_video;
	int n_programs;
	mpeg* Mpeg;
	char* basename;
	bool confirm;
	byte* buffer;
};

#endif //__mpegOut_hh_
