/***********************************************************************
 * 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 __OGMAUDIOSOURCE_H__
#define __OGMAUDIOSOURCE_H__

#include "../List.h"
#include "../AudioSource.h"
#include "OGMInputFile.h"
#include "OGMReadHandler.h"

// 16/11/2002, Cyrius : changed all lists to List2<ListNode2<...>>

class frameNode : public ListNode2<frameNode> {
public:
	s64 file_pos;
	s64 pos;
	u16 size;
	u16 samples;

	frameNode(void) {
		file_pos = 0;
		pos = 0;
		size = 0;
		samples = 0;
	};
};

class OGMAudioSource : public AudioSource {
private:
	bool can_cut_first_packet;
protected:
	char *file;
	char *desc;
	LONG buffer_size;
	OGMInputFile *input;
	List2<frameNode> frames;
	frameNode *firstFrame;
	frameNode *currentFrame;
	frameNode *lastFrame;
	void add_frame(u16 size, u16 samples);
public:
	OGMAudioSource(char *fn, LONG inputBufferSize);
	virtual ~OGMAudioSource();

	BOOL isOGM;
	BOOL isText;
	virtual BOOL init() {return FALSE;};
	virtual int _read(LONG lStart, LONG lCount, LPVOID lpBuffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead);
	virtual long samplesLag(__int64 lStart);
	char *getName(void) { return file; };
	char *getDesc(void) { return desc; };
	virtual bool isEOS(void) { return false; };
	virtual __int64 getFilePos(long lStart);
};

class subNode : public ListNode2<subNode> {
public:
	char *sub;
	s64 pos;
	s32 samples;

	subNode(void) {
		pos = 0;
		samples = 0;
		sub = NULL;
	};

	~subNode(void) {
		if(sub)
			delete[] sub;
	};
};


class OGMTextSourceSRT : public OGMAudioSource {
private:
	List2<subNode> subs;
	subNode *firstSub;
	subNode *currentSub;
	subNode *lastSub;
	s64 last_e;
public:
	OGMTextSourceSRT(char *fn);
	virtual ~OGMTextSourceSRT(void);
	virtual BOOL init();
	BOOL add_times(char *line);
	BOOL add_sub(char *line);
	void add_sub(s32 samples);
	virtual long samplesLag(__int64 lStart) { return 0; };
	virtual int _read(LONG lStart, LONG lCount, LPVOID lpBuffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead);
	virtual bool isEOS(void);
};


class OGMAudioSourceOGM : public OGMAudioSource {
protected:
	int num_stream;
	IAVIReadHandler *pAVIFile;
	IAVIReadStream *pAVIStream;

public:
	OGMAudioSourceOGM(char *fn, OGMReadHandler *handler, int num_stream, bool is_inputfile=false);
	virtual ~OGMAudioSourceOGM(void);
	virtual BOOL init();
	int _read(LONG lStart, LONG lCount, LPVOID lpBuffer, LONG cbBuffer, LONG *lBytesRead, LONG *lSamplesRead);
	long samplesLag(__int64 lStart) { return ((OGMReadStream *)pAVIStream)->samplesLag(lStart); };
	IAVIReadStream *getStream(void) { return pAVIStream; };
	IAVIReadHandler *getHandler(void) { return pAVIFile; };
	int Stream(void) { return num_stream; };
	__int64 FramePos(long lStart);
};

class OGMTextSourceOGM : public OGMAudioSourceOGM {
public:
	OGMTextSourceOGM(char *fn, OGMReadHandler *handler, int num_stream, bool is_inputfile=false);
	virtual BOOL init();
	virtual bool isEOS(void);
};

////////////////////////////////////////////////////////////////
/*
 * For Layer I files use this formula: 
 *
 *   FrameLengthInBytes = (12 * BitRate / SampleRate + Padding) * 4
 *
 * For Layer II & III files use this formula: 
 *
 *   FrameLengthInBytes = 144 * BitRate / SampleRate + Padding
 *
 * For Layer I :
 *   max BitRate is 448000 for MPEG V1, and 256000 for MPEG V2/2.5
 *   min SampleRate is 32000 for MPEG V1, and 8000 for MPEG V2/2.5
 *   so max size is 676 for MPEG V1, and 1540 for MPEG V2/2.5
 * For Layer II/III, it's :
 *   384000 and 256000
 *   still 32000 and 8000
 *   so max sizes are 1729 and 4609
 *
 * Layer I : 1 frame = 384 samples
 * Layer II/III : 1 frame = 1152 samples
 */


#define MP3_M1_MAXFRAMESIZE     1540
#define MP3_M2_MAXFRAMESIZE     4609
#define MP3_MAXFRAMESIZE        4609
#define MP3_SYNCBLOCK_LEN       4
#define MP3_SYNCWORD            0xFFE0
#define MP3_L1_SAMPLESPERFRAME  384
#define MP3_L23_SAMPLESPERFRAME 1152

