有网友购买了我的ONVIF视频课程 (注:CSDN已经把课程下架了,说不符合要求),问了我几个问题,其中一个是实现ONVIF服务器的获取RTSP地址功能,本文整理出一个思路,愿帮到在学习ONVIF路上的诸君。
我录制的视频是很早之前的,一直没抽时间再录一个实战视频,所以凡是购买的网友,均会进行指导。当然,限于能力,也不是所有的问题都解答。

官方WSDL说明

ONVIF协议通过GetStreamUri获取流地址,在官方wsdl页面搜索GetStreamUri可看到该命令的详细信息。
详细字段如图1所示:

GetStreamUri是客户端发起的请求,共2大字段:
第1个是ProfileToken,亦即要获取的媒体profile名称——因为不同的profile,可以有不同的媒体参数。最简单的例子,摄像头有2路视频输出,720P和1080P,则会有2个媒体profile(使用不同的token来表示),因此,需要指定获取的是哪一个profile的流地址。
第2个是流参数设置StreamSetup。说明如下:

  • Stream:一个枚举类型,指定单播还是多播。
  • Transport:指定传输的协议。
    GetStreamUriResponse是响应包,其字段由服务端填充,客户端只要组装好GetStreamUri发送出来,等待响应包即可。
  • Uri:即流地址。
  • InvalidAfterConnect:指示只有连接后uri是否有效,设置为false。
  • InvalidAfterReboot:指示重启后uri是否有效,设置为false。
  • Timeout:超时时间,设置为0表示永久有效,——即使profile发生改变。

笔者存疑:InvalidAfterConnect、InvalidAfterReboot在字面上和解释上似乎不通,但对比官方说明中的ValidUntilConnectt ValidUntilReboot似乎又说得通,笔者怀疑是wsdl文档更新过程表述不一致导致的。在代码中,务必让这2个字段设置为false。

代码实现思路

下面分别从客户端、服务器讲讲代码实现思路。

客户端获取代码

首先,设置_trt__GetStreamUri结构体为指定的profile名称。——profile名称由其它函数获取。
其次,设置tt__StreamSetup结构体为单播,枚举值为tt__StreamType__RTP_Unicast。
再次,设置tt__Transport结构体字段,协议为tt__TransportProtocol__UDP。
最后,调用soap_call___trt__GetStreamUri函数。在_trt__GetStreamUriResponse中的MediaUri带有Uri,此亦本文开头提到的流地址

服务端返回代码

在响应GetStreamUri的函数中,判断_trt__GetStreamUri带的字段,如指针有效性、profile有效性,传输协议的判断。
然后设置trt__GetStreamUriResponse的MediaUri,包括Uri、InvalidAfterConnect、InvalidAfterReboot和Timeout。其中,Uri就是RTSP媒体器地址。
关于RTSP地址的设置,可以固定一种格式,在流服务器中固定,再在ONVIF服务器中固定,但这样不方便。也可以在流服务器中生成,然后通过进程通信的方式通知ONVIF服务器,这样方便维护。

代码结构体

文中涉及的结构体较多,较复杂,有删改。

