Linux c++ onvif客户端开发(9):GetProfiles

发布于:2024-04-26 ⋅ 阅读:(25) ⋅ 点赞:(0)

本文是Linux c++ onvif客户端开发系列文章之一:

 1. 什么是Profile

这个接口的Profile可以理解为一条通道。 主码流、主码流是不同的通道,因此它们有不同的Profle。

每个Profile有独立的VideoSource,VideoEncoder,Analytics,Metadata等。

每个Profle的属性包括Profile token和Profile name。其中Profile token是很重要的属性,访问这个Profle属性的时候都会要求传这个数据。

2. Media2

Media2是https://www.onvif.org/onvif/ver20/media/wsdl/media.wsdl,这个规范支持H265。本文所讲解的也是这个规范。

3. GetProfiles

接口有两个可选参数Token和Type

ONVIF Device Test Tool 随手掏 

4. 获取所有 Profile token和name

发送

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <GetProfiles xmlns="http://www.onvif.org/ver20/media/wsdl">
      <Token>Profile000</Token>
    </GetProfiles>
  </s:Body>
</s:Envelope>

接收

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:sc="http://www.w3.org/2003/05/soap-encoding" xmlns:tr2="http://www.onvif.org/ver20/media/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema">
  <s:Body>
    <tr2:GetProfilesResponse>
      <tr2:Profiles token="Profile000" fixed="true">
        <tr2:Name>Profile000</tr2:Name>
      </tr2:Profiles>
      <tr2:Profiles token="Profile001" fixed="true">
        <tr2:Name>Profile001</tr2:Name>
      </tr2:Profiles>
    </tr2:GetProfilesResponse>
  </s:Body>
</s:Envelope>

token是很重要的数据,后面要考的。

C++实现

先声明

struct Media20Profile {
    std::string token;
    std::string name;
};

class Device {
public:
    Device(const std::string &ip, const std::string &user,
           const std::string &passwd, int default_timeout = 2);
    ~Device();

    int Probe(int timeout = 1);

    std::string xaddr() const { return xaddr_; }

    int GetDeviceInformation(DeviceInformation &device_info,
                             Fault *fault = nullptr);


    // 获取服务地址集
    int GetServices(std::map<std::string, Service> &services,
                    Fault *fault = nullptr);

    // 获取Profiles 名称和token
    int GetProfiles(std::vector<Media20Profile> &profiles,
                    Fault *fault = nullptr,
                    const std::string &media_xaddr = std::string());

    // 根据profile token 获取source 和video encoder配置
    int GetProfiles(ProfileConfigurations &profile_configurations,
                    const std::string &profile_token,
                    const std::string &media_xaddr = std::string());


private:
    std::string ip_;
    std::string username_;
    std::string password_;
    int default_timeout_;

    std::string xaddr_;
};

 实现

int Device::GetProfiles(std::vector<Media20Profile> &profiles, Fault *fault,
                        const std::string &media_xaddr) {
    //  xmlns:trt="http://www.onvif.org/ver10/media/wsdl
    //  xmlns:ns1="http://www.onvif.org/ver20/media/wsdl"

    std::unique_ptr<Soap> soap(new Soap(default_timeout_));

    soap_wsse_add_UsernameTokenDigest(soap->soap(), nullptr, username_.data(),
                                      password_.data());

    // 支持H265
    struct _ns1__GetProfiles media2_req;
    struct _ns1__GetProfilesResponse media2_resp;

    int result = 0;
    result = soap_call___ns1__GetProfiles(
        soap->soap(), media_xaddr.empty() ? xaddr_.data() : media_xaddr.data(),
        NULL, &media2_req, media2_resp);

    if (SOAP_OK != result) {
        soap->FillFault(fault);
    } else {
        for (auto &i : media2_resp.Profiles) {
            Media20Profile prof{.token = i->token, .name = i->Name};
            profiles.emplace_back(prof);
        }
    }

    return result;
}

media_xaddr 是通过GetServices拿到的数据,对应命名空间http://www.onvif.org/ver20/media/wsdl的 xaddr。一般也可以直接用设备的xaddr。

5. 获取Profles详细信息

如果请求里面指定 Token和Type,那么接口也会返回这个Profile的详细信息。比如视频源信息、视频编码器信息等。

发送

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <GetProfiles xmlns="http://www.onvif.org/ver20/media/wsdl">
      <Token>Profile000</Token>
      <Type>VideoEncoder</Type>
    </GetProfiles>
  </s:Body>
</s:Envelope>

