当前位置: 首页 > article >正文

Onvif服务端开发

实现了Onvif服务端的设备搜索和RTSP流的功能。用 ONVIF Device Manager 测试工具可以成功搜索到设备和获取到RTSP流,有的路由器可能不支持239.255.255.250组播,我一开始用的电信的那种光猫路由器二合一的,一直搜不到设备,后面用Socket调试工具发现根本收不到组播消息,换了个小米的路由器就可以了🥲。RTSP服务端我是直接用的 live555, 完整代码我已上传,不需要积分就能下载。主要是看onvif_server.c 和 onvif_server_interface.c 文件,onvif_server.c 主要是创建socket服务,onvif_server_interface.c 主要是实现相关的onvif服务接口。相关代码如下:

onvif_server.c:

#include <pthread.h>
#include "soapH.h"
#include "macro.h"

void *onvif_discovered_server(void *arg)
{
    struct soap soap_udp;
    int socked_fd;

    // 初始化 SOAP 服务器对象
    soap_init1(&soap_udp, SOAP_IO_UDP | SOAP_XML_IGNORENS);
    soap_udp.bind_flags = SO_REUSEADDR; // 允许重复绑定
    soap_udp.port = 3702;

    soap_set_namespaces(&soap_udp, namespaces);

    // 绑定端口
    socked_fd = soap_bind(&soap_udp, NULL, soap_udp.port, 10);
    if (socked_fd < 0)
    {
        printf("%d soap_bind failed\n", __LINE__);
        soap_print_fault(&soap_udp, stderr);
        goto end;
    }

    // 加入组播
    struct ip_mreq mreqcon;
    mreqcon.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
    mreqcon.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(soap_udp.master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreqcon, sizeof(mreqcon)) < 0)
    {
        printf("setsockopt error, error message: %s\n", strerror(errno));
        goto end;
    }

    while (1)
    {
        socked_fd = soap_serve(&soap_udp);
        if (socked_fd != SOAP_OK)
        {
            printf("%d soap_serve failed\n", __LINE__);
            soap_print_fault(&soap_udp, stderr);
        }

        soap_destroy(&soap_udp);
        soap_end(&soap_udp);
    }

end:
    soap_done(&soap_udp);
    return NULL;
}

int http_get(struct soap *soap)
{
    FILE *fd = NULL;
    static char buf[1024 * 5] = {0};

    fd = fopen(PATH_HTML, "rb");
    if (!fd)
        return 404;
    if (soap_response(soap, SOAP_HTML) == SOAP_OK) // HTTP response header with text/html
    {
        size_t r = fread(buf, 1, sizeof(buf), fd);
        if (r > 0)
            soap_send(soap, buf);
    }

    soap_end_send(soap);
    fclose(fd);

    return SOAP_OK;
}

void *onvif_http_server(void *arg)
{
    struct soap soap_tcp;
    int socked_fd;
    fd_set readfds;
    struct timeval timeout;

    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    soap_init1(&soap_tcp, SOAP_XML_INDENT);
    soap_tcp.port = DEVICE_PORT;
    soap_tcp.bind_flags = SO_REUSEADDR;
    soap_tcp.send_timeout = 3; // send timeout is 3s
    soap_tcp.recv_timeout = 3; // receive timeout is 3s
    soap_tcp.fget = http_get;

    soap_set_namespaces(&soap_tcp, namespaces);

    socked_fd = soap_bind(&soap_tcp, DEVICE_IP, soap_tcp.port, 10);
    if (socked_fd < 0)
    {
        printf("%d soap_bind failed\n", __LINE__);
        soap_print_fault(&soap_tcp, stderr);
        goto end;
    }

    int socked_fd_new = -1;
    while (1)
    {
        socked_fd_new = soap_accept(&soap_tcp);
        if (!soap_valid_socket(socked_fd_new))
        {
            printf("soap_accept failed\n");
            soap_print_fault(&soap_tcp, stderr);
            goto end;
        }

        FD_ZERO(&readfds);
        FD_SET(socked_fd_new, &readfds);

        int activity = select(socked_fd_new + 1, &readfds, NULL, NULL, &timeout);
        if (activity < 0)
        {
            printf("select error\n");
            goto end;
        }

        if (FD_ISSET(socked_fd_new, &readfds))
        {
            if (soap_serve(&soap_tcp) != SOAP_OK)
            {
                printf("%d soap_serve failed, error: %d\n", __LINE__, soap_tcp.error);
                soap_print_fault(&soap_tcp, stderr);
            }
        }

        soap_destroy(&soap_tcp);
        soap_end(&soap_tcp);
    }

end:
    soap_done(&soap_tcp);
    return NULL;
}