class _trt__GetStreamUri
{ public:
/// <PRE><BLOCKQUOTE>
///   Stream Setup that should be used with the uri
/// </BLOCKQUOTE></PRE>
/// Element "StreamSetup" of XSD type "http://www.onvif.org/ver10/schema":StreamSetup.tt__StreamSetup*                     StreamSetup                    1;    ///< Required element.
/// <PRE><BLOCKQUOTE>
///   The ProfileToken element indicates the media profile to use and will define the configuration of the content of the stream.
/// </BLOCKQUOTE></PRE>
/// Element "ProfileToken" of XSD type "http://www.onvif.org/ver10/schema":ReferenceToken.tt__ReferenceToken                   ProfileToken                   1;    ///< Required element.
/// A handle to the soap struct context that manages this instance when instantiated by a context or NULL otherwise (automatically set).struct soap                         *soap                          ;
};class tt__StreamSetup
{ public:
/// <PRE><BLOCKQUOTE>
///   Defines if a multicast or unicast stream is requested
/// </BLOCKQUOTE></PRE>
/// Element "Stream" of XSD type "http://www.onvif.org/ver10/schema":StreamType.enum tt__StreamType                  Stream                         1;    ///< Required element.
/// Element "Transport" of XSD type "http://www.onvif.org/ver10/schema":Transport.tt__Transport*                       Transport                      1;    ///< Required element.
/// @todo <any namespace="##any" minOccurs="0" maxOccurs="unbounded">
/// @todo Schema extensibility is user-definable.
///       Consult the protocol documentation to change or insert declarations.
///       Use wsdl2h option -x to remove this element.
///       Use wsdl2h option -d for xsd__anyType DOM (soap_dom_element).
/// Size of the array of XML or DOM nodes is 0..unbounded.std::vector<xsd__anyType           > __any                         0;    ///< Catch any element content in DOM.
/// @todo <anyAttribute namespace="##any">.
/// @todo Schema extensibility is user-definable.
///       Consult the protocol documentation to change or insert declarations.
///       Use wsdl2h option -x to remove this attribute.
///       Use wsdl2h option -d for xsd__anyAttribute DOM (soap_dom_attribute).@xsd__anyAttribute                    __anyAttribute                ;    ///< Store anyAttribute content in DOM soap_dom_attribute linked node structure.
/// A handle to the soap struct context that manages this instance when instantiated by a context or NULL otherwise (automatically set).struct soap                         *soap                          ;
};enum tt__StreamType
{tt__StreamType__RTP_Unicast,    ///< xs:string value="RTP-Unicast"tt__StreamType__RTP_Multicast,    ///< xs:string value="RTP-Multicast"
};class tt__Transport
{ public:
/// <PRE><BLOCKQUOTE>
///   Defines the network protocol for streaming, either UDP=RTP/UDP, RTSP=RTP/RTSP/TCP or HTTP=RTP/RTSP/HTTP/TCP
/// </BLOCKQUOTE></PRE>
/// Element "Protocol" of XSD type "http://www.onvif.org/ver10/schema":TransportProtocol.enum tt__TransportProtocol           Protocol                       1;    ///< Required element.
/// <PRE><BLOCKQUOTE>
///   Optional element to describe further tunnel options. This element is normally not needed
/// </BLOCKQUOTE></PRE>
/// Element "Tunnel" of XSD type "http://www.onvif.org/ver10/schema":Transport.tt__Transport*                       Tunnel                         0;    ///< Optional element.
/// A handle to the soap struct context that manages this instance when instantiated by a context or NULL otherwise (automatically set).struct soap                         *soap                          ;
};enum tt__TransportProtocol
{tt__TransportProtocol__UDP,    ///< xs:string value="UDP"tt__TransportProtocol__TCP,    ///< xs:string value="TCP"tt__TransportProtocol__RTSP,    ///< xs:string value="RTSP"tt__TransportProtocol__HTTP,    ///< xs:string value="HTTP"
};

响应包结构体:

