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