首页 > 建站教程 > 其他 >  详细的webrtc-streamer访问摄像机视频流教程正文

详细的webrtc-streamer访问摄像机视频流教程

前言

最近公司在搞流媒体,我推荐了webrtc-streamer进行搭建,使用了一段时间后,出现新的需求,需要将内网的摄像机进行公网访问,我查询了几乎所有的帖子和github的问题回复,都没有给我一个准确的答案,经过不断尝试和摸索,我终于成功了,我希望将我的过程记录下来,让更多的中国开发者可以少走弯路,我对于webrtc不是很了解,但是这并不影响我使用开源的webrtc-streamer进行开发。


一、webrtc-streamer的API

webrtc-streamer的服务地址:192.168.1.8:8000

查询所有api:http://192.168.1.8:8000/api/help

[
"/api/addIceCandidate",
"/api/call",
"/api/createOffer",
"/api/getAudioDeviceList",
"/api/getIceCandidate",
"/api/getIceServers",
"/api/getMediaList",
"/api/getPeerConnectionList",
"/api/getStreamList",
"/api/getVideoDeviceList",
"/api/hangup",
"/api/help",
"/api/log",
"/api/setAnswer",
"/api/version"
]


关键api:/api/getPeerConnectionList


我使用它来判断当前的webrtc-streamer正在连接的通道


2个通道:


   ICE: 交互式连接建立(Interactive Connectivity Establishment)

   ice_state:交互式连接状态(2:已连接/5:断开连接)

   pc_state:客户端连接状态(2:正常/3:断开)


已连接:

    "ice_state": 2

    "pc_state": 2


正在断开:

    "ice_state": 5

    "pc_state": 3


这种状态未知:

    "ice_state": 0

    "pc_state": 0


断开:

    无任何json数据


正常连接的json如下(sdp内容过多已删除):

[
  {
    "0.07123060004985127": {
      "ice_state": 2,
      "pc_state": 2,
      "sdp": "",
      "signaling_state": 0,
      "streams": {
        "15661718658374446496": {
          "15661718658374446496_video": {
            "kind": "video",
            "state": 1
          }
        }
      }
    }
  }
]


二、webrtc-streamer的启动命令介绍

./webrtc-streamer [-H http port] [-S[embeded stun address]] -[v[v]]  [url1]...[urln] 
./webrtc-streamer [-H http port] [-s[external stun address]] -[v[v]] [url1]...[urln]
./webrtc-streamer -V
    -v[v[v]]           : verbosity
    -V                 : 打印版本
    -H [hostname:]port : HTTPServer绑定 (default 0.0.0.0:8000)
-w webroot         : 获取文件的路径
-c sslkeycert      : HTTPS的私钥和证书路径
-N nbthreads       : HTTP服务器的线程数
-A passwd          : 用于HTTP服务器访问的密码文件
-D authDomain      : HTTP服务器访问的身份验证域(默认值:mydomain.com)
-S[stun_address]                   : 使用嵌入的STUN服务器绑定到地址(默认值为0.0.0.0:3478)
-s[stun_address]                   : 使用外部的STUN服务器绑定到地址(默认值为0.0.0.0:3478)
-t[username:password@]turn_address : 使用外部TURN中继服务器(默认:禁用)
-T[username:password@]turn_address : 使用嵌入式TURN中继服务器(默认:禁用)
-a[audio layer]                    : 指定要使用的音频捕获层(默认值:0)
-q[filter]                         : 指定发布筛选器(默认值:.*)
-o                                 : 使用空编解码器(保持帧编码)
-C config.json                     : 从JSON配置文件加载URL
-R [Udp port range min:max]        : 设置webrtc-udp端口范围(默认值为0:65535)
-n name -u videourl -U audiourl    : 注册视频url和音频url的名称
[url]                              : 要在源列表中注册的url


举例:

指定绑定ip端口:./webrtc-streamer -H 192.168.1.8:8123

webrtc-streamer


注意几个细节:

1、-o 这个命令务必要加上,不加的话你会发现你的cpu预览几路马上飙升到100%。

2、 -s/-S/-t/-T这几个命令后面不要有空格。

3、只支持H264的视频码流,H265不支持。


三、webrtc-streamer的安装部署

1.下载地址

https://github.com/mpromonet/webrtc-streamer/releases


2.windows版本部署

下载windows版本压缩包,解压后如下图

webrtc-streamer


在当前目录下输入命令webrtc-streamer.exe -H 192.168.1.227:8000 -o

再次强调 -o  为了不转码,进而降低cpu负荷。

webrtc-streamer


3.Linux版本部署

系统环境都正常的情况安装步骤如下:

    1.webrtc-streamer包:webrtc-streamer-v0.7.2-Linux-x86_64-Release.tar.gz

    2.拷贝到root下,解压:tar -xvf webrtc-streamer-v0.7.2-Linux-x86_64-Release.tar.gz

    3.进入webrtc-streamer-v0.7.2-Linux-x86_64-Release:cd webrtc-streamer-v0.7.2-Linux-x86_64-Release