class _trt__GetStreamUriResponse
{ public:/// </BLOCKQUOTE></PRE>
/// Element "MediaUri" of XSD type "http://www.onvif.org/ver10/schema":MediaUri.tt__MediaUri*                        MediaUri                       1;    ///< Required element.
/// A handle to the soap struct context that manages this instance when instantiated by a context or NULL otherwise (automatically set).struct soap                         *soap                          ;
};class tt__MediaUri
{ public:
/// <PRE><BLOCKQUOTE>
///   Stable Uri to be used for requesting the media stream
/// </BLOCKQUOTE></PRE>
/// Element "Uri" of XSD type xs:anyURI.xsd__anyURI                          Uri                            1;    ///< Required element.
/// <PRE><BLOCKQUOTE>
///   Indicates if the Uri is only valid until the connection is established. The value shall be set to "false".
/// </BLOCKQUOTE></PRE>
/// Element "InvalidAfterConnect" of XSD type xs:boolean.bool                                 InvalidAfterConnect            1;    ///< Required element.
/// <PRE><BLOCKQUOTE>
///   Indicates if the Uri is invalid after a reboot of the device. The value shall be set to "false".
/// </BLOCKQUOTE></PRE>
/// Element "InvalidAfterReboot" of XSD type xs:boolean.bool                                 InvalidAfterReboot             1;    ///< Required element.
/// <PRE><BLOCKQUOTE>
///   Duration how long the Uri is valid. This parameter shall be set to PT0S to indicate that this stream URI is indefinitely valid even if the profile changes
/// </BLOCKQUOTE></PRE>
/// Element "Timeout" of XSD type xs:duration.xsd__duration                        Timeout                        1;    ///< Required element.
/// @todo <any namespace="##any" minOccurs="0" maxOccurs="unbounded">
/// @todo Schema extensibility is user-definable.
///       Consult the protocol documentation to change or insert declarations.
///       Use wsdl2h option -x to remove this element.
///       Use wsdl2h option -d for xsd__anyType DOM (soap_dom_element).
/// Size of the array of XML or DOM nodes is 0..unbounded.std::vector<xsd__anyType           > __any                         0;    ///< Catch any element content in DOM.
/// @todo <anyAttribute namespace="##any">.
/// @todo Schema extensibility is user-definable.
///       Consult the protocol documentation to change or insert declarations.
///       Use wsdl2h option -x to remove this attribute.
///       Use wsdl2h option -d for xsd__anyAttribute DOM (soap_dom_attribute).@xsd__anyAttribute                    __anyAttribute                ;    ///< Store anyAttribute content in DOM soap_dom_attribute linked node structure.
/// A handle to the soap struct context that manages this instance when instantiated by a context or NULL otherwise (automatically set).struct soap                         *soap                          ;
};

后记

文中只针对GetStreamUri字段进行说明,未提到ONVIF的连接、ONVIF鉴权等事宜。
本文出现的函数、枚举,均为很久前笔者生成的ONVIF框架代码,不表示本文发表时生成的ONVIF代码亦如是。
文中提到的profile,可搜索网上资料,也可参考笔者之前写的文章。
ONVIF不实现RTSP流服务,仅提供一个渠道让客户端获取流地址而已。实际项目中,可使用live555(笔者曾经研究过一段时间,其它服务未接触)实现。
由于ONVIF可参考资料较少,文中难免有错漏之处,欢迎指正,一起学习,共同进步。

参考资料:

onvif GetStreamUri

李迟 2019.4.15 周一 深夜

