处理搜索结果
事件EVT_STREAMSEARCHMODE_RESULT有好几处,分别为Alarm和Map项目中的ReplayDialog,CUModel中的VideoReplayModel,VideoDownloadModel和CUBase中的SearchResultWnd。而和录像回放中的录像搜索有关的是CUModel中的VideoReplayModel和CUBase中的SearchResultWnd
CUModel/VideoReplayModel
LRESULT CVideoReplayModel::OnRefreshSearchResult(IEventData *pData)
{
IMitModel* pMitModel = GetInlPtr<IMitModel*>(_T("MitModel"));
if(NULL == pMitModel)
{
return S_FALSE;
}
StreamSearchMode::StreamSearchData *data = dynamic_cast<StreamSearchMode::StreamSearchData*>(pData);
if(data && data->result.size() != 0)
{
StreamSearchMode::TVideoSearchResult *result = &(*(data->result.begin()));
if(result == NULL || (result->id != StreamSearchMode::eReplay && result->id != StreamSearchMode::eEMap && result->id != StreamSearchMode::eAlarm))
{ //result->id用于确定搜索的请求来源
return S_FALSE;
}
//判断搜索成功与否
if(result->resultFlag == StreamSearchMode::VideoSubSucceed
|| result->resultFlag == StreamSearchMode::VideoSearchSucceed)
{
CloseVideoReplayAll(); //关闭当前所有回放
m_sdpBaseTime = result->condition.begin;
//整理搜索结果
//清空已有搜索结果
for(std::list<ReplayItemData>::iterator it_del = m_ItemBuf.begin(); it_del != m_ItemBuf.end(); it_del++)
{
for(std::vector<TRecordTimeSlice>::iterator it_tmp = it_del->slices.begin();
it_tmp != it_del->slices.end(); it_tmp++)
{
it_tmp->flags.clear();
}
it_del->slices.clear();
}
m_ItemBuf.clear();
for(std::vector<VideoResult>::iterator it_del1 = m_results.begin(); it_del1 != m_results.end(); it_del1++)
{
for(std::list<TRecordTimeSlice>::iterator it_file = it_del1->slices.begin();
it_file != it_del1->slices.end(); it_file++)
{
it_file->flags.clear();
}
it_del1->slices.clear();
}
m_results.clear();
//通道插入将没有录像文件的通道放在后面
//可以将没有文件的通道不显示出来且不参与分屏,目前显示
int i = 1;
for(std::vector<StreamSearchMode::TChannelVideoRecord>::iterator it = result->records.begin(); it != result->records.end(); it++)
{
if(it->files.size() == 0)
{
continue;
}
ReplayItemData item;
item.oid = Type_cast<CString>((*it).source);
item.nSpeed = 0;
item.bEdit = false;
item.nBright = 8;
item.nContrast = 8;
item.cur_time = 0;
//保存搜索结果
VideoResult oneCh;
oneCh.source = (*it).source;
oneCh.slices.clear();
item.nIndexItem = i;
i++;
std::list<StreamSearchMode::TRecordFileEx> vTempFiles;
for(std::vector<StreamSearchMode::TRecordFileEx>::iterator iter = it->files.begin(); iter != it->files.end(); iter++)
{ //排序插入
TSDPLocalTime testBeg;
TSDPLocalTime testEnd;
sdpGetLocalTime(iter->begin, testBeg);
sdpGetLocalTime(iter->end, testEnd);
if(iter->begin == iter->end) //录像文件长度为0
{
continue;
}
if (vTempFiles.size()==0)
{
//第一个插入
vTempFiles.push_back(*iter);
continue;
}
std::list<StreamSearchMode::TRecordFileEx>::iterator it_tmp = vTempFiles.begin();
for(; it_tmp != vTempFiles.end(); it_tmp++)
{
if (it_tmp->begin > iter->begin)
{
vTempFiles.insert(it_tmp, *iter);
break;
}
}
if (it_tmp == vTempFiles.end())
{
vTempFiles.push_back(*iter);
}
}
//合并文件时间片
std::list<StreamSearchMode::TRecordFileEx>::iterator it_cur = vTempFiles.begin();
std::list<StreamSearchMode::TRecordFileEx>::iterator it_next;
while(it_cur != vTempFiles.end())
{
TRecordTimeSlice slice;
slice.begin = it_cur->begin;
slice.end = it_cur->end;
slice.flags = it_cur->flags;
it_next = it_cur;
while (1)
{
it_next++;
if(it_next == vTempFiles.end())
{
break;
}
if(it_next->begin > slice.end)
{
break;
}
else
{
for(std::vector<StreamSearchMode::TRecordFlags>::iterator it_flags=it_next->flags.begin(); it_flags!=it_next->flags.end(); ++it_flags)
{
slice.flags.push_back(*it_flags);
}
slice.end = it_next->end;
}
}
oneCh.slices.push_back(slice);
item.slices.push_back(slice);
it_cur = it_next;
}
//修正时间片的最后一个片段的结束时间
ULONG slicesLength = item.slices.size();
if(slicesLength > 0)
{
TRecordTimeSlice& tmp_slice = item.slices.at(slicesLength-1);
tmp_slice.end = tmp_slice.end > result->condition.end ? result->condition.end : tmp_slice.end;
}
if(oneCh.slices.size() > 0)
{
std::list<TRecordTimeSlice>::iterator it_oneCh = oneCh.slices.end();
it_oneCh--;
it_oneCh->end = it_oneCh->end > result->condition.end ? result->condition.end : it_oneCh->end;
}
it_cur = vTempFiles.begin();
SDPTIME temp_begin = it_cur->begin;
it_cur = vTempFiles.end();
it_cur--;
SDPTIME temp_end = it_cur->end > result->condition.end?result->condition.end:it_cur->end;
CHAR szPid[MITOIDLEN] = {0};
TMitObjIdKVPair kv;
mitGetPid(item.oid, MITOIDLEN, szPid, &kv);
IMitModel* pMitModel = GetInlPtr<IMitModel*>(_T("MitModel"));
if (NULL == pMitModel)
{
return S_FALSE;
}
EncoderInfo info;
if(!pMitModel->GetDevInfo(szPid,info))
{
return S_FALSE;
}
if (result->condition.place == ERecordPlace_centerServer)
{
item.fileRes.Format(_T("%s\\\\replay=%s\\%d\\%I64d\\%I64d"), it_cur->source.c_str(), info.sn, kv.rid, temp_begin, temp_end);
}
else
{
item.fileRes.Format(_T("%s%s"), it_cur->source.c_str(), it_cur->name.c_str());
}
item.bExistedFile = true;
item.oidSrc = Type_cast<CString>(it_cur->source);
oneCh.srcParent = it_cur->source;
item.tm_begin = item.slices.at(0).begin;
item.tm_end = item.slices.at(0).end;
if (item.tm_begin < m_sdpBaseTime)
{
item.jumpPos = (m_sdpBaseTime - item.tm_begin)/1000; // 从零点开始播放
}
item.streamId = -1;
item.status = eReplayStatusStop;
item.sliceIndex = 0;
item.bPlaying = false;
std::list<TRecordTimeSlice>::iterator tmp = oneCh.slices.begin();
while (tmp != oneCh.slices.end())
{ //搜索录像文件结果展示,升序排列
TSDPLocalTime begin,end;
sdpGetLocalTime((*tmp).begin, begin);
sdpGetLocalTime((*tmp).end, end);
CString str;
str.Format(_T("%2d-%02d-%02d %02d:%02d:%02d --> %2d-%02d-%02d %02d:%02d:%02d "),
begin.year, begin.month, begin.day, begin.hour, begin.min, begin.sec,
end.year, end.month, end.day, end.hour, end.min, end.sec);
tmp++;
}
m_ItemBuf.push_back(item);
oneCh.nIndex=0; // 有可能本通道并没有文件,但此索引不影响使用
m_results.push_back(oneCh);
}
//插入空白通道
for (std::vector<StreamSearchMode::TChannelVideoRecord>::iterator it = result->records.begin(); it!=result->records.end(); it++)
{
if (it->files.size()!=0)
continue;
ReplayItemData item;
item.oid = Type_cast<CString>((*it).source);
item.bExistedFile = false;
item.nIndexItem = i;
item.bEdit=false;
i++;
item.status = eReplayStatusStop; //重新设置标识
item.streamId = -1;
item.bSound = FALSE;
item.tm_begin=0;
item.tm_end = 0;
item.bValid = false;
item.bPlaying = false;
m_ItemBuf.push_back(item); //没有录像文件的通道尾部插入
//保存搜索结果
VideoResult oneCh;
oneCh.source = (*it).source;
oneCh.slices.clear();
oneCh.nIndex = 0; //有可能本通道并没有文件,但此索引不影响使用
m_results.push_back(oneCh);
}
InitScreenSpace(m_ItemBuf.size()); //初始化分屏
}
}
Notify(EVT_QUERY_FINISH, pData);
return S_OK;
}
ReplayItemData为保存缓存回放数据的结构体
struct ReplayItemData
{
bool bValid; //用于移除和添加指定通道
bool bExistedFile; //该通道是否存在录像文件
CString oid; //通道oid
CString oidSrc; //通道oid的上一级,主要是针对nru回放,如果是非nru,则为通道所属的设备
CString fileRes; //用于启动回放的文件标识符
SDPTIME tm_begin; //文件开始时间,以ms计算
SDPTIME tm_end; //文件结束时间,以ms计算
SDPTIME cur_time; //异步回放需要的参数,
int sliceIndex;
std::vector<TRecordTimeSlice> slices;
bool bEdit; //是否剪辑该通道
bool bSound; //该窗口视频是否开启音频
int nBright; //亮度
int nContrast; //对比度
SDPTIME jumpPos;
int nSpeed; //取值范围[-4,+4]
UINT nIndexItem; //回放窗口索引位
LONG streamId; //流id
EReplayStreamStatus status;
bool bLocalZoom; //是否处在本地放大状态
bool bPlaying;
};
TRecordTimeSlice为记录录像时间段的结构体
struct TRecordTimeSlice
{
SDPTIME begin; //起始时间
SDPTIME end; //结束时间
std::vector<StreamSearchMode::TRecordFlags> flags; //录像段类型标记
};
TRecordFlags为记录视频文件录像段类型标记的结构体
struct TRecordFlags
{
SDPTIME time; //时间
ULONG flags; //录像类型标记(ERecordTypeFlags枚举的或值,为0表示没有录像)
std::string fileName;
ULONG fileSize;
SDPTIME begTime;
SDPTIME endTime;
};
VideoResult为保存通道视频记录的结构体
struct VideoResult
{
std::string source; //通道源
std::string srcParent; //上一级oid,nru则为纳入源,设备为设备oid
int nIndex; //当前播放文件索引,从0开始
std::list<TRecordTimeSlice> slices; //搜索结果时间片列表
};
事件EVT_QUERY_FINISH的响应函数位于项目Replay中的SearchPane
void CSearchPane::OnQueryFinished(IEventData *data)
{
StreamSearchMode::StreamSearchData *evtData = dynamic_cast<StreamSearchMode::StreamSearchData*>(data);
if (evtData && evtData->result.size() != 0)
{
StreamSearchMode::TVideoSearchResult *result = &(*(evtData->result.begin()));
if(result == NULL || result->id != (LONG)StreamSearchMode::eReplay)
{
return;
}
::SendMessage(m_tipsDlg->m_hWnd, QUERYFINISHED, 0,0); //关闭提示框
bool bNull = true;
CWnd * videoWnd = NULL;
::SendMessage(CReplayUI::replayUI->GetSafeHwnd(), WM_GET_VIDEOWND, WPARAM(&videoWnd), 0); //获取回放面板的句柄
CString str, strTips;
GetModuleCString(strTips, IDS_TIPS);
if (result->resultFlag==StreamSearchMode::VideoSearchSucceed
|| result->resultFlag==StreamSearchMode::VideoSubSucceed)
{
for (std::vector<StreamSearchMode::TChannelVideoRecord>::iterator it = result->records.begin(); it != result->records.end(); it++)
{
if ((*it).files.size()!=0)
{
bNull=false;
break;
}
}
if (bNull)
{
GetModuleCString(str, IDS_SEARCH_NO_VIDEO);
CenterMessageBox(videoWnd, str, strTips, MB_OK|MB_ICONINFORMATION);
}
}
else
{
GetModuleCString(str, IDS_SEARCH_FAILED);
CenterMessageBox(videoWnd, str, strTips, MB_OK|MB_ICONERROR);
}
}
}
CUBase/SearchResultWnd
LRESULT CSearchResultWnd::OnStreamSearchResult(IEventData *pData)
{
StreamSearchMode::StreamSearchData *evtData = dynamic_cast<StreamSearchMode::StreamSearchData*>(pData);
if(evtData && evtData->result.size() != 0)
{
StreamSearchMode::TVideoSearchResult *result = &(*(evtData->result.begin()));
if(result == NULL || result->id != (LONG)m_id)
{
return S_FALSE;
}
bool bSuc = false; // true包含半成功
for(std::vector<StreamSearchMode::TVideoSearchResult>::iterator it=evtData->result.begin(); it != evtData->result.end(); it++)
{
if(it->resultFlag == StreamSearchMode::VideoSearchSucceed
|| it->resultFlag == StreamSearchMode::VideoSubSucceed)
{
bSuc = true;
break;
}
}
if (bSuc)
{ //全部通道搜索成功,或者部分通道搜索成功
//刷新结果显示区域
m_table_result.RefreshVideoSearchResult(evtData->result);
// 将筛选标志置为所有
m_pict_status = 0xFFFFFFFF;
}
}
return S_OK;
}
调用RefreshVideoSearchResult转换搜索结果
void CVideoSearchResultTable::RefreshVideoSearchResult(std::vector<StreamSearchMode::TVideoSearchResult> ¶ms)
{
if(params.size() == 0)
return;
int i;
for(i = 0;i < MAX_NUM_REPLAY_SUP; i++)
{
m_SearchResult[i].bValid = false;
m_SearchResult[i].files.clear();
m_SearchResult[i].ch_oid = "";
m_SearchResult[i].nru_oid = "";
}
//刷新结果时初始化显示全天
m_dLeftTime = 0;
m_nDegreeResize = 0;
//当天的起始时间SDPTIME值
TSDPLocalTime tmpTime;
sdpGetLocalTime(params.begin()->condition.begin,tmpTime); //搜索条件里面的开始时间不一定是一天的凌晨
tmpTime.hour = 0;
tmpTime.min = 0;
tmpTime.sec = 0;
tmpTime.ms = 0;
sdpMakeLocalTime(m_sdptime_base, tmpTime);
TSDPLocalTime time;
sdpGetLocalTime(m_sdptime_base, time);
INT searchDay = time.day;
i = 0;
m_nValidChannel=0;
std::vector<StreamSearchMode::TVideoSearchResult>::iterator it_result = params.begin();
for(; it_result != params.end(); it_result++)
{
std::vector<StreamSearchMode::TChannelVideoRecord>::iterator it = it_result->records.begin();
for(;it != it_result->records.end(); it++)
{// 先填有录像的通道
if ((*it).files.size()==0)
continue;
m_nValidChannel++;
m_SearchResult[i].bValid=true;
m_SearchResult[i].nSearchDay=searchDay;
m_SearchResult[i].ch_oid=(*it).source;
if (it_result->condition.oidNru.size() != 0)
{ //nru录像
std::vector<std::string>::iterator it_nruoid = it_result->condition.oidNru.begin();
for (std::vector<std::string>::iterator it_oid = it_result->condition.choid.begin();
it_oid != it_result->condition.choid.end(); it_oid++,it_nruoid++)
{
if (m_SearchResult[i].ch_oid.compare(*it_oid) == 0)
{
m_SearchResult[i].nru_oid = *it_nruoid;
break;
}
}
}
for (std::vector<StreamSearchMode::TRecordFileEx>::iterator it_Rec = (*it).files.begin(); it_Rec != (*it).files.end(); it_Rec++)
{
m_SearchResult[i].files.push_back(*it_Rec);
}
i++;
}
}
it_result = params.begin();
for (; it_result != params.end(); it_result++)
{
std::vector<StreamSearchMode::TChannelVideoRecord>::iterator it = it_result->records.begin();
for (;it!=it_result->records.end(); it++)
{ //将没有录像的通道殿后
if ((*it).files.size()!=0)
continue;
m_nValidChannel++;
m_SearchResult[i].bValid=true;
m_SearchResult[i].nSearchDay=searchDay;
m_SearchResult[i].ch_oid=(*it).source;
if (it_result->condition.oidNru.size() != 0)
{ //nru录像
std::vector<std::string>::iterator it_nruoid = it_result->condition.oidNru.begin();
for (std::vector<std::string>::iterator it_oid = it_result->condition.choid.begin();
it_oid != it_result->condition.choid.end(); it_oid++,it_nruoid++)
{
if (m_SearchResult[i].ch_oid.compare(*it_oid)==0)
{
m_SearchResult[i].nru_oid = *it_nruoid;
break;
}
}
}
i++;
}
}
m_nBaseChannelIndex = 0; //优先使用前4个窗口
if (m_replayModel == eAsyncReplay)
{ //异步模式,切换当前显示的通道时,重新输入数据,中间最多存在1秒的空白,SetCurTime刷新当前时间
for (int i = 0; i < 4; i++)
{
m_timeCursor[i].strOid = Type_cast<CString>(m_SearchResult[i+m_nBaseChannelIndex].ch_oid);
m_timeCursor[i].bVisible=false;
m_timeCursor[i].curTime = 0;
m_timeCursor[i].posPre = 0;
m_timeCursor[i].posCur=0;
}
}
m_status_filter = 0XFFFFFFFF;
CalcDisplayRect();
CRect rect;
GetClientRect(&rect);
InvalidateRect(&rect);
UpdateWindow();
m_btn_UpPage.EnableWindow(FALSE); // 初始显示前4路
BOOL bStatus = m_nValidChannel <= 4 ? FALSE : TRUE;
::SendMessage(GetParent()->GetSafeHwnd(), RT_DOWNBTN_STATUS, WPARAM(bStatus),0);
}