/***********************************************************************
 * VirtualDub Modification for OGM
 *
 * Copyright (C) 2002 Cyrius
 *
 * 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 (see the file COPYING); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * or visit http://www.gnu.org/copyleft/gpl.html
 *
 ***********************************************************************
 *
 *
 *
 */

#ifndef __OGMOUTPUT_H__
#define __OGMOUTPUT_H__

#include "../InputFile.h"
#include "../AVIOutput.h"
#include "OGMPacketizer.h"
#include "../FastWriteStream.h"
#include "OGMReadHandler.h"
#include "OGMSerialGenerator.h"
#include "OGMAudioSource.h"
#include "../FrameSubset.h"

comment_list  *get_chapter_time(comment_list *comments, int num_chapter);
comment_list  *get_chapter_name(comment_list *comments, int num_chapter);
void           delete_comments(comment_list **comments);

struct extra_data {
	bool is_vorbis;
	bool is_text;
	OGMAudioSource *audio;

	void *operator new(unsigned int nAlloc) {
		extra_data *new_data = (extra_data *)malloc(nAlloc);
		if(new_data) {
			new_data->is_vorbis = false;
			new_data->is_text = false;
			new_data->audio = NULL;
		}
		return new_data;
	}
};

class OGMOutputFile : public AVIOutput {
private:
	bool bDemux;
	FrameSubset *inputSubset;
	s64 lStartMS;
	s64 lEndMS;
	s64 usPerFrame;
	SerialGenerator *intern_generator;
	SerialGenerator *s_generator;
	comment_list *video_comments;
	comment_list *audio_comments;
	comment_list *audio2_comments;
	char *file;
	static char szME[];
	long n_frames;
	long n_frame;
	bool                     eos_packets_produced;
	int video_serial;
	int audio_serial;
	int audio2_serial;
	comment_list  *translate_comments(comment_list *comments);
	void           translate_chapters(comment_list **new_comments, comment_list *comments);
	void           sendComments(Packetizer *pktz, comment_list *comments);
	void           setComments(OGMReadStream *stream, Packetizer *pktz, comment_list *comments);
protected:
	packetizer_mesh         *packetizers;
	FastWriteStream *fastIO;
	HANDLE		hFile;
	bool		fCaching;
	int                      _state;
	packetizer_mesh         *add_packetizer(int num_stream
											, Packetizer *packetizer
											, void *extra=NULL
											, bool will_have_few_packets=false);
	Packetizer              *get_packetizer(int num_stream, bool *few_packets=NULL);
	packetizer_mesh         *get_packetizer_mesh(int num_stream);
	bool                     pending_header(void);
	muxer_page              *get_header(void);
	void                     produce_eos_packets(void);
	muxer_page              *get_mpage(void);
	muxer_page              *get_first_mpage(void);
	void                     write_mpage(muxer_page *m_page);
	bool                     pending_mpages(void);
	void produce_eos_packet(int serial);
public:
	OGMOutputFile(comment_list *video_comments, comment_list *audio_comments, comment_list *audio2_comments, bool bDemux=false);
	virtual ~OGMOutputFile(void);
	void initialize(void);
	virtual BOOL process_data(int serial, bool key_frame, LPVOID buffer, LONG length, LONG nSamples);
	void process_pending_mpages(void);
	void flush_packetizers(void);
	void disable_os_caching();
	// For compatibility with AVIOutput :
	virtual BOOL initOutputStreams();
	virtual BOOL init(const char *szFile, LONG xSize, LONG ySize, BOOL videoIn, BOOL audioIn, BOOL audio2In, LONG bufferSize, BOOL is_interleaved);
	BOOL finalize();
	BOOL isPreview();

	void writeIndexedChunk(FOURCC ckid, LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer);

	virtual void write_headers(void);
	virtual int add_stream(OGMAudioSource *audioSource, comment_list *comments);
	long prepareStream(int serial, __int64 start);
	void update_granulepos(int serial, long time_offset_ms);
	BOOL writeToStream(int serial, LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer, LONG lSamples) {
		return process_data(serial, (dwIndexFlags==AVIIF_KEYFRAME?true:false), lpBuffer, cbBuffer, lSamples);
	};
	void setSubset(FrameSubset *subset, long start_ms, long end_ms, long usPerFrame);
};

class OGMAudioOutputStream : public AVIAudioOutputStream {
private:
	int serial;
public:
	OGMAudioOutputStream(class AVIOutput *out) : AVIAudioOutputStream(out) {};
	void setSerial(int serial) { this->serial = serial; };
	BOOL write(LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer, LONG lSamples) {
		BOOL success = ((OGMOutputFile *)output)->process_data(serial, (dwIndexFlags==AVIIF_KEYFRAME?true:false), lpBuffer, cbBuffer, lSamples);
		if(success) lTotalSamplesWritten += lSamples;
		return success;
	};
	BOOL finalize() {return TRUE; };
	void update_granulepos(long offset_ms) {
		((OGMOutputFile *)output)->update_granulepos(serial, offset_ms);
	};
};

class OGMVideoOutputStream : public AVIVideoOutputStream {
private:
	int serial;
public:
	OGMVideoOutputStream(class AVIOutput *out) : AVIVideoOutputStream(out) {};
	void setSerial(int serial) { this->serial = serial; };
	BOOL write(LONG dwIndexFlags, LPVOID lpBuffer, LONG cbBuffer, LONG lSamples) {
		BOOL success = ((OGMOutputFile *)output)->process_data(serial, (dwIndexFlags==AVIIF_KEYFRAME?true:false), lpBuffer, cbBuffer, lSamples);
		if(success) lTotalSamplesWritten += lSamples;
		return success;
	};
	BOOL finalize() {return TRUE; };
};


#endif /* __OGMOUTPUT_H__ */