千千梦丶琪 发表于 2024-8-5 16:03:52

Web 播放 RTSP(Webrtc方案)

Web 播放 RTSP(Webrtc方案)

需求背景

项目需要在 web 上播放海康摄像头,这个在各种智慧类应用上应该是常见需求,在前几年的时候也有这个需求,当时候通过旧版本谷歌浏览器可以直接播放 rtmp 解决了题目;现在谷歌浏览器已经不再支持,项目上又有这个需求,筹划好好处置惩罚下。大概需求内容项目有多个车,每个车有多个摄像头,web对这些摄像头进行管理呈现。
Web 播放视频流方案

web 播放视频流有多种方案有 HLS、flv、webrtc 等等,我们这里选用 webrtc 方案,webrtc 播放视频是网页原生支持的音视频通信技术,对比其他其他方案有低时延等长处
Webrtc 实践


[*] 海康摄像头推送 rtsp 流,web 播放 webrtc,搜索 rtsp 转 webrtc 发现开源项目 https://github.com/deepch/RTSPtoWebRTC,golang 编写,参照项目说明,项目跑起来很简单,代码仓库拉下来运行就行了,RTSPtoWebRTC 项目自带 http 署理了简单 web 页面
[*] 按照项目说明将 config 修改为本地海康摄像头地址,重新运行验证,摄像头就播放出来了
https://img-blog.csdnimg.cn/direct/e9134e65d3204e5ebb28be559ecd2247.png
https://img-blog.csdnimg.cn/direct/8a1a7bdd325145bea5996f661055eeaa.png
[*] 自身项目为前后端分离,开始迁移该项目标 webrtc 代码到自己的项目中,编写一个 Webrtc 组件
export function WebRtcPlayer(props: { suuid: string, url: string }) {
    let ref = useRef<HTMLVideoElement>();
    useEffect(() => {
      let { suuid, url } = props;

      let stream = new MediaStream();
      const pc = new RTCPeerConnection();
      pc.onnegotiationneeded = async () => {
            let offer = await pc.createOffer();
            await pc.setLocalDescription(offer);
            let formData = new FormData();
            formData.append('suuid', suuid);
            formData.append('data', btoa(pc.localDescription.sdp));

            fetch(`${APP_CONFIG.rtc}/stream/receiver/` + suuid, {
                method: "POST",
                body: formData
            }).then(resp => {
                return resp.text()
            }).then(data => {
                try {
                  pc.setRemoteDescription(new RTCSessionDescription({
                        type: 'answer',
                        sdp: atob(data)
                  }))
                } catch (e) {
                  console.warn(e);
                }
            })
      };

      pc.ontrack = function (event) {
            stream.addTrack(event.track);
            ref.current.srcObject = stream;
            log(event.streams.length + ' track is delivered')
      }

      pc.oniceconnectionstatechange = e => log(pc.iceConnectionState)

      let log = msg => {
            // document.getElementById('div').innerHTML += msg + '<br>'
      }

      //新增加的http接口
      let formData = new FormData();
      formData.append('suuid', suuid);
      formData.append('url', url);
      fetch(`${APP_CONFIG.rtc}/codec`, {
            method: "POST",
            body: formData
      })
            .then(resp => resp.json())
            .then(data => {
                (data as any[]).forEach(el => {
                  pc.addTransceiver(el.Type, {
                        'direction': 'sendrecv'
                  })
                })
                pc.setRemoteDescription(new RTCSessionDescription({
                  type: 'answer',
                  sdp: atob(data)
                }))
            }).catch(e => {
                console.warn(e);
            })

      //demo中使用的接口
      // fetch("http://127.0.0.1:8083/stream/codec/" + suuid)
      //   .then(resp => resp.json())
      //   .then(data => {
      //         (data as any[]).forEach(el => {
      //             pc.addTransceiver(el.Type, {
      //               'direction': 'sendrecv'
      //             })
      //         })
      //         pc.setRemoteDescription(new RTCSessionDescription({
      //             type: 'answer',
      //             sdp: atob(data)
      //         }))
      //   }).catch(e => {
      //         console.warn(e);
      //   })
    }, [])
    return <video ref={ref} style={{ width: "600px" }} autoPlay muted controls />
}
其中 fetch(${APP_CONFIG.rtc}/stream/receiver/ + suuid 和 fetch(http://127.0.0.1:8083/stream/codec/ + suuid) 是项目 demo 中利用到的接口,项目跑起,可以在项目里看到摄像头,开端完成。

[*] 观察项目代码,发现:

[*]config 配置了 rtsp 流地址信息,on_demand 便是否是未哀求也处置惩罚 rtsp
[*]http 接口用于信令互换(/stream/codec/ 用于查询配置返回 codec 信息,/stream/receiver/ 用于发起一个协程go RTSPWorkerLoop)

[*] 我的项目是内网情况且 rtsp 需要预先设置好改动就要重启有点麻烦,于是做出修改:

[*]config 修改配置 on_demand 为 false,网页未哀求则不处置惩罚 rtsp,满足大量 rtsp 配置选播放
[*]去掉 ice 配置,ice 配置是一个公网情况用的,内网没有
[*]新增 http 接口动态传入设备的摄像头配置,传递参数 key 和 rtsp 地址,假如 key 在配置里不存在则写入 config,其他和 /stream/codec/ 代码一致

完成修改后运行项目播放 ok,断网播放 ok,本地服务器 docker 摆设再次测试发现没法播放,毗连断了 WritePacket WebRTC Client Offline,

[*]搜索题目,发现项目 issue:https://github.com/deepch/RTSPtoWebRTC/issues/183,修改 docker 配置 network:"host"解决题目,再次测试播放 ok
https://img-blog.csdnimg.cn/direct/00ddcdf8790b4c64ae54d4eea8c32c59.png

[*]项目摆设 RTSPtoWebRTC 能播通信链路 ok,基本可以在项目上利用,固然项目 RTSPtoWebRTC 自己是 demo 型,一些细节未处置惩罚,比如 /stream/codec/ 接口内部在 coGe(suuid string) []av.CodecData 方法里直接 100 次循环,但是并未完成视频的期待,导致在后续流程 sps()会报错 index out of range,这个可以修改期待代码解决

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Web 播放 RTSP(Webrtc方案)