webrtc-streamer


    4.执行 ./webrtc-streamer -H 192.168.1.10:8000 -o


四、springboot整合webrtc-streamer

1、前端部分:

       项目需要引入的js:webrtcstreamer.js、adapter.min.js、jquery-1.7.1.min.js

       我这里配置了24个video用来测试,分别支持宇视、大华、海康的RTSP流。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="adapter.min.js"></script>
    <script type="text/javascript" src="webrtcstreamer.js"></script>
    <script type="text/javascript" src="jquery-1.7.1.min.js"></script>
    <style>
        video {
            width: 300px;
            height: 200px;
        }
    </style>
</head>
<body>
<p>视频播放</p>
<div>
    <video id="video1" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video2" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video3" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video4" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video5" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video6" muted autoplay loop controls>muted controls disablePictureInPicture</video>
</div>
<div>
    <video id="video7" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video8" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video9" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video10" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video11" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video12" muted autoplay loop controls>muted controls disablePictureInPicture</video>
</div>
<div>
    <video id="video13" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video14" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video15" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video16" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video17" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video18" muted autoplay loop controls>muted controls disablePictureInPicture</video>
</div>
<div>
    <video id="video19" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video20" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video21" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video22" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video23" muted autoplay loop controls>muted controls disablePictureInPicture</video>
    <video id="video24" muted autoplay loop controls>muted controls disablePictureInPicture</video>
</div>
<script>
    var cameralist = new Array();
    var camera64 = {type: "hik", ipaddr: "192.168.1.64", username: "admin", password: "hik12345", port: 554};
    window.onload = function () {
        // 初始化内容
        cameralist.push(camera64);
        console.log(cameralist);
    }
    let num = 0;
 
    function getCamera() {
        let obj = cameralist[num];
        console.log(obj);
        num++;
        if (num == 1) {
            num = 0;
        }
        return obj;
    }
 
    let webRtcServer = null;
    let videoMap = new Map();
    $('video').click(function (e) {
        let ID = e.target.id;//获取当前点击事件的元素
        console.log(ID);
        if (videoMap.get(ID) != null) {
            closeVideo(ID, videoMap.get(ID));
        } else {
            let camera = getCamera();
            console.log(camera);
            if (camera.type == "ys") {
                realViewYs("192.168.1.11", ID, camera.username, camera.password, camera.ipaddr, camera.port);
            } else if (camera.type == "dh") {
                realViewDh("192.168.1.11", ID, camera.username, camera.password, camera.ipaddr, camera.port);
            } else {
                realViewHik("112.98.126.2", ID, camera.username, camera.password, camera.ipaddr, camera.port);
            }
        }
    });
 
 
    //预览海康相机
    function realViewHik(serverip, elem, username, password, ipaddr, port) {
        webRtcServer = new WebRtcStreamer(elem, "http://" + serverip + ":28000");
        let rtspUrl = "rtsp://" + username + ":" + password + "@" + ipaddr + ":" + port + "/ch1/main/av_stream";
        let option = "rtptransport=tcp";
        console.log("rtsp地址:" + rtspUrl);
        webRtcServer.connect(rtspUrl, null, option, null);
        videoMap.set(elem, webRtcServer);
    }
 
    //预览大华相机
    function realViewDh(serverip, elem, username, password, ipaddr, port) {
        webRtcServer = new WebRtcStreamer(elem, "http://" + serverip + ":8000");
        let rtspUrl = "rtsp://" + username + ":" + password + "@" + ipaddr + ":" + port + "/cam/realmonitor?channel=1&subtype=0";
        let option = "rtptransport=tcp";
        console.log("rtsp地址:" + rtspUrl);
 
        webRtcServer.connect(rtspUrl, null, option, null);
        videoMap.set(elem, webRtcServer);
    }
 
    //预览宇视相机
    function realViewYs(serverip, elem, username, password, ipaddr, port) {
        webRtcServer = new WebRtcStreamer(elem, "http://" + serverip + ":8000");
        let rtspUrl = "rtsp://" + username + ":" + password + "@" + ipaddr + ":" + port + "/media/video1/multicast";
        console.log("rtsp地址:" + rtspUrl);
        let option = "rtptransport=tcp";
        webRtcServer.connect(rtspUrl, null, option, null);
        videoMap.set(elem, webRtcServer);
    }
 
    function closeVideo(id, webrtc) {
        webrtc.disconnect();
        videoMap.delete(id);
    }
 
    //页面退出时销毁
    // window.onbeforeunload = function () {
    //     alert("页面关闭");
    //     webRtcServer.disconnect();
    // }
    //页面离开或者浏览器关闭的时候触发
    window.onbeforeunload = function (event) {
        $.ajax({
            // url: "../getIp",
            url: "http://127.0.0.1:12344/ard/videocall",
            type: "post",
            contentType: "application/json",
            dataType: "json",
            data: JSON.stringify({"cmd": "close", "url": "https://anruida.app.zihai.shop/?id=zns&pass=ard"}),
            success: function (data) {
            }
        });
        webRtcServer.disconnect();
    };
 
