IPC 代理 总结
想要做一个IPC 代理 需要了解 整个IPC 的服务 以及通信接口,目前IPC 通信 包括流数据传输、流数据控制、 IPC 摄像头控制;
数据传输 指媒体流,流数据控制 指调控流的meta 如码率、通道等,IPC 摄像头控制 可以控制摄像头的转向。
目前IPC 对接 客户端 可以使用onvif 和 国标GB 协议;
onvif
- NVR 客户端 需要 联通 IPC ,有两种模式,一种是主动发现 一种是手动配置 IP 和 端口,主动发现 使用udp 广播报文,IPC 设备 收到广播报文告诉NVR 自己的地址 XAddrs,(一个IPC 可以告诉),以及 device 获取接口url http://ip/onvif/device_service;
- NVR 客户端 获取到设备接口后,获取设备能力 ,需要知道该IPC 设备支持哪些能力 属性等 ,onvif 基于 http 使用 soap、wsdl 等描述语言, post 请求 http://ip/onvif/device_service GetCapbilities; IPC 会把 流媒体服务器media 的地址 响应回来 http://ip/onvif/media 。
- GetProfiles, 获取流的token 和 多路流的哪一路,一路代表一个流地址;
- GetStreamUri 携带token 获取流媒体播放地址,token 101 第一路流等;
- 使用流地址开始 拉流,可以使用ONVIF Device Test Tool 进行调试 ;
- 摄像头控制 url
ONVIF代理对接
如果我们需要对原始流处理后再播放,接入一个代理,可以使用nginx (透传)+ 页面改写 改写流地址,但是要注意 content-length 头和 chunk 头处理,参考 image_filter 模块。可以使用ONVIF Device Test Tool 进行调试 或者通过抓包对比IPC 直连方式调试。
对于event 的代理需要做双向代理,NVR 中可以配置 对某些 事件的 报警 event,NVR 需要告诉IPC 要针对哪些 事件进行上报,IPC 告诉客户端 过来拉,客户端向IPC 拉取;需要做更多测试;
ONVIF总结
- NVR 的广播模式 需要与IPC 在同一局域网,若使用手动配置IP,IPC 需要外网地址。相比较, SIP 协议更适合外网系统,onvif 适合局域网。
- onvif 有时返回500 是由于服务 对某些消息 不支持,与代理报文的准确性无关;
国标 SIP
在国标体系中,主要有 sip 服务器 、流媒体服务器、IPC、全球眼 管理和播放客户端 角色,sip 服务器 在整个体系中扮演管理角色,在一个庞大的IPC 分布式端网络,相关部门需要快速了解整个IPC 的 用途、地点等,因此有特殊的编号,类似onvif 里面的 P G S 等概念。采用主动注册体系更方便 分布式IPC 的接入和管理,同时能够利用NAT 机制 和 内部网络通信。SIP 服务器除了注册管理外,还要进行协调 流媒体服务器和 IPC 之前的事务时序,
由于IPC 内网,流媒体服务器公用外网,因此需要IPC 主动推送到流媒体服务器。全球眼从流媒体服务器获取拉流地址播放。通信采用SIP 和sdp 方式;
- IPC 向 SIP 服务器进行注册,通过抓包 使用 wireshark 搜索 sip 可以对比国标协议,REGISTER 请求;
- 全球眼客户端点击播放时 会产生INVITE 请求,在sdp 中描述play 信息 告知 IPC 客户端 流媒体服务器地址,RTP SSRC 等,以及协商封包格式等
- 客户端推流
- 保活、控制 等等…
v=0
o=34020000001320000002 0 0 IN IP4 192.168.1.31
s=XLIPCAM
c=IN IP4 192.168.1.31
t=0 0
m=video 6090 RTP/AVP 96
a=rtpmap:96 MP2P/90000
SIP 代理对接
如果我们需要对原始流处理后再播放,接入一个代理. 对接原有sip 服务器, 实现点主要在于如何对接原有SIP服务器 和 IPC,SIP代理可以有两种模式,一种是SIP 级联,一种是控制网关,SIP 级联相当于代理部分又是一套SIP 系统,需要实现SIP 服务器的角色等;而控制网关则需要实现一个IPC 客户端功能,但是拉流来源来自真实的IPC 内容。操作IPC 指令同样需要能够理解并下达真实IPC。
我们采用 ffmpeg 从IPC 拉流并压缩,将压缩后的内容通过本地TCP 套接字传递给代理,代理将相应的视频内容进行ps封包 rtp 封包怼到流媒体服务器。
ffmpeg -f rtsp -rtsp_transport tcp -i "rtsp://admin:admin123@192.168.1.64:554/Streaming/Channels/101?transportmode=unicast&profile=Profile_101" -vcodec libx264 -preset faster -tune zerolatency -threads 1 -rc-lookahead 0 -maxrate 900k -minrate 900k -b:v 900k -g 50 -sc_threshold 0 -an -f h264 unix:///home/ffmpeg.sock
ffmpeg -f rtsp -rtsp_transport tcp -i "rtsp://admin:admin123@192.168.1.64:554/Streaming/Channels/101?transportmode=unicast&profile=Profile_101" -vcodec libx264 -profile baseline -vf scale=1920:1080 -preset fast -tune zerolatency -maxrate 800k -minrate 600k -b:v 700k -bufsize 700k -keyint_min 50 -g 50 -sc_threshold 0 -an -f rtp rtp://192.168.11.253:5160?localrtpport=5061
问题总结
解决问题方法:找代码,相关函数 github搜索;QQ 群;对比IPC 抓包;软件的调试器;
RTP SDP 文件打开后再推流 VLC 无法播放sdp VLC 调试信息
黑屏===》帧ps 封包,没有使用h264 的原始数据raw data 无法解包
VLC 打开sdp 开始绿花屏====》 可能I 帧 丢失 要等I 帧下次刷新
VLC 打开sdp 等待===》等待I 帧到来打开
帧率设置不对===》 花屏
时间 模糊 windows udp 丢包
多线程I 帧 无法解包花屏 (本地播放因为本地有多个CPU播放正常, 远程服务器不一定使用多线程解压,并行压缩分为同一个帧内并行和帧间并行 ,此时ffmpeg 需使用一个线程压缩)
全球眼无法播放,有 音频封包 但是没有真实音频数据, 音频去掉相关bit,但是没有去掉结构体, bit 长度有计算结构体 0
绿屏 设置了使用h264 解码ps封包
花屏 丢帧 帧率 缓冲区
丢帧 ffmpeg 推流帧率缩小一半 从40 到 20
无法播放 SPLIT_IDR 以4 位 分隔,真实 输入源 可能 3位 4位 分隔 混合
ffmpeg 从内存中读取数据(或将数据输出到内存)
FFMPEG基于内存的转码实例——输入输出视频均在内存