onvif学习笔记10:获取RTSP流地址相关推荐

  1. cgo+gSoap+onvif学习总结:5、获取profileToken、rtsp流地址、快照地址及cgo程序signal SIGSEGV: segmentation violation解决方法

    cgo+gSoap+onvif学习总结:5.获取profileToken.rtsp流地址.快照地址及cgo偶发signal SIGSEGV: segmentation violation分割违例解决方 ...

  2. LiveNVR Onvif/RTSP流媒体软件接入监控摄像头后如何获取直播流地址进行大屏展示、播放端拉流、网页播放监控视频等...

    1.LiveNVR介绍 LiveNVR的安防监控的视频直播,可以按标准的Onvif/RTSP协议接入监控设备,也可以通过海康.大华.天地伟业等厂家私有SDK接入监控,实现web页面的播放和录像回放. ...

  3. LiveNVR配置拉转RTSP传统海康大华安防摄像机直播流输出RTSP/RTMP/HLS/HTTP-FLV如何获取直播流地址

    LiveNVR配置拉转RTSP传统海康大华安防摄像机直播流输出RTSP/RTMP/HLS/HTTP-FLV如何获取直播流地址 1. Onvif/RTSP流媒体服务 2.配置拉转直播流 2.1 RTSP ...

  4. flink1.12.0学习笔记第2篇-流批一体API

    flink1.12.0学习笔记第 2 篇-流批一体API flink1.12.0学习笔记第1篇-部署与入门 flink1.12.0学习笔记第2篇-流批一体API flink1.12.0学习笔记第3篇- ...

  5. thinkphp学习笔记10—看不懂的路由规则

    原文:thinkphp学习笔记10-看不懂的路由规则 路由这部分貌似在实际工作中没有怎么设计过,只是在用默认的设置,在手册里面看到部分,艰涩难懂. 1.路由定义 要使用路由功能需要支持PATH_INF ...

  6. onvif学习笔记9:OSD命令学习

    几个月前写了篇介绍OSD坐标系统的文章:<onvif学习笔记6:onvif的OSD坐标小记>,但没有涉及接口,因为当时并不懂.后面发现网络上除了ONVIF官网外,基本没有什么资料介绍ONV ...

  7. JavaWeb黑马旅游网-学习笔记10【项目代码】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

  8. SpringMVC:学习笔记(10)——整合Ckeditor且实现图片上传

    SpringMVC:学习笔记(10)--整合Ckeditor且实现图片上传 配置CKEDITOR 精简文件 解压之后可以看到ckeditor/lang下面有很多语言的js,如果不需要那么多种语言的,可 ...

  9. springmvc学习笔记(10)-springmvc注解开发之商品改动功能

    springmvc学习笔记(10)-springmvc注解开发之商品改动功能 springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmv ...

最新文章

  1. 仰望众位Oracle大牛
  2. nginx 的upstream流程是怎样在CONTENT阶段执行的
  3. springboot多数据源动态切换和自定义mybatis分页插件
  4. Mac下Android studio 之NDK配置教程(二)
  5. 【Java基础】使用带有标签的break,跳出多层循环
  6. spring boot处理请求返回值的格式(自定义消息转换器)
  7. JAVA中toString方法的作用(转)
  8. 【script】lambda的使用
  9. recv java_Java与Python的recv()网络函数的等价性
  10. 《实时控制软件设计》团队项目第三天工作日志
  11. SQL server 表数据改变触发发送邮件
  12. 数据分类分级指南分级方法
  13. php 解压 中文文件夹,如何把文件夹压缩为rar
  14. 计算机cmp代表什么意思,CMP是什么
  15. datealive软件最新_约会大作战手游官网版下载-约会大作战正版手游下载地址v3.79_86PS软件园...
  16. 疾病地图制作_助力旅游业复工复产,这份山西中医文旅地图请收好,就在你家门口...
  17. 编写应用程序,计算两个非零正整数的最大公约数和最小公倍数,要求两个非零正整数从键盘输入。
  18. linux的一些命令
  19. 原生Android打造一个炫酷的底部导航栏
  20. 这一季绿色智能制造“英雄联盟”已集结, 有哪些新鲜点?

热门文章

  1. php 获取 flv 部分视频,php – 获取flv视频长度
  2. 宁德时代拟再投240亿元扩产宜宾基地
  3. 清华毕业生应聘“保姆”,年薪40万:她凭什么拿高薪?
  4. 降价200!华为部分手机已取消充电器和数据线,网友表示可以接受
  5. 华为申请注册姚安娜商标
  6. 特斯拉Model Y在6月份销售7500辆 是Model X两倍多
  7. 瑞幸咖啡首席技术官也离职了:并未参加公司财务造假
  8. 4+64GB版的4G手机定价1699?网友:多了个1吧...
  9. 真的能去太空旅游了!单人票价......打扰了!
  10. 被国产机所迫?苹果或将每半年发布一次新iPhone