int create_onvif_server()
{
    pthread_t thread1, thread2;
    pthread_attr_t attr1, attr2;

    pthread_attr_init(&attr1);
    pthread_attr_init(&attr2);

    pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED);
    pthread_attr_setdetachstate(&attr2, PTHREAD_CREATE_DETACHED);

    if (pthread_create(&thread1, &attr1, onvif_discovered_server, NULL) != 0)
        return -1;
    if (pthread_create(&thread2, &attr2, onvif_http_server, NULL) != 0)
        return -1;

    pthread_attr_destroy(&attr1);
    pthread_attr_destroy(&attr2);

    return 0;
}

 onvif_server_interface.c,这里只写出已经实现了的接口函数:

#include "wsaapi.h"
#include "soapH.h"
#include "soapStub.h"
#include "macro.h"
#include "wsseapi.h"

// 该函数从 soapClient.c 文件中拷贝过来的
SOAP_FMAC5 int SOAP_FMAC6 soap_send___wsdd__ProbeMatches(struct soap *soap, const char *soap_endpoint, const char *soap_action, struct wsdd__ProbeMatchesType *wsdd__ProbeMatches)
{
    struct __wsdd__ProbeMatches soap_tmp___wsdd__ProbeMatches;
    if (soap_action == NULL)
        soap_action = "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01/ProbeMatches";
    soap_tmp___wsdd__ProbeMatches.wsdd__ProbeMatches = wsdd__ProbeMatches;
    soap_begin(soap);
    soap_set_version(soap, 2);  /* use SOAP1.2 */
    soap->encodingStyle = NULL; /* use SOAP literal style */
    soap_serializeheader(soap);
    soap_serialize___wsdd__ProbeMatches(soap, &soap_tmp___wsdd__ProbeMatches);
    if (soap_begin_count(soap))
        return soap->error;
    if ((soap->mode & SOAP_IO_LENGTH))
    {
        if (soap_envelope_begin_out(soap) || soap_putheader(soap) || soap_body_begin_out(soap) || soap_put___wsdd__ProbeMatches(soap, &soap_tmp___wsdd__ProbeMatches, "-wsdd:ProbeMatches", "") || soap_body_end_out(soap) || soap_envelope_end_out(soap))
            return soap->error;
    }
    if (soap_end_count(soap))
        return soap->error;
    if (soap_connect(soap, soap_endpoint, soap_action) || soap_envelope_begin_out(soap) || soap_putheader(soap) || soap_body_begin_out(soap) || soap_put___wsdd__ProbeMatches(soap, &soap_tmp___wsdd__ProbeMatches, "-wsdd:ProbeMatches", "") || soap_body_end_out(soap) || soap_envelope_end_out(soap) || soap_end_send(soap))
        return soap_closesock(soap);
    return SOAP_OK;
}

// 鉴权
int onvif_access_control(struct soap *soap)

{
    const char *username = soap_wsse_get_Username(soap);
    if (!username)
    {
        soap_wsse_delete_Security(soap); // remove old security headers before returning!
        return soap->error;              // no username: return FailedAuthentication (from soap_wsse_get_Username)
    }

    if (strcmp(username, USERNAME) != 0)
    {
        printf("username error\n");
        soap_wsse_delete_Security(soap);
        return 401;
    }

    if (soap_wsse_verify_Password(soap, PASSWORD))
    {
        soap_wsse_delete_Security(soap); // remove old security headers before returning!
        return soap->error;              // no username: return FailedAuthentication (from soap_wsse_verify_Password)
    }

    return 0;
}

// 实现 __wsdd__Probe 函数,用于处理 WS-Discovery Probe 请求
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Probe(struct soap *soap, struct wsdd__ProbeType *wsdd__Probe)
{
    printf("-------- %s --------\n", __func__);

    // 定义一个 ProbeMatches 结构,用于存储多个 ProbeMatch 条目
    struct wsdd__ProbeMatchesType ProbeMatches;

    // 假设设备仅有一个匹配项 (一个服务)
    int MatchSize = 1;

    // 初始化 ProbeMatches 结构,清零内存
    memset(&ProbeMatches, 0, sizeof(ProbeMatches));

    // 分配内存给 ProbeMatch 数组
    // 使用 soap_malloc 分配内存,这样 gSOAP 可以自动管理其生命周期
    ProbeMatches.ProbeMatch = (struct wsdd__ProbeMatchType *)soap_malloc(soap, sizeof(struct wsdd__ProbeMatchType) * MatchSize);
    if (!ProbeMatches.ProbeMatch)
        return SOAP_FAULT; // 内存分配失败,返回 SOAP Fault
    // 初始化 ProbeMatches.ProbeMatch
    soap_default_wsdd__ProbeMatchType(soap, ProbeMatches.ProbeMatch);

    // 设置实际的 ProbeMatch 数量
    ProbeMatches.__sizeProbeMatch = MatchSize;

    // 获取第一个(也是唯一一个) ProbeMatch 条目
    struct wsdd__ProbeMatchType *ProbeMatch = &ProbeMatches.ProbeMatch[0];

    // ----------------------------
    // 填充 EndpointReference 信息
    // ----------------------------
    /*
     * EndpointReference 用于标识设备的唯一地址 (URI)。
     * 通常使用设备的 UUID 来生成一个 URN 格式的地址。
     */
    ProbeMatch->wsa__EndpointReference.Address = (char *)soap_malloc(soap, 256);
    if (!ProbeMatch->wsa__EndpointReference.Address)
        return SOAP_FAULT;
    // 格式化地址为 "urn:uuid:device_uuid"
    snprintf(ProbeMatch->wsa__EndpointReference.Address, 256, "urn:uuid:%s", "12345678-1234-1234-1234-1234567890ab");

    // -------------------
    // 填充 Types 信息
    // -------------------
    /*
     * Types 用于描述设备的类型,根据 ONVIF 规范,通常包括设备提供的服务类型。
     * 例如,"tdn:NetworkVideoTransmitter" 表示设备是一个网络视频传输器。
     */
    ProbeMatch->Types = (char *)soap_malloc(soap, 256);
    if (!ProbeMatch->Types)
        return SOAP_FAULT;
    strcpy(ProbeMatch->Types, "tdn:NetworkVideoTransmitter");

    // -------------------
    // 填充 Scopes 信息
    // -------------------
    /*
     * Scopes 用于描述设备的作用域信息,提供更详细的设备分类和属性。
     * 例如,设备类型、制造商、型号、位置等。
     * 作用域以空格分隔的 URI 形式表示。
     */
    ProbeMatch->Scopes = (struct wsdd__ScopesType *)soap_malloc(soap, sizeof(struct wsdd__ScopesType));
    if (!ProbeMatch->Scopes)
        return SOAP_FAULT;
    ProbeMatch->Scopes->__item = (char *)soap_malloc(soap, 512);
    if (!ProbeMatch->Scopes->__item)
        return SOAP_FAULT;
    // 示例作用域信息,根据实际情况调整
    snprintf(ProbeMatch->Scopes->__item, 512,
             "onvif://www.onvif.org/type/video_encoder "
             "onvif://www.onvif.org/type/audio_encoder "
             "onvif://www.onvif.org/hardware/%s "
             "onvif://www.onvif.org/name/%s",
             "MyDeviceHardware", "MyONVIFDevice");

    // -------------------
    // 填充 XAddrs 信息
    // -------------------
    /*
     * XAddrs 提供设备服务的访问地址 (URL),通常包括 HTTP 或 HTTPS 地址。
     * 该地址用于访问设备的 Onvif 服务,如设备管理、媒体服务等。
     */
    ProbeMatch->XAddrs = (char *)soap_malloc(soap, 256);
    if (!ProbeMatch->XAddrs)
        return SOAP_FAULT;
    // 格式化服务访问地址
    snprintf(ProbeMatch->XAddrs, 256, "http://%s:%d/onvif/device_service", DEVICE_IP, DEVICE_PORT);

    // ---------------------------
    // 填充 MetadataVersion 信息
    // ---------------------------
    /*
     * MetadataVersion 表示设备元数据的版本号,用于跟踪设备描述的变化。
     * 每当设备的元数据(如服务列表、配置等)发生变化时,应递增此版本号。
     */
    ProbeMatch->MetadataVersion = 1;

    // Build SOAP Header
    soap->header->wsa__RelatesTo = (struct wsa__Relationship *)soap_malloc(soap, sizeof(struct wsa__Relationship));
    if (!soap->header->wsa__RelatesTo)
        return SOAP_FAULT;
    // 初始化 soap->header->wsa__RelatesTo
    soap_default__wsa__RelatesTo(soap, soap->header->wsa__RelatesTo);

    soap->header->wsa__RelatesTo->__item = soap->header->wsa__MessageID;
    soap->header->wsa__Action = soap_strdup(soap, "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches");
    soap->header->wsa__To = soap_strdup(soap, "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous");

    // 发送 ProbeMatches 响应
    return soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &ProbeMatches);
}

