本次项目使用Aliplayer 播放器 播放rtmp直播流(户外摄像头的直播流),视频监控是用的阿里云的视频监控。

前端框架:layui

需求:

 1、使用阿里播放器插件Aliplayer,实现rtmp流的直播播放;

 2、实现PTZ云台控制。

3、调用PTZ云台控制接口的时候,公共参数中的签名结果串,是经过计算获得的,签名方式HMAC-SHA1。

java前端有什么插件可以直接播放rtsp流_html


 

踩坑点:

1、签名串算的时候踩坑了,先下载各sha1算法的插件,调试的时候,对着官方文档的例子先算一下,是否输出正确,如果不正确报错,阿里云也会给返回值,可根据返回结果查看一下哪里的问题。

https://help.aliyun.com/document_detail/109568.html?spm=a2c4g.11186623.2.12.26d9200frMF1JS

2、Aliplayer播放rtmp格式,加载直播流之后画面不动,花了很多时间去查资料。开始以为是因为配置参数写法格式错误,后来发现加引号和不加引号其实都可以。

最后提的阿里工单,解决办法:

给播放器参数加上

rtmpBufferTime: 0,
showBuffer: 0,

(rmtp流是纯视频流,没有音频流,参数设置是对于纯视频流的播放兼容参数)

这次是在有参考的情况下还用了这么长时间调试,实在是不应该啊。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
    <title>Aliplayer在线配置</title>
    <link rel="stylesheet" href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css" />
    <script type="text/javascript" charset="utf-8" src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js"></script>
    <link rel="stylesheet" href="layuiadmin/layui/css/layui.css" media="all">
    <style>
        #set {
        position: absolute;
        right: 15px;
        top: 15px;
        z-index: 9999
        }

    #control{width: 200px;height: 200px;}
    #control ul li{width: 33.33%;float: left;margin-bottom: 10px;text-align: center;}
    .bgcon{
    padding: 10px 5px 5px;
    width: 210px;
    height: 132px;
    display: table;
    background-color: rgba(0,142,240,.1);
    border-radius: 5px;
    border: 1px solid rgba(0,142,240,.2);
    margin-bottom: 10px;
}

    </style>
</head>

<body>
    <button class="layui-btn layui-btn-normal" id="set">设置</button>
    <div class="prism-player" id="player-con">
    </div>
    <div id="control" style="display: none;padding: 10px">
        <ul class="bgcon">
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(0.5,0.5,0)" onmouseup="stop_move()"><span>↖ </span></button>
            </li>
            <li><button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(0,0.5,0)" onmouseup="stop_move()"><span>↑ </span></button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(-0.5,0.5,0)" onmouseup="stop_move()"><span>↗ </span></button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(0.5,0,0)" onmouseup="stop_move()"><span>← </span></button>
            </li>
            <li style="text-align: center;line-height: 38px;position: relative; ">
                方向调节 </button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(-0.5,0,0)" onmouseup="stop_move()"><span>→ </span></button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(0.5,-0.5,0)" onmouseup="stop_move()"><span>↙ </span></button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(0,-0.5,0)" onmouseup="stop_move()"><span>↓ </span></button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(-0.5,-0.5,0)" onmouseup="stop_move()"><span>↘ </span></button>
            </li>
        </ul>
        <ul class="bgcon">
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_adjust(0,-0.5)" onmouseup="stop_adjust()"><span>-</span></button>
            </li>
            <li style="line-height: 38px;"> 变焦
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_adjust(0,0.5)" onmouseup="stop_adjust()"><span>+</span></button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(0, 0, -0.5)" onmouseup="stop_move()"><span>-</span></button>
            </li>
            <li style="line-height: 38px;">
                变倍 </button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_move(0, 0, 0.5)" onmouseup="stop_move()"><span>+</span></button>
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_adjust(-0.5,0)" onmouseup="stop_adjust()"><span>-</span></button>
            </li>
            <li style="line-height: 38px;">
                光圈
            </li>
            <li>
                <button type="button" class="layui-btn layui-btn-normal" onmousedown="start_adjust(0.5,0)" onmouseup="stop_adjust()"><span>+</span></button>
            </li>
        </ul>
    </div>
    <script src="layuiadmin/layui/layui.js"></script>
    <script>
    layui.config({
        version: true, //一般用于更新模块缓存,设为 true 即让浏览器不缓存。
        base: 'layuiadmin/' //静态资源所在路径
    }).extend({
        index: 'lib/index' //主入口模块
    }).use(['index', 'layer', 'commonUtils', 'request'], function() {
        var $ = layui.$,
            commonUtils = layui.commonUtils,
            request = layui.request,
            layer = layui.layer;
        var id = 'xxxx'; //摄像头设备id
        var AccessKeyId = 'xxx';//阿里云控制台的密钥
        var AccessKeySecret = 'xxxx';

        var player = null;
        if (player) {
            player.dispose(); //销毁
            $('#player-con').empty();
        }
        player = new Aliplayer({
            id: "player-con",
            width: "100%",
            height: "400px",
            autoplay: true, //自动播放
            rePlay: false,//重播视频
            isLive: true,//是否直播
            useH5Prism: true, //指定使用H5播放器。
            useFlashPrism: false, //指定使用Flash播放器
            rtmpBufferTime: 0,
            showBuffer: 0,
            stashInitialSizeForFlv: 30, //H5播放flv时,初始缓存大小,只在直播下起作用。 
            source: 'rtmp://....' //rtmp格式的地址
        }, function(player) {
            // player.on("ready", function(e) {}); 
        });


        $("#set").click(function() {
            layer.open({
                type: 1,
                anim: -1,
                title: 'control',
                closeBtn: 1,
                // shade: 0.1,
                shadeClose: true,
                content: $('#control'),
                area: ['240px', '420px']
            })
        })

       //摄像头移动
        window.start_move = function(pan, tilt, zoom) {

            var params = {
                Action: 'ContinuousMove',
                Id: id,
                Pan: pan,
                Tilt: tilt,
                Zoom: zoom,
                Version: '2018-12-12',
                AccessKeyId: AccessKeyId,
                Signature: '',
                SignatureMethod: 'HMAC-SHA1',
                Timestamp: Timestamp(),
                SignatureVersion: '1.0',
                SignatureNonce: commonUtils.UUID(),
                Format: 'JSON'
            };

            params.Signature = Signature(params);
 
            ali_api(params)
        }
       //停止转动
        window.stop_move = function() {
            const params = {
                Action: 'StopMove',
                Id: id,
                Pan: true,
                Tilt: true,
                Zoom: true,
                Version: '2018-12-12',
                AccessKeyId: AccessKeyId,
                Signature: '',
                SignatureMethod: 'HMAC-SHA1',
                Timestamp: Timestamp(),
                SignatureVersion: '1.0',
                SignatureNonce: commonUtils.UUID(),
                Format: 'JSON'
            };

            params.Signature = Signature(params);
            ali_api(params)
        }
        //设置光圈,焦点
        window.start_adjust = function(Iris, Focus) {

            var params = {
                Action: 'ContinuousAdjust',
                Id: id,
                Iris: Iris,
                Focus: Focus,
                Version: '2018-12-12',
                AccessKeyId: AccessKeyId,
                Signature: '',
                SignatureMethod: 'HMAC-SHA1',
                Timestamp: Timestamp(),
                SignatureVersion: '1.0',
                SignatureNonce: commonUtils.UUID(),
                Format: 'JSON'
            };

            params.Signature = Signature(params);

            ali_api(params)
        }
        //停止设置光圈焦点
        window.stop_adjust = function() {
            const params = {
                Action: 'StopAdjust',
                Id: id,
                Iris: true,
                Focus: true,
                Version: '2018-12-12',
                AccessKeyId: AccessKeyId,
                Signature: '',
                SignatureMethod: 'HMAC-SHA1',
                Timestamp: Timestamp(),
                SignatureVersion: '1.0',
                SignatureNonce: commonUtils.UUID(),
                Format: 'JSON'
            };

            params.Signature = Signature(params);
            ali_api(params)
        }
        //发送请求
        function ali_api(params) {

            $.ajax({
                url: 'http://vs.cn-qingdao.aliyuncs.com',
                type: 'GET',
                async: true,
                data: params,
                success: function(res, status, xhr) {

                },
                error: function(jqXHR, textStatus, errorThrown) {
                    layer.msg(errorThrown);
                }
            })



        }
        /* 签名结果串 计算。
           关于签名的计算方法,参见签名机制。
           https://help.aliyun.com/document_detail/109568.html?spm=a2c4g.11186623.2.12.58c1200f7NANPp
         */

        function Signature(params) {
            var data = [];
            var keys = Object.keys(params).sort();

            for (var i = 0; i < keys.length; i++) {
                var key = keys[i];
                if (key === 'Signature') {
                    continue;
                }
                data.push(key + '=' + params[key]);
            }
            var CanonicalizedQueryString = escape(data.join('&'));

            var StringToSign = ('GET&%2F&' + CanonicalizedQueryString).replace(/%3A/g, '%253A');

            return commonUtils.hmacsha1(AccessKeySecret + '&', StringToSign).toString(); //第一个参数为Key ,第二个参数为 StringToSign
        }

        //时间戳
        function Timestamp() {
            var timestamp = (new Date().getTime()) - (60 * 60 * 8 * 1000);
            var date = new Date(timestamp);
            return date.getFullYear() +
                '-' +
                ('00' + (date.getMonth() + 1)).substr(-2) +
                '-' +
                ('00' + date.getDate()).substr(-2) +
                'T' +
                ('00' + date.getHours()).substr(-2) +
                ':' +
                ('00' + date.getMinutes()).substr(-2) +
                ':' +
                ('00' + date.getSeconds()).substr(-2) +
                'Z';
        }

    });
    </script>
