#pragma once


#ifdef ARCH_X32
#define PT_TO_64BIT( p )	( (DWORD64)0x00000000ffffffff & (DWORD64)(p) )
#else
#define PT_TO_64BIT( p )	( (DWORD64)(p) )
#endif

#ifndef _VIDEO_FORMAT_DEFINE_
#define _VIDEO_FORMAT_DEFINE_
typedef enum
{
	VIDEO_FORMAT_UNKNOWN			= 0x00,
	VIDEO_FORMAT_YUV444				= 0x01,
	VIDEO_FORMAT_YUV444P			= 0x02,
	VIDEO_FORMAT_YUV422				= 0x03,
	VIDEO_FORMAT_YUV422P			= 0x04,
	VIDEO_FORMAT_YUV420				= 0x05,
	VIDEO_FORMAT_YUV420P			= 0x06,

	VIDEO_FORMAT_RGB8				= 0x11,
	VIDEO_FORMAT_RGB16				= 0x12,
	VIDEO_FORMAT_RGB24				= 0x13,
	VIDEO_FORMAT_RGB32				= 0x14,

	VIDEO_FORMAT_GENERIC_JPEG		= 0x41,		// Generic JPEG
	VIDEO_FORMAT_GENERIC_MPEG4		= 0x42,		// Generic MPEG4
	VIDEO_FORMAT_GENERIC_H264		= 0x43,		// Generic H.264
	VIDEO_FORMAT_GENERIC_H265		= 0x44,		// Generic H.265
}VIDEO_FORMAT;
#endif

typedef enum
{
	AUDIO_FORMAT_UNKNOWN			= 0x00,
	AUDIO_FORMAT_PCM				= 0x01,
	AUDIO_FORMAT_ACM				= 0x02,
	AUDIO_FORMAT_GENERIC_G711A		= 0x21,
	AUDIO_FORMAT_GENERIC_G711U		= 0x22,
	AUDIO_FORMAT_GENERIC_G726		= 0x23,
}AUDIO_FORMAT;

typedef enum
{
	VDL_MODEL_UNKNOWN				= 0,
	VDL_MODEL_RTP_GENERIC			= 21000,
}VDL_MODEL;

typedef enum
{
	VDL_DATA_UNKNOWN				= 0,
	VDL_DATA_VIDEO,
	VDL_DATA_AUDIO,
	VDL_DATA_CONNECTING,
	VDL_DATA_META,
}VDL_DATA;

typedef enum
{
	VDL_DATA_EX_UNKNOWN				= 0,
	VDL_DATA_EX_H264_HEADER,
}VDL_DATA_EX;

typedef enum
{
	VDL_PROTOCOL_UNKNOWN			= 0,
	VDL_PROTOCOL_UDP,
	VDL_PROTOCOL_TCP,
	VDL_PROTOCOL_HTTP,
	VDL_PROTOCOL_MULTICAST,
}VDL_PROTOCOL;

#define	VDL_NAME_LEN				512
#define	VDL_TITLE_LEN				512
#define	VDL_ADDR_LEN				128
#define	VDL_AUTH_LEN				64
#define	VDL_MAX_STREAMS				5
#define	VDL_STREAM_LEN				128

typedef struct
{
	char							name[VDL_NAME_LEN];
	char							title[VDL_TITLE_LEN];
	VDL_MODEL						model;
}VDL_DEV_ID;

typedef enum
{
	VDL_CAMSDK_UNKNOWN = 0,
	VDL_CAMSDK_HIKVISION = 1
}VDL_CAMSDK_TYPE;

typedef enum
{
	VDL_CAMSDK_AUDIO_INOUT_INDEPENDENTLY = 0,
	VDL_CAMSDK_AUDIO_INOUT_TOGETHER = 1
}VDL_CAMSDK_AUDIO_TYPE;

typedef enum
{
	VDL_DEV_LINK_UNKNOWN = 0,
	VDL_DEV_LINK_AUDIO_IN,
	VDL_DEV_LINK_AUDIO_OUT

} VDL_DEV_LINK_TYPE;

typedef struct
{
	BOOL							use;

	VDL_CAMSDK_TYPE					type;
	VDL_CAMSDK_AUDIO_TYPE			audio_type;
	BOOL							in;
	BOOL							out;

	char							addr[VDL_ADDR_LEN];
	WORD							port;
	char							id[VDL_AUTH_LEN];
	char							pw[VDL_AUTH_LEN];
}VDL_CAMSDK_AUDIO_INFO;

