前言
本文主要介绍图像抓拍功能,通过自研的sip库(mysipsdk.dll)对接真实设备,使用http方式实现图像数据传输,最终达到图像抓拍与保存的目的。
基本要求
- 图像格式宜使用JPEG;
- 图像分辨率宜采用与主码流相同的分辨率;
- 抓拍图像文件命令宜遵循如下格式:
协议接口
- MESSAGE消息头Content-type头域为Content-type:Application/MANSCDP+xml;
- 图像传输方式宜使用http;
- 图像抓拍传输完成中的SessionID应与图像抓拍配置中的SessionID一致;
流程图
流程说明:
- SIP服务器(mysipsdk.dll)向设备端发送图像抓拍配置命令;
- 设备端返回200 OK;
- 设备端返回图像抓拍配置响应;
- SIP服务器(mysipsdk.dll)返回200 OK;
- 设备端将图像数据传输至图片存储服务器;
- 设备端发送图像抓拍传输完成消息;
- SIP服务器(mysipsdk.dll)返回200 OK;
设计
- SIP服务器(mysipsdk.dll)向设备端发送图像抓拍配置命令;
参数说明:
SnapNum:连拍张数,最多10张,当为手动抓拍时取值为1
Interval:单张抓拍间隔时间,单位:秒,最短为1秒
UploadURL:抓拍图像上传路径,例如:http://192.168.1.121/uploadsnapshot?token=xxx
SessionID:会话ID,由平台生成,用于关联抓拍的图像和平台请求,SessionID由大小写英文字母、数字、短划线组成,长度32~128字节
代码示例:
int CGBDeviceConfig::SnapShotConfig_(CMyGBDevice* device, const std::string& deviceID, const std::string& request)
{
if (!device || deviceID.empty() || request.empty())
return -1;
Json::Value value;
Json::Reader reader;
if (!reader.parse(request.c_str(), value))
return -1;
std::string sn = GetConfigSN();
std::string uploadURL = value["uploadURL"].asString();
std::string sessionID = value["sessionID"].asString();
int snapNum = value["snapNum"].asInt();
int interval = value["interval"].asInt();
char snapShotInfo[500] = { 0 };
snprintf(snapShotInfo, 500,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<Control>\n"
"<CmdType>DeviceConfig</CmdType>\n"
"<SN>%s</SN>\n"
"<DeviceID>%s</DeviceID>\n"
"<SnapShotConfig>\n"
"<SnapNum>%d</SnapNum>\n"
"<Interval>%d</Interval>\n"
"<UploadURL>%s</UploadURL>\n"
"<SessionID>%s</SessionID>\n"
"</SnapShotConfig>\n"
"</Control>\n"
, sn.c_str()
, deviceID.c_str()
, snapNum
, interval
, uploadURL.c_str()
, sessionID.c_str()
);
return CMySipContext::GetInstance().SendSipMessage(device, snapShotInfo);
}
- 设备端发送图像抓拍传输完成消息,SIP服务器(mysipsdk.dll)做解析;
主要流程:
1) 接收响应消息;
2) xml解析;
3) 判断CmdType是否为"UploadSnapShotFinished";
4) 如果3)步骤为是,解析返回消息并回调至应用层;
图像抓拍返回字段说明:
CmdType:固定为字符串"UploadSnapShotFinished"
SessionID:会话ID,由平台生成,用于关联抓拍的图像和平台请求
SnapShotList:抓拍图像标识列表
SnapShotFileID:抓拍图像唯一标识,由前端抓拍设备生成
代码示例:
bool CDeviceConfigMethod::OnRecvMsg(pjsip_rx_data* rdata)
{
if (PJSIP_OTHER_METHOD == rdata->msg_info.cseq->method.id)
{
CMyXmlParser xmlParser(CMySipContext::GetInstance().GetMessageBody(rdata));
CMyDynamicStruct dynamicStruct;
dynamicStruct.Set(xmlParser.GetXml());
auto cmd = xmlParser.GetXml()->RootElement()->Value();
auto cmdType = dynamicStruct.Get("CmdType");
if ("UploadSnapShotFinished" == cmdType)
{
CSnapShotFinishInfo snapShotInfo;
snapShotInfo.deviceID = dynamicStruct.Get("DeviceID");
snapShotInfo.sessionID = dynamicStruct.Get("SessionID");
std::string snapShotList = dynamicStruct.Get("SnapShotList");
Json::Reader reader;
Json::Value value;
reader.parse(snapShotList, value);
int size = value.size();
for (int i = 0; i < size; i++)
{
Json::Value val = value[i];
std::string snapShotfileID = val["SnapShotFileID"].asString();
snapShotInfo.snapShotFileIDs.push_back(snapShotfileID);
}
// 回调至应用层,需注册
if (m_dataCB)
m_dataCB(m_handleType, m_user, &snapShotInfo);
}
else
{
return false;
}
Response(rdata, PJSIP_SC_OK, NoHead);
return true;
}
return false;
}