ONVIF协议网络摄像机客户端使用gsoap获取RTSP流地址GStreamer拉流播放

什么是ONVIF协议


        
ONVIF(开放式网络视频接口论坛)是一个全球性的开放式行业论坛,旨在促进开发和使用基于物理IP的安全产品接口的全球开放标准。

        ONVIF规范的目标是建立一个网络视频框架协议,使不同厂商生产的网络视频产品完全互通。

        1:设备管控和控制:通过Web Services提供接口,使用SOAP协议进行数据交互。

        2:音视频流‌:通过RTP/RTSP进行传输。

        3:‌统一接口‌:抽象了功能的接口,统一了对设备配置和操作的方式,使得控制端不再关心设备的型号,而是关注设备提供的Web Service‌23。

        学习并使用ONVIF协议我个人觉得要理清楚角色,就网络摄像机而言,对于应用场景可分为客户端和服务端。使用的网络摄像机就是服务端,也就是了解ONVIF出现最多的web services服务端,想要使用这个对接网络摄像机就是从这里面获取相关信息。    

        开发客户端通过ONVIF规范接口和网络摄像机进行通讯,其中常见的功能有:

        1:获取网络相机的基本信息

        2:修改网络的系统日期、时间

        3:修改网络摄像机的网络配置(IP、子网掩码等)

        4:获取、修改网络摄像头的各种参数(视频分辨率、码率、帧率、OSD(叠加信息)、云平台控制)

        在onvif协议中,有一些列profile的技术规格。引入这些规格是使得终端用户能够更容易区分各个profile所支持的特性,而无需确定各个版本间的兼容性。

        其中应用于视频流的主要是使用profile S 技术规格。

        ONVIF官方profile地址

在学习ONVIF协议时会出现很多名词:Web Service、WSDL、XML、SOAP。刚接触的初学者会一脸懵逼,这些都是什么玩意有什么用,以我对他们的了解而言,这些也就了解一下皮毛就行了,不用纯手搓从底层开始搓。因为有一个很强大的工具来简化这个过程那即是gsoap

gsoap官网:http://www.cs.fsu.edu/~engelen/soap.html

需要什么功能在使用这个工具的时候直接连接。

就像这样的链接:

http://www.onvif.org/onvif/ver20/util/operationIndex.html

http://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl

http://www.onvif.org/onvif/ver10/deviceio.wsdl

http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl

http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl

http://www.onvif.org/onvif/ver10/analyticsdevice.wsdl

http://www.onvif.org/onvif/ver10/display.wsdl

http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl

http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl

http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl

http://www.onvif.org/onvif/ver10/Receiver.wsdl

http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl

http://www.onvif.org/onvif/ver10/Recording.wsdl

http://www.onvif.org/onvif/ver10/Replay.wsdl

http://www.onvif.org/onvif/ver10/Search.wsdl

需要什么链接什么

2:怎么使用

我是基于linux平台来进行相关的开发,那就需要自己去gsoap官网下载对应的工具库然后编译,很简单这个。

1:去官网下载相关的文件http://sourceforge.net/projects/gsoap2

2:解压压缩包然后进行配置

./configure --prefix=/usr/local/gSOAP

3:编译 make

4:安装:sudo make install

然后生成的编译好的库就在/usr/local/gSOAP这个路径下面

然后去文件夹bin里面找到

这两个工具程序,这俩是用来生成头文件框架的直接用就可以了

先把gsoap库里面的文件拷贝到自己的工程中

然后需要什么链接什么:

./wsdl2h -P -x -c -s -t ./typemap.dat -o  onvif.h https://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl https://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl

./wsdl2h -P -x -c -s -t ./typemap.dat -o  onvif.h https://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl https://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl

根据上面的介绍,需要什么功能后面连接什么wsdl。

然后运行

soapcpp2 -C -c -x -I import -I custom xxx.h

然后就会生成这些文件了

那么基本框架就OK了

然后就是自己写程序了

我的程序

#include <gst/gst.h>
#include "soapH.h"

