当前,在国内安防领域,海康摄像头一直是受各个解决方案比较青睐的摄像头选择。本项目主要应用海康摄像头对桥梁道路车辆运行情况进行监控。当桥梁称重系统检测到车辆异常信号后,触发摄像服务程序,采集摄像头在该时间段内的是视频数据(事件的前五秒与后五秒)并保存为MP4文件,上传至FTP服务供后期使用。
海康摄像头获取回放视频文件通常为H.264编码格式,rtp,ps,ts封装协议的视频文件,安放领域较长使用的视频封装协议。而web页面只支持MP4封装协议的文件播放。所以本方案采用获取裸码流,并使用libmp4V2的方法进行MP4协议封装
static void CALLBACK PlayBackH264DataCallBack(LONG lPlayHandle, NET_DVR_PACKET_INFO_EX *struPackInfo, void *pUser)
{
StructH264Process *obj = static_cast<StructH264Process *>(pUser);
switch (struPackInfo->dwPacketType)
{
case FILE_HEAD: // 头
break;
case VIDEO_I_FRAME: // I 帧
obj->MP4.getConvertMP4File(struPackInfo->pPacketBuffer, struPackInfo->dwPacketSize, struPackInfo->dwPacketType);
break;
case VIDEO_B_FRAME: // B 帧
break;
case VIDEO_P_FRAME: // P 帧
obj->MP4.getConvertMP4File(struPackInfo->pPacketBuffer, struPackInfo->dwPacketSize, struPackInfo->dwPacketType);
break;
default: // 其他数据
break;
}
}
CHKProcess::CHKProcess(QObject *parent) : QObject(parent)
{
}
int CHKProcess::init(QString host, int port, QString usr, QString pwd)
{
//---------------------------------------
// 初始化
NET_DVR_Init();
//设置连接时间与重连时间
NET_DVR_SetConnectTime(2000, 1);
NET_DVR_SetReconnect(10000, true);
//---------------------------------------
// 注册设备
//登录参数,包括设备地址、登录用户、密码等
NET_DVR_USER_LOGIN_INFO struLoginInfo = {0};
struLoginInfo.bUseAsynLogin = 0; //同步登录方式
strcpy(struLoginInfo.sDeviceAddress, host.toStdString().data()); //设备IP地址
struLoginInfo.wPort = port; //设备服务端口
strcpy(struLoginInfo.sUserName, usr.toStdString().data()); //设备登录用户名
strcpy(struLoginInfo.sPassword, pwd.toStdString().data()); //设备登录密码
//设备信息, 输出参数
NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = {0};
m_userId = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
if (m_userId< 0)
{
qDebug()<<"HIKVISION login fail,last error"<<NET_DVR_GetLastError();
NET_DVR_Cleanup();
return -1;
}
qDebug()<<"HIKVISION connect!";
return 0;
}
void CHKProcess::downLoadFile(uint64_t startTime, uint64_t endTime,QString enventId,QString did)
{
p_H264Process.isfinish = false;
p_H264Process.isok = false;
QString fileName = QCoreApplication::applicationDirPath()+"/cache/V_"+enventId+"_"+did+".mp4";
if(!p_H264Process.MP4.CreateMP4File(fileName.toStdString()))
{
qDebug()<<"Failed to create MP4 file";
p_H264Process.isfinish = true;
p_H264Process.isok = false;
p_H264Process.MP4.getMP4FileClose();
p_H264Process.MP4.init();
return;
}
uint64_t currentTime = QDateTime::currentDateTime().toTime_t();
if((startTime>endTime) || (startTime>currentTime))
{
qDebug()<<"startTime:Command time parameter error";
p_H264Process.isfinish = true;
p_H264Process.isok = false;
p_H264Process.MP4.getMP4FileClose();
p_H264Process.MP4.init();
return;
}
if(currentTime<endTime)
{
if(endTime - currentTime>100)
{
qDebug()<<"Error:The end time is more than 100 seconds ahead of the current time";
p_H264Process.isfinish = true;
p_H264Process.isok = false;
p_H264Process.MP4.getMP4FileClose();
p_H264Process.MP4.init();
return;
}
QThread::sleep(endTime-currentTime);
}
QString strStartTime = QDateTime::fromTime_t(startTime).toString("yyyyMMddhhmmss");
QString strEndTime = QDateTime::fromTime_t(endTime).toString("yyyyMMddhhmmss");
QDate startDate = QDate::fromString(strStartTime.mid(0,8),"yyyyMMdd");
QDate endDate = QDate::fromString(strEndTime.mid(0,8),"yyyyMMdd");
QTime qstartTime = QTime::fromString(strStartTime.mid(8,6),"hhmmss");
QTime qendTime = QTime::fromString(strEndTime.mid(8,6),"hhmmss");
//按时间回放
NET_DVR_VOD_PARA struVodPara = { 0 };
struVodPara.dwSize = sizeof(struVodPara);
struVodPara.struIDInfo.dwSize = sizeof(NET_DVR_STREAM_INFO);
struVodPara.struIDInfo.dwChannel = 1;
struVodPara.hWnd = NULL;
struVodPara.struBeginTime.dwYear = startDate.year();
struVodPara.struBeginTime.dwMonth = startDate.month();
struVodPara.struBeginTime.dwDay = startDate.day();
struVodPara.struBeginTime.dwHour = qstartTime.hour();
struVodPara.struBeginTime.dwMinute = qstartTime.minute();
struVodPara.struBeginTime.dwSecond = qstartTime.second();
struVodPara.struEndTime.dwYear = endDate.year();
struVodPara.struEndTime.dwMonth = endDate.month();
struVodPara.struEndTime.dwDay = endDate.day();
struVodPara.struEndTime.dwHour = qendTime.hour();
struVodPara.struEndTime.dwMinute = qendTime.minute();
struVodPara.struEndTime.dwSecond = qendTime.second();
//---------------------------------------
//按时间回放
p_H264Process.hPlayback = NET_DVR_PlayBackByTime_V40(m_userId, &struVodPara);
if(p_H264Process.hPlayback < 0)
{
printf("NET_DVR_PlayBackByTime_V40 fail,last error %d\n", NET_DVR_GetLastError());
p_H264Process.isfinish = true;
p_H264Process.isok = false;
p_H264Process.MP4.getMP4FileClose();
p_H264Process.MP4.init();
return;
}
//---------------------------------------
//开始
if (!NET_DVR_PlayBackControl_V40(p_H264Process.hPlayback, NET_DVR_PLAYSTART, NULL, 0, NULL, NULL))
{
printf("HK play back control start failed [%d]\n", NET_DVR_GetLastError());
p_H264Process.isfinish = true;
p_H264Process.isok = false;
p_H264Process.MP4.getMP4FileClose();
p_H264Process.MP4.init();
return;
}
NET_DVR_SetPlayBackESCallBack(p_H264Process.hPlayback,PlayBackH264DataCallBack,&p_H264Process);
QThread::sleep(10); //10s延迟用于等待视频流数据返回
if(!NET_DVR_StopPlayBack(p_H264Process.hPlayback))
{
printf("HK failed to stop play back [%d]\n",NET_DVR_GetLastError());
p_H264Process.isfinish = true;
p_H264Process.isok = false;
p_H264Process.MP4.getMP4FileClose();
p_H264Process.MP4.init();
return;
}
p_H264Process.MP4.getMP4FileClose();
p_H264Process.MP4.init();
p_H264Process.isok = true;
p_H264Process.isfinish = true;
qDebug()<<"HK"<<" Video download complete %100";
qDebug()<<"*";
//---------------------------------------
//设置文件封装格式
int p = 4;
if(!NET_DVR_PlayBackControl_V40(hPlayback,NET_DVR_SET_TRANS_TYPE,&p,4,NULL,NULL))
{
qDebug()<<"HK Play setting failed,last error "<<NET_DVR_GetLastError();
p_isok = false;
return;
}
//开始下载
if(!NET_DVR_PlayBackControl_V40(hPlayback, NET_DVR_PLAYSTART, NULL, 0, NULL,NULL))
{
qDebug()<<"HK Play back control failed,last error "<<NET_DVR_GetLastError();
p_isok = false;
return;
}
int nPos = 0;
for(nPos = 0; nPos < 100&&nPos>=0; nPos = NET_DVR_GetDownloadPos(hPlayback))
{
QThread::msleep(500);
}
if(!NET_DVR_StopGetFile(hPlayback))
{
printf("HK failed to stop get file [%d]\n",NET_DVR_GetLastError());
p_isok = false;
return;
}
if(nPos<0||nPos>100)
{
qDebug()<<"HK download err,last error "<<NET_DVR_GetLastError();
QFile file(fileName);
if(file.open(QIODevice::ReadOnly))
{
if(file.size() == 0)
{
p_isok = false;
qDebug()<<"Video download fail,not upload ftp!";
return;
}
}
}
p_isok = true;
qDebug()<<"HK"<<QString("V_")+enventId+"_"+did+".mp4"<<" Video download complete %"<<nPos<<"\n";
qDebug()<<"*";
}
CHKProcess::~CHKProcess()
{
//注销用户
NET_DVR_Logout(m_userId);
//释放SDK资源
NET_DVR_Cleanup();
}