www.pudn.com > mysee.zip > CaptureServer.cpp


/* 
*  Openmysee 
* 
*  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; if not, write to the Free Software 
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
* 
*/ 
#include "stdafx.h" 
#include "CaptureServer.h" 
 
// { Implementation of CaptureServer 
CaptureServer::CaptureServer() 
: parentWindow(0), videoData(0), audioData(0), passwordStatus(2), 
  m_llVideoTime(0), m_llAudioTime(0), m_bTransDataEnd(FALSE),m_bIsOnlyOnePin(FALSE) 
{ 
	memset(&videoStruct, 0, sizeof(videoStruct)); 
	memset(&audioStruct, 0, sizeof(audioStruct)); 
	cfgData.reconnectSecond = 120; 
} 
 
CaptureServer::~CaptureServer() 
{ 
	for(UINT i = 0; i < bufferList.size();++i) 
	{ 
		delete clientList[i]; 
		delete bufferList[i]; 
		delete logList[i]; 
	} 
 
	bufferList.clear(); 
	clientList.clear(); 
	logList.clear(); 
 
	TE_CleanupLibrary(); 
	SAFE_ARRAYDELETE(audioData); 
	SAFE_ARRAYDELETE(videoData); 
 
	::DeleteCriticalSection(&m_SamQueueCSec); 
} 
 
BOOL CaptureServer::Init() 
{ 
	TE_InitLibrary();  
 
	if(!LoadConfigFile()) 
		return FALSE; 
 
	logList.resize(cfgData.spAddress.size()); 
	bufferList.resize(cfgData.spAddress.size()); 
	clientList.resize(cfgData.spAddress.size()); 
 
	NormalAddress addr; 
	addr.sin_family = AF_INET; 
	addr.sin_port = htons(SP4CS_PORT); 
	int i = 0; 
	for(list::iterator it = cfgData.spAddress.begin(); it != cfgData.spAddress.end(); ++it) 
	{ 
		addr.sin_addr.s_addr = inet_addr(it->data()); 
		logList[i] = new LogMgr(); 
		logList[i]->Init(); 
		logList[i]->PrintTime(TRUE); 
 
		bufferList[i] = new BufferMgr(this); 
		if(!bufferList[i]) 
			return FALSE; 
 
		clientList[i] = new SPClient(this, addr, bufferList[i], logList[i]); 
		if(!clientList[i]) 
			return FALSE; 
		i++; 
		Sleep(100); // 防止按照时间取得文件名相同 
	} 
 
	totalBytes = 0; 
	GetSystemTime(&startTime); 
 
	::InitializeCriticalSection(&m_SamQueueCSec); 
 
	//cfgData.savePath = "f:\\"; 
 
	return TRUE; 
} 
 
