📄 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<string>::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<BYTE>(*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<BYTE>(*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<BYTE>(*(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));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -