• 纯前端如何在网页端播放摄像头的实时画面


    如何在网页端播放摄像头的实时画面

    初衷

    写这篇博客已经是项目过去很久了,之所以写是因为当时被这个问题为难了很久。我原本是做后端的,涉及到前端的东西,当时是两眼一黑。好在最后还是解决了。当相信这个内容还是有价值的,所以今天整理出来,帮助未来可能需求的人。

    应对的场景

    希望在自己的Web应用中播放局域网(不能上云),或是广域网的摄像头实时画面。

    涉及到的范围

    1. Nodejs 以及 Express
    2. WebSocket html页面拉流
    3. ffmpeg 推流用
    4. node-rtsp-stream 主要依赖这个东西,将 rtsp 流推送到 Ws
    5. JSMpeg 主要用来播放 ws 流画面

    这个解决方案是全前端方案,所以后端的流处理都是用Node处理的。

    解决问题的思路

    1. 首先要拿到摄像头的播放Rtsp通道。(有些是带密码的,有些不带密码)。
    2. 使用ffmpeg将rtsp流转成ws流。
    3. 当客户端请求播放摄像头画面的时候,Node接受请求,并将流地址返回给前端。
    4. 前端使用 JSMpeg 去播放ws流,画面呈现。
    5. 闭关的时候,仍然请求后端,用Node处理。闭关推流进程。

    摄像头的Rtsp地址

    因为这里没有摄像头,所以我在网上搜索了一个流地址:

      rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov'
    

    如果电脑中装了 VCL,则可以使用VCL的流地址播放功能去播放,这里我就不做演示了。

    ffmpeg 下载,安装,配置环境变量

    这里我在gitHub上找到了一个ffmepg下载地址 ,这个版本是windows版本的。

    安装就不用说了,下一步,下一步即可,最后就说配置环境变量。其作用就是在命令行状态下可以直接通过 ffmpeg 访问到文件。

    nodejs 和 Express

    nodejs 我就不详细介绍了,express也一样,这两个东西要是不会,这篇文章也就不用看了。

    然后就是写代码接受前端到http请求了。可以参考博客园里面的express介绍。稍后我会贴出代码,建议看看文档。

    Express参考

    接受请求的代码

    var express = require('express');
    const requestmanager = require('../lib/RequestManager')
    var router = express.Router();
    
    router.get('/', function (req, res) {
        res.send('Carmeras Server is Runing...');
    });
    
    /* GET users listing. */
    router.post('/', function (req, res) {
        var cfg = req.body
        let result = new requestmanager().Open(cfg)
        res.json(result)
    });
    
    router.post('/close', function (req, res) {
        var cfg = req.body
        new requestmanager().Close(cfg)
        res.json({ state: 'close the rtsp stream success.' })
    })
    
    

    这里用到了 node-rtsp-stream 、express 、express.Router 还引用了一个 RequestManager,这是我自己写的一个管理请求的包,代码如下:

    const Stream = require('node-rtsp-stream')
    const os = require('os');
    ///获取本机ip///
    function getIPAdress() {
        var interfaces = os.networkInterfaces();
        for (var devName in interfaces) {
            var iface = interfaces[devName];
            for (var i = 0; i < iface.length; i++) {
                var alias = iface[i];
                if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
                    return alias.address;
                }
            }
        }
    }
    const args = []
    const requestManager = function () { }
    //这里是在原型上加上打开和关闭两个方法
    requestManager.prototype = {
        Open: function (arg) {
            let result = {}
            if (args.length == 0) {
                result = this._create(arg)
                result = this._openVideo(result)
            } else {
                args.forEach(a => {
                    if (a.rtspUrl == arg.rtspUrl) {
                        result = a
                    }
                })
                if (result.port === undefined || result.rtspUrl === undefined) {
                    result = this._create(arg)
                    result = this._openVideo(result)
                }
            }
            result = Object.assign(result,{url:`ws:\\${getIPAdress()}:${result.port}`})
            return result;
        },
        Close: function (arg) {
            let result = {}
            let idx = -1
            idx = args.findIndex(a => a.rtspUrl == arg.rtspUrl)
            if (idx !== -1) {
                args[idx].stream.stop()
                result = args.splice(idx, 1)
            } else {
    
            }
            console.log(args)
            return result
        },
        //这里是产生一个随机端口号,用来推流使用。
        _randomPort: function () {
            let port = Math.floor(Math.random() * (4001 - 3001) + 3001)
            return port
        },
        //这里是核心推流代码,其实很简单。
        _openVideo: function (arg) {
            arg.stream = new Stream({
                name: 'name',
                //streamUrl: 'rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov',
                streamUrl: arg.rtspUrl,
                wsPort: arg.port,
                ffmpegOptions: { // options ffmpeg flags
                    '-stats': '', // an option with no neccessary value uses a blank string
                    '-r': 30, // options with required values specify the value after the key
                    '-s': arg.size,
                    '-codec:a': 'mp2',
                    '-ar': 44100,
                    '-ac': 1,
                    '-b:a': '128k'
                }
            })
            return arg
        },
        //这里创建参数。
        _create: function (arg) {
            let target = {
                rtspUrl: 'rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov',
                port: this._randomPort(),
                size: '1024*768',
                stream: null
            }
            let source = {
                rtspUrl: arg.rtspUrl,
                port: this._randomPort(),
                size: arg.size,
                stream: null
            }
            Object.assign(target, source)
            args.push(target)
            return target
        }
    
    }
    
    module.exports = requestManager
    

    当 Open方法被调用的时候,node-rtsp-stream会调用 ffmepg 程序开始推流。其参数如下:

     ffmpegOptions: { // options ffmpeg flags
                    '-stats': '', // an option with no neccessary value uses a blank string
                    '-r': 30, // options with required values specify the value after the key
                    '-s': arg.size,
                    '-codec:a': 'mp2',
                    '-ar': 44100,
                    '-ac': 1,
                    '-b:a': '128k'
                }
    

    这里关注 -s 它是设置画幅大小的。所以我这里用到了参数 arg.size。带_(下划线)的方法内部使用。 关键位置都给了注视了,一般应该是看的懂了。

    JSMpeg 播放 和请求打开关闭

    这是个第三方库,在gitee和gitHub上都有,这里列出Gitee上的地址JSMpeg
    我用到的关键代码就几句

     /*初始化并播放*/
     let player = new JSMpeg.Player(url, opt);
     /*销毁关闭*/
     player.destroy()
    

    至于请求,可以用axios 或是 jquery库,我这里用的是 jquery

           var player
            //关闭
            function closeStream() { 
                $.post("http://127.0.0.1:3000/cameras/close/", { rtspUrl: $('#rtsp').val() }, function (result) {
                    player.destroy()
                })
            }
    
            //打开
            function start() { 
                var rstp = $('#rtsp').val() 
                var size = $('#size').val()
                $.post("http://127.0.0.1:3000/cameras/", { rtspUrl:rstp, size:  size }, function (result) {  
                    var url = "ws://127.0.0.1:" + result.port;
                    var canvas = document.getElementById('video-canvas');
                    let opt = {
                        canvas: canvas,
                        poster: "0.jpg",
                    }
                    player = new JSMpeg.Player(url, opt);
                })
    
            }
    
    

    完整的Html如下:

    <!DOCTYPE html>
    
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <title>DEMO node-rtsp-stream-jsmpeg</title>
        <script src="https://jsmpeg.com/jsmpeg.min.js"></script>
        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    
        <style type="text/css">
            html,
            body {
    
                text-align: center;
            }
    
            input[type='text'] {
                 450px;
            }
        </style>
    </head>
    
    <body>
        <div>
            <!-- <span>rtsp : <input type="text" name="rtsp" id="rtsp"  value="rtsp://admin:xcs123456@192.168.3.11:554/h264/ch1/main/av_stream"></span><br /> -->
            <span>rtsp : <input type="text" name="rtsp" id="rtsp"  value="rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"></span><br />
                   
            <span>rtsp : <input type="text" name="size" id="size" value="1024*768"></span><br />
            <canvas id="video-canvas">
            </canvas><br />
    
            <input type="button" value="Start Stream" onclick="start()">
            <input type="button" value="Close Stream" onclick="closeStream()">
        </div>
    
     
        <script type="text/javascript">
            var player
    
            function closeStream() { 
                $.post("http://127.0.0.1:3000/cameras/close/", { rtspUrl: $('#rtsp').val() }, function (result) {
                    player.destroy()
                })
            }
    
    
            function start() { 
                var rstp = $('#rtsp').val() 
                var size = $('#size').val()
                $.post("http://127.0.0.1:3000/cameras/", { rtspUrl:rstp, size:  size }, function (result) {  
                    var url = "ws://127.0.0.1:" + result.port;
                    var canvas = document.getElementById('video-canvas');
                    let opt = {
                        canvas: canvas,
                        poster: "0.jpg",
                    }
                    player = new JSMpeg.Player(url, opt);
                })
    
            } 
        </script> 
    </body>
    

    以上就是全部的内容,完整代码可以到gitee上下载

    如果以上内容,对你有帮助,请帮忙推荐,谢谢!

  • 相关阅读:
    outer的使用
    MySQL按天,按周,按月,按时间段统计
    使用@JsonFormat引起的时间比正常时间慢8小时解决方法
    CPU上下文切换的次数和时间(context switch)
    Spring Controller 获取请求参数的几种方法
    MySQL 5.7 跟踪优化器
    tomcat 配置https
    Tomcat启动时项目重复加载,导致资源初始化两次的问题
    JSP中文乱码问题终极解决方案
    ClassCastException: org.apache.tomcat.websocket.server.WsServerContainer cannot be cast to javax.websocket.server.ServerContainer
  • 原文地址:https://www.cnblogs.com/LearningC/p/15925172.html
Copyright © 2020-2023  润新知