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 }