void CaptureServer::Stop() 
{ 
	/*此处之所以直接PutSample而不做任何限制是因为 
	  CaptureServer的PutSample可以保证当音视频流 
	  全部结束时一定能够把队列取空。如果是中途 
	  应用层强制停止,有可能会造成某路队列数据 
	  非空,但这是没法避免的,此时此处处理或者 
	  是把数据丢掉只保留前面的同步后数据,或者 
	  把剩余队列中不同步数据也写入,此处采用后者。 
	  在依靠底层返回EC_COMPLETE来触发Stop是不会 
	  出现此现象的。 
	*/ 
	 
	::EnterCriticalSection(&m_SamQueueCSec); 
	int ii = m_AudioSamQueue.size(); 
	int iii = m_VideoSamQueue.size(); 
 
	SAMPLEDATA *pSAMPLEDATA = NULL; 
	while(m_AudioSamQueue.size() > 0 && m_VideoSamQueue.size() > 0) 
	{		 
		if (m_AudioSamQueue.front()->samplehr.start >= m_VideoSamQueue.front()->samplehr.start) 
		{ 
			pSAMPLEDATA = m_VideoSamQueue.front(); 
			m_zzlWriter.PutSample(pSAMPLEDATA->samplehr, pSAMPLEDATA->pData); 
			m_VideoSamQueue.pop(); 
			delete pSAMPLEDATA->pData; 
			pSAMPLEDATA->pData = NULL; 
			delete pSAMPLEDATA; 
			pSAMPLEDATA = NULL; 
		} 
		else 
		{ 
			pSAMPLEDATA = m_AudioSamQueue.front(); 
			m_zzlWriter.PutSample(pSAMPLEDATA->samplehr, pSAMPLEDATA->pData); 
			m_AudioSamQueue.pop(); 
			delete pSAMPLEDATA->pData; 
			pSAMPLEDATA->pData = NULL; 
			delete pSAMPLEDATA; 
			pSAMPLEDATA = NULL; 
		}	 
	} 
	 
	int iiii = m_VideoSamQueue.size(); 
	int iiiii = m_AudioSamQueue.size(); 
 
	while(m_AudioSamQueue.size() > 0) 
	{ 
		SAMPLEDATA *pSAMPLEDATA = m_AudioSamQueue.front(); 
		m_zzlWriter.PutSample(pSAMPLEDATA->samplehr, pSAMPLEDATA->pData); 
		m_AudioSamQueue.pop(); 
		delete pSAMPLEDATA->pData; 
		delete pSAMPLEDATA; 
	} 
	 
	while(m_VideoSamQueue.size() > 0) 
	{ 
		SAMPLEDATA *pSAMPLEDATA = m_VideoSamQueue.front(); 
		m_zzlWriter.PutSample(pSAMPLEDATA->samplehr, pSAMPLEDATA->pData); 
		m_VideoSamQueue.pop(); 
		delete pSAMPLEDATA->pData; 
		delete pSAMPLEDATA; 
	} 
	m_bTransDataEnd = TRUE; 
	TRACE5("CaptureServer::Stop处理剩余包\n"); 
 
	::LeaveCriticalSection(&m_SamQueueCSec); 
	/* 
	::EnterCriticalSection(&m_SamQueueCSec); 
	int ii = m_AudioSamQueue.size(); 
	while(m_AudioSamQueue.size() > 0) 
	{ 
		SAMPLEDATA *pSAMPLEDATA = m_AudioSamQueue.front(); 
		m_zzlWriter.PutSample(pSAMPLEDATA->samplehr, pSAMPLEDATA->pData); 
		m_AudioSamQueue.pop(); 
		delete pSAMPLEDATA->pData; 
		delete pSAMPLEDATA; 
	} 
	int iii = m_VideoSamQueue.size(); 
	while(m_VideoSamQueue.size() > 0) 
	{ 
		SAMPLEDATA *pSAMPLEDATA = m_VideoSamQueue.front(); 
		m_zzlWriter.PutSample(pSAMPLEDATA->samplehr, pSAMPLEDATA->pData); 
		m_VideoSamQueue.pop(); 
		delete pSAMPLEDATA->pData; 
		delete pSAMPLEDATA; 
	} 
	m_bTransDataEnd = TRUE; 
	::LeaveCriticalSection(&m_SamQueueCSec); 
	*/ 
} 
 
