前端使用Aliplayer 播放器 播放rtmp直播流

    技术2022-07-10  137

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

    前端框架:layui

    需求:

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

     2、实现PTZ云台控制。

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

    相关文档:

     播放器的属性接口说明文档

    https://help.aliyun.com/document_detail/125572.html?spm=a2c4g.11186623.4.1.131d1c4cC756EZ

    视频监控部分接口文档

    https://help.aliyun.com/document_detail/109559.html?spm=a2c4g.11186623.6.569.2c187d8aGDFSEd

     

    踩坑点:

    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&/&' + CanonicalizedQueryString).replace(/:/g, '%3A'); 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()); }

     

    Processed: 0.012, SQL: 9