把dist加入版本库

This commit is contained in:
langhuihui
2020-01-29 11:08:16 +08:00
parent 45748aa006
commit 4e0934451b
36 changed files with 2355 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
.DS_Store
node_modules
/dist
# local env files
.env.local

1
dashboard/dist/css/app.b4fc79e8.css vendored Normal file
View File

@@ -0,0 +1 @@
#app,body,html{height:100%}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#184c18;position:relative}#app>div:first-child{position:absolute;top:10px;left:30px;font-size:x-large}.content{padding-top:60px}.feature-title[data-v-54efad41]{color:#eb5e46;font-weight:700;font-size:larger}p[data-v-54efad41]{margin:30px;font-size:20px}img[data-v-54efad41]{margin:20px}.root[data-v-e34eab40]{background:#d3d3d3}.root>img[data-v-e34eab40]{width:300px;margin:30px}@-webkit-keyframes recording-data-v-7b106554{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}@keyframes recording-data-v-7b106554{0%{opacity:.2}50%{opacity:1}to{opacity:.2}}.recording[data-v-7b106554]{-webkit-animation:recording-data-v-7b106554 1s infinite;animation:recording-data-v-7b106554 1s infinite}.layout[data-v-7b106554]{padding-bottom:30px;position:relative}.room[data-v-7b106554]{width:250px;margin:10px;text-align:left}.empty[data-v-7b106554]{color:#eb5e46;width:100%;min-height:500px;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.empty[data-v-7b106554],.status[data-v-7b106554]{display:-webkit-box;display:-ms-flexbox;display:flex}.status[data-v-7b106554]{position:fixed;left:5px;bottom:10px}.status>div[data-v-7b106554]{margin:0 5px}

File diff suppressed because one or more lines are too long

17
dashboard/dist/docs/404.html vendored Normal file
View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Monibuca</title>
<meta name="description" content="">
<link rel="preload" href="/docs/assets/css/styles.ad3166d6.css" as="style"><link rel="preload" href="/docs/assets/js/app.ad3166d6.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.83ce04b6.js"><link rel="prefetch" href="/docs/assets/js/2.142d04d2.js"><link rel="prefetch" href="/docs/assets/js/3.2b6c987b.js"><link rel="prefetch" href="/docs/assets/js/4.ad90d74a.js"><link rel="prefetch" href="/docs/assets/js/5.36121818.js">
<link rel="stylesheet" href="/docs/assets/css/styles.ad3166d6.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><div class="content"><h1>404</h1><blockquote>There's nothing here.</blockquote><a href="/docs/" class="router-link-active">Take me home.</a></div></div></div>
<script src="/docs/assets/js/app.ad3166d6.js" defer></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="12" height="13"><g stroke-width="2" stroke="#aaa" fill="none"><path d="M11.29 11.71l-4-4"/><circle cx="5" cy="5" r="4"/></g></svg>

After

Width:  |  Height:  |  Size: 216 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{161:function(t,e,s){"use strict";s.r(e);var n=s(0),i=Object(n.a)({},(function(){var t=this.$createElement;this._self._c;return this._m(0)}),[function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"content"},[e("h1",{attrs:{id:"更新历史"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#更新历史","aria-hidden":"true"}},[this._v("#")]),this._v(" 更新历史")]),e("ul",[e("li",[this._v("2020/1/27\n1.0完成")])])])}],!1,null,null,null);e.default=i.exports}}]);

View File

@@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{164:function(t,n,e){"use strict";e.r(n);var s=e(0),c=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"content"})}),[],!1,null,null,null);n.default=c.exports}}]);

View File

