7-Onvif协议:IPC客户端之PTZ控制

参考文章

https://blog.csdn.net/zhizhengguan/article/details/109379719?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171765035116800184113873%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=171765035116800184113873&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-1-109379719-null-null.142

https://blog.csdn.net/chi_qing/article/details/89319101

一、PTZ控制简介

​ 在安防摄像头中,不仅仅涉及到固定摄像头的枪击,同样还包含可以360°转动的球机。因此对球机的云台方向控制是Onvif协议开发过程中必不可少的过程。

二、PTZ摄像机中PTZ分别代表什么?

  • P: pan,表示相机水平方向上移动,即相机的旋转
  • T: Tilt, 表示垂直方向上的移动,即相机镜头的高低俯仰
  • Z: Zoom,表示变焦,即调整相机的焦距

三、客户端实现PTZ控制的流程

  1. 通过设备服务地址(形如http://192.168.1.137:81/onvif/device_service),调用**ONVIF_GetPTZCapabilities()**函数接口,获取到PTZ的URL(形如http://192.168.1.137:81/onvif/ptz);
  2. 通过PTZ的URL,调用**ONVIF_GetPTZProfilesToken()**函数接口,获取到ProfileToken;
  3. 对数据类型进行填充;
  4. 调用函数接口实现摄像头转动功能。

四、相关数据结构与函数

所以函数与数据结构定义在client\onvif_head\onvif.h

调用ptz.wsdl的以下接口,文件路径https://www.onvif.org/ver20/ptz/wsdl/ptz.wsdl

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.函数

函数原型在client\application\soapClient.cpp

1.AbsoluteMove(绝对移动)

int soap_call___tptz__AbsoluteMove(
    struct soap *soap,
    NULL, // char *endpoint = NULL selects default endpoint for this operation
    NULL, // char *action = NULL selects default action for this operation
    // input parameters:
    _tptz__AbsoluteMove*                tptz__AbsoluteMove,
    // output parameters:
    _tptz__AbsoluteMoveResponse        &tptz__AbsoluteMoveResponse
  );

在这里插入图片描述
在这里插入图片描述

2.ContinuousMove(沿某方向持续移动)

int soap_call___tptz__ContinuousMove(
    struct soap *soap,
    NULL, // char *endpoint = NULL selects default endpoint for this operation
    NULL, // char *action = NULL selects default action for this operation
    // input parameters:
    _tptz__ContinuousMove*              tptz__ContinuousMove,
    // output parameters:
    _tptz__ContinuousMoveResponse      &tptz__ContinuousMoveResponse
);

在这里插入图片描述
在这里插入图片描述

3.RelativeMove(相对移动)

int soap_call___tptz__RelativeMove(
    struct soap *soap,
    NULL, // char *endpoint = NULL selects default endpoint for this operation
    NULL, // char *action = NULL selects default action for this operation
    // input parameters:
    _tptz__RelativeMove*                tptz__RelativeMove,
    // output parameters:
    _tptz__RelativeMoveResponse        &tptz__RelativeMoveResponse
);

在这里插入图片描述
在这里插入图片描述

2.数据结构

绝对位置移动的数据结构为 _tptz__AbsoluteMove,class类型的数据结构定义在client\soap\soapStub.h下

在这里插入图片描述

其中ProfileToken是一个标识。可以用获取配置文件函数soap_call___trt__GetProfiles获得,函数定义:

soap_call___trt__GetProfiles(struct soap *soap, const char *soap_endpoint, const char 

**tt__PTZVector**为转动位置结构体,class类型的数据结构也定义在client\soap\soapStub.h下

struct tt__PTZVector {
        /** Optional element 'tt:PanTilt' of XSD type 'tt:Vector2D' */
        struct tt__Vector2D *PanTilt;//2维坐标结构体
        /** Optional element 'tt:Zoom' of XSD type 'tt:Vector1D' */
        struct tt__Vector1D *Zoom;//1维坐标结构体
};

在这里插入图片描述

tt__Vector2D 2维坐标,class类型的数据结构也定义在client\soap\soapStub.h下

# 图片中为C++版本,下述代码为c版本
struct tt__Vector2D {
        /** Required attribute 'x' of XSD type 'xsd:float' */
        float x;   //Pan
        /** Required attribute 'y' of XSD type 'xsd:float' */
        float y;   //Tilt
         /** Optional attribute 'space' of XSD type 'xsd:anyURI' */
        //URI:一般填入"http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace"即可
        char *space;
};

在这里插入图片描述

tt__Vector1D 1维坐标,class类型的数据结构也定义在client\soap\soapStub.h下

struct tt__Vector1D {
        /** Required attribute 'x' of XSD type 'xsd:float' */
        float x;
        /** Optional attribute 'space' of XSD type 'xsd:anyURI' */
        char *space;
};

在这里插入图片描述

相对位置移动函数和连续移动函数的参数可参考绝对位置移动函数的参数查找方法,这些class类型的数据结构都定义在client\soap\soapStub.h下

五、功能实现(c++)

函数实现说明具体参考ONVIF_PTZAbsoluteMove()的代码注释

头文件:

struct OnvifPTZInfo
{
    int status;
    float p;
    float t;
    float z;
};

struct ONVIFPTZAbsoluteMoveInfo
{
    float absoluteP;
    float absoluteT;
    float absoluteZ;
    float vp;
    float vt;
    float vz;
};

struct ONVIFPTZRelativeMoveInfo
{
    float relativeP;
    float relativeT;
    float relativeZ;
    float vp;
    float vt;
    float vz;
};

enum PTZCMD
{
    PTZ_CMD_LEFT,
    PTZ_CMD_RIGHT,
    PTZ_CMD_UP,
    PTZ_CMD_DOWN,
    PTZ_CMD_LEFTUP,
    PTZ_CMD_LEFTDOWN,
    PTZ_CMD_RIGHTUP,
    PTZ_CMD_RIGHTDOWN,
    PTZ_CMD_ZOOM_IN,
    PTZ_CMD_ZOOM_OUT,
};

int ONVIF_GetPTZCapabilities(const std::string& deviceXAddr, std::string *ptzXAddr);
bool ONVIF_GetPTZProfilesToken(const std::string& mediaXAddr, std::string *ptzprofilesToken);
int ONVIF_PTZ_GetStatus(const std::string& ptzXAddr, const std::string& ProfileToken, struct OnvifPTZInfo * ptzInfo);
int ONVIF_PTZStopMove(const std::string& ptzXAddr, const std::string& ProfileToken);
int ONVIF_PTZAbsoluteMove(const std::string& ptzXAddr, const std::string& ProfileToken, struct ONVIFPTZAbsoluteMoveInfo *ptzAbsoluteMoveInfo);
int ONVIF_PTZRelativeMove(const std::string& ptzXAddr, const std::string& ProfileToken, struct ONVIFPTZRelativeMoveInfo *ptzRelativeMoveInfo);
int ONVIF_PTZContinuousMove(const std::string& ptzXAddr, const std::string& ProfileToken, enum PTZCMD cmd, float speed);

函数的实现:

所有移动命令应以非阻塞方式执行,表示不应等到请求的移动操作完成。新的移动请求可以覆盖最后的移动操作。

1.ONVIF_GetPTZCapabilities()

int ONVIF_GetPTZCapabilities(const std::string& deviceXAddr, std::string *ptzXAddr)
{
    int result = 0;
    struct soap *soap = nullptr;
    _tds__GetCapabilities            devinfo_req;
    _tds__GetCapabilitiesResponse    devinfo_resp;


            SOAP_ASSERT(!deviceXAddr.empty());
            SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));

    result = soap_call___tds__GetCapabilities(soap, deviceXAddr.c_str(), NULL, &devinfo_req, devinfo_resp);
    SOAP_CHECK_ERROR(result, soap, "GetCapabilities");
    

    if(devinfo_resp.Capabilities->PTZ != nullptr)
    {
        *ptzXAddr=devinfo_resp.Capabilities->PTZ->XAddr;
    }
    else
    {
        *ptzXAddr="null";
    }
       

#if DEBUG
    std::cout << "---------------------ONVIF_GetPTZCapabilities------------------" << "\n";
    std::cout << "PTZ:" << *ptzXAddr << "\n";
    std::cout << "-------------------------------------------------------------" << "\n";
#endif

    EXIT:

    if (nullptr != soap) {
        ONVIF_soap_delete(soap);
    }
    return result;
}

