EasyDarwin开源流媒体云平台之云台ptz控制设计与实现
本文转自EasyDarwin开源团队成员Alex的博客:http://blog.csdn.net/cai6811376/article/details/51912692
近日,EasyDarwin云平台加入云台控制功能,完善了云平台的功能,提升了用户体验。具体设计以及实现如下。
流程设计
客户端通过RESTful接口向云平台发送控制命令;
云平台组织控制报文向设备发送;
设备执行后向云平台返回控制响应报文;
云平台接收响应报文后将控制结果返回给客户端。
- 接口设计
首先我们设计云台控制的接口,接口为RESTful方式接口。
http://[ip]:[port]/api/ptzcontrol?device=001001000058&channel=0&actiontype=single&c
ommand=down&speed=5&protocol=onvif
device: 设备序列号;
channel: 通道;
protocol: 控制模式, 包括 Onvif、 SDK;
actiontype: ptz 控制模式, 分为连续( Continuous)、 单步( Single);
command: ptz 控制命令包括转动、 变焦等,
stop/up/down/left/right/zoomin/zoomout/focusin/focusout/aperturein/apertureout;
speed: ptz 控制速度。
- 通讯报文设计
//云平台响应客户端控制
{
"EasyDarwin" : {
"Body" : {
"Channel" : "0",
"Protocol" : "ONVIF",
"Reserve" : "1",
"Serial" : "001001000058"
},
"Header" : {
"CSeq" : "2",
"ErrorNum" : "200",
"ErrorString" : "Success OK",
"MessageType" : "MSG_SC_PTZ_CONTROL_ACK",
"Version" : "1.0"
}
}
}
//云平台向设备发送控制报文
{
"EasyDarwin" : {
"Body" : {
"ActionType" : "SINGLE",
"Channel" : "0",
"Command" : "DOWN",
"From" : "f6a221eec46b47dea8ae1a2bd11f8d02",
"Protocol" : "ONVIF",
"Reserve" : "1",
"Serial" : "001001000058",
"Speed" : "5",
"To" : "245d6ec33cd247b7b7524219552db4d8",
"Via" : "27823d2e8b6b4032b453d435a16b7be8"
},
"Header" : {
"CSeq" : "1",
"MessageType" : "MSG_SD_CONTROL_PTZ_REQ",
"Version" : "1.0"
}
}
}
//设备响应云平台控制
{
"EasyDarwin" : {
"Body" : {
"Channel" : "0",
"From" : "245d6ec33cd247b7b7524219552db4d8",
"Protocol" : "ONVIF",
"Reserve" : "1",
"Serial" : "001001000058",
"To" : "f6a221eec46b47dea8ae1a2bd11f8d02",
"Via" : "27823d2e8b6b4032b453d435a16b7be8"
},
"Header" : {
"CSeq" : "1",
"ErrorNum" : "200",
"ErrorString" : "Success OK",
"MessageType" : "MSG_DS_CONTROL_PTZ_ACK",
"Version" : "1.0"
}
}
}
格式说明:
Serial:设备序列号;
Channel: 摄像机通道号;
Protocol: 指定 ptz 控制方式, ONVIF 协议或者设备 SDK;
ActionType: ptz 控制类型, 包括连续或者单步;
Command: ptz 控制命令, 包括停止, 上下左右旋转, 变焦等等;
Speed: ptz 控制速度;
From: EasyCMS 接收 Client 访问的 SessionID;
To: EasyCMS 向 Device 发送报文的 SessionID;
Via: EasyCMS 的 ServiceID;
- 实现
//EasyCMS HTTPSession.cpp
//在session map中查找device session,组织控制报文,通过device session发送给设备
OSRefTableEx* deviceMap = QTSServerInterface::GetServer()->GetDeviceSessionMap();
OSRefTableEx::OSRefEx* theDevRef = deviceMap->Resolve(chSerial);
if (theDevRef == NULL)
return EASY_ERROR_DEVICE_NOT_FOUND;
OSRefReleaserEx releaser(deviceMap, chSerial);
HTTPSession* pDevSession = static_cast<HTTPSession *>(theDevRef->GetObjectPtr());
EasyProtocolACK reqreq(MSG_SD_CONTROL_PTZ_REQ);
EasyJsonValue headerheader, bodybody;
char chTemp[16] = { 0 };
UInt32 uDevCseq = pDevSession->GetCSeq();
sprintf(chTemp, "%d", uDevCseq);
headerheader[EASY_TAG_CSEQ] = string(chTemp);
headerheader[EASY_TAG_VERSION] = EASY_PROTOCOL_VERSION;
string strProtocol(chProtocol);
string strActionType(chActionType);
string strCmd(chCmd);
boost::to_upper(strProtocol);
boost::to_upper(strActionType);
boost::to_upper(strCmd);
bodybody[EASY_TAG_SERIAL] = chSerial;
bodybody[EASY_TAG_CHANNEL] = chChannel;
bodybody[EASY_TAG_PROTOCOL] = strProtocol;
bodybody[EASY_TAG_RESERVE] = chReserve;
bodybody[EASY_TAG_ACTION_TYPE] = strActionType;
bodybody[EASY_TAG_CMD] = strCmd;
bodybody[EASY_TAG_SPEED] = chSpeed;
bodybody[EASY_TAG_FROM] = fSessionID;
bodybody[EASY_TAG_TO] = pDevSession->GetValue(EasyHTTPSessionID)->GetAsCString();
bodybody[EASY_TAG_VIA] = QTSServerInterface::GetServer()->GetCloudServiceNodeID();
reqreq.SetHead(headerheader);
reqreq.SetBody(bodybody);
string buffer = reqreq.GetMsg();
StrPtrLen theValue(const_cast<char*>(buffer.c_str()), buffer.size());
pDevSession->SendHTTPPacket(&theValue, false, false);
//EasyCamera EasyCMSSession.cpp processControlPTZReq
//EasyCamera接收控制报文,调用EasyCameraSource的控制接口
QTSS_Error EasyCMSSession::processControlPTZReq() const
{
EasyMsgSDControlPTZREQ ctrlPTZReq(fContentBuffer);
string serial = ctrlPTZReq.GetBodyValue(EASY_TAG_SERIAL);
string protocol = ctrlPTZReq.GetBodyValue(EASY_TAG_PROTOCOL);
string channel = ctrlPTZReq.GetBodyValue(EASY_TAG_CHANNEL);
string reserve = ctrlPTZReq.GetBodyValue(EASY_TAG_RESERVE);
string actionType = ctrlPTZReq.GetBodyValue(EASY_TAG_ACTION_TYPE);
string command = ctrlPTZReq.GetBodyValue(EASY_TAG_CMD);
string speed = ctrlPTZReq.GetBodyValue(EASY_TAG_SPEED);
string from = ctrlPTZReq.GetBodyValue(EASY_TAG_FROM);
string to = ctrlPTZReq.GetBodyValue(EASY_TAG_TO);
string via = ctrlPTZReq.GetBodyValue(EASY_TAG_VIA);
if (serial.empty() || channel.empty() || command.empty())
{
return QTSS_ValueNotFound;
}
QTSS_RoleParams params;
params.cameraPTZParams.inActionType = EasyProtocol::GetPTZActionType(actionType);
params.cameraPTZParams.inCommand = EasyProtocol::GetPTZCMDType(command);
params.cameraPTZParams.inSpeed = EasyUtil::String2Int(speed);
QTSS_Error errCode = QTSS_NoErr;
UInt32 fCurrentModule = 0;
UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kControlPTZRole);
for (; fCurrentModule < numModules; ++fCurrentModule)
{
QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kControlPTZRole, fCurrentModule);
errCode = theModule->CallDispatch(Easy_ControlPTZ_Role, ¶ms);
}
EasyJsonValue body;
body[EASY_TAG_SERIAL] = serial;
body[EASY_TAG_CHANNEL] = channel;
body[EASY_TAG_RESERVE] = reserve;
body[EASY_TAG_PROTOCOL] = protocol;
body[EASY_TAG_FROM] = to;
body[EASY_TAG_TO] = from;
body[EASY_TAG_VIA] = via;
EasyMsgDSControlPTZACK rsp(body, ctrlPTZReq.GetMsgCSeq(), getStatusNo(errCode));
string msg = rsp.GetMsg();
StrPtrLen jsonContent(const_cast<char*>(msg.data()));
HTTPRequest httpAck(&QTSServerInterface::GetServerHeader(), httpResponseType);
if (httpAck.CreateResponseHeader())
{
if (jsonContent.Len)
httpAck.AppendContentLengthHeader(jsonContent.Len);
//Push msg to OutputBuffer
char respHeader[2048] = { 0 };
StrPtrLen* ackPtr = httpAck.GetCompleteHTTPHeader();
strncpy(respHeader, ackPtr->Ptr, ackPtr->Len);
fOutputStream->Put(respHeader);
if (jsonContent.Len > 0)
fOutputStream->Put(jsonContent.Ptr, jsonContent.Len);
}
return errCode;
}
//EasyCamera EasyCameraSource.cpp ControlPTZ
QTSS_Error EasyCameraSource::ControlPTZ(Easy_CameraPTZ_Params* params)
{
QTSS_Error result = QTSS_RequestFailed;
if (cameraLogin())
{
HI_S32 error;
if (params->inActionType == EASY_PTZ_ACTION_TYPE_CONTINUOUS)
{
error = HI_NET_DEV_PTZ_Ctrl_Standard(m_u32Handle, getPTZCMDFromCMDType(params->inCommand), params->inSpeed);
}
else if (params->inActionType == EASY_PTZ_ACTION_TYPE_SINGLE)
{
error = HI_NET_DEV_PTZ_Ctrl_StandardEx(m_u32Handle, getPTZCMDFromCMDType(params->inCommand));
}
else
{
return QTSS_BadArgument;
}
if (error == HI_SUCCESS)
{
result = QTSS_NoErr;
}
else
{
result = QTSS_RequestFailed;
}
}
return result;
}
获取更多信息
Github:https://github.com/easydarwin
Copyright © EasyDarwin.org 2012-2016
EasyDarwin开源流媒体云平台之云台ptz控制设计与实现的更多相关文章
- EasyDarwin开源流媒体云平台支持EasyCamera摄像机、EasyCamera手机直播监控、EasyNVR等多终端接入
云平台架构 EasyDarwin开源流媒体云平台目前已经包括了EasyCMS中心管理服务.EasyDarwin流媒体服务.EasyCamera设备端(支持Arm_Linux.Android.PC).E ...
- EasyDarwin开源流媒体云平台之语音对讲功能设计与实现
本文由EasyDarwin开源团队成员Alex贡献:http://blog.csdn.net/cai6811376/article/details/52006958 EasyDarwin云平台一直在稳 ...
- EasyCamera Android安卓移动视频监控单兵设备接入EasyDarwin开源流媒体云平台
前言 随着Android系统的不断更新和发展,现在越来越多的硬件产品选择用安卓系统作为运行环境,电视机,机顶盒.门禁.行车记录仪.车载系统.单兵设备等等,Android系统底层还是Linux,但对上层 ...
- EasyDarwin开源流媒体云平台设计与实现(分布式+负载均衡)
前言 早在2013年我就设计了一套架构非常简单的分布式流媒体服务器平台<基于Darwin实现的分布式流媒体直播服务器系统>,当时的考虑如今看来有诸多的细节点没有考虑到:1.CMS是单点部署 ...
- EasyDarwin开源流媒体云平台之EasyRMS录播服务器功能设计
需求背景 EasyDarwin开发团队维护EasyDarwin开源流媒体服务器也已经很多年了,之前也陆陆续续尝试过很多种服务端录像的方案,有:在EasyDarwin中直接解析收到的RTP包,重新组包录 ...
- EasyDarwin开源流媒体云平台VS调试断点提示“还没有为该文档加载任何符号”的解决办法
本文转自EasyDarwin开源团队成员Alex的博客:http://blog.csdn.net/cai6811376/article/details/52063666 近日,我们EasyDarwin ...
- EasyDarwin开源流媒体云平台中boost Base64编解码后与源长度不匹配的bug
本文转自EasyDarwin团队Alex的博客:http://blog.csdn.net/cai6811376 EasyDarwin云平台中部分协议使用了Base64编码昨晚报文通信的载体.比如在对摄 ...
- 开源流媒体云视频平台EasyDarwin中EasyCMS服务是如何进行命令转发和消息路由的
EasyCMS介绍 EasyCMS做为EasyDarwin开源流媒体云平台解决方案的一部分,主要进行的是设备的接入和Session(DeviceSession & ClientSession) ...
- EasyDarwin开源流媒体项目
本文转自EasyDarwin CSDN官方博客:http://blog.csdn.net/easydarwin EasyDarwin是由国内开源流媒体团队维护和迭代的一整套开源流媒体视频平台框架,从2 ...
随机推荐
- APUE 学习笔记(六) 进程控制
1. fork 创建新进程 fork创建的新进程称为子进程,fork函数调用一次,返回两次. 两次返回的唯一区别就是子进程的返回值是0,而父进程的返回值是新子进程的进程ID 在fork之后是父进程先执 ...
- Session挂起
异常信息: toString() unavailable - no suspended threads 使用Spring管理 ,在使用hibernate时使用如下语句Session session = ...
- 35深入理解C指针之---结构体基础
一.结构体基础 1.定义:结构体大大加强了C的数据聚合能力,可以使得不同类型的数据进行结合 2.特征: 1).结构体可以使得不同类型的数据进行结合 2).结构体可以使用内置的数据类型,包括指针 3). ...
- 不要使用 reader.Peek() 去读取每行数据
1.问题描述 使用SteamRead的Peek()和ReadLine()来读取流中的数据,如果数据行数太多,会读取不完整(后面有些数据就读不出来了). 比如: while (srResponseRea ...
- 在IOS11中position:fixed弹出框中的input出现光标错位的问题
问题出现的背景: 在IOS11中position:fixed弹出框中的input出现光标错位的问题 解决方案 一.设计交互方面最好不要让弹窗中出现input输入框: 二.前端处理此兼容性的方案思路: ...
- ssh的简单介绍
SSH简单介绍与运用 一.什么是SSH? SSH是一种网络协议,用于计算机之间的加密登录. OpenSSH 提供了以下几个工具: 1. ssh:实现 SSH 协议,用以建立安全连接,它替代了较早的 ...
- HDU 1018.Big Number-Stirling(斯特林)公式 取N阶乘近似值
最近一堆题目要补,一直咸鱼,补了一堆水题都没必要写题解.备忘一下这个公式. Stirling公式的意义在于:当n足够大时,n!计算起来十分困难,虽然有很多关于n!的等式,但并不能很好地对阶乘结果进行估 ...
- bzoj 1453: [Wc]Dface双面棋盘
1453: [Wc]Dface双面棋盘 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 617 Solved: 317[Submit][Status][ ...
- 【IOI2014】Game
题目简述 健佳是一个喜欢做游戏的小男生.当有人问问题时,他更喜欢通过玩游戏的方式作答,而不是直接回答.健佳碰到了他的朋友梅玉,跟她讲了台湾的航空网.在台湾有 $n$ 个城市(编号为 $0, \dots ...
- mac下 JMeter 4.0 进行多用户接口压力测试
1.最近在做公司的内部系统,需要进行多用户压力测试,于是上网在官网下载了Jmeter 压缩包,并放在指定的目录解压,打开解压后文件夹到bin目录下: 执行sh jmeter Jmeter就启动起来了 ...