SOAP_FMAC5 int SOAP_FMAC6 __tds__GetCapabilities(struct soap *soap, struct _tds__GetCapabilities *tds__GetCapabilities, struct _tds__GetCapabilitiesResponse *tds__GetCapabilitiesResponse)
{
    printf("-------- %s --------\n", __func__);

    /*
    int ret = onvif_access_control(soap);
    if (ret != 0)
        return ret;
    */

    tds__GetCapabilitiesResponse->Capabilities = (struct tt__Capabilities *)soap_malloc(soap, sizeof(struct tt__Capabilities));
    memset(tds__GetCapabilitiesResponse->Capabilities, 0, sizeof(struct tt__Capabilities));

    // Media
    if (tds__GetCapabilities->Category[0] == tt__CapabilityCategory__Media ||
        tds__GetCapabilities->Category[0] == tt__CapabilityCategory__All)
    {
        tds__GetCapabilitiesResponse->Capabilities->Media = (struct tt__MediaCapabilities *)soap_malloc(soap, sizeof(struct tt__MediaCapabilities));
        memset(tds__GetCapabilitiesResponse->Capabilities->Media, 0, sizeof(struct tt__MediaCapabilities));
        tds__GetCapabilitiesResponse->Capabilities->Media->XAddr = (char *)soap_malloc(soap, sizeof(char) * 256);
        memset(tds__GetCapabilitiesResponse->Capabilities->Media->XAddr, 0, sizeof(char) * 256);
        sprintf(tds__GetCapabilitiesResponse->Capabilities->Media->XAddr, "http://%s:%d/onvif/media_service", DEVICE_IP, DEVICE_PORT);
        //<Media><StreamingCapabilities>
        tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities = (struct tt__RealTimeStreamingCapabilities *)soap_malloc(soap, sizeof(struct tt__RealTimeStreamingCapabilities));
        memset(tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities, 0, sizeof(struct tt__RealTimeStreamingCapabilities));
        tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities->RTPMulticast = (enum xsd__boolean *)soap_malloc(soap, sizeof(enum xsd__boolean));
        *(tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities->RTPMulticast) = xsd__boolean__false_; // 表示设备不支持RTP的多播功能
        tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities->RTP_USCORERTSP_USCORETCP = (enum xsd__boolean *)soap_malloc(soap, sizeof(enum xsd__boolean));
        *(tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities->RTP_USCORERTSP_USCORETCP) = xsd__boolean__true_; // 表示设备支持通过RTSP的TCP传输方式
        tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities->RTP_USCORETCP = (enum xsd__boolean *)soap_malloc(soap, sizeof(enum xsd__boolean));
        *(tds__GetCapabilitiesResponse->Capabilities->Media->StreamingCapabilities->RTP_USCORETCP) = xsd__boolean__true_; // 表示设备支持RTP协议的TCP传输方式
    }

    // 返回成功
    return SOAP_OK;
}