@@ -0,0 +1 @@
(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{165:function(s,a,t){"use strict";t.r(a);var e=t(0),n=Object(e.a)({},(function(){var s=this.$createElement;this._self._c;return this._m(0)}),[function(){var s=this,a=s.$createElement,t=s._self._c||a;return t("div",{staticClass:"content"},[t("h1",{attrs:{id:"jessica"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#jessica","aria-hidden":"true"}},[s._v("#")]),s._v(" Jessica")]),t("p",[s._v("该插件为基于WebSocket协议传输音视频的订阅者音视频数据以裸数据的形式进行传输我们需要Jessibuca播放器来进行播放\nJessibua播放器已内置于源码中该播放器通过js解码H264并用canvas进行渲染可以运行在几乎所有的终端浏览器上面。\n在Monibuca的Web界面中预览功能就是使用的Jessibuca播放器。")]),t("h2",{attrs:{id:"配置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#配置","aria-hidden":"true"}},[s._v("#")]),s._v(" 配置")]),t("p",[s._v("目前仅有的配置是监听的端口号")]),t("div",{staticClass:"language-toml extra-class"},[t("pre",{pre:!0,attrs:{class:"language-toml"}},[t("code",[t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("[")]),t("span",{pre:!0,attrs:{class:"token table class-name"}},[s._v("Plugins.Jessica")]),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("]")]),s._v("\n"),t("span",{pre:!0,attrs:{class:"token key property"}},[s._v("ListenAddr")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v("=")]),s._v(" "),t("span",{pre:!0,attrs:{class:"token string"}},[s._v('":8080"')]),s._v("\n")])])])])}],!1,null,null,null);a.default=n.exports}}]);

File diff suppressed because one or more lines are too long

173
dashboard/dist/docs/develop.html vendored Normal file
View File

@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>插件开发 | Monibuca</title>
<meta name="description" content="">
<link rel="preload" href="/docs/assets/css/styles.ad3166d6.css" as="style"><link rel="preload" href="/docs/assets/js/app.ad3166d6.js" as="script"><link rel="preload" href="/docs/assets/js/2.142d04d2.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.83ce04b6.js"><link rel="prefetch" href="/docs/assets/js/3.2b6c987b.js"><link rel="prefetch" href="/docs/assets/js/4.ad90d74a.js"><link rel="prefetch" href="/docs/assets/js/5.36121818.js">
<link rel="stylesheet" href="/docs/assets/css/styles.ad3166d6.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/docs/" class="home-link router-link-active"><!----><span class="site-name">
Monibuca
</span></a><div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><!----></div></header><div class="sidebar-mask"></div><div class="sidebar"><!----><ul class="sidebar-links"><li><a href="/docs/" class="sidebar-link">起步</a></li><li><a href="/docs/develop.html" class="active sidebar-link">插件开发</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/docs/develop.html#插件的定义" class="sidebar-link">插件的定义</a></li><li class="sidebar-sub-header"><a href="/docs/develop.html#插件的安装" class="sidebar-link">插件的安装</a></li><li class="sidebar-sub-header"><a href="/docs/develop.html#开发订阅者插件" class="sidebar-link">开发订阅者插件</a></li><li class="sidebar-sub-header"><a href="/docs/develop.html#开发发布者插件" class="sidebar-link">开发发布者插件</a></li><li class="sidebar-sub-header"><a href="/docs/develop.html#开发钩子插件" class="sidebar-link">开发钩子插件</a></li></ul></li><li><a href="/docs/history.html" class="sidebar-link">更新日志</a></li><li><div class="sidebar-group collapsable"><p class="sidebar-heading"><span>内置插件</span><span class="arrow right"></span></p><!----></div></li></ul></div><div class="page"><div class="content"><h1 id="插件开发"><a href="#插件开发" aria-hidden="true" class="header-anchor">#</a> 插件开发</h1><h2 id="插件的定义"><a href="#插件的定义" aria-hidden="true" class="header-anchor">#</a> 插件的定义</h2><p>所谓的插件,没有什么固定的规则,只需要完成<code>安装</code>操作即可。插件可以实现任意的功能扩展,最常见的是实现某种传输协议用来推流或者拉流</p><h2 id="插件的安装"><a href="#插件的安装" aria-hidden="true" class="header-anchor">#</a> 插件的安装</h2><p>下面是内置插件jessica的源码代表了典型的插件安装</p><div class="language-go extra-class"><pre class="language-go"><code><span class="token keyword">package</span> jessica
<span class="token keyword">import</span> <span class="token punctuation">(</span>
<span class="token punctuation">.</span> <span class="token string">&quot;github.com/langhuihui/monibuca/monica&quot;</span>
<span class="token string">&quot;log&quot;</span>
<span class="token string">&quot;net/http&quot;</span>
<span class="token punctuation">)</span>
<span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token function">new</span><span class="token punctuation">(</span>ListenerConfig<span class="token punctuation">)</span>
<span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">InstallPlugin</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>PluginConfig<span class="token punctuation">{</span>
Name<span class="token punctuation">:</span> <span class="token string">&quot;Jessica&quot;</span><span class="token punctuation">,</span>
Type<span class="token punctuation">:</span> PLUGIN_SUBSCRIBER<span class="token punctuation">,</span>
Config<span class="token punctuation">:</span> config<span class="token punctuation">,</span>
Run<span class="token punctuation">:</span> run<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">func</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
log<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;server Jessica start at %s&quot;</span><span class="token punctuation">,</span> config<span class="token punctuation">.</span>ListenAddr<span class="token punctuation">)</span>
log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span><span class="token function">ListenAndServe</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>ListenAddr<span class="token punctuation">,</span> http<span class="token punctuation">.</span><span class="token function">HandlerFunc</span><span class="token punctuation">(</span>WsHandler<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div><p>当主程序读取配置文件完成解析后会调用各个插件的Run函数上面代码中执行了一个http的端口监听</p><h2 id="开发订阅者插件"><a href="#开发订阅者插件" aria-hidden="true" class="header-anchor">#</a> 开发订阅者插件</h2><p>所谓订阅者就是用来从流媒体服务器接收音视频流的程序例如RTMP协议执行play命令后、http-flv请求响应程序、websocket响应程序。内置插件中录制flv程序也是一个特殊的订阅者。
下面是http-flv插件的源码供参考</p><div class="language-go extra-class"><pre class="language-go"><code><span class="token keyword">package</span> HDL
<span class="token keyword">import</span> <span class="token punctuation">(</span>
<span class="token punctuation">.</span> <span class="token string">&quot;github.com/langhuihui/monibuca/monica&quot;</span>
<span class="token string">&quot;github.com/langhuihui/monibuca/monica/avformat&quot;</span>
<span class="token string">&quot;github.com/langhuihui/monibuca/monica/pool&quot;</span>
<span class="token string">&quot;log&quot;</span>
<span class="token string">&quot;net/http&quot;</span>
<span class="token string">&quot;strings&quot;</span>
<span class="token punctuation">)</span>
<span class="token keyword">var</span> config <span class="token operator">=</span> <span class="token function">new</span><span class="token punctuation">(</span>ListenerConfig<span class="token punctuation">)</span>
<span class="token keyword">func</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">InstallPlugin</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>PluginConfig<span class="token punctuation">{</span>
Name<span class="token punctuation">:</span> <span class="token string">&quot;HDL&quot;</span><span class="token punctuation">,</span>
Type<span class="token punctuation">:</span> PLUGIN_SUBSCRIBER<span class="token punctuation">,</span>
Config<span class="token punctuation">:</span> config<span class="token punctuation">,</span>
Run<span class="token punctuation">:</span> run<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">func</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
log<span class="token punctuation">.</span><span class="token function">Printf</span><span class="token punctuation">(</span><span class="token string">&quot;HDL start at %s&quot;</span><span class="token punctuation">,</span> config<span class="token punctuation">.</span>ListenAddr<span class="token punctuation">)</span>
log<span class="token punctuation">.</span><span class="token function">Fatal</span><span class="token punctuation">(</span>http<span class="token punctuation">.</span><span class="token function">ListenAndServe</span><span class="token punctuation">(</span>config<span class="token punctuation">.</span>ListenAddr<span class="token punctuation">,</span> http<span class="token punctuation">.</span><span class="token function">HandlerFunc</span><span class="token punctuation">(</span>HDLHandler<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">func</span> <span class="token function">HDLHandler</span><span class="token punctuation">(</span>w http<span class="token punctuation">.</span>ResponseWriter<span class="token punctuation">,</span> r <span class="token operator">*</span>http<span class="token punctuation">.</span>Request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
sign <span class="token operator">:=</span> r<span class="token punctuation">.</span>URL<span class="token punctuation">.</span><span class="token function">Query</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">&quot;sign&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">:=</span> AuthHooks<span class="token punctuation">.</span><span class="token function">Trigger</span><span class="token punctuation">(</span>sign<span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span><span class="token number">403</span><span class="token punctuation">)</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
stringPath <span class="token operator">:=</span> strings<span class="token punctuation">.</span><span class="token function">TrimLeft</span><span class="token punctuation">(</span>r<span class="token punctuation">.</span>RequestURI<span class="token punctuation">,</span> <span class="token string">&quot;/&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> strings<span class="token punctuation">.</span><span class="token function">HasSuffix</span><span class="token punctuation">(</span>stringPath<span class="token punctuation">,</span> <span class="token string">&quot;.flv&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
stringPath <span class="token operator">=</span> strings<span class="token punctuation">.</span><span class="token function">TrimRight</span><span class="token punctuation">(</span>stringPath<span class="token punctuation">,</span> <span class="token string">&quot;.flv&quot;</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token boolean">_</span><span class="token punctuation">,</span> ok <span class="token operator">:=</span> AllRoom<span class="token punctuation">.</span><span class="token function">Load</span><span class="token punctuation">(</span>stringPath<span class="token punctuation">)</span><span class="token punctuation">;</span> ok <span class="token punctuation">{</span>
<span class="token comment">//atomic.AddInt32(&amp;hdlId, 1)</span>
w<span class="token punctuation">.</span><span class="token function">Header</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Set</span><span class="token punctuation">(</span><span class="token string">&quot;Transfer-Encoding&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;chunked&quot;</span><span class="token punctuation">)</span>
w<span class="token punctuation">.</span><span class="token function">Header</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Set</span><span class="token punctuation">(</span><span class="token string">&quot;Content-Type&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;video/x-flv&quot;</span><span class="token punctuation">)</span>
w<span class="token punctuation">.</span><span class="token function">Write</span><span class="token punctuation">(</span>avformat<span class="token punctuation">.</span>FLVHeader<span class="token punctuation">)</span>
p <span class="token operator">:=</span> OutputStream<span class="token punctuation">{</span>
Sign<span class="token punctuation">:</span> sign<span class="token punctuation">,</span>
SendHandler<span class="token punctuation">:</span> <span class="token keyword">func</span><span class="token punctuation">(</span>packet <span class="token operator">*</span>pool<span class="token punctuation">.</span>SendPacket<span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> avformat<span class="token punctuation">.</span><span class="token function">WriteFLVTag</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> packet<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
SubscriberInfo<span class="token punctuation">:</span> SubscriberInfo<span class="token punctuation">{</span>
ID<span class="token punctuation">:</span> r<span class="token punctuation">.</span>RemoteAddr<span class="token punctuation">,</span> Type<span class="token punctuation">:</span> <span class="token string">&quot;FLV&quot;</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>
p<span class="token punctuation">.</span><span class="token function">Play</span><span class="token punctuation">(</span>stringPath<span class="token punctuation">)</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
w<span class="token punctuation">.</span><span class="token function">WriteHeader</span><span class="token punctuation">(</span><span class="token number">404</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>其中核心逻辑就是创建OutputStream对象每一个订阅者需要提供SendHandler函数用来接收来自发布者广播出来的音视频数据。
最后调用该对象的Play函数进行播放。请注意Play函数会阻塞当前goroutine。</p><h2 id="开发发布者插件"><a href="#开发发布者插件" aria-hidden="true" class="header-anchor">#</a> 开发发布者插件</h2><p>所谓发布者就是提供音视频数据的程序例如接收来自OBS、ffmpeg的推流的程序。内置插件中集群功能里面有一个特殊的发布者它接收来自源服务器的音视频数据然后在本服务器中广播音视频。
以此为例,我们需要提供一个结构体定义来表示特定的发布者:</p><div class="language-go extra-class"><pre class="language-go"><code><span class="token keyword">type</span> Receiver <span class="token keyword">struct</span> <span class="token punctuation">{</span>
InputStream
io<span class="token punctuation">.</span>Reader
<span class="token operator">*</span>bufio<span class="token punctuation">.</span>Writer
<span class="token punctuation">}</span>
</code></pre></div><p>其中InputStream 是固定的,必须包含,且必须以组合继承的方式定义。其余的成员则是任意的。
发布者的发布动作需要特定条件的触发,例如在集群插件中,当本服务器有订阅者订阅了某个流,而该流并没有发布者的时候就会触发向源服务器拉流的函数:</p><div class="language-go extra-class"><pre class="language-go"><code><span class="token keyword">func</span> <span class="token function">PullUpStream</span><span class="token punctuation">(</span>streamPath <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
addr<span class="token punctuation">,</span> err <span class="token operator">:=</span> net<span class="token punctuation">.</span><span class="token function">ResolveTCPAddr</span><span class="token punctuation">(</span><span class="token string">&quot;tcp&quot;</span><span class="token punctuation">,</span> config<span class="token punctuation">.</span>Master<span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token function">MayBeError</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
conn<span class="token punctuation">,</span> err <span class="token operator">:=</span> net<span class="token punctuation">.</span><span class="token function">DialTCP</span><span class="token punctuation">(</span><span class="token string">&quot;tcp&quot;</span><span class="token punctuation">,</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> addr<span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token function">MayBeError</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
brw <span class="token operator">:=</span> bufio<span class="token punctuation">.</span><span class="token function">NewReadWriter</span><span class="token punctuation">(</span>bufio<span class="token punctuation">.</span><span class="token function">NewReader</span><span class="token punctuation">(</span>conn<span class="token punctuation">)</span><span class="token punctuation">,</span> bufio<span class="token punctuation">.</span><span class="token function">NewWriter</span><span class="token punctuation">(</span>conn<span class="token punctuation">)</span><span class="token punctuation">)</span>
p <span class="token operator">:=</span> <span class="token operator">&amp;</span>Receiver<span class="token punctuation">{</span>
Reader<span class="token punctuation">:</span> conn<span class="token punctuation">,</span>
Writer<span class="token punctuation">:</span> brw<span class="token punctuation">.</span>Writer<span class="token punctuation">,</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> p<span class="token punctuation">.</span><span class="token function">Publish</span><span class="token punctuation">(</span>streamPath<span class="token punctuation">,</span> p<span class="token punctuation">)</span> <span class="token punctuation">{</span>
p<span class="token punctuation">.</span><span class="token function">WriteByte</span><span class="token punctuation">(</span>MSG_SUBSCRIBE<span class="token punctuation">)</span>
p<span class="token punctuation">.</span><span class="token function">WriteString</span><span class="token punctuation">(</span>streamPath<span class="token punctuation">)</span>
p<span class="token punctuation">.</span><span class="token function">WriteByte</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
p<span class="token punctuation">.</span><span class="token function">Flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> v <span class="token operator">:=</span> <span class="token keyword">range</span> p<span class="token punctuation">.</span>Subscribers <span class="token punctuation">{</span>
p<span class="token punctuation">.</span><span class="token function">Auth</span><span class="token punctuation">(</span>v<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
<span class="token keyword">defer</span> p<span class="token punctuation">.</span><span class="token function">Cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">for</span> <span class="token punctuation">{</span>
cmd<span class="token punctuation">,</span> err <span class="token operator">:=</span> brw<span class="token punctuation">.</span><span class="token function">ReadByte</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token function">MayBeError</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
<span class="token keyword">switch</span> cmd <span class="token punctuation">{</span>
<span class="token keyword">case</span> MSG_AUDIO<span class="token punctuation">:</span>
<span class="token keyword">if</span> audio<span class="token punctuation">,</span> err <span class="token operator">:=</span> p<span class="token punctuation">.</span><span class="token function">readAVPacket</span><span class="token punctuation">(</span>avformat<span class="token punctuation">.</span>FLV_TAG_TYPE_AUDIO<span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">==</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
p<span class="token punctuation">.</span><span class="token function">PushAudio</span><span class="token punctuation">(</span>audio<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">case</span> MSG_VIDEO<span class="token punctuation">:</span>
<span class="token keyword">if</span> video<span class="token punctuation">,</span> err <span class="token operator">:=</span> p<span class="token punctuation">.</span><span class="token function">readAVPacket</span><span class="token punctuation">(</span>avformat<span class="token punctuation">.</span>FLV_TAG_TYPE_VIDEO<span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">==</span> <span class="token boolean">nil</span> <span class="token operator">&amp;&amp;</span> <span class="token function">len</span><span class="token punctuation">(</span>video<span class="token punctuation">.</span>Payload<span class="token punctuation">)</span> <span class="token operator">&gt;</span> <span class="token number">2</span> <span class="token punctuation">{</span>
tmp <span class="token operator">:=</span> video<span class="token punctuation">.</span>Payload<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token comment">// 第一个字节保存着视频的相关信息.</span>
video<span class="token punctuation">.</span>VideoFrameType <span class="token operator">=</span> tmp <span class="token operator">&gt;&gt;</span> <span class="token number">4</span> <span class="token comment">// 帧类型 4Bit, H264一般为1或者2</span>
p<span class="token punctuation">.</span><span class="token function">PushVideo</span><span class="token punctuation">(</span>video<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">case</span> MSG_AUTH<span class="token punctuation">:</span>
cmd<span class="token punctuation">,</span> err <span class="token operator">=</span> brw<span class="token punctuation">.</span><span class="token function">ReadByte</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token function">MayBeError</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
bytes<span class="token punctuation">,</span> err <span class="token operator">:=</span> brw<span class="token punctuation">.</span><span class="token function">ReadBytes</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">if</span> <span class="token function">MayBeError</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span>
<span class="token punctuation">}</span>
subId <span class="token operator">:=</span> strings<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token function">string</span><span class="token punctuation">(</span>bytes<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">:</span><span class="token function">len</span><span class="token punctuation">(</span>bytes<span class="token punctuation">)</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">&quot;,&quot;</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
<span class="token keyword">if</span> v<span class="token punctuation">,</span> ok <span class="token operator">:=</span> p<span class="token punctuation">.</span>Subscribers<span class="token punctuation">[</span>subId<span class="token punctuation">]</span><span class="token punctuation">;</span> ok <span class="token punctuation">{</span>
<span class="token keyword">if</span> cmd <span class="token operator">!=</span> <span class="token number">1</span> <span class="token punctuation">{</span>
v<span class="token punctuation">.</span><span class="token function">Cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>正在该函数中会向源服务器建立tcp连接然后发送特定命令表示需要拉流当我们接收到源服务器的数据的时候就调用PushVideo和PushAudio函数来广播音视频。</p><p>核心逻辑是调用InputStream的Publish以及PushVideo、PushAudio函数</p><h2 id="开发钩子插件"><a href="#开发钩子插件" aria-hidden="true" class="header-anchor">#</a> 开发钩子插件</h2></div><div class="page-edit"><!----><!----></div><div class="page-nav"><p class="inner"><span class="prev">
<a href="/docs/" class="prev router-link-active">
起步
</a></span><span class="next"><a href="/docs/history.html">
更新日志
</a>
</span></p></div></div></div></div>
<script src="/docs/assets/js/app.ad3166d6.js" defer></script><script src="/docs/assets/js/2.142d04d2.js" defer></script>
</body>
</html>

26
dashboard/dist/docs/history.html vendored Normal file
View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>更新历史 | Monibuca</title>
<meta name="description" content="">
<link rel="preload" href="/docs/assets/css/styles.ad3166d6.css" as="style"><link rel="preload" href="/docs/assets/js/app.ad3166d6.js" as="script"><link rel="preload" href="/docs/assets/js/3.2b6c987b.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.83ce04b6.js"><link rel="prefetch" href="/docs/assets/js/2.142d04d2.js"><link rel="prefetch" href="/docs/assets/js/4.ad90d74a.js"><link rel="prefetch" href="/docs/assets/js/5.36121818.js">
<link rel="stylesheet" href="/docs/assets/css/styles.ad3166d6.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/docs/" class="home-link router-link-active"><!----><span class="site-name">
Monibuca
</span></a><div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><!----></div></header><div class="sidebar-mask"></div><div class="sidebar"><!----><ul class="sidebar-links"><li><a href="/docs/" class="sidebar-link">起步</a></li><li><a href="/docs/develop.html" class="sidebar-link">插件开发</a></li><li><a href="/docs/history.html" class="active sidebar-link">更新日志</a></li><li><div class="sidebar-group collapsable"><p class="sidebar-heading"><span>内置插件</span><span class="arrow right"></span></p><!----></div></li></ul></div><div class="page"><div class="content"><h1 id="更新历史"><a href="#更新历史" aria-hidden="true" class="header-anchor">#</a> 更新历史</h1><ul><li>2020/1/27
1.0完成</li></ul></div><div class="page-edit"><!----><!----></div><div class="page-nav"><p class="inner"><span class="prev">
<a href="/docs/develop.html" class="prev">
插件开发
</a></span><span class="next"><a href="/docs/plugins/jessica.html">
Jessica
</a>
</span></p></div></div></div></div>
<script src="/docs/assets/js/app.ad3166d6.js" defer></script><script src="/docs/assets/js/3.2b6c987b.js" defer></script>
</body>
</html>

54
dashboard/dist/docs/index.html vendored Normal file
View File

@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Monibuca快速起步 | Monibuca</title>
<meta name="description" content="">
<link rel="preload" href="/docs/assets/css/styles.ad3166d6.css" as="style"><link rel="preload" href="/docs/assets/js/app.ad3166d6.js" as="script"><link rel="preload" href="/docs/assets/js/1.83ce04b6.js" as="script"><link rel="prefetch" href="/docs/assets/js/2.142d04d2.js"><link rel="prefetch" href="/docs/assets/js/3.2b6c987b.js"><link rel="prefetch" href="/docs/assets/js/4.ad90d74a.js"><link rel="prefetch" href="/docs/assets/js/5.36121818.js">
<link rel="stylesheet" href="/docs/assets/css/styles.ad3166d6.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/docs/" class="home-link router-link-exact-active router-link-active"><!----><span class="site-name">
Monibuca
</span></a><div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><!----></div></header><div class="sidebar-mask"></div><div class="sidebar"><!----><ul class="sidebar-links"><li><a href="/docs/" class="active sidebar-link">起步</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/docs/#介绍" class="sidebar-link">介绍</a></li><li class="sidebar-sub-header"><a href="/docs/#启动" class="sidebar-link">启动</a></li><li class="sidebar-sub-header"><a href="/docs/#配置" class="sidebar-link">配置</a></li></ul></li><li><a href="/docs/develop.html" class="sidebar-link">插件开发</a></li><li><a href="/docs/history.html" class="sidebar-link">更新日志</a></li><li><div class="sidebar-group collapsable"><p class="sidebar-heading"><span>内置插件</span><span class="arrow right"></span></p><!----></div></li></ul></div><div class="page"><div class="content"><h1 id="monibuca快速起步"><a href="#monibuca快速起步" aria-hidden="true" class="header-anchor">#</a> Monibuca快速起步</h1><h2 id="介绍"><a href="#介绍" aria-hidden="true" class="header-anchor">#</a> 介绍</h2><p>Monibuca 是一个开源的流媒体服务器开发框架适用于快速定制化开发流媒体服务器可以对接CDN厂商作为回源服务器也可以自己搭建集群部署环境。
丰富的内置插件提供了流媒体服务器的常见功能例如rtmp server、http-flv、视频录制、QoS等。除此以外还内置了后台web界面方便观察服务器运行的状态。
也可以自己开发后台管理界面通过api方式获取服务器的运行信息。
Monibuca 提供了可供定制化开发的插件机制,可以任意扩展其功能。</p><h2 id="启动"><a href="#启动" aria-hidden="true" class="header-anchor">#</a> 启动</h2><p>启用所有内置插件</p><div class="language-go extra-class"><pre class="language-go"><code><span class="token keyword">package</span> main
<span class="token keyword">import</span> <span class="token punctuation">(</span>
<span class="token punctuation">.</span> <span class="token string">&quot;github.com/langhuihui/monibuca/monica&quot;</span>
<span class="token boolean">_</span> <span class="token string">&quot;github.com/langhuihui/monibuca/plugins&quot;</span>
<span class="token punctuation">)</span>
<span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">Run</span><span class="token punctuation">(</span><span class="token string">&quot;config.toml&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">select</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h2 id="配置"><a href="#配置" aria-hidden="true" class="header-anchor">#</a> 配置</h2><p>要使用<code>Monibuca</code>,需要编写一个<code>toml</code>格式的配置文件,通常可以放在程序的同级目录下例如:<code>config.toml</code>(名称不是必须为<code>config</code>)</p><p>该配置文件主要是为了定制各个插件的配置,例如监听端口号等,具体还是要看各个插件的设计。</p><blockquote><p>如果你编写了自己的插件,就必须在该配置文件中写入对自己插件的配置信息</p></blockquote><p>如果注释掉部分插件的配置,那么该插件就不会启用,典型的配置如下:</p><div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">Plugins.HDL</span><span class="token punctuation">]</span>
<span class="token key property">ListenAddr</span> <span class="token punctuation">=</span> <span class="token string">&quot;:2020&quot;</span>
<span class="token punctuation">[</span><span class="token table class-name">Plugins.Jessica</span><span class="token punctuation">]</span>
<span class="token key property">ListenAddr</span> <span class="token punctuation">=</span> <span class="token string">&quot;:8080&quot;</span>
<span class="token punctuation">[</span><span class="token table class-name">Plugins.RTMP</span><span class="token punctuation">]</span>
<span class="token key property">ListenAddr</span> <span class="token punctuation">=</span> <span class="token string">&quot;:1935&quot;</span>
<span class="token punctuation">[</span><span class="token table class-name">Plugins.GateWay</span><span class="token punctuation">]</span>
<span class="token key property">ListenAddr</span> <span class="token punctuation">=</span> <span class="token string">&quot;:81&quot;</span>
<span class="token comment">#[Plugins.Cluster]</span>
<span class="token comment">#Master = &quot;localhost:2019&quot;</span>
<span class="token comment">#ListenAddr = &quot;:2019&quot;</span>
<span class="token comment">#</span>
<span class="token comment">#[Plugins.Auth]</span>
<span class="token comment">#Key=&quot;www.monibuca.com&quot;</span>
<span class="token comment">#[Plugins.RecordFlv]</span>
<span class="token comment">#Path=&quot;./resouce&quot;</span>
<span class="token punctuation">[</span><span class="token table class-name">Plugins.QoS</span><span class="token punctuation">]</span>
<span class="token key property">Suffix</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;high&quot;</span><span class="token punctuation">,</span><span class="token string">&quot;medium&quot;</span><span class="token punctuation">,</span><span class="token string">&quot;low&quot;</span><span class="token punctuation">]</span>
</code></pre></div><p>具体配置的含义,可以参考每个插件的说明</p></div><div class="page-edit"><!----><!----></div><div class="page-nav"><p class="inner"><!----><span class="next"><a href="/docs/develop.html">
插件开发
</a>
</span></p></div></div></div></div>
<script src="/docs/assets/js/app.ad3166d6.js" defer></script><script src="/docs/assets/js/1.83ce04b6.js" defer></script>
</body>
</html>

19
dashboard/dist/docs/plugins/index.html vendored Normal file
View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Monibuca</title>
<meta name="description" content="">
<link rel="preload" href="/docs/assets/css/styles.ad3166d6.css" as="style"><link rel="preload" href="/docs/assets/js/app.ad3166d6.js" as="script"><link rel="preload" href="/docs/assets/js/4.ad90d74a.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.83ce04b6.js"><link rel="prefetch" href="/docs/assets/js/2.142d04d2.js"><link rel="prefetch" href="/docs/assets/js/3.2b6c987b.js"><link rel="prefetch" href="/docs/assets/js/5.36121818.js">
<link rel="stylesheet" href="/docs/assets/css/styles.ad3166d6.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/docs/" class="home-link router-link-active"><!----><span class="site-name">
Monibuca
</span></a><div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><!----></div></header><div class="sidebar-mask"></div><div class="sidebar"><!----><ul class="sidebar-links"><li><a href="/docs/" class="sidebar-link">起步</a></li><li><a href="/docs/develop.html" class="sidebar-link">插件开发</a></li><li><a href="/docs/history.html" class="sidebar-link">更新日志</a></li><li><div class="sidebar-group collapsable"><p class="sidebar-heading"><span>内置插件</span><span class="arrow right"></span></p><!----></div></li></ul></div><div class="page"><div class="content"></div><div class="page-edit"><!----><!----></div><!----></div></div></div>
<script src="/docs/assets/js/app.ad3166d6.js" defer></script><script src="/docs/assets/js/4.ad90d74a.js" defer></script>
</body>
</html>

View File

@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Jessica | Monibuca</title>
<meta name="description" content="">
<link rel="preload" href="/docs/assets/css/styles.ad3166d6.css" as="style"><link rel="preload" href="/docs/assets/js/app.ad3166d6.js" as="script"><link rel="preload" href="/docs/assets/js/5.36121818.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.83ce04b6.js"><link rel="prefetch" href="/docs/assets/js/2.142d04d2.js"><link rel="prefetch" href="/docs/assets/js/3.2b6c987b.js"><link rel="prefetch" href="/docs/assets/js/4.ad90d74a.js">
<link rel="stylesheet" href="/docs/assets/css/styles.ad3166d6.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/docs/" class="home-link router-link-active"><!----><span class="site-name">
Monibuca
</span></a><div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><!----></div></header><div class="sidebar-mask"></div><div class="sidebar"><!----><ul class="sidebar-links"><li><a href="/docs/" class="sidebar-link">起步</a></li><li><a href="/docs/develop.html" class="sidebar-link">插件开发</a></li><li><a href="/docs/history.html" class="sidebar-link">更新日志</a></li><li><div class="sidebar-group collapsable"><p class="sidebar-heading open"><span>内置插件</span><span class="arrow down"></span></p><ul class="sidebar-group-items"><li><a href="/docs/plugins/jessica.html" class="active sidebar-link">Jessica</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/docs/plugins/jessica.html#配置" class="sidebar-link">配置</a></li></ul></li></ul></div></li></ul></div><div class="page"><div class="content"><h1 id="jessica"><a href="#jessica" aria-hidden="true" class="header-anchor">#</a> Jessica</h1><p>该插件为基于WebSocket协议传输音视频的订阅者音视频数据以裸数据的形式进行传输我们需要Jessibuca播放器来进行播放
Jessibua播放器已内置于源码中该播放器通过js解码H264并用canvas进行渲染可以运行在几乎所有的终端浏览器上面。
在Monibuca的Web界面中预览功能就是使用的Jessibuca播放器。</p><h2 id="配置"><a href="#配置" aria-hidden="true" class="header-anchor">#</a> 配置</h2><p>目前仅有的配置是监听的端口号</p><div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">Plugins.Jessica</span><span class="token punctuation">]</span>
<span class="token key property">ListenAddr</span> <span class="token punctuation">=</span> <span class="token string">&quot;:8080&quot;</span>
</code></pre></div></div><div class="page-edit"><!----><!----></div><div class="page-nav"><p class="inner"><span class="prev">
<a href="/docs/history.html" class="prev">
更新日志
</a></span><!----></p></div></div></div></div>
<script src="/docs/assets/js/app.ad3166d6.js" defer></script><script src="/docs/assets/js/5.36121818.js" defer></script>
</body>
</html>

80
dashboard/dist/docs/service-worker.js vendored Normal file
View File

@@ -0,0 +1,80 @@
/**
* Welcome to your Workbox-powered service worker!
*
* You'll need to register this file in your web app and you should
* disable HTTP caching for this file too.
* See https://goo.gl/nhQhGp
*
* The rest of the code is auto-generated. Please don't update this file
* directly; instead, make changes to your Workbox build configuration
* and re-run your build process.
* See https://goo.gl/2aRDsh
*/
importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js");
/**
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
* See https://goo.gl/S9QRab
*/
self.__precacheManifest = [
{
"url": "404.html",
"revision": "a3d9e915fd09958cab2da343fcad58b0"
},
{
"url": "assets/css/styles.ad3166d6.css",
"revision": "4a6b650244e5b709f84a81ad0565b485"
},
{
"url": "assets/img/search.83621669.svg",
"revision": "83621669651b9a3d4bf64d1a670ad856"
},
{
"url": "assets/js/1.83ce04b6.js",
"revision": "3cabebb5c79c8280aee24ac6e4545650"
},
{
"url": "assets/js/2.142d04d2.js",
"revision": "027f4f643a10a465692035fe692cd94f"
},
{
"url": "assets/js/3.2b6c987b.js",
"revision": "27a988ab518e3f04db65045269d55841"
},
{
"url": "assets/js/4.ad90d74a.js",
"revision": "dcbfc54b67e9e6e33dbb2a303e842bdc"
},
{
"url": "assets/js/5.36121818.js",
"revision": "550520f0f388530dfbc4cc40a3dee264"
},
{
"url": "assets/js/app.ad3166d6.js",
"revision": "fdeb68e4b7b08c2c7bdcaf7462f34b16"
},
{
"url": "develop.html",
"revision": "f7461297bdc3ce303d517f0fc6dedd78"
},
{
"url": "history.html",
"revision": "c4ba2b13246f7a9e0039852fe381de6e"
},
{
"url": "index.html",
"revision": "3371a6066d0c2229a521d0659f25b174"
},
{
"url": "plugins/index.html",
"revision": "511b5cef98368f5f0ab35e667766e367"
},
{
"url": "plugins/jessica.html",
"revision": "65ca2965d5d514441d64b4d5e38cd696"
}
].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

BIN
dashboard/dist/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
dashboard/dist/img/alipay.e872ea78.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

870
dashboard/dist/img/ionicons.a2c4a261.svg vendored Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 542 KiB

BIN
dashboard/dist/img/logo.b5357057.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
dashboard/dist/img/wechat.ff453262.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

1
dashboard/dist/index.html vendored Normal file
View File

@@ -0,0 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>Monibuca</title><script src=jessibuca/ajax.js></script><script src=jessibuca/renderer.js></script><link href=/css/app.b4fc79e8.css rel=preload as=style><link href=/css/chunk-vendors.22ebf426.css rel=preload as=style><link href=/js/app.9cc902b4.js rel=preload as=script><link href=/js/chunk-vendors.ae8ac63d.js rel=preload as=script><link href=/css/chunk-vendors.22ebf426.css rel=stylesheet><link href=/css/app.b4fc79e8.css rel=stylesheet></head><body><noscript><strong>We're sorry but dashboard doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.ae8ac63d.js></script><script src=/js/app.9cc902b4.js></script></body></html>

535
dashboard/dist/jessibuca/ajax.js vendored Normal file
View File

@@ -0,0 +1,535 @@
// a simple ajax
!(function () {
var jsonType = 'application/json';
var htmlType = 'text/html';
var xmlTypeRE = /^(?:text|application)\/xml/i;
var blankRE = /^\s*$/; // \s
/*
* default setting
* */
var _settings = {
type: "GET",
beforeSend: noop,
success: noop,
error: noop,
complete: noop,
context: null,
xhr: function () {
return new window.XMLHttpRequest();
},
accepts: {
json: jsonType,
xml: 'application/xml, text/xml',
html: htmlType,
text: 'text/plain'
},
crossDomain: false,
timeout: 0,
username: null,
password: null,
processData: true,
promise: noop
};
function noop() {
}
var ajax = function (options) {
//
var settings = extend({}, options || {});
//
for (var key in _settings) {
if (settings[key] === undefined) {
settings[key] = _settings[key];
}
}
//
try {
var q = {};
var promise = new Promise(function (resolve, reject) {
q.resolve = resolve;
q.reject = reject;
});
promise.resolve = q.resolve;
promise.reject = q.reject;
settings.promise = promise;
}
catch (e) {
//
settings.promise = {
resolve: noop,
reject: noop
};
}
//
if (!settings.crossDomain) {
settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && RegExp.$2 !== window.location.href;
}
var dataType = settings.dataType;
// jsonp
if (dataType === 'jsonp') {
//
var hasPlaceholder = /=\?/.test(settings.url);
if (!hasPlaceholder) {
var jsonpCallback = (settings.jsonp || 'callback') + '=?';
settings.url = appendQuery(settings.url, jsonpCallback)
}
return JSONP(settings);
}
// url
if (!settings.url) {
settings.url = window.location.toString();
}
//
serializeData(settings);
var mime = settings.accepts[dataType]; // mime
var baseHeader = {}; // header
var protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol; // protocol
var xhr = _settings.xhr();
var abortTimeout;
// X-Requested-With header
// For cross-domain requests, seeing as conditions for a preflight are
// akin to a jigsaw puzzle, we simply never set it to be sure.
// (it can always be set on a per-request basis or even using ajaxSetup)
// For same-domain requests, won't change header if already provided.
if (!settings.crossDomain && !baseHeader['X-Requested-With']) {
baseHeader['X-Requested-With'] = 'XMLHttpRequest';
}
// mime
if (mime) {
//
baseHeader['Accept'] = mime;
if (mime.indexOf(',') > -1) {
mime = mime.split(',', 2)[0]
}
//
xhr.overrideMimeType && xhr.overrideMimeType(mime);
}
// contentType
if (settings.contentType || (settings.data && settings.type.toUpperCase() !== 'GET')) {
baseHeader['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded; charset=UTF-8');
}
// headers
settings.headers = extend(baseHeader, settings.headers || {});
// on ready state change
xhr.onreadystatechange = function () {
// readystate
if (xhr.readyState === 4) {
clearTimeout(abortTimeout);
var result;
var error = false;
//
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type'));
result = xhr.responseText;
try {
// xml
if (dataType === 'xml') {
result = xhr.responseXML;
}
// json
else if (dataType === 'json') {
result = blankRE.test(result) ? null : JSON.parse(result);
}
}
catch (e) {
error = e;
}
if (error) {
ajaxError(error, 'parseerror', xhr, settings);
}
else {
ajaxSuccess(result, xhr, settings);
}
}
else {
ajaxError(null, 'error', xhr, settings);
}
}
};
// async
var async = 'async' in settings ? settings.async : true;
// open
xhr.open(settings.type, settings.url, async, settings.username, settings.password);
// xhrFields
if (settings.xhrFields) {
for (var name in settings.xhrFields) {
xhr[name] = settings.xhrFields[name];
}
}
// Override mime type if needed
if (settings.mimeType && xhr.overrideMimeType) {
xhr.overrideMimeType(settings.mimeType);
}
// set request header
for (var name in settings.headers) {
// Support: IE<9
// IE's ActiveXObject throws a 'Type Mismatch' exception when setting
// request header to a null-value.
//
// To keep consistent with other XHR implementations, cast the value
// to string and ignore `undefined`.
if (settings.headers[name] !== undefined) {
xhr.setRequestHeader(name, settings.headers[name] + "");
}
}
// before send
if (ajaxBeforeSend(xhr, settings) === false) {
xhr.abort();
return false;
}
// timeout
if (settings.timeout > 0) {
abortTimeout = window.setTimeout(function () {
xhr.onreadystatechange = noop;
xhr.abort();
ajaxError(null, 'timeout', xhr, settings);
}, settings.timeout);
}
// send
xhr.send(settings.data ? settings.data : null);
return settings.promise;
};
/*
* method get
* */
ajax.get = function (url, data, success, dataType) {
if (isFunction(data)) {
dataType = dataType || success;
success = data;
data = undefined;
}
return ajax({
url: url,
data: data,
success: success,
dataType: dataType
});
};
/*
* method post
*
* dataType:
* */
ajax.post = function (url, data, success, dataType) {
if (isFunction(data)) {
dataType = dataType || success;
success = data;
data = undefined;
}
return ajax({
type: 'POST',
url: url,
data: data,
success: success,
dataType: dataType
})
};
/*
* method getJSON
* */
ajax.getJSON = function (url, data, success) {
if (isFunction(data)) {
success = data;
data = undefined;
}
return ajax({
url: url,
data: data,
success: success,
dataType: 'json'
})
};
/*
* method ajaxSetup
* */
ajax.ajaxSetup = function (target, settings) {
return settings ? extend(extend(target, _settings), settings) : extend(_settings, target);
};
/*
* utils
*
* */
// triggers and extra global event ajaxBeforeSend that's like ajaxSend but cancelable
function ajaxBeforeSend(xhr, settings) {
var context = settings.context;
//
if (settings.beforeSend.call(context, xhr, settings) === false) {
return false;
}
}
// ajax success
function ajaxSuccess(data, xhr, settings) {
var context = settings.context;
var status = 'success';
settings.success.call(context, data, status, xhr);
settings.promise.resolve(data, status, xhr);
ajaxComplete(status, xhr, settings);
}
// status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
function ajaxComplete(status, xhr, settings) {
var context = settings.context;
settings.complete.call(context, xhr, status);
}
// type: "timeout", "error", "abort", "parsererror"
function ajaxError(error, type, xhr, settings) {
var context = settings.context;
settings.error.call(context, xhr, type, error);
settings.promise.reject(xhr, type, error);
ajaxComplete(type, xhr, settings);
}
// jsonp
/*
* tks: https://www.cnblogs.com/rubylouvre/archive/2011/02/13/1953087.html
* */
function JSONP(options) {
//
var callbackName = options.jsonpCallback || 'jsonp' + (new Date().getTime());
var script = window.document.createElement('script');
var abort = function () {
// 设置 window.xxx = noop
if (callbackName in window) {
window[callbackName] = noop;
}
};
var xhr = {abort: abort};
var abortTimeout;
var head = window.document.getElementsByTagName('head')[0] || window.document.documentElement;
// ie8+
script.onerror = function (error) {
_error(error);
};
function _error(error) {
window.clearTimeout(abortTimeout);
xhr.abort();
ajaxError(error.type, xhr, error.type, options);
_removeScript();
}
window[callbackName] = function (data) {
window.clearTimeout(abortTimeout);
ajaxSuccess(data, xhr, options);
_removeScript();
};
//
serializeData(options);
script.src = options.url.replace(/=\?/, '=' + callbackName);
//
script.src = appendQuery(script.src, '_=' + (new Date()).getTime());
//
script.async = true;
// script charset
if (options.scriptCharset) {
script.charset = options.scriptCharset;
}
//
head.insertBefore(script, head.firstChild);
//
if (options.timeout > 0) {
abortTimeout = window.setTimeout(function () {
xhr.abort();
ajaxError('timeout', xhr, 'timeout', options);
_removeScript();
}, options.timeout);
}
// remove script
function _removeScript() {
if (script.clearAttributes) {
script.clearAttributes();
} else {
script.onload = script.onreadystatechange = script.onerror = null;
}
if (script.parentNode) {
script.parentNode.removeChild(script);
}
//
script = null;
delete window[callbackName];
}
return options.promise;
}
// mime to data type
function mimeToDataType(mime) {
return mime && (mime === htmlType ? 'html' : mime === jsonType ? 'json' : xmlTypeRE.test(mime) && 'xml') || 'text'
}
// append query
function appendQuery(url, query) {
return (url + '&' + query).replace(/[&?]{1,2}/, '?');
}
// serialize data
function serializeData(options) {
// formData
if (isObject(options) && !isFormData(options.data) && options.processData) {
options.data = param(options.data);
}
if (options.data && (!options.type || options.type.toUpperCase() === 'GET')) {
options.url = appendQuery(options.url, options.data);
}
}
// serialize
function serialize(params, obj, traditional, scope) {
var _isArray = isArray(obj);
for (var key in obj) {
var value = obj[key];
if (scope) {
key = traditional ? scope : scope + '[' + (_isArray ? '' : key) + ']';
}
// handle data in serializeArray format
if (!scope && _isArray) {
params.add(value.name, value.value);
}
else if (traditional ? _isArray(value) : isObject(value)) {
serialize(params, value, traditional, key);
}
else {
params.add(key, value);
}
}
}
// param
function param(obj, traditional) {
var params = [];
//
params.add = function (k, v) {
this.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));
};
serialize(params, obj, traditional);
return params.join('&').replace('%20', '+');
}
// extend
function extend(target) {
var slice = Array.prototype.slice;
var args = slice.call(arguments, 1);
//
for (var i = 0, length = args.length; i < length; i++) {
var source = args[i] || {};
for (var key in source) {
if (source.hasOwnProperty(key) && source[key] !== undefined) {
target[key] = source[key];
}
}
}
return target;
}
// is object
function isObject(obj) {
var type = typeof obj;
return type === 'function' || type === 'object' && !!obj;
}
// is formData
function isFormData(obj) {
return obj instanceof FormData;
}
// is array
function isArray(value) {
return Object.prototype.toString.call(value) === "[object Array]";
}
// is function
function isFunction(value) {
return typeof value === "function";
}
// browser
window.ajax = ajax;
})();

25
dashboard/dist/jessibuca/ff.js vendored Normal file

File diff suppressed because one or more lines are too long

460
dashboard/dist/jessibuca/renderer.js vendored Normal file
View File

@@ -0,0 +1,460 @@
function Jessibuca(opt) {
this.canvasElement = opt.canvas;
this.contextOptions = opt.contextOptions;
this.videoBuffer = opt.videoBuffer || 1
if (!opt.forceNoGL) this.initContextGL();
if (this.contextGL) {
this.initProgram();
this.initBuffers();
this.initTextures();
};
this.decoderWorker = new Worker(opt.decoder || '264_mp3.js')
var _this = this
function draw(output) {
_this.drawNextOutputPicture(_this.width, _this.height, null, output)
postMessage({ cmd: "setBuffer", buffer: output }, '*', [output[0].buffer, output[1].buffer, output[2].buffer])
}
this.decoderWorker.onmessage = function (event) {
var msg = event.data
switch (msg.cmd) {
case "init":
console.log("decoder worker init")
postMessage({ cmd: "setVideoBuffer", time: _this.videoBuffer }, "*")
if (_this.onLoad) {
_this.onLoad()
delete _this.onLoad;
}
break
case "initSize":
_this.width = msg.w
_this.height = msg.h
if (_this.isWebGL()) {
// var buffer = new ArrayBuffer(msg.w * msg.h + (msg.w * msg.h >> 1))
// this.postMessage({ cmd: "setBuffer", buffer: buffer }, [buffer])
}
else {
_this.initRGB(msg.w, msg.h)
}
break
case "render":
if (_this.onPlay) {
_this.onPlay()
delete _this.onPlay;
}
// if (msg.compositionTime) {
// console.log(msg.compositionTime)
// setTimeout(draw, msg.compositionTime, msg.output)
// } else {
// draw(msg.output)
// }
draw(msg.output)
break
case "initAudio":
_this.initAudioPlay(msg.frameCount, msg.samplerate, msg.channels)
break
case "playAudio":
_this.playAudio(msg.buffer)
break
case "print":
console.log(msg.text);
break
case "printErr":
console.error(msg.text);
break
}
}
};
window.AudioContext = window.AudioContext || window.webkitAudioContext;
function _unlock() {
var context = Jessibuca.prototype.audioContext = Jessibuca.prototype.audioContext || new window.AudioContext();
context.resume();
var source = context.createBufferSource();
source.buffer = context.createBuffer(1, 1, 22050);
source.connect(context.destination);
if (source.noteOn)
source.noteOn(0);
else
source.start(0);
}
// document.addEventListener("mousedown", _unlock, true);
// document.addEventListener("touchend", _unlock, true);
Jessibuca.prototype.audioEnabled = function (flag) {
if (flag) {
_unlock()
this.audioEnabled = function (flag) {
if (flag) {
this.audioContext.resume();
} else {
this.audioContext.suspend();
}
}
}
}
Jessibuca.prototype.playAudio = function (data) {
var context = this.audioContext;
var isPlaying = false;
var isDecoding = false;
if (!context) return false;
var audioBuffers = [];
var decodeQueue = []
var _this = this
var playNextBuffer = function (e) {
// isPlaying = false;
if (audioBuffers.length) {
playBuffer(audioBuffers.shift())
}
//if (audioBuffers.length > 1) audioBuffers.shift();
};
var playBuffer = function (buffer) {
isPlaying = true;
var audioBufferSouceNode = context.createBufferSource();
audioBufferSouceNode.buffer = buffer;
audioBufferSouceNode.connect(context.destination);
// audioBufferSouceNode.onended = playNextBuffer;
audioBufferSouceNode.start();
if (!_this.audioInterval) {
_this.audioInterval = setInterval(playNextBuffer, buffer.duration * 1000 - 1);
}
// setTimeout(playNextBuffer, buffer.duration * 1000)
}
var tryPlay = function (buffer) {
if (decodeQueue.length) {
context.decodeAudioData(decodeQueue.shift(), tryPlay, console.error);
} else {
isDecoding = false
}
if (isPlaying) {
audioBuffers.push(buffer);
} else {
playBuffer(buffer)
}
}
var playAudio = function (data) {
decodeQueue.push(...data)
if (!isDecoding) {
isDecoding = true
context.decodeAudioData(decodeQueue.shift(), tryPlay, console.error);
}
}
this.playAudio = playAudio
playAudio(data)
}
Jessibuca.prototype.initAudioPlay = function (frameCount, samplerate, channels) {
var context = this.audioContext;
var isPlaying = false;
var audioBuffers = [];
if (!context) return false;
var resampled = samplerate < 22050;
var audioBuffer = resampled ? context.createBuffer(channels, frameCount << 1, samplerate << 1) : context.createBuffer(channels, frameCount, samplerate);
var playNextBuffer = function () {
isPlaying = false;
console.log("~", audioBuffers.length)
if (audioBuffers.length) {
playAudio(audioBuffers.shift());
}
//if (audioBuffers.length > 1) audioBuffers.shift();
};
var copyToCtxBuffer = channels > 1 ? function (fromBuffer) {
for (var channel = 0; channel < channels; channel++) {
var nowBuffering = audioBuffer.getChannelData(channel);
if (resampled) {
for (var i = 0; i < frameCount; i++) {
nowBuffering[i * 2] = nowBuffering[i * 2 + 1] = fromBuffer[i * (channel + 1)] / 32768;
}
} else
for (var i = 0; i < frameCount; i++) {
nowBuffering[i] = fromBuffer[i * (channel + 1)] / 32768;
}
}
} : function (fromBuffer) {
var nowBuffering = audioBuffer.getChannelData(0);
for (var i = 0; i < nowBuffering.length; i++) {
nowBuffering[i] = fromBuffer[i] / 32768;
}
// nowBuffering.set(fromBuffer);
};
var playAudio = function (fromBuffer) {
if (isPlaying) {
audioBuffers.push(fromBuffer);
console.log(audioBuffers.length)
return;
}
isPlaying = true;
copyToCtxBuffer(fromBuffer);
var source = context.createBufferSource();
source.buffer = audioBuffer;
source.connect(context.destination);
source.onended = playNextBuffer;
//setTimeout(playNextBuffer, audioBufferTime-audioBuffers.length*200);
source.start();
};
this.playAudio = playAudio;
}
/**
* Returns true if the canvas supports WebGL
*/
Jessibuca.prototype.isWebGL = function () {
return !!this.contextGL;
};
/**
* Create the GL context from the canvas element
*/
Jessibuca.prototype.initContextGL = function () {
var canvas = this.canvasElement;
var gl = null;
var validContextNames = ["webgl", "experimental-webgl", "moz-webgl", "webkit-3d"];
var nameIndex = 0;
while (!gl && nameIndex < validContextNames.length) {
var contextName = validContextNames[nameIndex];
try {
if (this.contextOptions) {
gl = canvas.getContext(contextName, this.contextOptions);
} else {
gl = canvas.getContext(contextName);
};
} catch (e) {
gl = null;
}
if (!gl || typeof gl.getParameter !== "function") {
gl = null;
}
++nameIndex;
};
this.contextGL = gl;
};
/**
* Initialize GL shader program
*/
Jessibuca.prototype.initProgram = function () {
var gl = this.contextGL;
var vertexShaderScript = [
'attribute vec4 vertexPos;',
'attribute vec4 texturePos;',
'varying vec2 textureCoord;',
'void main()',
'{',
'gl_Position = vertexPos;',
'textureCoord = texturePos.xy;',
'}'
].join('\n');
var fragmentShaderScript = [
'precision highp float;',
'varying highp vec2 textureCoord;',
'uniform sampler2D ySampler;',
'uniform sampler2D uSampler;',
'uniform sampler2D vSampler;',
'const mat4 YUV2RGB = mat4',
'(',
'1.1643828125, 0, 1.59602734375, -.87078515625,',
'1.1643828125, -.39176171875, -.81296875, .52959375,',
'1.1643828125, 2.017234375, 0, -1.081390625,',
'0, 0, 0, 1',
');',
'void main(void) {',
'highp float y = texture2D(ySampler, textureCoord).r;',
'highp float u = texture2D(uSampler, textureCoord).r;',
'highp float v = texture2D(vSampler, textureCoord).r;',
'gl_FragColor = vec4(y, u, v, 1) * YUV2RGB;',
'}'
].join('\n');
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderScript);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.log('Vertex shader failed to compile: ' + gl.getShaderInfoLog(vertexShader));
}
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderScript);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.log('Fragment shader failed to compile: ' + gl.getShaderInfoLog(fragmentShader));
}
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log('Program failed to compile: ' + gl.getProgramInfoLog(program));
}
gl.useProgram(program);
this.shaderProgram = program;
};
/**
* Initialize vertex buffers and attach to shader program
*/
Jessibuca.prototype.initBuffers = function () {
var gl = this.contextGL;
var program = this.shaderProgram;
var vertexPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 1, -1, 1, 1, -1, -1, -1]), gl.STATIC_DRAW);
var vertexPosRef = gl.getAttribLocation(program, 'vertexPos');
gl.enableVertexAttribArray(vertexPosRef);
gl.vertexAttribPointer(vertexPosRef, 2, gl.FLOAT, false, 0, 0);
var texturePosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texturePosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 0, 0, 0, 1, 1, 0, 1]), gl.STATIC_DRAW);
var texturePosRef = gl.getAttribLocation(program, 'texturePos');
gl.enableVertexAttribArray(texturePosRef);
gl.vertexAttribPointer(texturePosRef, 2, gl.FLOAT, false, 0, 0);
this.texturePosBuffer = texturePosBuffer;
};
/**
* Initialize GL textures and attach to shader program
*/
Jessibuca.prototype.initTextures = function () {
var gl = this.contextGL;
var program = this.shaderProgram;
var yTextureRef = this.initTexture();
var ySamplerRef = gl.getUniformLocation(program, 'ySampler');
gl.uniform1i(ySamplerRef, 0);
this.yTextureRef = yTextureRef;
var uTextureRef = this.initTexture();
var uSamplerRef = gl.getUniformLocation(program, 'uSampler');
gl.uniform1i(uSamplerRef, 1);
this.uTextureRef = uTextureRef;
var vTextureRef = this.initTexture();
var vSamplerRef = gl.getUniformLocation(program, 'vSampler');
gl.uniform1i(vSamplerRef, 2);
this.vTextureRef = vTextureRef;
};
/**
* Create and configure a single texture
*/
Jessibuca.prototype.initTexture = function () {
var gl = this.contextGL;
var textureRef = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, textureRef);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.bindTexture(gl.TEXTURE_2D, null);
return textureRef;
};
/**
* Draw picture data to the canvas.
* If this object is using WebGL, the data must be an I420 formatted ArrayBuffer,
* Otherwise, data must be an RGBA formatted ArrayBuffer.
*/
Jessibuca.prototype.drawNextOutputPicture = function (width, height, croppingParams, data) {
var gl = this.contextGL;
if (gl) {
this.drawNextOuptutPictureGL(width, height, croppingParams, data);
} else {
this.drawNextOuptutPictureRGBA(width, height, croppingParams, data);
}
};
/**
* Draw the next output picture using WebGL
*/
Jessibuca.prototype.drawNextOuptutPictureGL = function (width, height, croppingParams, data) {
var gl = this.contextGL;
var texturePosBuffer = this.texturePosBuffer;
var yTextureRef = this.yTextureRef;
var uTextureRef = this.uTextureRef;
var vTextureRef = this.vTextureRef;
this.contextGL.viewport(0, 0, this.canvasElement.width, this.canvasElement.height);
// if (!croppingParams) {
// gl.viewport(0, 0, width, height);
// } else {
// gl.viewport(0, 0, croppingParams.width, croppingParams.height);
// var tTop = croppingParams.top / height;
// var tLeft = croppingParams.left / width;
// var tBottom = croppingParams.height / height;
// var tRight = croppingParams.width / width;
// var texturePosValues = new Float32Array([tRight, tTop, tLeft, tTop, tRight, tBottom, tLeft, tBottom]);
// gl.bindBuffer(gl.ARRAY_BUFFER, texturePosBuffer);
// gl.bufferData(gl.ARRAY_BUFFER, texturePosValues, gl.DYNAMIC_DRAW);
// }
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, yTextureRef);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data[0]);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, uTextureRef);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width / 2, height / 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data[1]);
gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(gl.TEXTURE_2D, vTextureRef);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width / 2, height / 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, data[2]);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
};
/**
* Draw next output picture using ARGB data on a 2d canvas.
*/
Jessibuca.prototype.drawNextOuptutPictureRGBA = function (width, height, croppingParams, data) {
// var canvas = this.canvasElement;
//var argbData = data;
//var ctx = canvas.getContext('2d');
// var imageData = ctx.getImageData(0, 0, width, height);
//this.imageData = this.ctx2d.getImageData(0, 0, width, height);
this.imageData.data.set(data);
//Module.print(typeof this.imageData.data);
if (!croppingParams) {
this.ctx2d.putImageData(this.imageData, 0, 0);
} else {
this.ctx2d.putImageData(this.imageData, -croppingParams.left, -croppingParams.top, 0, 0, croppingParams.width, croppingParams.height);
}
};
Jessibuca.prototype.ctx2d = null;
Jessibuca.prototype.imageData = null;
Jessibuca.prototype.initRGB = function (width, height) {
this.ctx2d = this.canvasElement.getContext('2d');
this.imageData = this.ctx2d.getImageData(0, 0, width, height);
this.clear = function () {
this.ctx2d.clearRect(0, 0, width, height)
};
//Module.print(this.imageData);
};
Jessibuca.prototype.close = function () {
if (this.audioInterval) {
clearInterval(this.audioInterval)
}
this.decoderWorker.postMessage({ cmd: "close" })
this.contextGL.clear(this.contextGL.COLOR_BUFFER_BIT);
}
Jessibuca.prototype.destroy = function(){
this.decoderWorker.terminate()
}
Jessibuca.prototype.play = function (url) {
this.decoderWorker.postMessage({ cmd: "play", url: url, isWebGL: this.isWebGL() })
}

2
dashboard/dist/js/app.9cc902b4.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dashboard/dist/js/app.9cc902b4.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -164,10 +164,10 @@
return rate > 1000 ? (rate / 1000) + "kHz" : rate + "Hz"
},
record(item) {
ajax.get("//" + location.host + "/api/record/flv",{streamPath:item.StreamPath})
window.ajax.get("//" + location.host + "/api/record/flv",{streamPath:item.StreamPath})
},
stopRecord(item){
ajax.get("//" + location.host + "/api/record/flv/stop",{streamPath:item.StreamPath})
window.ajax.get("//" + location.host + "/api/record/flv/stop",{streamPath:item.StreamPath})
},
isRecording(item) {
return item.SubscriberInfo && item.SubscriberInfo.find(x => x.Type == "FlvRecord")

View File

@@ -75,6 +75,7 @@ func (sse *SSE) WriteExec(cmd *exec.Cmd) error {
func init() {
_, currentFilePath, _, _ := runtime.Caller(0)
dashboardPath = path.Join(path.Dir(currentFilePath), "../../dashboard/dist")
log.Println(dashboardPath)
InstallPlugin(&PluginConfig{
Name: "GateWay",
Type: PLUGIN_HOOK,