欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

视频监控直播项目经验总结

程序员文章站 2022-07-13 12:07:03
...

项目说明

公司最近想要将智慧展厅中的海康摄像头布控系统功能 做成一套Web端的展示界面方便用于对外做展示。主要功能点:摄像视频监控播放,进出人员人脸识别报警,图表展示

  • 技术栈:React+Mobx+Echarts+Flvjs+Antd+Swiper

web端实现视频监控播放

关于海康摄像头输出

海康默认输出的是rtsp协议的视频流,而这在PC端是无法直接通过video的形式来播放的,所以这中间需要一层转码。

  • 常用的转码工具有FFmpeg,Live555
  • 转码方式: rstp–> rtmp,flv,hls

rtmp,flv,hls三者区别

由于rtmp需要flash支持,而chrome默认已经禁用了flash插件且到2020.12后停用flash,而flash本身也即将被淘汰,所以暂不考虑rtmp

- RTMP HLS HTTP-FLV
协议 TCP长连接 HTTP短连接 HTTP长链接
原理 每个时刻的数据收到后立刻转发 集合一段时间的数据,生成切片文件,并更新m3u8索引 将流媒体数据封装成 FLV 格式,然后通过 HTTP 协议传输给客户端【基于 HTTP/80 传输】。
延时 1-3秒 5-20秒(依切片情况) 1-3秒
Web支持 H5中需要用插件video.js 支持H5 H5中需要使用插件flv.js
其他 跨平台支持差,需要Flash技术支持 播放时需要多次请求,对网络质量要求高 需要flash技术支持(但可以通过flv.js来实现无flash播放),不支持多音频流,多视频流
缺陷 基于TCP,可能会被防火墙阻拦, 延迟高,网络要求高 会让流媒体资源缓存在本地客户端,在保密性方面不够好

项目应用方案

项目前后经过三次技术尝试:

  1. jsmpeg+canvas+websocket实现前端播放rtsp,参考html5播放rtsp方案
  2. hls+video.js实现H5播放【延迟高】
  3. flv+flv.js实现H5播放【最终方案】

canvas直接播放视频

这种方式前端用到jsmpeg插件,通过webSocket发送MPEG,前端通过js解析MPEG不断绘制canvas,包括音频。html5播放rtsp方案

  • ffmpeg解码:用于视频解码
  • node:搭建webSocket服务器,以及运行一个jsmpeg的js文件,
  • jsmpeg:运行主程序(绘制canvas播放视频及音频)

放弃原因:视频虽然能够正常播放,但容易花屏(搜索解决方案后说在ffmpeg解码时默认使用的是UDP协议,可以设置使用TCP进行解码可以解决),而且这套方案不适合放在生产环境上

hls视频流播放

起初用这套方案是因为后台只会转hls协议流视频,所以临时用这种方式实现播放,后端通过转码后给到的地址像这样http://xxxxxxx.m3u8,HLS是Apple公司推出的一种视频流协议,在IOS上兼容性可以说很好,而且视频做移动端项目,缺陷在于延迟较高,PC在播放容易卡顿

  • video.js:前端拿到HLS的视频地址后,只需要一个video.js用于视频播放即可(也可用hls.js包更小更方便,video.js在7.x版本后默认是引用了hls.js的)

flv直播

最终选择这套方案是因为flv相对hls延迟更低,可以无flash插件播放。最终确定后端实现rtsp到http-flv格式的转码,前端实现flv视频流的播放

  • 工具:flv.js
import React,{Component} from 'react'
import Flv from 'flv.js'

class VideoPlayer extends Component{
    videoNode = React.createRef()
    render(){
        setTimeout(()=>{
           this.reRenderVideo()
        },0)
        return(
            <div className="video-wrapper height-100">       
                <video style={{width:'100%',height:'100%'}} ref={this.videoNode} id="videoElement"></video>
            </div>
        )
    }
    componentDidMount(){
        if (this.flvPlayer) {
            this.flvPlayer.destroy();
        }
        var videoElement = this.videoNode.current;
        this.flvPlayer = Flv.createPlayer({
            type: 'flv',
            //后端最终给到的视频流地址
            url: 'http://192.168.0.253:9001/live?port=xxxx&app=xxxx&stream=bb646a3390', 
            muted:true,
        });
        this.flvPlayer.attachMediaElement(videoElement);
        this.flvPlayer.load();
        this.flvPlayer.play();
    }

    componentWillUnmount() {
        if (this.flvPlayer) {
            this.flvPlayer.destroy();
        }
    }
}
export default VideoPlayer;