SOAP_FMAC5 int SOAP_FMAC6 __trt__GetVideoSources(struct soap *soap, struct _trt__GetVideoSources *trt__GetVideoSources, struct _trt__GetVideoSourcesResponse *trt__GetVideoSourcesResponse)
{
    printf("-------- %s --------\n", __func__);

    int size = 1;
    trt__GetVideoSourcesResponse->__sizeVideoSources = size;
    trt__GetVideoSourcesResponse->VideoSources = (struct tt__VideoSource *)soap_malloc(soap, sizeof(struct tt__VideoSource) * size);
    memset(trt__GetVideoSourcesResponse->VideoSources, 0, sizeof(struct tt__VideoSource) * trt__GetVideoSourcesResponse->__sizeVideoSources);

    trt__GetVideoSourcesResponse->VideoSources->token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetVideoSourcesResponse->VideoSources->token, 0, sizeof(char) * 32);
    strcpy(trt__GetVideoSourcesResponse->VideoSources->token, "vs_SourceToken");

    trt__GetVideoSourcesResponse->VideoSources->Resolution = (struct tt__VideoResolution *)soap_malloc(soap, sizeof(struct tt__VideoResolution));
    memset(trt__GetVideoSourcesResponse->VideoSources->Resolution, 0, sizeof(struct tt__VideoResolution));
    trt__GetVideoSourcesResponse->VideoSources->Resolution->Width = VIDEO_WIDTH;
    trt__GetVideoSourcesResponse->VideoSources->Resolution->Height = VIDEO_HEIGHT;
    trt__GetVideoSourcesResponse->VideoSources->Framerate = FRAME_RATE;

    return SOAP_OK;
}

SOAP_FMAC5 int SOAP_FMAC6 __trt__GetProfile(struct soap *soap, struct _trt__GetProfile *trt__GetProfile, struct _trt__GetProfileResponse *trt__GetProfileResponse)
{
    printf("-------- %s --------\n", __func__);

    trt__GetProfileResponse->Profile = (struct tt__Profile *)soap_malloc(soap, sizeof(struct tt__Profile));
    memset(trt__GetProfileResponse->Profile, 0, sizeof(struct tt__Profile));

    trt__GetProfileResponse->Profile->Name = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfileResponse->Profile->Name, 0, sizeof(char) * 32);
    strcpy(trt__GetProfileResponse->Profile->Name, "MyProfile");
    trt__GetProfileResponse->Profile->token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfileResponse->Profile->token, 0, sizeof(char) * 32);
    strcpy(trt__GetProfileResponse->Profile->token, "ProfileToken");
    trt__GetProfileResponse->Profile->fixed = (enum xsd__boolean *)soap_malloc(soap, sizeof(enum xsd__boolean));
    *(trt__GetProfileResponse->Profile->fixed) = xsd__boolean__true_;

    // <VideoSourceConfiguration><name>和<VideoSourceConfiguration><token>
    trt__GetProfileResponse->Profile->VideoSourceConfiguration = (struct tt__VideoSourceConfiguration *)soap_malloc(soap, sizeof(struct tt__VideoSourceConfiguration));
    memset(trt__GetProfileResponse->Profile->VideoSourceConfiguration, 0, sizeof(struct tt__VideoSourceConfiguration));
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->Name = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfileResponse->Profile->VideoSourceConfiguration->Name, 0, sizeof(char) * 32);
    strcpy(trt__GetProfileResponse->Profile->VideoSourceConfiguration->Name, "vs_name");
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfileResponse->Profile->VideoSourceConfiguration->token, 0, sizeof(char) * 32);
    strcpy(trt__GetProfileResponse->Profile->VideoSourceConfiguration->token, "vs_token");
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->SourceToken = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfileResponse->Profile->VideoSourceConfiguration->SourceToken, 0, sizeof(char) * 32);
    strcpy(trt__GetProfileResponse->Profile->VideoSourceConfiguration->SourceToken, "vs_SourceToken");
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->UseCount = 1;
    // <VideoSourceConfiguration><Bounds>
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->Bounds = (struct tt__IntRectangle *)soap_malloc(soap, sizeof(struct tt__IntRectangle));
    memset(trt__GetProfileResponse->Profile->VideoSourceConfiguration->Bounds, 0, sizeof(struct tt__IntRectangle));
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->Bounds->x = 0;
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->Bounds->y = 0;
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->Bounds->width = VIDEO_WIDTH;
    trt__GetProfileResponse->Profile->VideoSourceConfiguration->Bounds->height = VIDEO_HEIGHT;

    // <VideoEncoderConfiguration>
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration = (struct tt__VideoEncoderConfiguration *)soap_malloc(soap, sizeof(struct tt__VideoEncoderConfiguration));
    memset(trt__GetProfileResponse->Profile->VideoEncoderConfiguration, 0, sizeof(struct tt__VideoEncoderConfiguration));
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Name = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Name, 0, sizeof(char) * 32);
    strcpy(trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Name, "ve_name");
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfileResponse->Profile->VideoEncoderConfiguration->token, 0, sizeof(char) * 32);
    strcpy(trt__GetProfileResponse->Profile->VideoEncoderConfiguration->token, "ve_token");
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->UseCount = 1;
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Encoding = tt__VideoEncoding__H264;
    // <VideoEncoderConfiguration><Resolution>、<RateControl>
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Resolution = (struct tt__VideoResolution *)soap_malloc(soap, sizeof(struct tt__VideoResolution));
    memset(trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Resolution, 0, sizeof(struct tt__VideoResolution));
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Resolution->Width = VIDEO_WIDTH;
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Resolution->Height = VIDEO_HEIGHT;
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->Quality = 10;
    // <VideoEncoderConfiguration><RateControl>
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->RateControl = (struct tt__VideoRateControl *)soap_malloc(soap, sizeof(struct tt__VideoRateControl));
    memset(trt__GetProfileResponse->Profile->VideoEncoderConfiguration->RateControl, 0, sizeof(struct tt__VideoRateControl));
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->RateControl->FrameRateLimit = FRAME_RATE;
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->RateControl->EncodingInterval = 1;
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->RateControl->BitrateLimit = 6000;
    // <VideoEncoderConfiguration><H264>
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->H264 = (struct tt__H264Configuration *)soap_malloc(soap, sizeof(struct tt__H264Configuration));
    memset(trt__GetProfileResponse->Profile->VideoEncoderConfiguration->H264, 0, sizeof(struct tt__H264Configuration));
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->H264->GovLength = 120;
    trt__GetProfileResponse->Profile->VideoEncoderConfiguration->H264->H264Profile = tt__H264Profile__High;

    return SOAP_OK;
}