2.ONVIF_GetPTZProfilesToken()

bool ONVIF_GetPTZProfilesToken(const std::string& mediaXAddr, std::string *ptzprofilesToken)
{
    int result = 0;
    struct soap *soap = nullptr;
    _trt__GetProfiles           devinfo_req;
    _trt__GetProfilesResponse   devinfo_resp;

            SOAP_ASSERT(!mediaXAddr.empty());
            SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));

    ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
    result = soap_call___trt__GetProfiles(soap, mediaXAddr.c_str(), nullptr, &devinfo_req, devinfo_resp);
    SOAP_CHECK_ERROR(result, soap, "ONVIF_GetProfiles");

            SOAP_ASSERT(devinfo_resp.__sizeProfiles > 0);

    *ptzprofilesToken = devinfo_resp.Profiles[0]->token;
#if DEBUG
    std::cout << "-----------------ONVIF_GetPTZProfilesToken-------------------" << "\n";
    std::cout << *ptzprofilesToken << "\n";
    std::cout << "-------------------------------------------------------------" << "\n";
#endif 
    EXIT:
    if (nullptr != soap) {
        ONVIF_soap_delete(soap);
    }

    return result;
}

3.ONVIF_PTZ_GetStatus()

// 获取当前ptz的位置以及状态
int ONVIF_PTZ_GetStatus(const std::string& ptzXAddr, const std::string& ProfileToken, struct OnvifPTZInfo * ptzInfo){
    int result = 0;
    struct soap *soap = nullptr;
    _tptz__GetStatus           getStatus;
    _tptz__GetStatusResponse   getStatusResponse;

            SOAP_ASSERT(!ptzXAddr.empty());
            SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));


    ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);


    getStatus.ProfileToken = const_cast<char *>(ProfileToken.c_str());
    result = soap_call___tptz__GetStatus(soap, ptzXAddr.c_str(), nullptr, &getStatus, getStatusResponse);
    SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZ_GetStatus");

    if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__IDLE){
        ptzInfo->status = 0;
    }else if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__MOVING){
        ptzInfo->status = 1;
    }else if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__UNKNOWN){
        ptzInfo->status = 2;
    }

    ptzInfo->p = getStatusResponse.PTZStatus->Position->PanTilt->x;
    ptzInfo->t = getStatusResponse.PTZStatus->Position->PanTilt->y;
    ptzInfo->z = getStatusResponse.PTZStatus->Position->Zoom->x;