typedef struct
{
	char							addr[VDL_ADDR_LEN];
	WORD							port;
	char							id[VDL_AUTH_LEN];
	char							pw[VDL_AUTH_LEN];
	int								streams;
	char							url[VDL_MAX_STREAMS][VDL_STREAM_LEN];	// name
	int								url_hres_disp;
	int								url_lres_disp;
	int								url_record;

	char							model_name[VDL_TITLE_LEN];
	char							token[VDL_MAX_STREAMS][VDL_NAME_LEN];	// token (uuid)
	VDL_PROTOCOL					protocol[VDL_MAX_STREAMS];
	char							motion_topic[VDL_ADDR_LEN];
	char							alarm_topic[VDL_ADDR_LEN];
	int								stream_protocol;	// 0 : TCP, 1: HTTP, 2: HTTPS

	VDL_CAMSDK_AUDIO_INFO			camsdk_audio_info;
}VDL_IP_INFO;

typedef struct
{
	VDL_DEV_ID						id;
	union
	{
		VDL_IP_INFO					ip;
	};
}VDL_DEV_INFO;



#define	VDL_FRAME_UNKNOWN			0
#define	VDL_FRAME_I					1
#define VDL_FRAME_P					2
#define VDL_FRAME_B					3

typedef struct
{
	WORD							sps_pos;
	WORD							sps_size;
	WORD							pps_pos;
	WORD							pps_size;
	WORD							data_pos;
	DWORD							data_size;
}VDL_H264_HEADER;

typedef struct
{
	WORD							vps_pos;
	WORD							vps_size;
	WORD							sps_pos;
	WORD							sps_size;
	WORD							pps_pos;
	WORD							pps_size;
	WORD							data_pos;
	DWORD							data_size;
}VDL_H265_HEADER;

typedef struct
{
	WORD							mhvo_pos;						
	WORD							mhvo_size;
	WORD							vol_pos;
	WORD							vol_size;
	WORD							data_pos;
	DWORD							data_size;
}VDL_MPEG4_HEADER;

typedef struct
{
	WORD							lum_pos;
	WORD							chm_pos;
	WORD							com_pos;
	WORD							data_pos;
	DWORD							dri_val;
}VDL_JPEG_HEADER;

// type field of VDL_STREAM_EX
#define VDL_STREAM_EX_TYPE_REC_ONFOFF	0x00000001
#define VDL_STREAM_EX_TYPE_TEXT			0x00000011

typedef struct
{
	int								type;
	int								size;
	DWORD64							data;
}VDL_STREAM_EX;

// type field of VDL_STREAM user_data
#define VDL_VIDEO_USERTYPE_TIMING_INFO	0x00000001

typedef struct 
{
	DWORD	max_iframe_interval;
	int		max_fps;
	int		avg_fps;
} VIDEO_TIMING_INFO;

typedef struct
{
	VIDEO_FORMAT					format;
	DWORD64							stream;
	int								stream_length;
	BYTE							frame;
	BYTE							decoding_only;
	BYTE							fps;
	BYTE							reserved;
	BYTE							seq_no;
	WORD							width;
	WORD							height;
	BOOL							*p_ext_lock;
	union
	{
		VDL_H264_HEADER				h264;
		VDL_H265_HEADER				h265;
		VDL_MPEG4_HEADER			mpeg4;
		VDL_JPEG_HEADER				jpeg;
	}HEADER;
	int								user_type;
	int								user_size;
	DWORD64							user_data;
	VDL_STREAM_EX					ex;
}VDL_STREAM_VIDEO;

typedef struct
{
	AUDIO_FORMAT					format;
	DWORD64							stream;
	int								stream_length;
	int								bitrate;
	int								sampling_rate;
	int								channels;
	int								bits_per_sample;
	VDL_STREAM_EX					ex;
}VDL_STREAM_AUDIO;

typedef struct
{
	BOOL							triggered;
	DWORD							index1;
	DWORD							index2;
	VDL_STREAM_EX					ex;
}VDL_STREAM_EVENT;

typedef struct
{
	enum { RS485, RS232 }			serial_port;
	int								data_length;
	BYTE							serial_data[64];
	VDL_STREAM_EX					ex;
}VDL_STREAM_SERIAL;

typedef struct
{
	DWORD64							stream;
	int								stream_length;
	VDL_STREAM_EX					ex;
}VDL_STREAM_META;

