#include "stdafx.h"
#include "cmd.h"
#include "h264.h"
#include "aac.h"

#include "libTsMux.h"


void CreatUDP();
void CloseUDP();
void senddo(char* dat,int ln);

extern"C"
{
	void ParseIP(int argc, char** argv,char* ip);
}

//////////////////////////////////////////////////////////////////////////
struct MuxFile2Ts_t
{
	Buffer		read_buff;

	// h264
	HANDLE		h_video_file;
	Buffer		h264_buff;
	VBuffer		h264_nal_buff_list;
	h264_split_sys_t h264_sys;

	// aac
	HANDLE		h_audio_file;
	Buffer		aac_buff;
	VBuffer		aac_buff_list;
	aac_split_sys_t aac_split_sys;

	// ts stream
	HANDLE		h_ts_file;
	HANDLE		h_video_stream;
	HANDLE		h_audio_stream;
	VBuffer		ts_buff_list;
	Buffer		ts_write_buff;
	libTsMux	ts_mux_sys;

	// frame sync and pts
	Buffer		h264_frame_buff;
	int64_t		h264_group_offset;
	int64_t		h264_frame_count;
	int		h264_found_frame_start;
	int64_t		h264_pts;
	int64_t		h264_dts;
	int			h264_flags;

	int64_t		aac_frame_count;
	int64_t		aac_pts;

	MuxFile2Ts_t()
	{
		h_video_file = NULL;
		h_audio_file  = NULL;
		h_ts_file = NULL;
		h_video_stream = NULL;
		h_audio_stream = NULL;

		h264_group_offset = 0;
		h264_frame_count = 0;
		h264_found_frame_start = FALSE;
		h264_pts = 0;
		h264_dts = 0;
		h264_flags = 0;

		aac_frame_count = 0;
		aac_pts = 0;
	}

	~MuxFile2Ts_t()
	{
		if (h_video_file)
			CloseHandle(h_video_file);
		if (h_audio_file)
			CloseHandle(h_audio_file);
		if (h_ts_file)
			CloseHandle(h_ts_file);
		if (h_video_stream)
			ts_mux_sys.DelStream(h_video_stream);
		if (h_audio_stream)
			ts_mux_sys.DelStream(h_audio_stream);
		ts_mux_sys.Close();
	}
};

extern"C"
{
	void initts();
	int tsmux(); 
}

MuxFile2Ts_t* p_sys = new MuxFile2Ts_t();

static int FILE_READ_SIZE = 1024*1024*2;	//最大读取数据长度
static int TS_FILE_WRITE_SIZE = 188; //发送缓冲区大小

//////////////////////////////////////////////////////////////////////////
static BOOL TsMux(libTsMux* p_ts_mux, HANDLE hStream, PBYTE p_es_data, DWORD i_es_data_size, INT64 i_length, INT64 i_pts, INT64 i_dts, UINT32 i_flags)
{
	return p_ts_mux->Mux(hStream, 
		p_es_data, 
		i_es_data_size, 
		i_length, 
		i_pts, 
		i_dts, 
		i_flags);
}

//////////////////////////////////////////////////////////////////////////
static BOOL File2Buff(HANDLE h_file, Buffer* p_read, Buffer* p_data)
{
	BOOL b_read = FALSE;
	unsigned int i;

	if (p_data->m_nDataSize >= FILE_READ_SIZE)
		return TRUE;

	if (!p_read->m_nBufferSize)
		p_read->AllocateBuffer(FILE_READ_SIZE);

	if (p_data->m_nDataSize < FILE_READ_SIZE)
	{
		p_read->ClearData();
		if (ReadFile(h_file, p_read->m_pBuffer, p_read->m_nBufferSize, (DWORD*)&p_read->m_nDataSize, NULL) && 
			p_read->m_nDataSize)	//真正实现264数据赋值给p->read
		{
			p_data->AppendData(p_read->m_pData, p_read->m_nDataSize);
			b_read = TRUE;
		}
	}

	return b_read;
}	