</body>

调用的commonUtils.hmacsha1  方法

//调用的commonUtils.hmacsha1
hmacsha1:function(k, d, _p, _z) {
            // heavily optimized and compressed version of http://pajhome.org.uk/crypt/md5/sha1.js
            // _p = b64pad, _z = character size; not used here but I left them available just in case
            if (!_p) { _p = '='; }
            if (!_z) { _z = 8; }

            function _f(t, b, c, d) { if (t < 20) { return (b & c) | ((~b) & d); } if (t < 40) { return b ^ c ^ d; } if (t < 60) { return (b & c) | (b & d) | (c & d); } return b ^ c ^ d; }

            function _k(t) { return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : (t < 60) ? -1894007588 : -899497514; }

            function _s(x, y) { var l = (x & 0xFFFF) + (y & 0xFFFF),
                    m = (x >> 16) + (y >> 16) + (l >> 16); return (m << 16) | (l & 0xFFFF); }

            function _r(n, c) { return (n << c) | (n >>> (32 - c)); }

            function _c(x, l) { x[l >> 5] |= 0x80 << (24 - l % 32);
                x[((l + 64 >> 9) << 4) + 15] = l; var w = [80],
                    a = 1732584193,
                    b = -271733879,
                    c = -1732584194,
                    d = 271733878,
                    e = -1009589776; for (var i = 0; i < x.length; i += 16) { var o = a,
                        p = b,
                        q = c,
                        r = d,
                        s = e; for (var j = 0; j < 80; j++) { if (j < 16) { w[j] = x[i + j]; } else { w[j] = _r(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); } var t = _s(_s(_r(a, 5), _f(j, b, c, d)), _s(_s(e, w[j]), _k(j)));
                        e = d;
                        d = c;
                        c = _r(b, 30);
                        b = a;
                        a = t; } a = _s(a, o);
                    b = _s(b, p);
                    c = _s(c, q);
                    d = _s(d, r);
                    e = _s(e, s); } return [a, b, c, d, e]; }

            function _b(s) { var b = [],
                    m = (1 << _z) - 1; for (var i = 0; i < s.length * _z; i += _z) { b[i >> 5] |= (s.charCodeAt(i / 8) & m) << (32 - _z - i % 32); } return b; }

            function _h(k, d) { var b = _b(k); if (b.length > 16) { b = _c(b, k.length * _z); } var p = [16],
                    o = [16]; for (var i = 0; i < 16; i++) { p[i] = b[i] ^ 0x36363636;
                    o[i] = b[i] ^ 0x5C5C5C5C; } var h = _c(p.concat(_b(d)), 512 + d.length * _z); return _c(o.concat(h), 512 + 160); }

            function _n(b) { var t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
                    s = ''; for (var i = 0; i < b.length * 4; i += 3) { var r = (((b[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) | (((b[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) | ((b[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF); for (var j = 0; j < 4; j++) { if (i * 8 + j * 6 > b.length * 32) { s += _p; } else { s += t.charAt((r >> 6 * (3 - j)) & 0x3F); } } } return s; }

            function _x(k, d) { return _n(_h(k, d)); }
            return _x(k, d);
        }

调用的UUID() 随机数的函数

/**
     * 生成UUID
*/

random4: function() {
       return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}

UUID: function() {
  return (commonUtils.random4() + commonUtils.random4() + "-" + commonUtils.random4() + "-" + commonUtils.random4() + "-" + commonUtils.random4() + "-" + commonUtils.random4() + commonUtils.random4() + commonUtils.random4());
}