char* onvif() {
    struct soap *soap;
    struct _trt__GetProfilesResponse profilesResp;
    struct _trt__GetStreamUriResponse streamUriResp;
    char *rtspUri = NULL; // 用于存储RTSP URI的动态分配字符串

    // 初始化gSOAP运行时上下文
    soap = soap_new();
    if (soap == NULL) {
        fprintf(stderr, "soap_new failed\n");
        return NULL;
    }

    // 设置设备的端点URL和认证信息
    const char *device_url = "http://xxx.xxx.20.10:8000/onvif/device_service";
    soap->userid = "admin";
    soap->passwd = "admin";

    // 调用Web服务获取配置文件
    struct _trt__GetProfiles getProfiles;
    soap_call___trt__GetProfiles(soap, device_url, NULL, &getProfiles, &profilesResp);

    if (soap->error == SOAP_OK && profilesResp.Profiles) {
        // 假设我们使用第一个配置文件
        struct tt__Profile *profile = profilesResp.Profiles;

        // 获取每个配置文件的RTSP地址
        struct _trt__GetStreamUri getStreamUri;
        getStreamUri.ProfileToken = profile->token;

        // 分配并初始化Transport结构体
        struct tt__Transport *transport = (struct tt__Transport*)soap_malloc(soap, sizeof(struct tt__Transport));
        transport->Protocol = tt__TransportProtocol__RTSP; // 确保枚举值正确

        // 初始化StreamSetup结构体
        struct tt__StreamSetup streamSetup;
        streamSetup.Stream = tt__StreamType__RTP_Unicast; // 确保枚举值正确
        streamSetup.Transport = transport;

        // 赋值给getStreamUri.StreamSetup
        getStreamUri.StreamSetup = &streamSetup;

        soap_call___trt__GetStreamUri(soap, device_url, NULL, &getStreamUri, &streamUriResp);

        if (soap->error == SOAP_OK && streamUriResp.MediaUri) {
            // 动态分配字符串以存储RTSP URI
            rtspUri = malloc(strlen("rtsp://") + strlen(streamUriResp.MediaUri->Uri) + 1);
            if (rtspUri != NULL) {
                sprintf(rtspUri, "%s", streamUriResp.MediaUri->Uri);
            } else {
                fprintf(stderr, "Memory allocation failed for RTSP URI\n");
            }
        } else {
            soap_print_fault(soap, stderr);
        }

    } else {
        soap_print_fault(soap, stderr);
    }

    // 清理资源
    soap_destroy(soap);
    soap_end(soap);
    soap_free(soap);

    return rtspUri; // 返回动态分配的RTSP URI字符串
}

/* 回调函数 */
static void on_pad_added(GstElement *element, GstPad *pad, gpointer data);