typedef struct
{
	VDL_DATA						data_type;
	int								disp_tab;
	int								disp_ch;
	int								stream_ch;
	SYSTEMTIME						time;
	DWORD							t;
	WORD							ms;
	BYTE							pb_id;
	BYTE							last;
	char							name[VDL_NAME_LEN];
	char							title[VDL_TITLE_LEN];
	union
	{
		VDL_STREAM_VIDEO			video;
		VDL_STREAM_AUDIO			audio;
		VDL_STREAM_EVENT			evt;
		VDL_STREAM_SERIAL			serial;
		VDL_STREAM_META				meta;
	}DATA;
}VDL_STREAM;

static VDL_STREAM *CopyVDLStream( VDL_STREAM *stream )
{
	VDL_STREAM *copy = new VDL_STREAM( );
	memcpy( copy, stream, sizeof(VDL_STREAM) );
	BYTE *data = NULL;
	switch( stream->data_type )
	{
	case VDL_DATA_VIDEO:
		data = new BYTE[ copy->DATA.video.stream_length ];
		memcpy( data, (void*)stream->DATA.video.stream, copy->DATA.video.stream_length );
		copy->DATA.video.stream = PT_TO_64BIT( data );

		if( copy->DATA.video.user_size > 0 )
		{
			data = new BYTE[ copy->DATA.video.user_size ];
			memcpy( data, (void*)stream->DATA.video.user_data, copy->DATA.video.user_size );
			copy->DATA.video.user_data = PT_TO_64BIT( data );
		}

		if( copy->DATA.video.ex.size > 0 )
		{
			data = new BYTE[ copy->DATA.video.ex.size ];
			memcpy( data, (void*)stream->DATA.video.ex.data, copy->DATA.video.ex.size );
			copy->DATA.video.ex.data = PT_TO_64BIT( data );
		}
		break;
	case VDL_DATA_AUDIO:
		data = new BYTE[ copy->DATA.audio.stream_length ];
		memcpy( data, (void*)stream->DATA.audio.stream, copy->DATA.audio.stream_length );
		copy->DATA.audio.stream = PT_TO_64BIT( data );

		if( copy->DATA.audio.ex.size > 0 )
		{
			data = new BYTE[ copy->DATA.audio.ex.size ];
			memcpy( data, (void*)stream->DATA.audio.ex.data, copy->DATA.audio.ex.size );
			copy->DATA.audio.ex.data = PT_TO_64BIT( data );
		}
		break;
	case VDL_DATA_CONNECTING:
		if( copy->DATA.evt.ex.size > 0 )
		{
			data = new BYTE[ copy->DATA.evt.ex.size ];
			memcpy( data, (void*)stream->DATA.evt.ex.data, copy->DATA.evt.ex.size );
			copy->DATA.evt.ex.data = PT_TO_64BIT( data );
		}
		break;
	case VDL_DATA_META:
		if (copy->DATA.meta.stream_length > 0)
		{
			data = new BYTE[copy->DATA.meta.stream_length];
			memcpy( data, (void*)copy->DATA.meta.stream, copy->DATA.meta.stream_length );
			copy->DATA.meta.stream = PT_TO_64BIT( data );
		}
		break;
	default:
		return copy;
	}
	return copy;
}

static void DeleteVDLStream( VDL_STREAM *stream )
{
	switch( stream->data_type )
	{
	case VDL_DATA_VIDEO:
		delete [] ( BYTE* )stream->DATA.video.stream;
		delete [] ( BYTE* )stream->DATA.video.user_data;
		delete [] ( BYTE* )stream->DATA.video.ex.data;
		break;
	case VDL_DATA_AUDIO:
		delete [] ( BYTE* )stream->DATA.audio.stream;
		delete [] ( BYTE* )stream->DATA.audio.ex.data;
		break;
	case VDL_DATA_CONNECTING:
		delete [] ( BYTE* )stream->DATA.evt.ex.data;
		break;
	case VDL_DATA_META:
		delete [] ( BYTE* )stream->DATA.meta.stream;
		break;
	default:
		break;
	}
	delete stream;
}

static BOOL IsGPUBuffer( VDL_STREAM *stream )
{
	return FALSE;
}

typedef BOOL ( __stdcall *VDL_ON_CAPTURE )	( VDL_STREAM *stream, void *param );



typedef struct
{
	WORD							videos;
	WORD							audios;
	WORD							sensors;
	WORD							relays;
	DWORD							id_len : 6;
	DWORD							pw_len : 6;
	DWORD							r_cfg : 1;
	DWORD							reserved1 : 19;
	char							def_id[VDL_AUTH_LEN];
	char							def_pw[VDL_AUTH_LEN];
	WORD							def_port;
	WORD							reserved2;
}VDL_PARAM_CAP;