Swiper引入问题记录

由于需要用到多视频画面切换以及进出人员展示的swiper所以想用引用这个库。这里只记录遇到的问题

问题一:在componentDidMount中设置new Swiper('.swiper-container')时,没有相应效果。【原因猜想:DOM挂载的异步延迟使得swiper在加载时没有拿到相应的DOM,导致渲染不成功】

  1. 引入swiper上
import Swiper from 'swiper'
import 'swiper/css/swiper.min.css'
  1. 解决:通过setTimeout(()=>{},0)的方式延后设置。估计是DOM挂载完成时间问题

Echarts使用问题记录

echarts算是用得很多的一款数据可视化工作库了,这次主要难点在于它的渐变色块的实现吧
解决方法:使用echarts内置的渐变色生成器来实现,通过封装实现

import echarts from "echarts";

/*
* @description 利用echarts渐变生成器来实现图表渐变色
* @param {string} color1  起始色
* @param {string} color2  终止色
* @return {object}  渐变对象
* */
export function generateGradient(color1,color2){
    return new echarts.graphic.LinearGradient(
        0, 0, 1, 0,
        [
            {offset: 0, color: color1},
            {offset: 1, color: color2},
        ]
    )
}

/*
* @description 将传入的渐变起止色二维数组转化为echarts可用的渐变值
* @param {array} colorList 渐变色数组
* @return {array} 渐变值数组
* */
export function generateColorList(colorList ){
    if(colorList.length<=0){return false}
    let res = colorList.map(item=>{
        return generateGradient(item[0],item[1])
    })
    return res
}

项目打包优化

由于使用的是create-react-app脚手架搭建的项目,在打包时生成的文件还是挺大的,最大的js达到了1.1MB,这导致首屏加载白屏时间很长差不多要10s了

1. 开启webpack打包分析

  • 借助webpack-bundle-analyzer插件可以实现对打包后文件的文件大小分析
  • npm install -D webpack-bundle-analyzer
  • 通过npm run eject可以不可逆的打开create-react-app的自定义webpack配置,从而实现自定义
// webpack.config.js
const BundleAnalyzerPlugin= require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
..省略千字..
plugins:[
//打包大小分析
      new BundleAnalyzerPlugin(
        {
          analyzerMode: 'server',
          // analyzerHost: '127.0.0.1',
          analyzerPort: 8889,
          reportFilename: 'report.html',
          //  应该是`stat`,`parsed`或者`gzip`中的一个。
          defaultSizes: 'parsed',
          //  在默认浏览器中自动打开报告
          openAnalyzer: true,
          //  如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
          generateStatsFile: false,
          statsFilename: 'stats.json',
          statsOptions: null,
          logLevel: 'info' /*日志级别。可以是'信息','警告','错误'或'沉默'。*/

        })
   ]
  • 效果如下图
    视频监控直播项目经验总结

2. 服务端开启Gzip

  • 这一步让运维小哥做好对应服务的Gzip开启就好了,自己测试玩儿的服务器也可以用如下配置来开启某一服务的Gzip
location /cameraControl {
    # 映射服务器
    proxy_pass http://47.98.146.53:81/camera-control;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    index  index.html index.htm index.jsp;
    # 开启gzip压缩
    gzip  on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_comp_level 2;
    gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/javascript;
    gzip_disable "MSIE [1-6]\.";
    gzip_vary on;

}
  • 开启以后,通过chrome控制台可以查看是否开启成功,方法如下:打开Network–》在信息table头处右键–》Response Header–》勾选Content-Encoding
    视频监控直播项目经验总结

3. 引入的antd V3.24.0 默认引入的icons资源过大

在通过webpack-bundle-plugin打包分析可以看出,整个打包出来最大的js文件中,包含antd的内容也是最大的,而antd中光icons资源都占有了483K左右(parsed),优化方案:通过将icons资源单独打包出来,并异步加载引用实现主js包大小的缩减。【目前版本的antd即使不引用Icon组件一样会有这样么大的包,所以只能通过优化打包的方式缩减,未来antd优化了这一部分issue就可以再去除这步】

  • npm install webpack-ant-icon-loader
// webpack.config.js
optimization:{
	splitChunk:{
		chunks:function(chunk){
          // 这里的name 可以参考在使用`webpack-ant-icon-loader`时指定的`chunkName`
          return chunk.name !== 'antd-icons';
        },
	}
}
  • 最终打包后会发现多了一个antd-icons.14c2af0f.chunk.js文件,这就是分离出来的antd-icon,

最终效果图

视频监控直播项目经验总结