SOAP_FMAC5 int SOAP_FMAC6 __trt__GetProfiles(struct soap *soap, struct _trt__GetProfiles *trt__GetProfiles, struct _trt__GetProfilesResponse *trt__GetProfilesResponse)
{
    printf("-------- %s --------\n", __func__);

    trt__GetProfilesResponse->__sizeProfiles = 1;
    trt__GetProfilesResponse->Profiles = (struct tt__Profile *)soap_malloc(soap, sizeof(struct tt__Profile) * trt__GetProfilesResponse->__sizeProfiles);
    memset(trt__GetProfilesResponse->Profiles, 0, sizeof(struct tt__Profile) * trt__GetProfilesResponse->__sizeProfiles);

    int i = 0;
    trt__GetProfilesResponse->Profiles[i].Name = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfilesResponse->Profiles[i].Name, 0, sizeof(char) * 32);
    strcpy(trt__GetProfilesResponse->Profiles[i].Name, "MyProfile");
    trt__GetProfilesResponse->Profiles[i].token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfilesResponse->Profiles[i].token, 0, sizeof(char) * 32);
    strcpy(trt__GetProfilesResponse->Profiles[i].token, "ProfileToken");

    // <VideoSourceConfiguration><name>
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration = (struct tt__VideoSourceConfiguration *)soap_malloc(soap, sizeof(struct tt__VideoSourceConfiguration));
    memset(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration, 0, sizeof(struct tt__VideoSourceConfiguration));
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Name = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Name, 0, sizeof(char) * 32);
    strcpy(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Name, "vs_name");
    // <VideoSourceConfiguration><token>
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->token, 0, sizeof(char) * 32);
    strcpy(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->token, "vs_token");
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->SourceToken = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->SourceToken, 0, sizeof(char) * 32);
    strcpy(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->SourceToken, "vs_SourceToken");
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->UseCount = 1; // 表示该视频源配置的使用次数
    // <VideoSourceConfiguration><Bounds>
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Bounds = (struct tt__IntRectangle *)soap_malloc(soap, sizeof(struct tt__IntRectangle));
    memset(trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Bounds, 0, sizeof(struct tt__IntRectangle));
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Bounds->x = 0;
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Bounds->y = 0;
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Bounds->width = VIDEO_WIDTH;
    trt__GetProfilesResponse->Profiles[i].VideoSourceConfiguration->Bounds->height = VIDEO_HEIGHT;

    // <VideoEncoderConfiguration>
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration = (struct tt__VideoEncoderConfiguration *)soap_malloc(soap, sizeof(struct tt__VideoEncoderConfiguration));
    memset(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration, 0, sizeof(struct tt__VideoEncoderConfiguration));
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Name = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Name, 0, sizeof(char) * 32);
    strcpy(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Name, "ve_name");
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->token, 0, sizeof(char) * 32);
    strcpy(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->token, "ve_token");
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->UseCount = 1;                       // 表示视频编码配置的使用次数
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Encoding = tt__VideoEncoding__H264; // 视频编码格式
    // <VideoEncoderConfiguration><Resolution>
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Resolution = (struct tt__VideoResolution *)soap_malloc(soap, sizeof(struct tt__VideoResolution));
    memset(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Resolution, 0, sizeof(struct tt__VideoResolution));
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Resolution->Width = VIDEO_WIDTH;
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Resolution->Height = VIDEO_HEIGHT;
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->Quality = 10; //  视频质量
    // <VideoEncoderConfiguration><RateControl>
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->RateControl = (struct tt__VideoRateControl *)soap_malloc(soap, sizeof(struct tt__VideoRateControl));
    memset(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->RateControl, 0, sizeof(struct tt__VideoRateControl));
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->RateControl->FrameRateLimit = FRAME_RATE; // 帧率
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->RateControl->EncodingInterval = 1;        // 编码间隔
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->RateControl->BitrateLimit = 3000;         // 比特率限制
    // <VideoEncoderConfiguration><H264>
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->H264 = (struct tt__H264Configuration *)soap_malloc(soap, sizeof(struct tt__H264Configuration));
    memset(trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->H264, 0, sizeof(struct tt__H264Configuration));
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->H264->GovLength = 120;                     // GOP长度
    trt__GetProfilesResponse->Profiles[i].VideoEncoderConfiguration->H264->H264Profile = tt__H264Profile__High; // H.264 Profile

    return SOAP_OK;
}

