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 3ssoap_tcp.recv_timeout = 3; // receive timeout is 3ssoap_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.ProbeMatchsoap_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 Headersoap->header->wsa__RelatesTo = (struct wsa__Relationship *)soap_malloc(soap, sizeof(struct wsa__Relationship));if (!soap->header->wsa__RelatesTo)return SOAP_FAULT;// 初始化 soap->header->wsa__RelatesTosoap_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));// Mediaif (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 Profilereturn 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
相关文章:

Onvif服务端开发
实现了Onvif服务端的设备搜索和RTSP流的功能。用 ONVIF Device Manager 测试工具可以成功搜索到设备和获取到RTSP流,有的路由器可能不支持239.255.255.250组播,我一开始用的电信的那种光猫路由器二合一的,一直搜不到设备,后面用So…...

【jvm】主要参数
Java 虚拟机(JVM)有许多参数用于控制其行为和性能,下面是一些 主要的 JVM 启动参数,这些参数通常分为以下几类: 内存管理相关参数 这些参数主要用来配置 JVM 的内存分配策略、堆内存、栈内存等。 -Xms 设置 JVM 启动…...

【优选算法】—移动零(双指针算法)
云边有个稻草人-CSDN博客 想当一名牛的程序员怎么能少的了练习算法呢?! 今天就立即开启一个新专栏,专干算法,提高算法能力(废柴的我也在准备蓝桥杯哈哈)—— 目录 1.【 283. 移动零 - 力扣(Lee…...

PostgreSQL标识符长度限制不能超过63字节
文章目录 问题:标识符太长会被截断分析相关源码可以尝试以下案例 问题:标识符太长会被截断 在创建表时,发现表名太长会自动被截断,导致查询表时报错了。 分析 参考:https://www.postgresql.org/docs/current/limits…...

嵌入式硬件面试题
1、请问什么是通孔、盲孔和埋孔?孔径多大可以做机械孔,孔径多小必须做激光孔?请问激光微型孔可以直接打在元件焊盘上吗,为什么? 通孔是贯穿整个PCB的过孔,盲孔是从PCB表层连接到内层的过孔,埋孔…...

深度解析 OneCode 混合编译:创新驱动的开发变革
前言 在软件开发领域,不断追求高效、灵活与强大的开发模式是永恒的主题。OneCode 作为一款引领潮流的开发工具,其混合编译特性正逐渐成为开发界瞩目的焦点。本文将深入剖析 OneCode 的混合编译机制,揭示它如何为软件开发带来前所未有的变革与…...

[文献阅读] Unsupervised Deep Embedding for Clustering Analysis (无监督的深度嵌入式聚类)
文章目录 Abstract:摘要聚类深度聚类 KL散度深度嵌入式聚类(DEC)KL散度聚类软分配(soft assignment)KL散度损失训练编码器的初始化聚类中心的初始化 实验评估总结 Abstract: This week I read Unsupervised Deep Embedding for Clustering Analysis .It…...

ajax中get和post的区别,datatype返回的数据类型有哪些?web开发中数据提交的几种方式,有什么区别。
在 Web 开发中,GET 和 POST 是两种常见的 HTTP 请求方法,它们有一些显著的区别。此外,datatype 参数在 jQuery 的 ajax() 请求中指定了预期的响应数据类型。接下来,我会详细解释这些问题。 1. GET 和 POST 请求的区别 GET 请求 和…...

网络七层杀伤链
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&…...

GAN网络详解及涨点大全总结(源码)
(需要源码请私信或评论) GAN原理 GAN的基本原理建立在 生成模型和判别模型的博弈过程 上。这种独特的机制使得GAN能够在复杂的分布上实现高效的无监督学习。在这个过程中,生成器G和判别器D相互竞争,最终达到一种平衡状态,在此状态下,G能够产生高质量的合成样本,而D则无…...
【自动化】Python SeleniumUtil 工具 开启开发者模式 自动安装油猴用户脚本等
【自动化】Python SeleniumUtil 工具 【Python】使用Selenium 操作浏览器 自动化测试 记录-CSDN博客文章浏览阅读58次。文章浏览阅读42次。【附件】Selenium chromedriver 驱动及浏览器下载。【附件】Selenium chromedriver 驱动及浏览器下载-CSDN博客。3.安装Chrome浏览器驱动…...

【Linux打怪升级记 | 问题01】安装Linux系统忘记设置时区怎么办?3个方法教你回到东八区
🗺️博客地图 📍方法一、timedatectl 命令 📍方法二、手动链接 /etc/localtime 📍方法三、修改时区变量 在 Linux 系统中,可以通过以下3种方式将系统时区修改为 CST(中国标准时间,GMT8 或称 …...

android:sharedUserId 应用进程声明介绍
背景 adb install 安装系统软件报错,原因是签名不一致,进程改变。 代码分析 AndroidManifest.xml 定义的 android:sharedUserId 应用归属进程不同,从phone切换到system。 初始配置 <manifest xmlns:android="http://schemas.android.com/apk/res/android"c…...

解锁ApplicationContext vs BeanFactory: 谁更具选择性?
目录 一、聚焦源码回顾 (一)源码分析和理解 (二)简短的回顾对比建议 二、ApplicationContext vs BeanFactory特性对比 (一)主要特性总结 (二)直接建议 三、案例简单说明 &am…...

一篇梳理清楚http请求知识点
HTTP请求是Web开发中的重要组成部分,它涉及到客户端和服务器之间的通信。掌握HTTP请求的知识点对于前端开发和后端开发都至关重要。以下是关于HTTP请求的详细梳理,结合代码进行说明。 1. HTTP请求概述 HTTP(超文本传输协议)是一个…...

Kotlin - 协程结构化并发Structured Concurrency
前言 Kotlin的Project Lead,Roman Elizarov的一片文章https://elizarov.medium.com/structured-concurrency-722d765aa952介绍了Structured Concurrency发展的背景。相对Kotlin1.1时代,后来新增的Structured Concurrency理念,也就是我们现在所…...

新版国标GB28181设备端Android版EasyGBD支持国标GB28181-2022,支持语音对讲,支持位置上报,开源在Github
经过近3个月的迭代开发,新版本的国标GB28181设备端EasyGBD安卓Android版终于在昨天发布到Github了,最新的EasyGBD支持了国标GB28181-2022版,还支持了语音对讲、位置上报、本地录像等功能,比原有GB28181-2016版的EasyGBD更加高效、…...

豆包MarsCode测评:编程效率再提升
豆包MarsCode测评:编程效率再提升 本文正在参与豆包MarsCode AI 编程体验家活动 随着人工智能技术的发展,编程的方式也在悄然发生变化。最近,豆包推出的 AI 编程工具 MarsCode 在开发者社区引发了不小的关注。这是一款支持多种主流编程语言…...

二叉树 -- 堆(详解)
目录 1、堆的概念及结构 2、堆的实现(附代码) 2.1、向下调整算法建堆 3、堆的应用(附代码) 3.1、堆排序 3.2、TOP-K问题 1、堆的概念及结构 如果有一个关键码的集合K { k0,k1 ,k2 ,…,k(n-1) },把它的所有元素…...

【Apache Paimon】-- 11 -- Flink 消费 kakfa 写 S3 File
目录 1、项目构建 2、项目新增和修改 2.1 pom.xml 新增依赖 2.2 本地测试或者 flink on k8s 时,新增 S3FileSystemFactory.java 第一步:创建包=org.apache.flink.fs.s3hadoop 第二步:新增 java 类 S3FileSystemFactory 特别注意 (1)本地测试时需要新增以下内容 (…...

SQL MID()
SQL中的MID()函数是一个用于从指定位置开始截取字符串中指定长度的子串的函数。这个函数在数据库查询和数据处理中经常被使用,特别是在需要从较长的文本字段中提取特定信息时。 MID()函数的基本语法是:SELECT MID(column_name, start, length) FROM tab…...

jsp | servlet | spring forEach读取不了对象List
导致这个问题的原因有很多的,这里讲到的只是原因之一 原因 taglib不认识forEach 解决办法 添加<% taglib uri"http://java.sun.com/jsp/jstl/core" prefix"c" %> (我忘写这个东西了哈哈哈)...

【ArcGIS Pro微课1000例】0063:处理无人机数据(空三、生成DOM、DSM、DTM)
使用ArcGIS Pro 正射拼接处理无人机数据流程化工具,不需要额外产品许可的支持,只需要桌面是高级版许可即可支持。ArcGIS Pro处理无人机摄影测量数据主要内容有:空三、生成DOM、DSM、DTM。 文章目录 一、创建映射项目二、提交自由空三三、添加控制点优化四、提交产品生产一、…...

【pytorch】深度学习计算
1 层和块 块由类(class)表示。它的任何子类都必须定义一个将其输入转换为输出的前向传播函数,并且必须存储任何必需的参数。注意,有些块不需要任何参数。最后,为了计算梯度,块必须具有反向传播函数。 1.1…...

详解磁盘IO、网络IO、零拷贝IO、BIO、NIO、AIO、IO多路复用(select、poll、epoll)
1、什么是I/O 在计算机操作系统中,所谓的I/O就是输入(Input)和输出(Output),也可以理解为读(Read)和写(Write),针对不同的对象,I/O模式可以划分为…...

VPN技术-GRE隧道的配置
GRE隧道的配置 1, 在AR1上配置DHCP接口地址池,AR3上配置DHCP全局地址池 2, PC1获取的IP地址为10.10.10.253,PC2获取的IP地址为10.10.30.253 3,通过ip route-static将目的地址为10.10.30.253的流量引入到Tunnel #配…...

【spring-cloud-gateway总结】
文章目录 什么是gateway如何导入gateway依赖路由配置gateway配置断路器导包配置 什么是gateway 在微服务架构中,gateway网关是一个服务,它作为系统的唯一入口点,处理所有的客户端请求,然后将这些请求路由到适当的服务。提供了几个…...
数组相关简单算法
目录 1. 数据结构与算法 2. 数组中涉及的算法 2.1 2.2 数值型数组相关运算 2.3 数组赋值 2.4 数组复制/反转 2.5 数组查找 2.6 排序 1. 数据结构与算法 《数据结构与算法》是大学些许专业的必修或选修课,主要包含两方面知识: (1&#…...

在VBA中结合正则表达式和查找功能给文档添加交叉连接
在VBA中搜索文本有两种方式可用,一种是利用Range.Find对象(更常见的形式可能是Selection.Find,Selection是Range的子类,Selection.Find其实就是特殊的Range.Find),另一种方法是利用正则表达式,但…...

动手学深度学习-多层感知机-7前向传播、反向传播和计算图
目录 前向传播 前向传播计算图 反向传播 训练神经网络 小结 我们已经学习了如何用小批量随机梯度下降训练模型。 然而当实现该算法时,我们只考虑了通过前向传播(forward propagation)所涉及的计算。 在计算梯度时,我们只调用…...