#if DEBUG

    std::cout << "----------------------ONVIF_PTZ_GetStatus--------------------" << "\n";
    if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__IDLE){
        std::cout << "MoveStatus:IDLE " << std::endl;
    }else if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__MOVING){
        std::cout << "MoveStatus:MOVING " << std::endl;
    }else if(*getStatusResponse.PTZStatus->MoveStatus->PanTilt == tt__MoveStatus__UNKNOWN){
        std::cout << "MoveStatus:UNKNOWN " << std::endl;
    }
    std::cout << "当前p: "  << ptzInfo->p << "\n";
    std::cout << "当前t: "  << ptzInfo->t << "\n";
    std::cout << "当前z: "  << ptzInfo->z << "\n";
    std::cout << "-------------------------------------------------------------" << "\n";
#endif
    EXIT:
    if (nullptr != soap) {
        ONVIF_soap_delete(soap);
    }

    return 0;
}

4.ONVIF_PTZStopMove()

int ONVIF_PTZStopMove(const std::string& ptzXAddr, const std::string& ProfileToken){
    int result = 0;
    struct soap *soap = nullptr;
    _tptz__Stop tptzStop;
    _tptz__StopResponse tptzStopResponse;

            SOAP_ASSERT(!ptzXAddr.empty() && !ProfileToken.empty());
            SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));

    ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
    tptzStop.ProfileToken = const_cast<char *>(ProfileToken.c_str());
    result = soap_call___tptz__Stop(soap, ptzXAddr.c_str(), nullptr, &tptzStop, tptzStopResponse);
    SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZStopMove");

    EXIT:
    if (nullptr != soap) {
        ONVIF_soap_delete(soap);
    }
    return result;
}

5.ONVIF_PTZAbsoluteMove()