</script>


2、后端部分

        后端部分简单多了,初学者应该都会吧,直接配置个controller找这个html就行了。

@GetMapping("/")
String index() {
    return "view";
}


启动项目打开127.0.0.1:8080,至此,局域网内访问相机视频就完成了。


五、公网使用webrtc-streamer访问相机视频

通过上面的步骤局域网内访问相机视频流已经可以实现了,但是如果你想把项目部署到公网中进行访问就不行了。


公网部署步骤:

1、配置webrtc-streamer所在服务器的内网穿透地址,例如内网192.168.1.8:8000 映射到公网为110.154.21.14:18000

2、部署一个本地coturn服务器,配置conturn服务器配置文件,同时将conturn服务器的3478的tcp和udp端口进行公网映射。

3、前端js页面使用公网地址也就是110.154.21.14:18000配置webrtc-streamer

4、启动命令增加turn和stun服务器:webrtc-streamer.exe -o -H 192.168.1.8:8000 -S110.154.21.14:3478 -Tadmin:123456@110.154.21.14:3478


正式开始:

第一步,使用路由器将webrtc内网映射到公网,这个我相信你玩这个肯定会,不同的交换机配置不同。

第二步,Linux下WebRTC搭建私有turn/stun服务,目前coturn只支持linux。

    coturn是一个免费的开源的TURN/STUN服务器。coturn 服务器完整的实现了STUN/TURN/ICE协议,支持P2P穿透防火墙。

    STUN 服务器用于获取设备的外部网络地址。

    TURN 服务器是在点对点失败后用于通信中继。

    WebRTC 建立连接的步骤大概是这样的:

    客户端(浏览器)直接尝试直连;

    如果如果直连则通过 STUN 服务器进行穿透;

    如果无法穿透则通过 TURN 服务器进行中转。


1. 安装前准备

http://libevent.org/ 下载 libevent-2.1.12-stable.tar.gz

wget https://github.com/coturn/coturn/archive/4.5.1.1.tar.gz 下载 conturn-4.5.1.1.tar.gz (稳定版本)

(如果undefined reference to `SSL_CTX_up_ref'的错误换用稳定版本就好了。)


2. 安装gcc

yum install gcc-c++


3. 安装openssl-devel 

yum -y install openssl-devel


4. 安装libevent2

在http://libevent.org/下载libevent-2.1.8-stable.tar.gz

tar -zxvf libevent-2.1.8-stable.tar.gz

cd libevent-2.1.8-stable

./configure --prefix=/usr --libdir=/usr/lib64 (如果报错试试这个方式:./configure --prefix=/usr/local/coturn)

make

make install

成功没有出现报错信息


5. 安装conturn-4.5.1.1

tar -zxvf 4.5.1.1.tar.gz

cd coturn-4.5.1.1

./configure

make

make install


可以通过which turnserver验证。如果出现路径即为成功


6. 配置文件和签名,然后进入文件夹:

cd /usr/local/etc/ 会看到一个叫做 turnserver.conf.default的配置文件。将它备份:

cp turnserver.conf.default turnserver.conf


7. 在当前文件夹生成签名(自行输入):

openssl req -x509 -newkey rsa:2048 -keyout /usr/local/etc/turn_server_pkey.pem -out /usr/local/etc/turn_server_cert.pem -days 99999 -nodes


8. 修改配置文件

Vim turnserver.conf  参考如下

relay-device=eth0

listening-ip=#内网IP

listening-port=3478

tls-listening-port=5349

relay-ip=#内网IP

external-ip=#公网IP

relay-threads=50

lt-cred-mech

min-port=49152

max-port=65535

cert=/usr/local/etc/turn_server_cert.pem

pkey=/usr/local/etc/turn_server_pkey.pem

pidfile=”/var/run/turnserver.pid”

user=admin:123456

cli-password=123456

将配置文件更新如上。

   请一定要设置cli-password这一项,不设置会报错。

   注意检查cert和pkey的路径和名称。检查内网ip和公网ip是否填写准确。

   注意文本格式准确。


9. 启动turnserver

turnserver -o -a -f -user=admin:123456 -c /usr/local/etc/turnserver.conf -r xiamen

-o 是让程序在后台启动

-r 后面填个地区就行。

-user 一定要和配置文件中一样。

ps -ef|grep turnserver 指令查看是否启动服务,如果有


10. 验证

Trickle ICE:https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/

1、stun:+公网IP+端口,测试出现公网IP则代表部署成功

2、turn:+公网IP+端口,测试出现公网IP则代表部署成功