static BOOL H264Frame2TsMux(MuxFile2Ts_t* p_sys)
{
	h264_split_sys_t* p_h264_sys = &p_sys->h264_sys;
	BOOL bSet = FALSE;

	// 循环复用视频数据，直到视频数据跟音频数据同步
	while(TRUE)
	{
		if (!p_sys->h_video_stream)
			break;

		// 将nal数据取出存入帧缓存
		Buffer* p_h264_nal = p_sys->h264_nal_buff_list.GetFullBuffer();
		if (p_h264_nal == NULL)	// 需要读取数据
			break;
		p_sys->h264_frame_buff.AppendData(p_h264_nal->m_pData, p_h264_nal->m_nDataSize);

		// 解析视频帧信息
		BOOL b_new_frame = h264_parse_frame_info(&p_sys->h264_sys, 
			p_h264_nal->m_pData, 
			p_h264_nal->m_nDataSize, 
			&p_sys->h264_found_frame_start,
			&p_sys->h264_frame_count,
			&p_sys->h264_group_offset,
			&p_sys->h264_pts,
			&p_sys->h264_dts,
			&p_sys->h264_flags);
		p_sys->h264_nal_buff_list.AddEmptyBuffer(p_h264_nal);

		// 将帧缓存中的1帧视频数据递交给tsmux
		if (p_sys->h_video_stream && b_new_frame)
		{
			p_sys->ts_mux_sys.Mux(p_sys->h_video_stream, 
				p_sys->h264_frame_buff.m_pData,
				p_sys->h264_frame_buff.m_nDataSize, 
				INT64_C(1000000) * ((p_h264_sys->sps.offset_for_top_to_bottom_field == 0)?2:1) * p_h264_sys->sps.num_units_in_tick / p_h264_sys->sps.time_scale, 
				p_sys->h264_pts*1000, 
				p_sys->h264_dts*1000, 
				p_sys->h264_flags);

			p_sys->h264_frame_buff.ClearData();
		}
	}

	return bSet;
}

void ParseIP(int argc, char** argv,char* ip)
{
	int i;
	string temp[15];
	for (int i = 0; i < argc; i++)
	{
		string_t arg = *(argv + i);

		if ( arg.compare(_T("-ip")) == 0 && ( ( i + 1) < argc) )
		{
			*temp = *(argv + i + 1);	
		}
	}
	for(i=0;i<temp->length();i++)
	{
		*(ip+i) = *(temp->c_str()+i);
	}
}

//////////////////////////////////////////////////////////////////////////
static void WriteTs2File(PVOID pUserData, PBYTE pTsData, DWORD nTsDataSize)
{
	MuxFile2Ts_t* p_sys = (MuxFile2Ts_t*)pUserData;

	// 先将数据保存在缓冲链表中
	Buffer *p_ts_buff;
	p_ts_buff = p_sys->ts_buff_list.GetEmptyBuffer();
	if (!p_ts_buff)
		p_ts_buff = new Buffer();
	p_ts_buff->FillData(pTsData, nTsDataSize);
	p_sys->ts_buff_list.AddFullBuffer(p_ts_buff);

	// 等到缓冲链表中有足够数据时，全部取出来一次写入文件
	if (p_sys->ts_buff_list.GetDataSize() >= TS_FILE_WRITE_SIZE)
	{
		if (p_sys->ts_buff_list.GetData(p_sys->ts_write_buff.m_pBuffer, p_sys->ts_write_buff.m_nBufferSize))
		{
			DWORD dwResult;

			senddo((char*)p_sys->ts_write_buff.m_pBuffer,p_sys->ts_write_buff.m_nBufferSize);
		}
	}
}

static BOOL InitMuxFile2Ts(MuxFile2Ts_t* p_sys, LPCTSTR lpTsFileName, LPCTSTR lpVideoFileName, LPCTSTR lpAudioFileName)
{
	if (!lpTsFileName)
		return FALSE;

	// 打开视频文件
	if (lpVideoFileName && lpVideoFileName[0] != _T('\0'))
	{
		if (p_sys->h_video_file)
			CloseHandle(p_sys->h_video_file);//关掉已经打开的h264文件

		p_sys->h_video_file = CreateFile(lpVideoFileName, 
			GENERIC_READ, 
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,
			NULL);	//现在p_sys->h_video_file存的是h264文件的句柄

		if (p_sys->h_video_file == INVALID_HANDLE_VALUE) 
		{ 
			int iError = GetLastError();
			printf("Could not open video file (error %d)\n", iError);
			return FALSE;
		}
	}

	return TRUE;
}