int main(int argc, char *argv[]) {
    GstElement *pipeline, *source, *depay, *parse, *decoder, *convert, *sink;
    GstBus *bus;
    GstMessage *msg;
    GstStateChangeReturn ret;
    char *rtspUri = onvif();

    /* 初始化 GStreamer库 */
    gst_init(&argc, &argv);

    /* 创建各个元素 */
    source = gst_element_factory_make("rtspsrc", "source");// RTSP 源
    depay = gst_element_factory_make("rtph264depay", "depay");//H.264 RTP 解封装
    parse = gst_element_factory_make("h264parse", "parse");// H.264 解析器
    decoder = gst_element_factory_make("mppvideodec", "decoder");// MPP 视频解码器
    convert = gst_element_factory_make("videoconvert", "convert");// 视频格式转换
    sink = gst_element_factory_make("autovideosink", "sink");// 自动选择视频输出

    if (!source || !depay || !parse || !decoder || !convert || !sink) {
        g_printerr("Not all elements could be created.\n");
        return -1;
    }

    /* Create the empty pipeline */
    pipeline = gst_pipeline_new("test-pipeline");
    if (!pipeline) {
        g_printerr("无法创建管道\n");
        gst_object_unref(source);
        gst_object_unref(depay);
        gst_object_unref(parse);
        gst_object_unref(decoder);
        gst_object_unref(convert);
        gst_object_unref(sink);
        return -1;
    }

     /* 设置源的属性 */
    g_object_set(G_OBJECT(source), "location", rtspUri, NULL);

     /* 构建管道 */
    gst_bin_add_many(GST_BIN(pipeline), source, depay, parse, decoder, convert, sink, NULL);

     /* 手动连接元素 */
    if (gst_element_link(depay, parse) != TRUE ||
        gst_element_link(parse, decoder) != TRUE ||
        gst_element_link(decoder, convert) != TRUE ||
        gst_element_link(convert, sink) != TRUE) {
        g_printerr("Elements could not be linked.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* 动态连接 rtspsrc 到 rtph264depay */
    g_signal_connect(source, "pad-added", G_CALLBACK(on_pad_added), depay);

    /* 开始播放 */
    ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    /* 等待错误或 EOS(End-Of-Stream)消息 */
    bus = gst_element_get_bus(pipeline);
    msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS);

    /* 解析消息 */
    if (msg != NULL) {
        GError *err;
        gchar *debug_info;

        switch (GST_MESSAGE_TYPE(msg)) {
            case GST_MESSAGE_ERROR:
                gst_message_parse_error(msg, &err, &debug_info);
                g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
                g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");
                g_clear_error(&err);
                g_free(debug_info);
                break;
            case GST_MESSAGE_EOS:
                g_print("达到流末尾.\n");
                break;
            default:
                g_printerr("收到意外的消息.\n");
                break;
        }
        gst_message_unref(msg);
    }

    /* Free resources */
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
    return 0;
}
/* 回调函数,用于动态链接 rtspsrc 到 rtph264depay */
static void on_pad_added(GstElement *element, GstPad *pad, gpointer data) {
    GstPad *sinkpad;
    GstElement *depay = (GstElement *)data;

    g_print("Received new pad '%s' from '%s':\n", GST_PAD_NAME(pad), GST_ELEMENT_NAME(element));

    /* If our depay is already linked, we have nothing to do here */
    sinkpad = gst_element_get_static_pad(depay, "sink");
    if (sinkpad && gst_pad_is_linked(sinkpad)) {
        g_print("We are already linked. Ignoring.\n");
        gst_object_unref(sinkpad);
        return;
    }

     /* 尝试链接 */
    if (sinkpad && gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
        g_print("Type of the pad does not match type of sink pad.\n");
    } else {
        g_print("Link succeeded.\n");
    }

    /* 释放 sink pad */
    if (sinkpad) {
        gst_object_unref(sinkpad);
    }
}

我看好多文章都没说怎么编译的,直接用gcc就可以

就像这样,也可以把这些.c文件编译库连接,这样好一点。calcclient.是自己的程序,写好编译通过即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/927132.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Datawhale组队学习】模型减肥秘籍:模型压缩技术6——项目实践

NNI (Neural Network Intelligence) 是由微软开发的一个开源自动化机器学习&#xff08;AutoML&#xff09;库&#xff0c;用于帮助研究人员和开发人员高效地进行机器学习实验。它提供了一套丰富的工具来进行模型调优、神经网络架构搜索、模型压缩以及自动化的超参数搜索。 1…

通讯专题4.1——CAN通信之计算机网络与现场总线

从通讯专题4开始&#xff0c;来学习CAN总线的内容。 为了更好的学习CAN&#xff0c;先从计算机网络与现场总线开始了解。 1 计算机网络体系的结构 在我们生活当中&#xff0c;有许多的网络&#xff0c;如交通网&#xff08;铁路、公路等&#xff09;、通信网&#xff08;电信、…

【51单片机】程序实验910.直流电机-步进电机

主要参考学习资料&#xff1a;B站【普中官方】51单片机手把手教学视频 前置知识&#xff1a;C语言 单片机套装&#xff1a;普中STC51单片机开发板A4标准版套餐7 码字不易&#xff0c;求点赞收藏加关注(•ω•̥) 有问题欢迎评论区讨论~ 目录 程序实验9&10.直流电机-步进电机…

Qt支持RKMPP硬解的视频监控系统/性能卓越界面精美/实时性好延迟低/录像存储和回放/云台控制

一、前言 之前做的监控系统&#xff0c;已经实现了在windows上硬解码比如dxva2和d3d11va&#xff0c;后续又增加了linux上的硬解vdpau的支持&#xff0c;这几种方式都是跨系统的硬解实现方案&#xff0c;也是就是如果都是windows系统&#xff0c;无论X86还是ARM都通用&#xf…

Web API基本认知

作用和分类 作用&#xff1a;就是使用JS去操作html和浏览器 分类&#xff1a;DOM&#xff08;文档对象模型&#xff09;、BOM&#xff08;浏览器对象模型&#xff09; 什么是DOM DOM&#xff08;Document Object Model ——文档对象模型&#xff09;是用来呈现以及与任意 HTM…

Linux——自定义简单shell

shell 自定义shell目标普通命令和内建命令&#xff08;补充&#xff09; shell实现实现原理实现代码 自定义shell 目标 能处理普通命令能处理内建命令要能帮助我们理解内建命令/本地变量/环境变量这些概念理解shell的运行 普通命令和内建命令&#xff08;补充&#xff09; …

智能桥梁安全运行监测系统守护桥梁安全卫士

一、方案背景 桥梁作为交通基础设施中不可或缺的重要组成部分&#xff0c;其安全稳定的运行直接关联到广大人民群众的生命财产安全以及整个社会的稳定与和谐。桥梁不仅是连接两地的通道&#xff0c;更是经济发展和社会进步的重要纽带。为了确保桥梁的安全运行&#xff0c;桥梁安…

【Python网络爬虫笔记】5-(Request 带参数的get请求) 爬取豆瓣电影排行信息

目录 1.抓包工具查看网站信息2.代码实现3.运行结果 1.抓包工具查看网站信息 请求路径 url:https://movie.douban.com/typerank请求参数 页面往下拉&#xff0c;出现新的请求结果&#xff0c;参数start更新&#xff0c;每次刷新出20条新的电影数据 2.代码实现 # 使用网络爬…

新质驱动·科东软件受邀出席2024智能网联+低空经济暨第二届湾区汽车T9+N闭门会议

为推进广东省加快发展新质生产力&#xff0c;贯彻落实“百县千镇万村高质量发展工程”&#xff0c;推动韶关市新丰县智能网联新能源汽车、低空经济与数字技术的创新与发展&#xff0c;充分发挥湾区汽车产业链头部企业的带动作用。韶关市指导、珠三角湾区智能网联新能源汽车产业…

C#使用ExcelDataReader读取Xlsx文件为DataTable对象

创建控制台项目 在NuGet中安装ExcelDataReader.DataSet 3.7.0 创建一个xlsx文件 测试代码 读取xlsx文件内容&#xff0c;为一个DataTable对象。 读取xlsx时&#xff0c;xlsx文件不能被其他软件打开&#xff0c;否则会报“进程无法访问此文件”的错。 using ExcelDataRead…

“harmony”整合不同平台的单细胞数据之旅

其实在Seurat v3官方网站的Vignettes中就曾见过该算法&#xff0c;但并没有太多关注&#xff0c;直到看了北大张泽民团队在2019年10月31日发表于Cell的《Landscap and Dynamics of Single Immune Cells in Hepatocellular Carcinoma》&#xff0c;为了同时整合两类数据&#xf…

智慧银行反欺诈大数据管控平台方案(一)

智慧银行反欺诈大数据管控平台建设方案的核心在于通过整合先进的大数据技术和深度学习算法&#xff0c;打造一个全面、智能且实时的反欺诈系统&#xff0c;以有效识别、预防和应对各类金融欺诈行为。该方案涵盖数据采集、存储、处理和分析的全流程&#xff0c;利用多元化的数据…

基于 JNI + Rust 实现一种高性能 Excel 导出方案(上篇)

每个不曾起舞的日子,都是对生命的辜负。 ——尼采 一、背景:Web 导出 Excel 的场景 Web 导出 Excel 功能在数据处理、分析和共享方面提供了极大的便利,是许多 Web 应用程序中的重要功能。以下是一些典型的场景: 数据报表导出:在企业管理系统(如ERP、CRM)中,用户经常需…

使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件

使用 Tkinter 创建一个简单的 GUI 应用程序来合并视频和音频文件 Python 是一门强大的编程语言&#xff0c;它不仅可以用于数据处理、自动化脚本&#xff0c;还可以用于创建图形用户界面 (GUI) 应用程序。在本教程中&#xff0c;我们将使用 Python 的标准库模块 tkinter 创建一…

「Mac畅玩鸿蒙与硬件35」UI互动应用篇12 - 简易日历

本篇将带你实现一个简易日历应用&#xff0c;显示当前月份的日期&#xff0c;并支持选择特定日期的功能。用户可以通过点击日期高亮选中&#xff0c;还可以切换上下月份&#xff0c;体验动态界面的交互效果。 关键词 UI互动应用简易日历动态界面状态管理用户交互 一、功能说明…

江协科技最新OLED保姆级移植hal库

江协科技最新OLED移植到hal库保姆级步骤 源码工程存档 工程和源码下载(密码 1i8y) 原因 江协科技的开源OLED封装的非常完美, 可以满足我们日常的大部分开发, 如果可以用在hal库 ,将是如虎添翼, 为我们开发调试又增加一个新的瑞士军刀, 所以我们接下来手把手的去官网移植源码…

NLTK工具包

NLTK工具包 NLTK工具包安装 非常实用的文本处理工具&#xff0c;主要用于英文数据&#xff0c;历史悠久~ 安装命令&#xff1a; pip install nltk import nltk # nltk.download() # nltk.download(punkt) # nltk.download(stopwords) # nltk.download(maxent_ne_chunker) nl…

HarmonyOS:使用Emitter进行线程间通信

Emitter主要提供线程间发送和处理事件的能力&#xff0c;包括对持续订阅事件或单次订阅事件的处理、取消订阅事件、发送事件到事件队列等。 一、Emitter的开发步骤如下&#xff1a; 订阅事件 import { emitter } from kit.BasicServicesKit; import { promptAction } from kit.…

Unity之一键创建自定义Package包

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之一键创建自定义Package包 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01; …

【html网页页面007】html+css制作旅游主题内蒙古网页制作含注册表单(4页面附效果及源码)

旅游家乡主题网页制作 &#x1f964;1、写在前面&#x1f367;2、涉及知识&#x1f333;3、网页效果&#x1f308;4、网页源码4.1 html4.2 CSS4.3 源码获取 &#x1f40b;5、作者寄语 &#x1f964;1、写在前面 家乡网站主题内蒙古的网页 一共4个页面 网页使用htmlcss制作页面…