老师提出了一个项目,AR相关的,我选择用Web AR来开发。
在确定路线可行后,老师说要去买一个高清的摄像头,于是,买来了一个网络摄像头,海康威视的。
这个摄像头确实高清,可是它是联网的,不能直接接到电脑上来,所以就非常麻烦啦,于是有了这篇Blog。
初探
这个摄像头支持的协议应该是挺多的,我知道的有什么 ONVIF 啦 RTSP 啦,还有其他乱七八糟的协议。
经测试,摄像头视频流传输到电脑上控制页面上延迟还是挺低的,用它做AR应该不会有问题。
官方那个控制页面的画面显示并不是Web,而是装了个什么插件把画面贴在浏览器窗口上的,我并不能扒它的代码。
所以,这个问题是,这个视频流怎么传给浏览器呢?
首先想到的是,把摄像头想办法模拟成本地的USB摄像头,OBS Studio似乎有这个功能,海康家RTSP地址长这样:rtsp://user:pwd@127.0.0.1:554/Streaming/Channels/1,我把它给OBS Studio,能够成功显示,但是延迟高到好几秒,它是调用的ffmpeg进行的RTSP协议解码,这是我第二次在需要实时性的场合用到ffmpeg,也是第二次无法满足需求,感觉用ffmpeg就保证不了实时性。这种方法似乎行不通。
然后看了看ONVIF,这东西是是一种开放性的协议,但Github上找了一圈,没找到什么很有用的东西,但是RTSP协议找到貌似很有用的东西了。
弯路
首先是 RTSPtoWeb 这个项目能够轻松连接上摄像头,用多种协议传输到浏览器,但是似乎并不稳定,基本上都是断开的时候,但是偶尔能看到画面,感觉延迟还可以。它的作者还有 RTSPtoWebRTC 这个项目,功能一样,但是只有WebRTC这一个协议连接到浏览器。
感觉WebRTC这个协议的实时性是最好的,所以就在RTSPtoWebRTC这个项目上研究了一下。
我发现摄像机每隔几秒就会主动断开连接,我删除了程序上的重连延迟,基本上能用了,只是重连的时候会丢几帧,比较明显,这样的话老师应该也不会接受···
然后,我找到了 gortsplib 这个项目,跑了一下示例,它能把RTSP转换成MPEG-TS的文件存起来,于是我写了一个简单的HTTP服务器传输MPEG-TS,但是这样的延迟有好几秒···
在示例程序中,运行程序连接服务器的瞬间TS文件体积就开始增加了,猜测延迟主要出现在浏览器这边,浏览器为了能够不卡顿,总是缓存几秒视频,于是我开始寻找合适的播放器···
最终找到 wfs.js 这个项目,用这个不需要对视频封装,只需要传输H264视频裸流,但我不知道H264裸流是什么样子的,直接发NALU字节没用,先发完SPS和PPS再发NALU也没用,这个方法似乎也不行。
回到最开始,我抓RTSPtoWebRTC的包和gortsplib的包,对比发现,RTSPtoWebRTC连上后直接开始发视频流,而gortsplib是再创建一个UDP连接发送视频流,RTSPtoWebRTC断开的原因这样就找到了。
给RTSPtoWebRTC加上UDP传输数据感觉有点难,但是如果用gortsplib连接,收到的数据包给RTSPtoWebRTC编解码似乎可行···
接下来又是漫长的测试,摸索两个项目的数据结构,最终,gortsplib收发包和解码成NALU这个过程耦合度太高,我很难把他们拆开,但是RTSPtoWebRTC收发包和RTP解码编码器是分开的,于是我给RTSPtoWebRTC的解码编码器进行了修改,使其接受gortsplib解码过的NALU数据。
最后,改改小问题,历经三天,完成RTSP协议到WebRTC的低延迟转换。
成果
在我的12代i7笔记本上那个协议转换程序大约使用0.5%的处理器,经测试延迟大概在200毫秒左右,WebAR应该够用了。