static void MuxFile2Ts(MuxFile2Ts_t* p_sys)
{
	BOOL bVideoRead = TRUE;
	BOOL bAudioRead = TRUE;

	while ( !H264Frame2TsMux(p_sys) )
	{
		// 读取H264文件数据
		if ( !p_sys->h264_nal_buff_list.GetFullBufferCount() )
		{
			bVideoRead = File2Buff(p_sys->h_video_file, &p_sys->read_buff, &p_sys->h264_buff);	//这一句就是将264文件读入buff的语句,进入里面改成直接从H264码流获取数据
			if ( !bVideoRead )
				break;

			// 解析AnnexB数据,将数据分割保存到缓存链表中
			h264_parse_nal(&p_sys->h264_sys, &p_sys->h264_buff, &p_sys->h264_nal_buff_list);

			// 找到sps和pps，添加H264视频流
			if ( !p_sys->h_video_stream && p_sys->h264_sys.has_sps && p_sys->h264_sys.has_pps )
			{
				es_format_t	es_format;
				es_format_Init(&es_format, VIDEO_ES, FOURCC( 'h', '2', '6', '4' ));
				es_format.p_extra = p_sys->h264_sys.h264_extra.m_pData;
				es_format.i_extra = p_sys->h264_sys.h264_extra.m_nDataSize;

				p_sys->h_video_stream = p_sys->ts_mux_sys.AddStream(&es_format); 
				assert(p_sys->h_video_stream);
			}
		}
	}


	// 将TS缓存链表中未保存的残余数据写入TS文件
	while(TRUE)
	{
		INT32 nDataSize;
		nDataSize = p_sys->ts_buff_list.GetDataSize();
		if (nDataSize == 0)
			break;

		if (nDataSize > p_sys->ts_write_buff.m_nBufferSize)
			nDataSize = p_sys->ts_write_buff.m_nBufferSize;

		if (p_sys->ts_buff_list.GetData(p_sys->ts_write_buff.m_pBuffer, nDataSize))
		{
			DWORD dwResult;
		/*	dwResult = WriteFile (p_sys->h_ts_file, 
				p_sys->ts_write_buff.m_pBuffer, 
				nDataSize, 
				&dwResult, 
				NULL);*/
			senddo((char*)p_sys->ts_write_buff.m_pBuffer,nDataSize);
		//	printf("Wrote to file %d bytesgg.\n", nDataSize);
		}
	}
}

void initts()
{
	CreatUDP();
	assert(p_sys);

	// 创建TS复用器
	libTsMuxParam_t param_ts_mux;

	param_ts_mux.m_pGetTsDataCB = WriteTs2File;
	param_ts_mux.m_pUserData = p_sys;

	
	if ( !p_sys->ts_mux_sys.Open(param_ts_mux) )
	{
		printf("Could not open libTsMux.\n");
	}
	

	// 初始化缓存
	if ( !p_sys->read_buff.AllocateBuffer(FILE_READ_SIZE) )
		return;

	if ( !p_sys->h264_buff.AllocateBuffer(FILE_READ_SIZE*2) )
		return;

	if ( !p_sys->aac_buff.AllocateBuffer(FILE_READ_SIZE*2) )
		return;

	if ( !p_sys->ts_write_buff.AllocateBuffer(TS_FILE_WRITE_SIZE) )
		return;
}

int tsmux()
{
	do 
	{
		if ( !InitMuxFile2Ts(p_sys,"D:\\desktop.ts", "D:\\temp.h264", NULL) )
		{
			printf("Init failed.\n");
			break;
		}

		MuxFile2Ts(p_sys);

	} while (FALSE);
	CloseHandle(p_sys->h_video_file);
	CloseHandle(p_sys->h_ts_file);

//	delete p_sys;
//	p_sys = NULL;

	return 0;
}