SOAP_FMAC5 int SOAP_FMAC6 __trt__GetVideoSourceConfiguration(struct soap *soap, struct _trt__GetVideoSourceConfiguration *trt__GetVideoSourceConfiguration, struct _trt__GetVideoSourceConfigurationResponse *trt__GetVideoSourceConfigurationResponse)
{
    printf("-------- %s --------\n", __func__);

    trt__GetVideoSourceConfigurationResponse->Configuration = (struct tt__VideoSourceConfiguration *)soap_malloc(soap, sizeof(struct tt__VideoSourceConfiguration));
    memset(trt__GetVideoSourceConfigurationResponse->Configuration, 0, sizeof(struct tt__VideoSourceConfiguration));

    trt__GetVideoSourceConfigurationResponse->Configuration->UseCount = 1;
    trt__GetVideoSourceConfigurationResponse->Configuration->Name = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetVideoSourceConfigurationResponse->Configuration->Name, 0, sizeof(char) * 32);
    trt__GetVideoSourceConfigurationResponse->Configuration->token = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetVideoSourceConfigurationResponse->Configuration->token, 0, sizeof(char) * 32);
    strcpy(trt__GetVideoSourceConfigurationResponse->Configuration->Name, "vs_name");
    strcpy(trt__GetVideoSourceConfigurationResponse->Configuration->token, "vs_token");

    trt__GetVideoSourceConfigurationResponse->Configuration->SourceToken = (char *)soap_malloc(soap, sizeof(char) * 32);
    memset(trt__GetVideoSourceConfigurationResponse->Configuration->SourceToken, 0, sizeof(char) * 32);
    strcpy(trt__GetVideoSourceConfigurationResponse->Configuration->SourceToken, "vs_SourceToken");

    trt__GetVideoSourceConfigurationResponse->Configuration->Bounds = (struct tt__IntRectangle *)soap_malloc(soap, sizeof(struct tt__IntRectangle));
    memset(trt__GetVideoSourceConfigurationResponse->Configuration->Bounds, 0, sizeof(struct tt__IntRectangle));
    trt__GetVideoSourceConfigurationResponse->Configuration->Bounds->x = 0;
    trt__GetVideoSourceConfigurationResponse->Configuration->Bounds->y = 0;
    trt__GetVideoSourceConfigurationResponse->Configuration->Bounds->width = VIDEO_WIDTH;
    trt__GetVideoSourceConfigurationResponse->Configuration->Bounds->height = VIDEO_HEIGHT;

    return SOAP_OK;
}