// The MPEG versions
enum MpegVersion {MPEG_V1, MPEG_V2, MPEG_V25, MPEG_RESERVED};
// The layer versions
enum LayerVersion {LAYER_1, LAYER_2, LAYER_3, LAYER_RESERVED};
// The bitrates for MPeg Version 1
static s32 mp3_bitrate_V1[3][16] = {
{0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1},
{0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1},
{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1} };
// The bitrates for MPeg version 2 & 2.5
static s32 mp3_bitrate_V2[3][16] = {
{0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1},
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1} };
// The sample rates
static s32 mp3_sample_rate[4][3] = {
{44100, 22050, 11025},
{48000, 24000, 12000},
{32000, 16000, 8000},
{-1, -1, -1} };

// Number of channels
static s16 mp3_channels[4] = { 2, 2, 2, 1};


class OGMAudioSourceMP3 : public OGMAudioSource {
public:
	OGMAudioSourceMP3(char *fn, LONG inputBufferSize);
	BOOL init(void);
};

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

/*
 * According to the specs (see below), an AC3 frame is composed of 5 main parts :
 *  - si (synchonisation information header) (5 bytes)
 *  - bsi (bit stream information header)
 *  - 6 coded audio blocks
 *  - aux (ausiliary data block) (optional)
 *  - CRC (error check field)
 *
 * The si block begins with a synchonisation word (0x0B77), contains a crc
 * field, and two fields used to determine the sample rate, the bitrate and the
 * size (in words) of the frame (including the si block).
 * The biggest frame size is 1920 words (see table below) = 3840 bytes.
 *
 * Each coded audio block represents 256 new audio samples
 * , i.e. there is 256*6=1536 samples in a frame.
 *
 * One frame = 1/30th of a second (32ms in fact), so there is 30*1536=46080 samples
 * per second. So for nChannels, the samplerate is 46080/nChannels.
 *
 * The bsi block can contain timecode that can have a reolution of 1/64th of a frame.
 *
 */
#define AC3_MAXFRAMESIZE     3840
#define AC3_SYNCBLOCK_LEN    5
#define AC3_SYNCBLOCK2_LEN   7
#define AC3_SYNCWORD         0x0B77
#define AC3_SYNCWORD_BITS    0xFFFF
#define AC3_SAMPLESPERFRAME  1536
// Thos ones are not necessary, I tried to use them for fillinf the header
// but that don't work pretty weel (see before)
//#define AC3_FRAMESPERSECOND  30
//#define AC3_SAMPLESPERSECOND 46080
//#define AC3_MIN_DUR          (1./(AC3_FRAMESPERSECOND*64))

/*
 * Some of the AC3 specifications
 * Found on http://www.atsc.org, standards section, document A/52
 * Digital Audio Compression (AC-3) Standard
 */
// Sample rates used
static s32 ac3_sample_rate[4] = { 48000, 44100, 32000, -1 };
// Bitrates used
static s32 ac3_bitrate[38] = { 32, 32, 40, 40, 48, 48, 56, 56, 64, 64
										, 80, 80, 96, 96, 112, 112, 128, 128
										, 160, 160, 192, 192, 224, 224, 256, 256
										, 320, 320, 384, 384, 448, 448, 512, 512
										, 576, 576, 640, 640 };
// Size of a "frame" in words (2 bytes)
static s32 ac3_framesize[38][3] = {
			{ 64 , 69 , 96 }
		, { 64 , 70 , 96 }
		, { 80 , 87 , 120 }
		, { 80 , 88 , 120 }
		, { 96 , 104 , 144 }
		, { 96 , 105 , 144 }
		, { 112 , 121 , 168 }
		, { 112 , 122 , 168 }
		, { 128 , 139 , 192 }
		, { 128 , 140 , 192 }
		, { 160 , 174 , 240 }
		, { 160 , 175 , 240 }
		, { 192 , 208 , 288 }
		, { 192 , 209 , 288 }
		, { 224 , 243 , 336 }
		, { 224 , 244 , 336 }
		, { 256 , 278 , 384 }
		, { 256 , 279 , 384 }
		, { 320 , 348 , 480 }
		, { 320 , 349 , 480 }
		, { 384 , 417 , 576 }
		, { 384 , 418 , 576 }
		, { 448 , 487 , 672 }
		, { 448 , 488 , 672 }
		, { 512 , 557 , 768 }
		, { 512 , 558 , 768 }
		, { 640 , 696 , 960 }
		, { 640 , 697 , 960 }
		, { 768 , 835 , 1152 }
		, { 768 , 836 , 1152 }
		, { 896 , 975 , 1344 }
		, { 896 , 976 , 1344 }
		, { 1024 , 1114 , 1536 }
		, { 1024 , 1115 , 1536 }
		, { 1152 , 1253 , 1728 }
		, { 1152 , 1254 , 1728 }
		, { 1280 , 1393 , 1920 }
		, { 1280 , 1394 , 1920 } };
// Number of channels
static s16 ac3_channels[8] = { 2, 1, 2, 3, 3, 4, 4, 5};

class OGMAudioSourceAC3 : public OGMAudioSource {
public:
	OGMAudioSourceAC3(char *fn, LONG inputBufferSize);
	BOOL init(void);
};

#endif /* __OGMAUDIOSOURCE_H__ */