int ONVIF_PTZAbsoluteMove(const std::string& ptzXAddr, const std::string& ProfileToken, struct ONVIFPTZAbsoluteMoveInfo *ptzAbsoluteMoveInfo){
    int result = 0;
    //1、soap结构体初始化
    struct soap *soap = nullptr;
    _tptz__AbsoluteMove           absoluteMove;
    _tptz__AbsoluteMoveResponse   absoluteMoveResponse;

    SOAP_ASSERT(!ptzXAddr.empty() && !ProfileToken.empty());
    SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));

	//2、鉴权(用户认证)
    ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
    
    //3、配置文件获取(profiletoken),作为函数参数
    absoluteMove.ProfileToken = const_cast<char *>(ProfileToken.c_str());
	
    //4、为结构体分配内存并填充结构体
    absoluteMove.Position = soap_new_tt__PTZVector(soap);
    absoluteMove.Position->PanTilt = soap_new_tt__Vector2D(soap);
    absoluteMove.Position->Zoom = soap_new_tt__Vector1D(soap);
    absoluteMove.Speed = soap_new_tt__PTZSpeed(soap);
    absoluteMove.Speed->PanTilt = soap_new_tt__Vector2D(soap);
    absoluteMove.Speed->Zoom = soap_new_tt__Vector1D(soap);


    absoluteMove.Position->PanTilt->x = ptzAbsoluteMoveInfo->absoluteP;  // p
    absoluteMove.Position->PanTilt->y = ptzAbsoluteMoveInfo->absoluteT;   // t
    absoluteMove.Position->Zoom->x = ptzAbsoluteMoveInfo->absoluteZ;   // z

     // x 和y的绝对值越接近1,表示云台的速度越快
    absoluteMove.Speed->PanTilt->x = ptzAbsoluteMoveInfo->vp;
    absoluteMove.Speed->PanTilt->y = ptzAbsoluteMoveInfo->vt;
    absoluteMove.Speed->Zoom->x = ptzAbsoluteMoveInfo->vz;
    //5、发送调用命令
    result = soap_call___tptz__AbsoluteMove(soap,ptzXAddr.c_str(), nullptr,&absoluteMove,absoluteMoveResponse);
    SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZAbsoluteMove");

	//6、soap结构体清理
EXIT:
    if (nullptr != soap) {
        ONVIF_soap_delete(soap);
    }
    return 0;
}

6.ONVIF_PTZRelativeMove()

int ONVIF_PTZRelativeMove(const std::string& ptzXAddr, const std::string& ProfileToken, struct ONVIFPTZRelativeMoveInfo *ptzRelativeMoveInfo)
{   
    int result = 0;
    struct OnvifPTZInfo ptzInfo;
    struct ONVIFPTZAbsoluteMoveInfo ptzAbsoluteMoveInfo;
    ONVIF_PTZ_GetStatus(ptzXAddr, ProfileToken, &ptzInfo);
    ptzAbsoluteMoveInfo.absoluteP = ptzInfo.p + ptzRelativeMoveInfo->relativeP;
    ptzAbsoluteMoveInfo.absoluteT = ptzInfo.t + ptzRelativeMoveInfo->relativeT;
    ptzAbsoluteMoveInfo.absoluteZ = ptzInfo.z + ptzRelativeMoveInfo->relativeZ;
    ptzAbsoluteMoveInfo.vp = ptzRelativeMoveInfo->vp;
    ptzAbsoluteMoveInfo.vt = ptzRelativeMoveInfo->vt;
    ptzAbsoluteMoveInfo.vz = ptzRelativeMoveInfo->vz;
    
    result = ONVIF_PTZAbsoluteMove(ptzXAddr, ProfileToken, &ptzAbsoluteMoveInfo);

    return result;
    
}

7.ONVIF_PTZContinuousMove()