SOAP_FMAC5 int SOAP_FMAC6 __trt__GetStreamUri(struct soap *soap, struct _trt__GetStreamUri *trt__GetStreamUri, struct _trt__GetStreamUriResponse *trt__GetStreamUriResponse)
{
    printf("-------- %s --------\n", __func__);

    trt__GetStreamUriResponse->MediaUri = (struct tt__MediaUri *)soap_malloc(soap, sizeof(struct tt__MediaUri));
    memset(trt__GetStreamUriResponse->MediaUri, 0, sizeof(struct tt__MediaUri));

    trt__GetStreamUriResponse->MediaUri->Uri = (char *)soap_malloc(soap, sizeof(char) * 256);
    memset(trt__GetStreamUriResponse->MediaUri->Uri, 0, sizeof(char) * 256);
    sprintf(trt__GetStreamUriResponse->MediaUri->Uri, RTSP_URL);
    trt__GetStreamUriResponse->MediaUri->InvalidAfterConnect = xsd__boolean__true_;
    trt__GetStreamUriResponse->MediaUri->InvalidAfterReboot = xsd__boolean__true_;
    // 超时时间
    trt__GetStreamUriResponse->MediaUri->Timeout = 200;

    return 0;
}

参考了这个项目中的源码:onvif-server-with-rtsp

我的另一篇博客:Ubuntu 编译gSOAP库,并生成ONVIF代码框架_gsoap 生成-CSDN博客

相关资料:一个比较完善的Onvif服务端 ,不过源码要钱:happytimesoft

 


http://www.kler.cn/a/448121.html

相关文章:

  • microk8s使用
  • ROS1安装教程
  • 【Leetcode 热题 100】124. 二叉树中的最大路径和
  • 【Linux系统编程】:信号(2)——信号的产生
  • Connecting to Oracle 11g Database in Python
  • 圣诞快乐(h5 css js(圣诞树))
  • C++ 集合 list 使用
  • 【CSS in Depth 2 精译_085】14.2:CSS 蒙版的用法
  • YOLOv11模型改进-模块-引入多尺度前馈网络MSFN 用于解决噪声
  • MFC/C++学习系列之简单记录7
  • 前端优化之图片
  • 一区牛顿-拉夫逊算法+分解+深度学习!VMD-NRBO-Transformer-GRU多变量时间序列光伏功率预测
  • hive架构简述
  • Android Retrofit2OkHttp3添加统一的请求头Header
  • 基于前端技术UniApp和后端技术Node.js的电影购票系统
  • 基于LabVIEW的USRP信道测量开发
  • Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
  • 数智化医院分布式计算框架融合人工智能方向初步实现与能力转换浅析
  • 数位dp-acwing(数字游戏)
  • 基于单片机的步进电机控制系统的设计研究
  • 数据结构 (队列略版)
  • TCP常见问题
  • 如何在Ubuntu上利用Docker和Cpolar实现Excalidraw公网访问高效绘图——“cpolar内网穿透”
  • [极客大挑战 2019]HardSQL 1
  • 豆包MarsCode:小T的密码变换规则
  • RLDP(快速链路检测)防环