接收

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:sc="http://www.w3.org/2003/05/soap-encoding" xmlns:tr2="http://www.onvif.org/ver20/media/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema">
  <s:Body>
    <tr2:GetProfilesResponse>
      <tr2:Profiles token="Profile000" fixed="true">
        <tr2:Name>Profile000</tr2:Name>
        <tr2:Configurations>
          <tr2:VideoEncoder token="VideoEncoder000" GovLength="16" Profile="Main">
            <tt:Name>VideoEncoder000</tt:Name>
            <tt:UseCount>1</tt:UseCount>
            <tt:Encoding>H265</tt:Encoding>
            <tt:Resolution>
              <tt:Width>1280</tt:Width>
              <tt:Height>960</tt:Height>
            </tt:Resolution>
            <tt:RateControl ConstantBitRate="false">
              <tt:FrameRateLimit>10</tt:FrameRateLimit>
              <tt:BitrateLimit>2304</tt:BitrateLimit>
            </tt:RateControl>
            <tt:Multicast>
              <tt:Address>
                <tt:Type>IPv4</tt:Type>
                <tt:IPv4Address>224.1.2.4</tt:IPv4Address>
              </tt:Address>
              <tt:Port>40000</tt:Port>
              <tt:TTL>64</tt:TTL>
              <tt:AutoStart>false</tt:AutoStart>
            </tt:Multicast>
            <tt:Quality>3.000000</tt:Quality>
          </tr2:VideoEncoder>
        </tr2:Configurations>
      </tr2:Profiles>
    </tr2:GetProfilesResponse>
  </s:Body>
</s:Envelope>

C++实现

声明

这里我只定义了VideoSource,VideoEncoder相关配置。


struct Resolution {
    int width = 0;
    int height = 0;
};

struct RateControl {
    bool constant_bit_rate = false;
    float frame_rate_limit = 0;
    int bitrate_limit = 0;
};

struct VideoSourceConfiguration {
    std::string token;
    std::string source_token;
    std::string name;
};

struct VideoEncoderConfiguration {
    // GetVideoEncoderConfigurations 中的token和name,不是profile token。示例:
    // token="VideoEncoder000"   <tt:Name>VideoEncoder000</tt:Name>
    std::string token;
    int gov_length = 0;
    // Baseline Main High
    std::string profile;

    std::string name;
    std::string encoding;

    Resolution resolution;
    RateControl rate_control;

    float quality = 0;
};

struct ProfileConfigurations {
    Media20Profile profile;
    VideoSourceConfiguration video_source_config;
    VideoEncoderConfiguration video_encoder_config;
};

实现


int Device::GetProfiles(ProfileConfigurations &profile_configurations,
                        const std::string &token,
                        const std::string &media_xaddr) {

    std::unique_ptr<Soap> soap(new Soap(default_timeout_));

    soap_wsse_add_UsernameTokenDigest(soap->soap(), nullptr, username_.data(),
                                      password_.data());

    // 支持H265
    struct _ns1__GetProfiles media2_req;
    struct _ns1__GetProfilesResponse media2_resp;

    std::string profile_token(token);
    media2_req.Token = &profile_token;
    media2_req.Type.push_back(soap_ns1__ConfigurationEnumeration2s(
        soap->soap(), ns1__ConfigurationEnumeration::VideoSource));
    media2_req.Type.push_back(soap_ns1__ConfigurationEnumeration2s(
        soap->soap(), ns1__ConfigurationEnumeration::VideoEncoder));

    int result = 0;
    result = soap_call___ns1__GetProfiles(
        soap->soap(), media_xaddr.empty() ? xaddr_.data() : media_xaddr.data(),
        NULL, &media2_req, media2_resp);

    if (SOAP_OK != result) {
        return result;
    }

    for (auto &i : media2_resp.Profiles) {
        profile_configurations.profile.name = i->Name;
        profile_configurations.profile.token = i->token;

        if (i->Configurations) {
            if (i->Configurations->VideoSource) {
                auto vs = i->Configurations->VideoSource;
                profile_configurations.video_source_config.token = vs->token;
                profile_configurations.video_source_config.source_token =
                    vs->SourceToken;
                profile_configurations.video_source_config.name = vs->Name;
            }

            if (i->Configurations->VideoEncoder) {
                auto ve = i->Configurations->VideoEncoder;

                profile_configurations.video_encoder_config.token = ve->token;
                profile_configurations.video_encoder_config.gov_length =
                    *ve->GovLength;

                profile_configurations.video_encoder_config.profile =
                    *ve->Profile;
                profile_configurations.video_encoder_config.name = ve->Name;
                profile_configurations.video_encoder_config.encoding =
                    ve->Encoding;
                profile_configurations.video_encoder_config.resolution.width =
                    ve->Resolution->Width;
                profile_configurations.video_encoder_config.resolution.height =
                    ve->Resolution->Height;
                profile_configurations.video_encoder_config.rate_control
                    .constant_bit_rate = *ve->RateControl->ConstantBitRate;
                profile_configurations.video_encoder_config.rate_control
                    .bitrate_limit = ve->RateControl->BitrateLimit;
                profile_configurations.video_encoder_config.rate_control
                    .frame_rate_limit = ve->RateControl->FrameRateLimit;
                profile_configurations.video_encoder_config.quality =
                    ve->Quality;
            }
        }
    }

    return result;
}

6. 后记

1. 其他功能比如AudioSource, AudioEncoder自己去扩展

2. Soap,Fault 的定义参考前面文章 Linux c++ onvif客户端开发(7):struct soap包装类


网站公告

今日签到

点亮在社区的每一天
去签到