int ONVIF_PTZContinuousMove(const std::string& ptzXAddr, const std::string& ProfileToken, enum PTZCMD cmd, float speed){
    int result = 0;
    struct soap *soap = nullptr;
    _tptz__ContinuousMove continuousMove;
    _tptz__ContinuousMoveResponse continuousMoveResponse;

    SOAP_ASSERT(!ptzXAddr.empty() && !ProfileToken.empty());
    SOAP_ASSERT(nullptr != (soap = ONVIF_soap_new(SOAP_SOCK_TIMEOUT)));

    ONVIF_SetAuthInfo(soap, USERNAME, PASSWORD);
    continuousMove.ProfileToken = const_cast<char *>(ProfileToken.c_str());
    continuousMove.Velocity = soap_new_tt__PTZSpeed(soap);
    continuousMove.Velocity->PanTilt = soap_new_tt__Vector2D(soap);
    continuousMove.Velocity->Zoom = soap_new_tt__Vector1D(soap);



    switch (cmd)
    {
        case  PTZ_CMD_LEFT:
            continuousMove.Velocity->PanTilt->x = -speed;
            continuousMove.Velocity->PanTilt->y = 0;
            break;
        case  PTZ_CMD_RIGHT:
            continuousMove.Velocity->PanTilt->x = speed;
            continuousMove.Velocity->PanTilt->y = 0;
            break;
        case  PTZ_CMD_UP:
            continuousMove.Velocity->PanTilt->x = 0;
            continuousMove.Velocity->PanTilt->y = speed;
            break;
        case  PTZ_CMD_DOWN:
            continuousMove.Velocity->PanTilt->x = 0;
            continuousMove.Velocity->PanTilt->y = -speed;
            break;
        case  PTZ_CMD_LEFTUP:
            continuousMove.Velocity->PanTilt->x = -speed;
            continuousMove.Velocity->PanTilt->y = speed;
            break;
        case PTZ_CMD_LEFTDOWN:
            continuousMove.Velocity->PanTilt->x = -speed;
            continuousMove.Velocity->PanTilt->y = -speed;
            break;
        case  PTZ_CMD_RIGHTUP:
            continuousMove.Velocity->PanTilt->x = speed;
            continuousMove.Velocity->PanTilt->y = speed;
            break;
        case PTZ_CMD_RIGHTDOWN:
            continuousMove.Velocity->PanTilt->x = speed;
            continuousMove.Velocity->PanTilt->y = -speed;
            break;
        case  PTZ_CMD_ZOOM_IN:
            continuousMove.Velocity->PanTilt->x = 0;
            continuousMove.Velocity->PanTilt->y = 0;
            continuousMove.Velocity->Zoom->x = speed;
            break;
        case  PTZ_CMD_ZOOM_OUT:
            continuousMove.Velocity->PanTilt->x = 0;
            continuousMove.Velocity->PanTilt->y = 0;
            continuousMove.Velocity->Zoom->x = -speed;
            break;
        default:
            break;
    }

    // 也可以使用soap_call___tptz__RelativeMove实现
    result = soap_call___tptz__ContinuousMove(soap,ptzXAddr.c_str(), nullptr,&continuousMove,continuousMoveResponse);
    SOAP_CHECK_ERROR(result, soap, "ONVIF_PTZAbsoluteMove");
 EXIT:
    if (nullptr != soap) {
        ONVIF_soap_delete(soap);
    }
    return result; 
  • 62
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Java实现ONVIF的PTZ控制,可以按照以下步骤进行: 1. 首先,需要通过Java的网络编程技术连接到ONVIF设备。可以使用Java的Socket类库来建立网络连接。为此,需要知道ONVIF设备的IP地址和口号。 2. 通过建立的网络连接,可以发送SOAP消息来实现PTZ控制。ONVIF协议是基于SOAP的,使用SOAP消息来与设备进行通信。SOAP消息包含了控制云台的指令,比如移动、变焦、调亮度等。 3. 需要熟悉ONVIF协议中与PTZ相关的消息格式和内容。ONVIF协议定义了一系列用于设备管理和控制的消息结构。可以通过查阅ONVIF协议的文档来了解如何构建PTZ控制相关的消息。 4. 解析设备返回的响应消息,根据响应结果判断控制是否成功。设备会返回一个SOAP响应消息,其中包含了对控制指令的处理结果。可以使用Java的XML解析库来解析返回的SOAP响应消息。 5. 根据需要编写Java代码来完成PTZ控制的具体功能。可以通过构建合适的SOAP消息发送给设备,实现云台的移动、变焦、调光等操作。 6. 进行测试和调试,确保PTZ控制功能正常工作。可以通过编写简单的Java应用程序来测试PTZ控制功能,模拟用户对云台的操作。 需要注意的是,使用Java实现ONVIF的PTZ控制需要熟悉ONVIF协议的相关内容,并了解SOAP消息的构成和解析过程。此外,还需要有一定的网络编程经验和Java编程能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值