BOOL CaptureServer::LoadConfigFile() 
{ 
	char buf[MAX_PATH]; 
	GetModuleFileName(NULL, buf, MAX_PATH); 
	string path = buf; 
	int index = path.find_last_of('\\', path.length()); 
	path.resize(index+1); 
 
	ConfigFile cfgFile(path + "CaptureServer.cfg"); 
	if(cfgFile.fileNotFound) { 
		MessageBox(parentWindow, "无法找到配置文件CaptureServer.cfg。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
	string strSPList = cfgFile.Value("CaptureServer", "spAddress"); 
	if(cfgFile.stringNotFound) { 
		MessageBox(parentWindow, "配置文件中必须存在spAddress一项。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
	cfgData.chnlStr = cfgFile.Value("CaptureServer", "channelName"); 
	if(cfgFile.stringNotFound) { 
		MessageBox(parentWindow, "配置文件中必须存在channelName一项。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
	cfgData.savePath = cfgFile.Value("CaptureServer", "savepath"); 
	 
	if (false == cfgData.savePath.empty()) 
	{ 
		//补路径后的斜杠 
		string::const_iterator litSavePath = cfgData.savePath.end(); 
		--litSavePath; 
		if ('\\' != static_cast(*litSavePath)) 
		{ 
			cfgData.savePath += "\\";  
		} 
 
		//去除路径前的空格 
		while (' ' == *cfgData.savePath.c_str()) 
		{		 
			cfgData.savePath = cfgData.savePath.c_str() + 1; 
		}		 
	} 
	 
	 
	string lstrOnlyAudio = cfgFile.Value("CaptureServer", "isonlyaudio"); 
	 
	if (false == lstrOnlyAudio.empty()) 
	{ 
		//去除路径前的空格 
		while (' ' == *lstrOnlyAudio.c_str()) 
		{		 
			lstrOnlyAudio = lstrOnlyAudio.c_str() + 1; 
		}	 
 
		//lstrOnlyAudio = lstrOnlyAudio. 
		if ("true" == lstrOnlyAudio) 
		{ 
			SetAudioOrVideoOnly(TRUE);				 
		} 
		else if ("false" != lstrOnlyAudio) 
		{ 
			MessageBox(NULL,"isonlyaudio 项是非法字符","注意", MB_OK|MB_ICONSTOP); 
			return FALSE; 
		} 
	} 
 
	string reconnect = cfgFile.Value("CaptureServer", "ReconnectTime"); 
	if(!cfgFile.fileNotFound) { 
		cfgData.reconnectSecond = atoi(reconnect.data()); 
	} 
	string id = cfgFile.Value("CaptureServer","userID"); 
	if(cfgFile.fileNotFound){ 
		MessageBox(parentWindow, "配置文件中必须存在userID一项。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
	cfgData.userID = atoi(id.data()); 
 
	//读入的是32位密码 
	cfgData.password = cfgFile.Value("CaptureServer", "password"); 
	if(cfgFile.fileNotFound){ 
		MessageBox(parentWindow, "配置文件中必须存在password一项目。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
 
	string::const_iterator it = cfgData.chnlStr.begin(); 
 
	for(; it != cfgData.chnlStr.end(); it++) 
	{ 
		BYTE tmpChar = static_cast(*it); 
		if(isdigit(tmpChar) || isalpha(tmpChar)) 
			continue; 
		if(tmpChar == '[' || tmpChar == ']') 
			continue; 
		//GB18030-2000编码标准的第一个字节的编码范围在0x81 ~ 0xFE之间;第二个字节的编码范围在0x40 ~ 0x7E和0x80 ~ 0xFE之间。 
		//Big5编码标准的第一个字节的编码范围在0xA1 ~ 0xF9 之间;第二个字节的编码范围在0x40 ~ 0x7E 和0xA1 ~ 0xFE之间。 
		//两者的并集是第一个字节[0x81, 0xfe],第二个字节[0x40, 0x7e]、[0x80, 0xfe]; 
		if(tmpChar>=0x81 && tmpChar <= 0xfe && it+1 != cfgData.chnlStr.end()) { 
			tmpChar = static_cast(*(it+1)); 
			if( (tmpChar>=0x40 && tmpChar <= 0x7e) || (tmpChar>=0x80 && tmpChar <= 0xfe)) 
			{ 
				it++;	// 跳过一个汉字字符 
				continue; 
			} 
		} 
		MessageBox(parentWindow, "配置文件中channelName一项只能由字母、数字、汉字和方括弧组成。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
 
	cfgData.canLogin = TRUE; 
 
	istrstream is(strSPList.data()); 
	string line; 
	string ip; 
	string port; 
	NormalAddress tmpAddr; 
	while(getline(is,line, ':')) { 
		if(!line.length()) 
			continue; 
		tmpAddr.sin_addr.s_addr = TE_GetIP(line.data(), TRUE); 
		if(tmpAddr.sin_addr.s_addr == INADDR_NONE) 
			continue; 
		cfgData.spAddress.push_back(inet_ntoa(tmpAddr.sin_addr)); 
	} 
 
	if(cfgData.chnlStr.length() >= 64) { 
		MessageBox(parentWindow, "配置文件中channelName一项其长度必须小于64字符。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
	if(cfgData.password.length() != 32) { 
		MessageBox(parentWindow, "配置文件中Password一项其长度必须等于32字符。", "错误", MB_OK|MB_ICONERROR); 
		return FALSE; 
	} 
 
	return TRUE; 
} 
 
BOOL CaptureServer::SetFormatData(TVMEDIATYPESECTION& tv, BYTE* data, BOOL isAudio) 
{ 
	if(!data) 
		return FALSE; 
 
	// 因为SetAudioOrVideoOnly比SetFormatData先被调用,所以要在这里记录 
	bool bIsThisPinOnly = isAudio?audioStruct.bThisPinOnly:videoStruct.bThisPinOnly; 
 
	// 分别复制视频和音频数据 
	if(!isAudio) { 
		SAFE_ARRAYDELETE(videoData); 
		memcpy(&videoStruct, &tv, sizeof(TVMEDIATYPESECTION)); 
		if(videoStruct.cbFormat > 512) 
			return FALSE; 
		videoData = new BYTE[videoStruct.cbFormat]; 
		memcpy(videoData, data, videoStruct.cbFormat); 
 
		// 恢复 
		videoStruct.bThisPinOnly = bIsThisPinOnly; 
				 
	} 
	else { 
		SAFE_ARRAYDELETE(audioData); 
		memcpy(&audioStruct, &tv, sizeof(TVMEDIATYPESECTION)); 
		if(audioStruct.cbFormat > 512) 
			return FALSE; 
		audioData = new BYTE[audioStruct.cbFormat]; 
		memcpy(audioData, data, audioStruct.cbFormat); 
 
		// 恢复 
		audioStruct.bThisPinOnly = bIsThisPinOnly; 
	} 
 
	for(UINT i = 0; i < bufferList.size();++i) 
	{ 
		if(!bufferList[i]->AttachMediaDataToCurrentBlock(tv, data, isAudio, logList[i])) 
			return FALSE; 
	} 
 
	if((audioData&&videoData) || // 如果视频和音频的数据都有了 
		(audioData&&audioStruct.bThisPinOnly) || // 如果只有音频 
		(videoData&&videoStruct.bThisPinOnly)) { // 如果只有视频 
 
		// 如果需要保存zzl文件,则建立zzl文件 
		if(!cfgData.savePath.empty()) { 
			if(!m_zzlWriter.Init(cfgData.savePath, cfgData.chnlStr)) { 
				//MessageBox(parentWindow, "无法建立节目文件!", "错误", MB_OK); 
				return 0; 
			} 
			if(!m_zzlWriter.SetMediaType(audioStruct, audioData, videoStruct, videoData)) { 
				MessageBox(parentWindow, "无法建立节目文件!SetMediaType Error!", "错误", MB_OK); 
			} 
		} 
	} 
 
	return TRUE; 
} 
 
BOOL CaptureServer::GetFormatData(TVMEDIATYPESECTION& tv, PBYTE& data, BOOL isAudio) 
{ 
	if(!isAudio) 
	{ 
		if(audioStruct.bThisPinOnly) 
		{ 
			memset(&tv, 0, sizeof(tv)); 
			data = NULL; 
			return TRUE; 
		} 
 
		if(!videoData) 
			return FALSE; 
 
		memcpy(&tv, &videoStruct, sizeof(TVMEDIATYPESECTION)); 
		data = new BYTE[videoStruct.cbFormat]; 
		memcpy(data, videoData, videoStruct.cbFormat); 
	} 
	else 
	{ 
		if(videoStruct.bThisPinOnly) 
		{ 
			memset(&tv, 0, sizeof(tv)); 
			data = NULL; 
			return TRUE; 
		} 
 
		if(!audioData) 
			return FALSE; 
 
		memcpy(&tv, &audioStruct, sizeof(TVMEDIATYPESECTION)); 
		 
		data = new BYTE[audioStruct.cbFormat]; 
		memcpy(data, audioData, audioStruct.cbFormat); 
	} 
 
	return TRUE; 
} 
 
void CaptureServer::SetAudioOrVideoOnly(BOOL isAudio) 
{ 
	if(isAudio) 
	{ 
		audioStruct.bThisPinOnly = true; 
	} 
	else 
	{ 
		videoStruct.bThisPinOnly = true; 
	} 
	m_bIsOnlyOnePin = TRUE; 
	m_zzlWriter.SetIsSingleAudio(isAudio); 
} 
 
BOOL CaptureServer::PutSample(const SampleHeader& header, BYTE* pData) 
{ 
	totalBytes += header.size; 
 
	for(UINT i = 0; i < bufferList.size();++i) 
	{ 
		if(!bufferList[i]->PutSample(header, pData, logList[i])) 
			return FALSE; 
	} 
 
	if(!cfgData.savePath.empty()) 
	{ 
		::EnterCriticalSection(&m_SamQueueCSec); 
		//if(!m_bTransDataEnd) 
		{ 
			if(audioStruct.bThisPinOnly || videoStruct.bThisPinOnly) 
			{ 
				if(!m_zzlWriter.PutSample(header, pData)) 
				{ 
					ASSERT(FALSE); 
				} 
			} 
			else 
			{		 
				if(header.bAudioSample) 
				{ 
					if(m_llAudioTime >= m_llVideoTime + MAX_AVDELAY) 
					{ 
						BYTE *pSamData = new BYTE[header.size]; 
						SAMPLEDATA *pSAMPLEDATA = new SAMPLEDATA; 
						memset(pSAMPLEDATA, 0, sizeof(SAMPLEDATA)); 
						memcpy(&(pSAMPLEDATA->samplehr), &header, sizeof(SampleHeader)); 
						memcpy(pSamData, pData, header.size); 
						pSAMPLEDATA->pData = pSamData; 
						m_AudioSamQueue.push(pSAMPLEDATA); 
					} 
					else 
					{ 
						if(m_AudioSamQueue.size() > 0) 
						{ 
							BYTE *pSamData = new BYTE[header.size]; 
							SAMPLEDATA *pSAMPLEDATA = new SAMPLEDATA; 
							memset(pSAMPLEDATA, 0, sizeof(SAMPLEDATA)); 
							memcpy(&(pSAMPLEDATA->samplehr), &header, sizeof(SampleHeader)); 
							memcpy(pSamData, pData, header.size); 
							pSAMPLEDATA->pData = pSamData; 
							m_AudioSamQueue.push(pSAMPLEDATA); 
 
							SAMPLEDATA *pCurrentSampleData = m_AudioSamQueue.front(); 
							m_AudioSamQueue.pop(); 
 
							if(!m_zzlWriter.PutSample(pCurrentSampleData->samplehr, pCurrentSampleData->pData)) 
							{ 
								ASSERT(FALSE); 
							} 
 
							m_llAudioTime = pCurrentSampleData->samplehr.start; 
							delete pCurrentSampleData->pData; 
							delete pCurrentSampleData; 
						} 
						else 
						{ 
							if(!m_zzlWriter.PutSample(header, pData)) 
							{ 
								ASSERT(FALSE); 
							} 
 
							m_llAudioTime = header.start; 
						} 
					} 
 
					 
					//以音频的动力拉动视频符合误差范围的Sample 
					while(m_VideoSamQueue.size() > 0 && m_VideoSamQueue.front()->samplehr.start <= m_llAudioTime + MAX_AVDELAY) 
					{ 
						SAMPLEDATA *pCurrentSampleData = m_VideoSamQueue.front(); 
						if(!m_zzlWriter.PutSample(pCurrentSampleData->samplehr, pCurrentSampleData->pData)) 
						{ 
							ASSERT(FALSE); 
						} 
 
						m_VideoSamQueue.pop(); 
						m_llVideoTime = pCurrentSampleData->samplehr.start; 
						delete pCurrentSampleData->pData; 
						delete pCurrentSampleData; 
					} 
					 
				} 
				else 
				{ 
					if(m_llVideoTime >= m_llAudioTime + MAX_AVDELAY) 
					{ 
						BYTE *pSamData = new BYTE[header.size]; 
						SAMPLEDATA *pSAMPLEDATA = new SAMPLEDATA; 
						memset(pSAMPLEDATA, 0, sizeof(SAMPLEDATA)); 
						memcpy(&(pSAMPLEDATA->samplehr), &header, sizeof(SampleHeader)); 
						memcpy(pSamData, pData, header.size); 
						pSAMPLEDATA->pData = pSamData; 
						m_VideoSamQueue.push(pSAMPLEDATA); 
					} 
					else 
					{ 
						if(m_VideoSamQueue.size() > 0) 
						{ 
							BYTE *pSamData = new BYTE[header.size]; 
							SAMPLEDATA *pSAMPLEDATA = new SAMPLEDATA; 
							memset(pSAMPLEDATA, 0, sizeof(SAMPLEDATA)); 
							memcpy(&(pSAMPLEDATA->samplehr), &header, sizeof(SampleHeader)); 
							memcpy(pSamData, pData, header.size); 
							pSAMPLEDATA->pData = pSamData; 
							m_VideoSamQueue.push(pSAMPLEDATA); 
 
							SAMPLEDATA *pCurrentSampleData = m_VideoSamQueue.front(); 
							m_VideoSamQueue.pop(); 
 
							if(!m_zzlWriter.PutSample(pCurrentSampleData->samplehr, pCurrentSampleData->pData)) 
							{ 
								ASSERT(FALSE); 
							} 
 
							m_llVideoTime = pCurrentSampleData->samplehr.start; 
							delete pCurrentSampleData->pData; 
							delete pCurrentSampleData; 
						} 
						else 
						{ 
							if(!m_zzlWriter.PutSample(header, pData)) 
							{ 
								ASSERT(FALSE); 
							} 
 
							m_llVideoTime = header.start; 
						} 
					} 
				 
					//以视频的动力拉动音频符合误差范围的Sample 
					while(m_AudioSamQueue.size() > 0 && m_AudioSamQueue.front()->samplehr.start <= m_llVideoTime + MAX_AVDELAY) 
					{ 
						SAMPLEDATA *pCurrentSampleData = m_AudioSamQueue.front(); 
						if(!m_zzlWriter.PutSample(pCurrentSampleData->samplehr, pCurrentSampleData->pData)) 
						{ 
							ASSERT(FALSE); 
						} 
 
						m_AudioSamQueue.pop(); 
						m_llAudioTime = pCurrentSampleData->samplehr.start; 
						delete pCurrentSampleData->pData; 
						delete pCurrentSampleData; 
					} 
					 
				} 
			} 
		} 
 		::LeaveCriticalSection(&m_SamQueueCSec); 
	} 
 
	return TRUE; 
} 
 
float CaptureServer::GetSpeedInKBPS() 
{ 
	 
	if(!cfgData.savePath.empty()) 
		return (float)m_zzlWriter.GetBitRate();	// 由于压缩用的时间可能超过媒体文件的实际长度,所以此处统计的码率更加准确 
 
	SYSTEMTIME stNow; 
	GetSystemTime(&stNow); 
	LARGE_INTEGER llNow; 
	SystemTimeToFileTime(&stNow, (FILETIME*)&llNow); 
 
	LARGE_INTEGER llStart; 
	SystemTimeToFileTime(&startTime, (FILETIME*)&llStart); 
 
	if(llNow.QuadPart - llStart.QuadPart > 0) { 
		DbgLog((LOG_TRACE, 5, TEXT("Speed: %f"), totalBytes/(double)((llNow.QuadPart-llStart.QuadPart)/10000) )); 
		return static_cast(totalBytes/(double)((llNow.QuadPart-llStart.QuadPart)/10000)); 
	}	 
	else 
		return 0.0; 
} 
// Implementation of CaptureServer }