边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 -- 推流及公网环境(三)PART2
专栏目录
边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 – 整体介绍(一)
边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 – 边缘设备图像识别及部署(二)
边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 – 推流及公网环境(三)PART1
边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 -- 推流及公网环境(三)PART2
前言
从这一篇开始主要讲的就是怎么在公网环境下面获取视频流信息。其中步骤大致分成两个部分,1、产生网页可以识别的流信息。2、实现公网环境下的播放。
在本片中我会把我尝试的两种方式分别写下来,供大家参考。
准备工作和基础知识
请看:边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 – 推流及公网环境(三)PART1
方案一:hls推流和网络
请看:边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 – 推流及公网环境(三)PART1
方案二:webrtc推流和网络
这种方法是在和群里小伙伴沟通是否提到的,于是尝试了一下,的确效果很不错。基于webrtc进行网页的通信,当然这里面要稍显复杂,其中还有一个大坑。
webrtc的选择
webrtc知识一种视频的协议,目前来说只支持h264,经过这几年的发展大部分浏览器都已经适配webrtc功能。不光是电脑,IPhone也呢能够适配播放webrtc,但是鸿蒙好像还不可以。这里我只说用不说原理,不求甚解不然脑容量不够。
之前说过终端中使用了zlmediakit,根据官网显示是支持webrtc,常规的webrtc部署也完成了,但是网上实在找不到C++使用api实现webrtc的教程,于是这一步动作就卡了好几天。后来想到一种曲线救国的方案,系统已经可以产生检测后的rtsp了,再用webrtc-streamer来实现webrtc功能。
webrtc-streamer下载地址:https://github.com/mpromonet/webrtc-streamer
选择webrtc-streamer的原因就是,教程多,功能单一且能满足要求。为什么这么说呢,因为这个webrtc-streamer我们要部署在终端设备上,而不是服务器上。把所有的负载都均分到每一台机器上这是我们做这个项目的初衷。
部署测试
下载好webrtc-streamer-v0.8.5-Linux-arm64-Release.tar.gz
// 解压
tar -zxvf webrtc-streamer-v0.8.5-Linux-arm64-Release.tar.gz
// 进入目录
cd webrtc-streamer-v0.8.5-Linux-arm64-Release
进入目录会发现里面还有html?其实主程序就只有一个webrtc-streamer,html里面都是例子,同时有前端需要用到的js文件。
先不管其他的启动webrtc-streamer。
nohup ./webrtc-streamer > running.log 2>&1 &
没错就这么简单,一句话就行,它会默认打开8000端口。有兴趣弄清楚的可以去看看别的博客这方面真的很多不多说了。我们这里需要弄清webrtc-streamer和我们程序中的关系。
从这个关系可以看出网页端适合webrtc-streamer进行沟通获取视频流和终端检测程序并没有直接关系。类似于网页端和“WEBRTC-STREAMER”说:“我知道你家有个RTSP书叫做XXX,你不用直接给我,你读给我听。”
接下来可以在内网环境下进行页面编写和测试了。我是基于若依vue3搭建的系统就不写demo了直接改。
首先在index.html中加入两个js的引用,这两个文件是从webrtc-streamer的html中找到的。
<head>
...
<script type="text/javascript" src="/webrtcstreamer.js"></script>
<script type="text/javascript" src="/adapter.min.js"></script>
...
</head>
将webrtc播放封装成一个组件,方便后面的调用。我基本就是个前端菜鸟所以不好看将就一下了。
<template>
<div>
<header>
<h2 class="title">{{titleInfo}}{{insideTitle}}</h2>
</header>
<div class="content">
<video ref="videoElement" class="videoClass" :id="'video'+itemNO" autoplay muted playsinline controls></video>
</div>
<footer class="footer" style="display: block;padding: 12px;padding-right: 50px;margin: 12px;">
// 一些关于录制的代码
</footer>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ysFixWebmDuration from "fix-webm-duration"
const { proxy } = getCurrentInstance();
const props = defineProps({
serverUrl: {
type: String,
default: ''
},
videoUrl: {
type: String,
default: ''
},
audioUrl: {
type: String,
default: ''
},
options: {
type: String,
default: ''
},
codec: {
type: String,
default: null
},
itemNO:{
type: Number,String,
default: 0
},
titleInfo:{
type: String,
default: '视频'
}
});
const webRtcServer = ref(null);
const videoChunks = ref([])
const mediaRecorder = ref(null)
// 1录制2停止
const buttonDisable = ref(1)
const insideTitle = ref('')
const startTime = ref(0);
const initWebRtcServer = async () => {
nextTick(() => {
webRtcServer.value = new WebRtcStreamer('video'+props.itemNO, location.protocol + '//' + props.serverUrl);
webRtcServer.value.connect(props.videoUrl, props.audioUrl, props.options, undefined, props.codec);
});
};
// 屏幕录制
const handleScreenRecording = async () => {
// 后面的博客会说的
}
// 将blob数据转化为mp4格式,并保存到本地
const blobToFileSave = (blobData, type = 'video/mp4') => {
// 后面的博客会说的
}
onMounted(() => {
nextTick(() => {
initWebRtcServer(); // 传你的rtsp流地址
});
});
// 页面销毁时销毁webRtc
onUnmounted(() => {
webRtcServerDis();
});
function webRtcServerDis() {
if (webRtcServer.value) {
console.info('webRtcServerDis');
webRtcServer.value.disconnect();
}
};
</script>
<style scoped>
.title {
text-align: center;
}
.content {
flex-grow: 1;
overflow: auto;
min-height: 2em;
text-align: center;
position: relative;
width: 100%;
padding-bottom: 56.25%;
}
.videoClass {
width: 100%;
height: 100%;
margin: auto;
left: 0;
right: 0;
position: absolute;
background: grey;
}
</style>
其实从网页的调用也不难看出,前端主要需要知道webrtc-streamer的IP和端口,其次知道rtsp在内网地址和端口,就可以播放视频了。
进行内网测试会发现一切正常。观察网络请求看一下。
//对应发起请求
webRtcServer.value = new WebRtcStreamer('video'+props.itemNO, location.protocol + '//' + props.serverUrl);
webRtcServer.value.connect(props.videoUrl, props.audioUrl, props.options, undefined, props.codec);
//对应销毁请求hangup
webRtcServer.value.disconnect();
这里面还有个小注意点,webRtcServer.value.connect(props.videoUrl, props.audioUrl, props.options, undefined, props.codec);
中的props.videoUrl
、props.audioUrl
实际上是一个参数rtsp链接,类似rtsp://127.0.0.1:554/yunyan-live/test
这样才可以播放声音。props.options
也基本上是一个固定参数rtptransport=tcp%timeout=60
代表tcp链接,超时60秒关闭。销毁和超时一定要加上,流媒体服务器对CPU的负载会比较大。
解决坑点
坑一:内网环境下没问题,映射后不行
根据我简单的理解,既然webrtc使用tcp和服务器进行通行,还是使用frp应该没有问题。于是把webrtc的8000端口映射到公网的端口上IP(公):PORT,这样网页就可以直接调用播放。
于是我在电脑上访问了外网地址,点击播放成功。请注意此时我的电脑在内网环境
,也就是说通过内网IP可以访问到终端设备的。
将电脑连上手机热点,请注意此时我的电脑不在内网环境
,同样访问网页的外网地址点击播放,画面无法显示。
经过研究发现,webrtc-streamer如果想要公网使用需要配合coturn一起使用,好像也是一个方向代理工具,开始二次尝试。
coturn下载地址:https://github.com/coturn/coturn
我是实用编译安装的,网上也有别的教程,其实直接apt-get安装就好了,我是用的服务器是arm版本的ubuntu。
# 安装依赖
sudo apt install pkg-config libssl-dev libevent-dev -y
git clone git@github.com:coturn/coturn.git
cd coturn
sudo ./configure --prefix=/usr/local/coturn
# 编译安装
make && make install
# 修改环境变量可以直接调用指令
vi ~/.bashrc
##coturn,这是需要插入的内容
#export COTURN_HOME=/usr/local/coturn
#export PATH=$PATH:$COTURN_HOME/bin
source ~/.bashrc
#进入目录
cd /usr/local/coturn/etc
#复制一个配置文件出来,不过原版配置文件内容太多后面基本重新写了
sudo cp turnserver.conf.default turnserver.conf
#需要生成一个证书照抄就好
sudo openssl req -x509 -newkey rsa:2048 -keyout /usr/local/coturn/etc/turn_server_pkey.pem -out /usr/local/coturn/etc/turn_server_cert.pem -days 99999 -nodes
vi /usr/local/coturn/etc/turnserver.conf
cli-password=password#token越复杂越好
relay-device=enp0s6#服务器的网卡名称
listening-ip=10.0.0.251#服务器内网IP
listening-port=33478#根据需要设置
tls-listening-port=35349#根据需要设置
relay-ip=10.0.0.251#服务器内网IP
external-ip=XXXXXXXXXX#服务器公网IP
relay-threads=50
lt-cred-mech
min-port=49152
max-port=65535
cert=/usr/local/coturn/etc/turn_server_cert.pem
pkey=/usr/local/coturn/etc/turn_server_pkey.pem
pidfile=”/var/run/turnserver.pid”
user=admin:password
#启动coturn
turnserver -o -a -f -user=admin:password -c /usr/local/coturn/etc/turnserver.conf -r shijie
然后用浏览器打开这个地址https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/,这个网站可以测试部署的是否正确。具体原理没弄明白,不过按照上面步骤大概率不会出问题。
之后就是关于webrtc-streamer启动项的修改了,之前知识简单的启动没有加配置文件。现在需要修改成nohup ./webrtc-streamer -S公网IP:33478 -Tadmin:password@公网IP:33478 > running.log 2>&1 &
,觉得麻烦可以让AI帮你写一个sh脚本控制启动、关闭、重启。
坑二:webrtc导致cpu负载越来越高
其实负载高的问题网上一查就有解决方案就是在启动命令里面加上-o
,那么完整的启动命令就是nohup ./webrtc-streamer -o -S公网IP:33478 -Tadmin:password@公网IP:33478 > running.log 2>&1 &
。根据作者的描述-o
可以保持原码率播放,不需要解码和编码。
我在实际操作中加上-o
发现了一个问题,图像留影模糊。一开始一直以为是-o
导致的问题。在检查代码和研究中发现实在检测结果重新推流成rtsp时候出现了问题。在此不得不说vlc太过强大导致这个问题没有暴露。
其实每一帧画面在编码器封装时候有几个参数,1、画面数据,2、解码时间戳,3、播放时间戳。残影问题就是后面两个参数设置的有问题,导致webrtc无法正常运行。由于主程序是多线程的,这两个参数不好获取,于是在编码时候该用当前时间(毫秒)来解决。这样就可以正常播放了。
/**
* 输入单帧H264视频,帧起始字节00 00 01,00 00 00 01均可,请改用mk_media_input_frame方法
* @param ctx 对象指针
* @param data 单帧H264数据
* @param len 单帧H264数据字节数
* @param dts 解码时间戳,单位毫秒
* @param pts 播放时间戳,单位毫秒
* @return 1代表成功,0失败
*/
ret = mk_media_input_h264(ctx->media, enc_data, enc_data_size, millis, millis);
如果你喜欢这篇博客请点赞留言,后续会更新如何和云系统通信的以及保护进程做了些什么。
原文地址:https://blog.csdn.net/weixin_41864178/article/details/136735139
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!