Compare commits
244 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a521c63036 | ||
![]() |
ed5e7196f7 | ||
![]() |
664a64a025 | ||
![]() |
f097e66069 | ||
![]() |
2e8d4d2f3a | ||
![]() |
8bb63c9298 | ||
![]() |
c0b2a10601 | ||
![]() |
3179b892d6 | ||
![]() |
ef3a85ec21 | ||
![]() |
1a57aeb2a2 | ||
![]() |
85b134d333 | ||
![]() |
9969966b52 | ||
![]() |
5482ab4157 | ||
![]() |
6a78440a61 | ||
![]() |
61eaaab78f | ||
![]() |
54f01a064c | ||
![]() |
09570a6515 | ||
![]() |
00ff25e173 | ||
![]() |
f0735d3883 | ||
![]() |
314191abaf | ||
![]() |
33b5c465b6 | ||
![]() |
2b1bf24fb9 | ||
![]() |
4653f7b511 | ||
![]() |
86b16fe3fb | ||
![]() |
d05bd7bc55 | ||
![]() |
6f9fe7c646 | ||
![]() |
96d886c7a5 | ||
![]() |
ca2f69539d | ||
![]() |
0fd608aefc | ||
![]() |
d5e6a517fb | ||
![]() |
e035cf0846 | ||
![]() |
e7ff340c7a | ||
![]() |
91d1d5502b | ||
![]() |
b1ef460af1 | ||
![]() |
87f08066e5 | ||
![]() |
da69aae5fa | ||
![]() |
6e8081a411 | ||
![]() |
2f7bc14986 | ||
![]() |
504e22b558 | ||
![]() |
c7b2cbfee3 | ||
![]() |
70b5c553b9 | ||
![]() |
4486c612e4 | ||
![]() |
29f574ae73 | ||
![]() |
d12052eb4a | ||
![]() |
7a0964b501 | ||
![]() |
67ad3e669d | ||
![]() |
6c78c2f456 | ||
![]() |
16cf7725f3 | ||
![]() |
9d08fa47b3 | ||
![]() |
9b6e9bfbec | ||
![]() |
a18fc77b8b | ||
![]() |
edd7a6f047 | ||
![]() |
9ec70f0454 | ||
![]() |
6ca479371e | ||
![]() |
f65bd3a760 | ||
![]() |
91a9171c5c | ||
![]() |
0b51fecf48 | ||
![]() |
493bce72cb | ||
![]() |
a48057e713 | ||
![]() |
2dd008d960 | ||
![]() |
3f7e7b3666 | ||
![]() |
0791151557 | ||
![]() |
69f5d9d976 | ||
![]() |
dec17c1f26 | ||
![]() |
e6069322f8 | ||
![]() |
36ede9b9a2 | ||
![]() |
e4bc0ad5ea | ||
![]() |
33a58b0641 | ||
![]() |
cb71b2c7e2 | ||
![]() |
38b8923e6f | ||
![]() |
8b483e5139 | ||
![]() |
34c21e5e8f | ||
![]() |
b8a23517ba | ||
![]() |
d491b6206a | ||
![]() |
93ce7391a5 | ||
![]() |
611bd78b5c | ||
![]() |
b112187125 | ||
![]() |
e0c35fce2b | ||
![]() |
7bcf2cba27 | ||
![]() |
da5f970067 | ||
![]() |
711b4cc82c | ||
![]() |
f1bcb6f2c9 | ||
![]() |
306a7ffeff | ||
![]() |
9c8a2c5d83 | ||
![]() |
1a67f63932 | ||
![]() |
c761c6ce9b | ||
![]() |
cc9c0d67e2 | ||
![]() |
6df2a3b842 | ||
![]() |
c38bd36ecc | ||
![]() |
a769f1cbf4 | ||
![]() |
8ec0515f60 | ||
![]() |
e2113e03df | ||
![]() |
56bbc0ddf8 | ||
![]() |
563f966fe4 | ||
![]() |
0e3befd285 | ||
![]() |
e60871b55b | ||
![]() |
785be6a939 | ||
![]() |
7684856ccc | ||
![]() |
2e76b74e74 | ||
![]() |
e67b3f3bc8 | ||
![]() |
c17302a8fc | ||
![]() |
02738a1482 | ||
![]() |
0e1fe9a713 | ||
![]() |
8a059c51a9 | ||
![]() |
07a34d2642 | ||
![]() |
7dca6c9411 | ||
![]() |
eddbb35136 | ||
![]() |
65c3d90275 | ||
![]() |
531bcd57f1 | ||
![]() |
18bbedcff5 | ||
![]() |
6a2818916a | ||
![]() |
612501a403 | ||
![]() |
ca3397e544 | ||
![]() |
d01d254caa | ||
![]() |
7574a6ba6f | ||
![]() |
4c918df6e6 | ||
![]() |
f677beb2b7 | ||
![]() |
3adaedf6fc | ||
![]() |
5a9cf53485 | ||
![]() |
bff77f1365 | ||
![]() |
b608c38aec | ||
![]() |
d8537ec3a3 | ||
![]() |
c055f7fceb | ||
![]() |
afb0efb2ee | ||
![]() |
51832cd9a7 | ||
![]() |
454e19f8c0 | ||
![]() |
62111b41d1 | ||
![]() |
0eca8fd657 | ||
![]() |
ca16d405d0 | ||
![]() |
e1d500447a | ||
![]() |
e7da10649c | ||
![]() |
ccd0320090 | ||
![]() |
ee9d4d06b4 | ||
![]() |
089cc593be | ||
![]() |
9abd76b1e5 | ||
![]() |
6e65cc20a2 | ||
![]() |
ff71c7bd5a | ||
![]() |
8648f2ae20 | ||
![]() |
70e7fae954 | ||
![]() |
48b7ff1dee | ||
![]() |
d46e0d45b2 | ||
![]() |
5b41f67b80 | ||
![]() |
3a8b371560 | ||
![]() |
8abae09574 | ||
![]() |
476bb4a656 | ||
![]() |
bf5b4010d7 | ||
![]() |
8cee5c2c18 | ||
![]() |
43632cf852 | ||
![]() |
e4e96f8fc1 | ||
![]() |
57acc5f357 | ||
![]() |
23faad4405 | ||
![]() |
ec86b455a9 | ||
![]() |
f848e90a50 | ||
![]() |
7d05e4cc6c | ||
![]() |
b66e52a90f | ||
![]() |
da6554f536 | ||
![]() |
2b8e8bca98 | ||
![]() |
9009431a1f | ||
![]() |
99b9cc674f | ||
![]() |
67b338007a | ||
![]() |
111ba8aa5a | ||
![]() |
d5ab178841 | ||
![]() |
3a3dd3c73c | ||
![]() |
75865960c6 | ||
![]() |
bb4c39886d | ||
![]() |
4e92f395bf | ||
![]() |
64cf6e609d | ||
![]() |
65bbb5c04f | ||
![]() |
b0c6bff8ae | ||
![]() |
439eb0afc0 | ||
![]() |
f7e6c5084c | ||
![]() |
e0f424fd2c | ||
![]() |
98995de88a | ||
![]() |
b5c5976312 | ||
![]() |
c6dbda22f9 | ||
![]() |
1e78f687d7 | ||
![]() |
701b9b63f3 | ||
![]() |
58f134cda1 | ||
![]() |
d772ed3336 | ||
![]() |
fc4f13fa00 | ||
![]() |
2ee71755b7 | ||
![]() |
7e165fe9d4 | ||
![]() |
dd7a2e8dc7 | ||
![]() |
bd7f5249aa | ||
![]() |
bb9a154a00 | ||
![]() |
e3c7c9514e | ||
![]() |
b3a485ddfb | ||
![]() |
01a74b245e | ||
![]() |
4482f0232f | ||
![]() |
919f7ad78b | ||
![]() |
0c1f1c9770 | ||
![]() |
18a9398f66 | ||
![]() |
5828b8d803 | ||
![]() |
c328db87a8 | ||
![]() |
cc89bbb61b | ||
![]() |
cd34607c86 | ||
![]() |
cfb6dacf73 | ||
![]() |
eba5b6b8f1 | ||
![]() |
597407a4e5 | ||
![]() |
3fcd22d1e7 | ||
![]() |
65de4806c4 | ||
![]() |
55eb2218be | ||
![]() |
5c0b22b1df | ||
![]() |
474581d9b1 | ||
![]() |
3907422b3e | ||
![]() |
d3b7fa04ef | ||
![]() |
d16aa756f8 | ||
![]() |
8304314e49 | ||
![]() |
c2d0cbb1d0 | ||
![]() |
67ab443f1a | ||
![]() |
c80beec8f3 | ||
![]() |
1ce4fd2db0 | ||
![]() |
a20f30d76d | ||
![]() |
afa44eb173 | ||
![]() |
592034adce | ||
![]() |
6e8ac88aaf | ||
![]() |
da66df9302 | ||
![]() |
360f7faf35 | ||
![]() |
bee477e685 | ||
![]() |
4a0c4e36e7 | ||
![]() |
1ed3e6249f | ||
![]() |
1ac06ef252 | ||
![]() |
620d96b39c | ||
![]() |
66a396df0b | ||
![]() |
029abe3187 | ||
![]() |
40fba0d348 | ||
![]() |
73941d1e0b | ||
![]() |
709c2c6ac7 | ||
![]() |
f96bc11ddb | ||
![]() |
5563ddc0d2 | ||
![]() |
95657bd6df | ||
![]() |
b9e19e75c8 | ||
![]() |
eac623639d | ||
![]() |
fea6e98ca7 | ||
![]() |
649a5b558a | ||
![]() |
b3c8d35fad | ||
![]() |
ab745145d9 | ||
![]() |
a1bdc8528b | ||
![]() |
ecb931ccb0 | ||
![]() |
13c357493f | ||
![]() |
87776b9540 | ||
![]() |
543d735c41 | ||
![]() |
966f9b9d0d | ||
![]() |
5eb7f03dec |
13
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: monibuca
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
76
.github/workflows/go.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: Go
|
||||
|
||||
on:
|
||||
create:
|
||||
tags:
|
||||
- v4*
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Set up Env
|
||||
run: echo "version=${GITHUB_REF:11}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
|
||||
- name: Cache Go modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: runner.os−go−{ { hashFiles('**/go.sum') } }
|
||||
restore-keys: ${{ runner.os }}-go-
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
if: success() && startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
version: v1.8.3
|
||||
args: release --rm-dist
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Checkout m7s-import
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: langhuihui/m7s-import
|
||||
path: m7s-import
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Add bin to m7s-import
|
||||
if: success() && startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
cd m7s-import
|
||||
mkdir -p apps/m7s-website/src/public/bin
|
||||
cp ../dist/m7s_${{ env.version }}_windows_amd64.tar.gz apps/m7s-website/src/public/bin/m7s_windows_amd64.tar.gz
|
||||
cp ../dist/m7s_${{ env.version }}_darwin_amd64.tar.gz apps/m7s-website/src/public/bin/m7s_darwin_amd64.tar.gz
|
||||
cp ../dist/m7s_${{ env.version }}_darwin_arm64.tar.gz apps/m7s-website/src/public/bin/m7s_darwin_arm64.tar.gz
|
||||
cp ../dist/m7s_${{ env.version }}_linux_amd64.tar.gz apps/m7s-website/src/public/bin/m7s_linux_amd64.tar.gz
|
||||
cp ../dist/m7s_${{ env.version }}_linux_arm64.tar.gz apps/m7s-website/src/public/bin/m7s_linux_arm64.tar.gz
|
||||
releaseinfo=`curl -H "Accept: application/vnd.github+json" -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/releases/latest`
|
||||
body=`echo $releaseinfo | jq ".body" | sed -e 's/^"//' -e 's/"$//'`
|
||||
name=`echo $releaseinfo | jq ".name" | sed -e 's/^"//' -e 's/"$//'`
|
||||
touch apps/m7s-website/src/release.txt
|
||||
echo -e "# $name\n$body" | cat - apps/m7s-website/src/release.txt > temp && mv temp apps/m7s-website/src/release.txt
|
||||
sed "/## Changelog/d" -i apps/m7s-website/src/release.txt
|
||||
git config --global user.name 'langhuihui'
|
||||
git config --global user.email '178529795@qq.com'
|
||||
git add -A
|
||||
git commit -m '[automated commit] add bin & GitHub workflow'
|
||||
|
||||
- name: push to m7s-import
|
||||
uses: ad-m/github-push-action@master
|
||||
if: success() && startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
github_token: ${{ secrets.TOKEN }}
|
||||
directory: m7s-import
|
||||
repository: langhuihui/m7s-import
|
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
*.exe
|
||||
.vscode
|
||||
.idea
|
||||
resource
|
||||
*.log
|
||||
/monibuca
|
||||
node_modules
|
||||
shutdown.bat
|
||||
shutdown.sh
|
||||
.m7s
|
||||
debug.go
|
||||
dist/
|
||||
record/
|
||||
config2.yaml
|
||||
config1.yaml
|
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019-present, dexter
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
88
README.md
@@ -1 +1,87 @@
|
||||
[中文文档](http://monibuca.com/docs)
|
||||
# 主页
|
||||
|
||||
[https://m7s.live](https://m7s.live)
|
||||
|
||||
# 中文文档
|
||||
|
||||
[https://m7s.live/guide/introduction.html](https://m7s.live/guide/introduction.html)
|
||||
|
||||
# 文章
|
||||
|
||||
[重新定义流媒体服务器](https://www.infoq.cn/article/uiPl8dIuQmhipKb3q3Tz)
|
||||
|
||||
# 核心代码库和插件代码库
|
||||
|
||||
[https://github.com/Monibuca](https://github.com/Monibuca)
|
||||
|
||||
# 介绍
|
||||
|
||||
## 什么是Monibuca(m7s)?
|
||||
|
||||
Monibuca(发音:模拟不卡,m7s是其缩写,类似k8s) 是一个开源的Go语言开发的流媒体服务器开发框架。
|
||||
它基于go1.18+,此外并无任何其他依赖构建,并提供了一套插件式的二次开发模型,帮助你高效地开发流媒体服务器,你既可以直接使用官方提供的插件,也可以自己开发插件扩展任意的功能,所以Monibuca是可以支持**任意**流媒体协议的框架!
|
||||
|
||||
|
||||
> 流媒体服务器是一种用于分发流媒体的服务器端软件,可用于直播、监控、会议等需要实时观看音视频的场景。流媒体服务器区别于传统Web服务器对于实时性要求极高,需要使用各种传输协议,而Web服务器则主要以http/https协议为主。
|
||||
|
||||
Monibuca由三部分组成:引擎、插件、实例工程。
|
||||
- 引擎提供一套通用的流媒体数据缓存以及转发的机制,本身不关心协议如何实现
|
||||
- 插件提供其他所有的功能,并可以无限扩展
|
||||
- 实例工程是引入引擎和插件并启动引擎的项目工程,可以完全自己编写
|
||||
|
||||
## 插件式框架
|
||||
|
||||
Monibuca旨在构建一个通用的流媒体开发生态,所以从v1版本开始就考虑到业务和流转发的解耦,从而设计了一套可供任意扩展的插件机制。根据你的需求场景,可以灵活引入不同类型的插件:
|
||||
- 提供流媒体协议打包/解包,例如rtmp插件、rtsp插件等
|
||||
- 提供日志持久化的处理——logrotate插件
|
||||
- 提供录像功能——record插件
|
||||
- 提供丰富的调试功能——debug插件
|
||||
- 提供http回调能力——http插件
|
||||
|
||||
如果你是有经验的开发者,那么最佳的方式是在现有的插件基础上进行二次开发,并可向更多的人提供可重用的插件丰富生态。
|
||||
如果你是流媒体的初学者,那么最佳的方式是利用现有的插件拼凑出你需要的功能,并向有经验的开发者寻求帮助。
|
||||
|
||||
|
||||
## 名称的由来
|
||||
Monibuca这个单词来源于 `Monica` (莫妮卡),为了解决起名的难题,使用了三个名称分别是 `Monica` 、 `Jessica` 、`Rebecca` 用来代表服务器、播放器、推流器。由于莫妮卡、杰西卡、瑞贝卡,都带卡字,对直播来说寓意不好,所以改为莫妮不卡(`Monibuca`)、杰西不卡[Jessibuca](https://jessibuca.com)、瑞贝不卡[Rebebuca](https://rebebuca.com)。
|
||||
|
||||
## 安装
|
||||
- 官方提供已编译好的各个平台的二进制可执行文件(即绿色软件),所以无需安装任何其他软件即可运行。
|
||||
- 如果需要自己编译启动工程,则需要安装go1.18以上版本。
|
||||
|
||||
:::tip 配置go环境
|
||||
- go可以在https://golang.google.cn/dl 中下载到
|
||||
- 国内需要执行go env -w GOPROXY=https://goproxy.cn 来下载到被屏蔽的第三方库
|
||||
:::
|
||||
|
||||
官方提供了最新版本的下载链接:
|
||||
- [Linux](https://m7s.live/bin/m7s_linux_x86)
|
||||
- [Linux-arm64](https://m7s.live/bin/m7s_linux_arm64)
|
||||
- [Mac](https://m7s.live/bin/m7s_darwin_x86)
|
||||
- [Mac-arm64](https://m7s.live/bin/m7s_darwin_arm64)
|
||||
- [Windows](https://m7s.live/bin/m7s_windows_x86)
|
||||
|
||||
## 运行
|
||||
|
||||
### 可执行文件直接运行
|
||||
|
||||
- Linux 例如下载到了/opt/m7s_linux_x86,则 `cd /opt` 然后 `./m7s_linux_x86`
|
||||
- Mac 和Linux类似,需要注意的时候可能需要修改文件的可执行权限,也可以双击运行
|
||||
- Windows,直接双击m7s_windows_x86.exe即可启动
|
||||
|
||||
:::tip 运行多实例
|
||||
由于实例会监听http端口,所以如果需要运行多实例,就需要为每个实例指定不同的http端口,因此需要启动时指定配置文件,例如./m7s_linux_x86 -c config.yaml
|
||||
:::
|
||||
|
||||
### 自行编译启动工程
|
||||
1. `git clone https://github.com/langhuihui/monibuca`
|
||||
2. `cd monibuca`
|
||||
3. `go run main.go`
|
||||
|
||||
### 自行创建启动工程
|
||||
|
||||
可以观看视频教程:
|
||||
|
||||
- [从零启动 m7s V4](https://www.bilibili.com/video/BV1iq4y147N4/)
|
||||
|
||||
- [m7s v4 视频教程——插件引入](https://www.bilibili.com/video/BV1sP4y1g7BF/)
|
18
config.toml
@@ -1,18 +0,0 @@
|
||||
[Plugins.HDL]
|
||||
ListenAddr = ":2020"
|
||||
[Plugins.Jessica]
|
||||
ListenAddr = ":8080"
|
||||
[Plugins.RTMP]
|
||||
ListenAddr = ":1935"
|
||||
[Plugins.GateWay]
|
||||
ListenAddr = ":81"
|
||||
#[Plugins.Cluster]
|
||||
#Master = "localhost:2019"
|
||||
#ListenAddr = ":2019"
|
||||
#
|
||||
#[Plugins.Auth]
|
||||
#Key="www.monibuca.com"
|
||||
#[Plugins.RecordFlv]
|
||||
#Path="./resouce"
|
||||
[Plugins.QoS]
|
||||
Suffix = ["high","medium","low"]
|
36
config.yaml
Normal file
@@ -0,0 +1,36 @@
|
||||
# 支持零配置启动,即无需填写配置默认启用所有的插件。
|
||||
# 只需要填写需要修改的配置项即可。不需要将所有的配置都填写进来!!。
|
||||
# 全局配置参考 https://m7s.live/guide/config.html
|
||||
# 插件配置参考各个插件的文档
|
||||
# 插件都有一个enable配置,如果为false则不启用该插件,默认为true即不需要配置。
|
||||
|
||||
# global:
|
||||
# console:
|
||||
# secret: "ab0f6913670062af4d2f15c621205178"
|
||||
# http:
|
||||
# listenaddrtls: :8081
|
||||
# certfile: monibuca.com.pem
|
||||
# keyfile: monibuca.com.key
|
||||
# record:
|
||||
# enable: false
|
||||
# hls:
|
||||
# autorecord: true
|
||||
# fragment: 20
|
||||
# webtransport:
|
||||
# enable: false
|
||||
# certfile: monibuca.com.pem
|
||||
# keyfile: monibuca.com.key
|
||||
# gb28181:
|
||||
# # enable: false
|
||||
# rtsp:
|
||||
# # enable: false
|
||||
# pull:
|
||||
# pullonstart: true
|
||||
# pulllist:
|
||||
# live/rtsp: rtsp://admin:MOMA2021@47.94.226.17/Streaming/Channels/201?transportmode=unicast
|
||||
# hls:
|
||||
# # enable: false
|
||||
# pull:
|
||||
# pullonstart: true
|
||||
# pulllist:
|
||||
# live/hls: http://111.40.196.27/PLTV/88888888/224/3221225548/index.m3u8
|
11
config2.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
global:
|
||||
http:
|
||||
listenaddr: :8080
|
||||
rtsp:
|
||||
listenaddr: :8554
|
||||
rtmp:
|
||||
enable: false
|
||||
webtransport:
|
||||
enable: false
|
||||
hls:
|
||||
enable: false
|
21
dashboard/.gitignore
vendored
@@ -1,21 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
@@ -1,24 +0,0 @@
|
||||
# dashboard
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
|
||||
}
|
1
dashboard/dist/css/app.b4fc79e8.css
vendored
@@ -1 +0,0 @@
|
||||
#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}
|
17
dashboard/dist/docs/404.html
vendored
@@ -1,17 +0,0 @@
|
||||
<!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>
|
@@ -1 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 216 B |
1
dashboard/dist/docs/assets/js/1.83ce04b6.js
vendored
1
dashboard/dist/docs/assets/js/2.142d04d2.js
vendored
1
dashboard/dist/docs/assets/js/3.2b6c987b.js
vendored
@@ -1 +0,0 @@
|
||||
(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}}]);
|
1
dashboard/dist/docs/assets/js/4.ad90d74a.js
vendored
@@ -1 +0,0 @@
|
||||
(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}}]);
|
1
dashboard/dist/docs/assets/js/5.36121818.js
vendored
@@ -1 +0,0 @@
|
||||
(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}}]);
|
173
dashboard/dist/docs/develop.html
vendored
@@ -1,173 +0,0 @@
|
||||
<!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">"github.com/langhuihui/monibuca/monica"</span>
|
||||
<span class="token string">"log"</span>
|
||||
<span class="token string">"net/http"</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">&</span>PluginConfig<span class="token punctuation">{</span>
|
||||
Name<span class="token punctuation">:</span> <span class="token string">"Jessica"</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">"server Jessica start at %s"</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">"github.com/langhuihui/monibuca/monica"</span>
|
||||
<span class="token string">"github.com/langhuihui/monibuca/monica/avformat"</span>
|
||||
<span class="token string">"github.com/langhuihui/monibuca/monica/pool"</span>
|
||||
<span class="token string">"log"</span>
|
||||
<span class="token string">"net/http"</span>
|
||||
<span class="token string">"strings"</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">&</span>PluginConfig<span class="token punctuation">{</span>
|
||||
Name<span class="token punctuation">:</span> <span class="token string">"HDL"</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">"HDL start at %s"</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">"sign"</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">"/"</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">".flv"</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">".flv"</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(&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">"Transfer-Encoding"</span><span class="token punctuation">,</span> <span class="token string">"chunked"</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">"Content-Type"</span><span class="token punctuation">,</span> <span class="token string">"video/x-flv"</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">"FLV"</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">"tcp"</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">"tcp"</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">&</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">&&</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">></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">>></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">","</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
@@ -1,26 +0,0 @@
|
||||
<!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
@@ -1,54 +0,0 @@
|
||||
<!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">"github.com/langhuihui/monibuca/monica"</span>
|
||||
<span class="token boolean">_</span> <span class="token string">"github.com/langhuihui/monibuca/plugins"</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">"config.toml"</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">":2020"</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">":8080"</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">":1935"</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">":81"</span>
|
||||
<span class="token comment">#[Plugins.Cluster]</span>
|
||||
<span class="token comment">#Master = "localhost:2019"</span>
|
||||
<span class="token comment">#ListenAddr = ":2019"</span>
|
||||
<span class="token comment">#</span>
|
||||
<span class="token comment">#[Plugins.Auth]</span>
|
||||
<span class="token comment">#Key="www.monibuca.com"</span>
|
||||
<span class="token comment">#[Plugins.RecordFlv]</span>
|
||||
<span class="token comment">#Path="./resouce"</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">"high"</span><span class="token punctuation">,</span><span class="token string">"medium"</span><span class="token punctuation">,</span><span class="token string">"low"</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
@@ -1,19 +0,0 @@
|
||||
<!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>
|
26
dashboard/dist/docs/plugins/jessica.html
vendored
@@ -1,26 +0,0 @@
|
||||
<!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">":8080"</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
@@ -1,80 +0,0 @@
|
||||
/**
|
||||
* 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
Before Width: | Height: | Size: 21 KiB |
BIN
dashboard/dist/fonts/ionicons.143146fa.woff2
vendored
BIN
dashboard/dist/fonts/ionicons.99ac3308.woff
vendored
BIN
dashboard/dist/fonts/ionicons.d535a25a.ttf
vendored
BIN
dashboard/dist/img/alipay.e872ea78.png
vendored
Before Width: | Height: | Size: 38 KiB |
870
dashboard/dist/img/ionicons.a2c4a261.svg
vendored
Before Width: | Height: | Size: 542 KiB |
BIN
dashboard/dist/img/logo.b5357057.png
vendored
Before Width: | Height: | Size: 4.8 KiB |
BIN
dashboard/dist/img/wechat.ff453262.jpg
vendored
Before Width: | Height: | Size: 102 KiB |
1
dashboard/dist/index.html
vendored
@@ -1 +0,0 @@
|
||||
<!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
@@ -1,535 +0,0 @@
|
||||
// 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
460
dashboard/dist/jessibuca/renderer.js
vendored
@@ -1,460 +0,0 @@
|
||||
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
1
dashboard/dist/js/app.9cc902b4.js.map
vendored
44
dashboard/dist/js/chunk-vendors.ae8ac63d.js
vendored
@@ -1,20 +0,0 @@
|
||||
module.exports = {
|
||||
dest: 'public/docs',
|
||||
serviceWorker: true,
|
||||
themeConfig: {
|
||||
sidebar: [
|
||||
['/', '起步'],
|
||||
['/develop', '插件开发'],
|
||||
[ '/history', '更新日志' ],
|
||||
{
|
||||
title: '内置插件',
|
||||
path: '/plugins/',
|
||||
children: [
|
||||
'/plugins/jessica'
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
title: 'Monibuca',
|
||||
base: '/docs/'
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
import upperFirst from 'lodash/upperFirst'
|
||||
import camelCase from 'lodash/camelCase'
|
||||
export default ({
|
||||
Vue, // the version of Vue being used in the VuePress app
|
||||
options, // the options for the root Vue instance
|
||||
router, // the router instance for the app
|
||||
siteData // site metadata
|
||||
}) => {
|
||||
// ...apply enhancements to the app
|
||||
|
||||
const requireComponent = require.context(
|
||||
// The relative path of the components folder
|
||||
'../../src/components',
|
||||
// Whether or not to look in subfolders
|
||||
true,
|
||||
// The regular expression used to match base component filenames
|
||||
/.(vue|js)$/
|
||||
)
|
||||
|
||||
|
||||
requireComponent.keys().forEach(fileName => {
|
||||
// Get component config
|
||||
const componentConfig = requireComponent(fileName)
|
||||
const fc = fileName.split('/')
|
||||
const f = fc[fc.length - 1]
|
||||
// Get PascalCase name of component
|
||||
const componentName = upperFirst(
|
||||
camelCase(
|
||||
f.replace(/.*\//, '$1').replace(/\.\w+$/,'')
|
||||
)
|
||||
)
|
||||
// Register component globally
|
||||
Vue.component(
|
||||
componentName,
|
||||
componentConfig.default || componentConfig
|
||||
)
|
||||
})
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
# Monibuca快速起步
|
||||
## 介绍
|
||||
Monibuca 是一个开源的流媒体服务器开发框架,适用于快速定制化开发流媒体服务器,可以对接CDN厂商,作为回源服务器,也可以自己搭建集群部署环境。
|
||||
丰富的内置插件提供了流媒体服务器的常见功能,例如rtmp server、http-flv、视频录制、QoS等。除此以外还内置了后台web界面,方便观察服务器运行的状态。
|
||||
也可以自己开发后台管理界面,通过api方式获取服务器的运行信息。
|
||||
Monibuca 提供了可供定制化开发的插件机制,可以任意扩展其功能。
|
||||
|
||||
## 启动
|
||||
启用所有内置插件
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
. "github.com/langhuihui/monibuca/monica"
|
||||
_ "github.com/langhuihui/monibuca/plugins"
|
||||
)
|
||||
|
||||
func main() {
|
||||
Run("config.toml")
|
||||
select {}
|
||||
}
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
要使用`Monibuca`,需要编写一个`toml`格式的配置文件,通常可以放在程序的同级目录下例如:`config.toml`(名称不是必须为`config`)
|
||||
|
||||
该配置文件主要是为了定制各个插件的配置,例如监听端口号等,具体还是要看各个插件的设计。
|
||||
|
||||
> 如果你编写了自己的插件,就必须在该配置文件中写入对自己插件的配置信息
|
||||
|
||||
如果注释掉部分插件的配置,那么该插件就不会启用,典型的配置如下:
|
||||
```toml
|
||||
[Plugins.HDL]
|
||||
ListenAddr = ":2020"
|
||||
[Plugins.Jessica]
|
||||
ListenAddr = ":8080"
|
||||
[Plugins.RTMP]
|
||||
ListenAddr = ":1935"
|
||||
[Plugins.GateWay]
|
||||
ListenAddr = ":81"
|
||||
#[Plugins.Cluster]
|
||||
#Master = "localhost:2019"
|
||||
#ListenAddr = ":2019"
|
||||
#
|
||||
#[Plugins.Auth]
|
||||
#Key="www.monibuca.com"
|
||||
#[Plugins.RecordFlv]
|
||||
#Path="./resouce"
|
||||
[Plugins.QoS]
|
||||
Suffix = ["high","medium","low"]
|
||||
```
|
||||
具体配置的含义,可以参考每个插件的说明
|
@@ -1,178 +0,0 @@
|
||||
# 插件开发
|
||||
## 插件的定义
|
||||
所谓的插件,没有什么固定的规则,只需要完成`安装`操作即可。插件可以实现任意的功能扩展,最常见的是实现某种传输协议用来推流或者拉流
|
||||
|
||||
## 插件的安装
|
||||
下面是内置插件jessica的源码,代表了典型的插件安装
|
||||
```go
|
||||
package jessica
|
||||
|
||||
import (
|
||||
. "github.com/langhuihui/monibuca/monica"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var config = new(ListenerConfig)
|
||||
|
||||
func init() {
|
||||
InstallPlugin(&PluginConfig{
|
||||
Name: "Jessica",
|
||||
Type: PLUGIN_SUBSCRIBER,
|
||||
Config: config,
|
||||
Run: run,
|
||||
})
|
||||
}
|
||||
func run() {
|
||||
log.Printf("server Jessica start at %s", config.ListenAddr)
|
||||
log.Fatal(http.ListenAndServe(config.ListenAddr, http.HandlerFunc(WsHandler)))
|
||||
}
|
||||
```
|
||||
当主程序读取配置文件完成解析后,会调用各个插件的Run函数,上面代码中执行了一个http的端口监听
|
||||
|
||||
## 开发订阅者插件
|
||||
所谓订阅者就是用来从流媒体服务器接收音视频流的程序,例如RTMP协议执行play命令后、http-flv请求响应程序、websocket响应程序。内置插件中录制flv程序也是一个特殊的订阅者。
|
||||
下面是http-flv插件的源码,供参考
|
||||
```go
|
||||
package HDL
|
||||
|
||||
import (
|
||||
. "github.com/langhuihui/monibuca/monica"
|
||||
"github.com/langhuihui/monibuca/monica/avformat"
|
||||
"github.com/langhuihui/monibuca/monica/pool"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var config = new(ListenerConfig)
|
||||
|
||||
func init() {
|
||||
InstallPlugin(&PluginConfig{
|
||||
Name: "HDL",
|
||||
Type: PLUGIN_SUBSCRIBER,
|
||||
Config: config,
|
||||
Run: run,
|
||||
})
|
||||
}
|
||||
|
||||
func run() {
|
||||
log.Printf("HDL start at %s", config.ListenAddr)
|
||||
log.Fatal(http.ListenAndServe(config.ListenAddr, http.HandlerFunc(HDLHandler)))
|
||||
}
|
||||
|
||||
func HDLHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sign := r.URL.Query().Get("sign")
|
||||
if err := AuthHooks.Trigger(sign); err != nil {
|
||||
w.WriteHeader(403)
|
||||
return
|
||||
}
|
||||
stringPath := strings.TrimLeft(r.RequestURI, "/")
|
||||
if strings.HasSuffix(stringPath, ".flv") {
|
||||
stringPath = strings.TrimRight(stringPath, ".flv")
|
||||
}
|
||||
if _, ok := AllRoom.Load(stringPath); ok {
|
||||
//atomic.AddInt32(&hdlId, 1)
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
w.Header().Set("Content-Type", "video/x-flv")
|
||||
w.Write(avformat.FLVHeader)
|
||||
p := OutputStream{
|
||||
Sign: sign,
|
||||
SendHandler: func(packet *pool.SendPacket) error {
|
||||
return avformat.WriteFLVTag(w, packet)
|
||||
},
|
||||
SubscriberInfo: SubscriberInfo{
|
||||
ID: r.RemoteAddr, Type: "FLV",
|
||||
},
|
||||
}
|
||||
p.Play(stringPath)
|
||||
} else {
|
||||
w.WriteHeader(404)
|
||||
}
|
||||
}
|
||||
```
|
||||
其中,核心逻辑就是创建OutputStream对象,每一个订阅者需要提供SendHandler函数,用来接收来自发布者广播出来的音视频数据。
|
||||
最后调用该对象的Play函数进行播放。请注意:Play函数会阻塞当前goroutine。
|
||||
|
||||
## 开发发布者插件
|
||||
|
||||
所谓发布者,就是提供音视频数据的程序,例如接收来自OBS、ffmpeg的推流的程序。内置插件中,集群功能里面有一个特殊的发布者,它接收来自源服务器的音视频数据,然后在本服务器中广播音视频。
|
||||
以此为例,我们需要提供一个结构体定义来表示特定的发布者:
|
||||
```go
|
||||
type Receiver struct {
|
||||
InputStream
|
||||
io.Reader
|
||||
*bufio.Writer
|
||||
}
|
||||
```
|
||||
其中InputStream 是固定的,必须包含,且必须以组合继承的方式定义。其余的成员则是任意的。
|
||||
发布者的发布动作需要特定条件的触发,例如在集群插件中,当本服务器有订阅者订阅了某个流,而该流并没有发布者的时候就会触发向源服务器拉流的函数:
|
||||
```go
|
||||
func PullUpStream(streamPath string) {
|
||||
addr, err := net.ResolveTCPAddr("tcp", config.Master)
|
||||
if MayBeError(err) {
|
||||
return
|
||||
}
|
||||
conn, err := net.DialTCP("tcp", nil, addr)
|
||||
if MayBeError(err) {
|
||||
return
|
||||
}
|
||||
brw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
|
||||
p := &Receiver{
|
||||
Reader: conn,
|
||||
Writer: brw.Writer,
|
||||
}
|
||||
if p.Publish(streamPath, p) {
|
||||
p.WriteByte(MSG_SUBSCRIBE)
|
||||
p.WriteString(streamPath)
|
||||
p.WriteByte(0)
|
||||
p.Flush()
|
||||
for _, v := range p.Subscribers {
|
||||
p.Auth(v)
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
defer p.Cancel()
|
||||
for {
|
||||
cmd, err := brw.ReadByte()
|
||||
if MayBeError(err) {
|
||||
return
|
||||
}
|
||||
switch cmd {
|
||||
case MSG_AUDIO:
|
||||
if audio, err := p.readAVPacket(avformat.FLV_TAG_TYPE_AUDIO); err == nil {
|
||||
p.PushAudio(audio)
|
||||
}
|
||||
case MSG_VIDEO:
|
||||
if video, err := p.readAVPacket(avformat.FLV_TAG_TYPE_VIDEO); err == nil && len(video.Payload) > 2 {
|
||||
tmp := video.Payload[0] // 第一个字节保存着视频的相关信息.
|
||||
video.VideoFrameType = tmp >> 4 // 帧类型 4Bit, H264一般为1或者2
|
||||
p.PushVideo(video)
|
||||
}
|
||||
case MSG_AUTH:
|
||||
cmd, err = brw.ReadByte()
|
||||
if MayBeError(err) {
|
||||
return
|
||||
}
|
||||
bytes, err := brw.ReadBytes(0)
|
||||
if MayBeError(err) {
|
||||
return
|
||||
}
|
||||
subId := strings.Split(string(bytes[0:len(bytes)-1]), ",")[0]
|
||||
if v, ok := p.Subscribers[subId]; ok {
|
||||
if cmd != 1 {
|
||||
v.Cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
正在该函数中会向源服务器建立tcp连接,然后发送特定命令表示需要拉流,当我们接收到源服务器的数据的时候,就调用PushVideo和PushAudio函数来广播音视频。
|
||||
|
||||
核心逻辑是调用InputStream的Publish以及PushVideo、PushAudio函数
|
||||
|
||||
## 开发钩子插件
|
||||
|
@@ -1,4 +0,0 @@
|
||||
# 更新历史
|
||||
|
||||
- 2020/1/27
|
||||
1.0完成
|
@@ -1,10 +0,0 @@
|
||||
# Jessica
|
||||
该插件为基于WebSocket协议传输音视频的订阅者,音视频数据以裸数据的形式进行传输,我们需要Jessibuca播放器来进行播放
|
||||
Jessibua播放器已内置于源码中,该播放器通过js解码H264并用canvas进行渲染,可以运行在几乎所有的终端浏览器上面。
|
||||
在Monibuca的Web界面中预览功能就是使用的Jessibuca播放器。
|
||||
## 配置
|
||||
目前仅有的配置是监听的端口号
|
||||
```toml
|
||||
[Plugins.Jessica]
|
||||
ListenAddr = ":8080"
|
||||
```
|
19251
dashboard/package-lock.json
generated
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"name": "dashboard",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"docs:build": "vuepress build docs",
|
||||
"docs:dev": "vuepress dev docs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/g2plot": "^0.11.22",
|
||||
"core-js": "^3.4.4",
|
||||
"view-design": "^4.0.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-router": "^3.1.3",
|
||||
"vuex": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^4.1.0",
|
||||
"@vue/cli-plugin-eslint": "^4.1.0",
|
||||
"@vue/cli-plugin-router": "^4.1.0",
|
||||
"@vue/cli-plugin-vuex": "^4.1.0",
|
||||
"@vue/cli-service": "^4.1.0",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-plugin-vue": "^5.0.0",
|
||||
"iview-loader": "^1.3.0",
|
||||
"less": "^3.0.4",
|
||||
"less-loader": "^5.0.0",
|
||||
"loadash": "^1.0.0",
|
||||
"vue-cli-plugin-iview": "^2.0.0",
|
||||
"vue-cli-plugin-vuepress": "^0.1.1",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"vuepress": "^0.10.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
},
|
||||
"rules": {
|
||||
"vue/no-parsing-error": [
|
||||
2,
|
||||
{
|
||||
"x-invalid-end-tag": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
]
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
<!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.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.685ed1cc.js"><link rel="prefetch" href="/docs/assets/js/2.a6d3efaf.js"><link rel="prefetch" href="/docs/assets/js/3.a9fbea98.js"><link rel="prefetch" href="/docs/assets/js/4.727e40e9.js"><link rel="prefetch" href="/docs/assets/js/5.78b155e8.js"><link rel="prefetch" href="/docs/assets/js/6.35a311c9.js"><link rel="prefetch" href="/docs/assets/js/7.ab3a52c1.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" data-server-rendered="true"><div class="theme-container"><div class="content"><h1>404</h1><blockquote>How did we get here?</blockquote><a href="/docs/" class="router-link-active">Take me home.</a></div></div></div>
|
||||
<script src="/docs/assets/js/app.92893aed.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1 +0,0 @@
|
||||
<?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>
|
Before Width: | Height: | Size: 216 B |
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[1],{168:function(t,e,n){"use strict";n.r(e);var a=n(0),s=Object(a.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:"关于-monibuca"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#关于-monibuca","aria-hidden":"true"}},[this._v("#")]),this._v(" 关于 Monibuca")])])}],!1,null,null,null);e.default=s.exports}}]);
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{167:function(t,e,s){"use strict";s.r(e);var a=s(0),i=Object(a.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:"page-2"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#page-2","aria-hidden":"true"}},[this._v("#")]),this._v(" Page 2")]),e("p",[this._v("this is a second page")])])}],!1,null,null,null);e.default=i.exports}}]);
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{166: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}}]);
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[4],{165:function(t,e,i){"use strict";i.r(e);var s=i(0),a=Object(s.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:"page-3-with-custom-link-page"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#page-3-with-custom-link-page","aria-hidden":"true"}},[this._v("#")]),this._v(" Page 3 with custom link page")]),e("p",[this._v("this is a third page")])])}],!1,null,null,null);e.default=a.exports}}]);
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{164:function(t,e,s){"use strict";s.r(e);var a=s(0),i=Object(a.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:"page-1"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#page-1","aria-hidden":"true"}},[this._v("#")]),this._v(" Page 1")]),e("p",[this._v("this is a page")])])}],!1,null,null,null);e.default=i.exports}}]);
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{163: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}}]);
|
@@ -1 +0,0 @@
|
||||
(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{162:function(t,s,a){"use strict";a.r(s);var e=a(0),i=Object(e.a)({},(function(){var t=this.$createElement;this._self._c;return this._m(0)}),[function(){var t=this.$createElement,s=this._self._c||t;return s("div",{staticClass:"content"},[s("h1",{attrs:{id:"jessica"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#jessica","aria-hidden":"true"}},[this._v("#")]),this._v(" Jessica")]),s("h2",{attrs:{id:"配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置","aria-hidden":"true"}},[this._v("#")]),this._v(" 配置")])])}],!1,null,null,null);s.default=i.exports}}]);
|
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Page 2 | Monibuca</title>
|
||||
<meta name="description" content="">
|
||||
|
||||
|
||||
<link rel="preload" href="/docs/assets/css/styles.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="preload" href="/docs/assets/js/2.a6d3efaf.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.685ed1cc.js"><link rel="prefetch" href="/docs/assets/js/3.a9fbea98.js"><link rel="prefetch" href="/docs/assets/js/4.727e40e9.js"><link rel="prefetch" href="/docs/assets/js/5.78b155e8.js"><link rel="prefetch" href="/docs/assets/js/6.35a311c9.js"><link rel="prefetch" href="/docs/assets/js/7.ab3a52c1.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.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/install.html" class="sidebar-link">安装</a></li><li><a href="/docs/config.html" class="active 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"><h1 id="page-2"><a href="#page-2" aria-hidden="true" class="header-anchor">#</a> Page 2</h1><p>this is a second page</p></div><div class="page-edit"><!----><!----></div><div class="page-nav"><p class="inner"><span class="prev">
|
||||
← <a href="/docs/install.html" class="prev">
|
||||
安装
|
||||
</a></span><span class="next"><a href="/docs/develop.html">
|
||||
插件开发
|
||||
</a> →
|
||||
</span></p></div></div></div></div>
|
||||
<script src="/docs/assets/js/app.92893aed.js" defer></script><script src="/docs/assets/js/2.a6d3efaf.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,25 +0,0 @@
|
||||
<!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.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="preload" href="/docs/assets/js/3.a9fbea98.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.685ed1cc.js"><link rel="prefetch" href="/docs/assets/js/2.a6d3efaf.js"><link rel="prefetch" href="/docs/assets/js/4.727e40e9.js"><link rel="prefetch" href="/docs/assets/js/5.78b155e8.js"><link rel="prefetch" href="/docs/assets/js/6.35a311c9.js"><link rel="prefetch" href="/docs/assets/js/7.ab3a52c1.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.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/install.html" class="sidebar-link">安装</a></li><li><a href="/docs/config.html" class="sidebar-link">配置</a></li><li><a href="/docs/develop.html" class="active 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 class="page-nav"><p class="inner"><span class="prev">
|
||||
← <a href="/docs/config.html" class="prev">
|
||||
配置
|
||||
</a></span><span class="next"><a href="/docs/history.html">
|
||||
更新日志
|
||||
</a> →
|
||||
</span></p></div></div></div></div>
|
||||
<script src="/docs/assets/js/app.92893aed.js" defer></script><script src="/docs/assets/js/3.a9fbea98.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Page 3 with custom link page | Monibuca</title>
|
||||
<meta name="description" content="">
|
||||
|
||||
|
||||
<link rel="preload" href="/docs/assets/css/styles.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="preload" href="/docs/assets/js/4.727e40e9.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.685ed1cc.js"><link rel="prefetch" href="/docs/assets/js/2.a6d3efaf.js"><link rel="prefetch" href="/docs/assets/js/3.a9fbea98.js"><link rel="prefetch" href="/docs/assets/js/5.78b155e8.js"><link rel="prefetch" href="/docs/assets/js/6.35a311c9.js"><link rel="prefetch" href="/docs/assets/js/7.ab3a52c1.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.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/install.html" class="sidebar-link">安装</a></li><li><a href="/docs/config.html" 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="page-3-with-custom-link-page"><a href="#page-3-with-custom-link-page" aria-hidden="true" class="header-anchor">#</a> Page 3 with custom link page</h1><p>this is a third page</p></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.92893aed.js" defer></script><script src="/docs/assets/js/4.727e40e9.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,22 +0,0 @@
|
||||
<!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.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="preload" href="/docs/assets/js/1.685ed1cc.js" as="script"><link rel="prefetch" href="/docs/assets/js/2.a6d3efaf.js"><link rel="prefetch" href="/docs/assets/js/3.a9fbea98.js"><link rel="prefetch" href="/docs/assets/js/4.727e40e9.js"><link rel="prefetch" href="/docs/assets/js/5.78b155e8.js"><link rel="prefetch" href="/docs/assets/js/6.35a311c9.js"><link rel="prefetch" href="/docs/assets/js/7.ab3a52c1.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.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></li><li><a href="/docs/install.html" class="sidebar-link">安装</a></li><li><a href="/docs/config.html" 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"><h1 id="关于-monibuca"><a href="#关于-monibuca" aria-hidden="true" class="header-anchor">#</a> 关于 Monibuca</h1></div><div class="page-edit"><!----><!----></div><div class="page-nav"><p class="inner"><!----><span class="next"><a href="/docs/install.html">
|
||||
安装
|
||||
</a> →
|
||||
</span></p></div></div></div></div>
|
||||
<script src="/docs/assets/js/app.92893aed.js" defer></script><script src="/docs/assets/js/1.685ed1cc.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Page 1 | Monibuca</title>
|
||||
<meta name="description" content="">
|
||||
|
||||
|
||||
<link rel="preload" href="/docs/assets/css/styles.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="preload" href="/docs/assets/js/5.78b155e8.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.685ed1cc.js"><link rel="prefetch" href="/docs/assets/js/2.a6d3efaf.js"><link rel="prefetch" href="/docs/assets/js/3.a9fbea98.js"><link rel="prefetch" href="/docs/assets/js/4.727e40e9.js"><link rel="prefetch" href="/docs/assets/js/6.35a311c9.js"><link rel="prefetch" href="/docs/assets/js/7.ab3a52c1.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.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/install.html" class="active sidebar-link">安装</a></li><li><a href="/docs/config.html" 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"><h1 id="page-1"><a href="#page-1" aria-hidden="true" class="header-anchor">#</a> Page 1</h1><p>this is a page</p></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/config.html">
|
||||
配置
|
||||
</a> →
|
||||
</span></p></div></div></div></div>
|
||||
<script src="/docs/assets/js/app.92893aed.js" defer></script><script src="/docs/assets/js/5.78b155e8.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,19 +0,0 @@
|
||||
<!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.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="preload" href="/docs/assets/js/6.35a311c9.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.685ed1cc.js"><link rel="prefetch" href="/docs/assets/js/2.a6d3efaf.js"><link rel="prefetch" href="/docs/assets/js/3.a9fbea98.js"><link rel="prefetch" href="/docs/assets/js/4.727e40e9.js"><link rel="prefetch" href="/docs/assets/js/5.78b155e8.js"><link rel="prefetch" href="/docs/assets/js/7.ab3a52c1.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.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/install.html" class="sidebar-link">安装</a></li><li><a href="/docs/config.html" 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.92893aed.js" defer></script><script src="/docs/assets/js/6.35a311c9.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,22 +0,0 @@
|
||||
<!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.92893aed.css" as="style"><link rel="preload" href="/docs/assets/js/app.92893aed.js" as="script"><link rel="preload" href="/docs/assets/js/7.ab3a52c1.js" as="script"><link rel="prefetch" href="/docs/assets/js/1.685ed1cc.js"><link rel="prefetch" href="/docs/assets/js/2.a6d3efaf.js"><link rel="prefetch" href="/docs/assets/js/3.a9fbea98.js"><link rel="prefetch" href="/docs/assets/js/4.727e40e9.js"><link rel="prefetch" href="/docs/assets/js/5.78b155e8.js"><link rel="prefetch" href="/docs/assets/js/6.35a311c9.js">
|
||||
<link rel="stylesheet" href="/docs/assets/css/styles.92893aed.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/install.html" class="sidebar-link">安装</a></li><li><a href="/docs/config.html" 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><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/history.html" class="prev">
|
||||
更新日志
|
||||
</a></span><!----></p></div></div></div></div>
|
||||
<script src="/docs/assets/js/app.92893aed.js" defer></script><script src="/docs/assets/js/7.ab3a52c1.js" defer></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,96 +0,0 @@
|
||||
/**
|
||||
* 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": "0e4ff0fd403c5d29a13752bf3ef14d6d"
|
||||
},
|
||||
{
|
||||
"url": "assets/css/styles.92893aed.css",
|
||||
"revision": "07fa9a1fb782ef296585900714fac621"
|
||||
},
|
||||
{
|
||||
"url": "assets/img/search.83621669.svg",
|
||||
"revision": "83621669651b9a3d4bf64d1a670ad856"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/1.685ed1cc.js",
|
||||
"revision": "97247c4d4a60db87b22488bfdf99197d"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/2.a6d3efaf.js",
|
||||
"revision": "dca15d8c2b94dadcdce4386e7d628716"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/3.a9fbea98.js",
|
||||
"revision": "7f6bca508f94f8f508a61cd05b582084"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/4.727e40e9.js",
|
||||
"revision": "b8fca87e9c559c1fe3fa03b76d15c3bd"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/5.78b155e8.js",
|
||||
"revision": "73d1f3053737ad68ee4ec4fa395fcae9"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/6.35a311c9.js",
|
||||
"revision": "8bd2ad3294cf6a29e7326ca860d43250"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/7.ab3a52c1.js",
|
||||
"revision": "437c1f4739f884dcff81135f7bc8450c"
|
||||
},
|
||||
{
|
||||
"url": "assets/js/app.92893aed.js",
|
||||
"revision": "6962a63ee86d8a65c9ae46100427d812"
|
||||
},
|
||||
{
|
||||
"url": "config.html",
|
||||
"revision": "73b0335d99419df53f57913cd7303509"
|
||||
},
|
||||
{
|
||||
"url": "develop.html",
|
||||
"revision": "bc1b3cad3f88b61fee351464cffc7d0f"
|
||||
},
|
||||
{
|
||||
"url": "history.html",
|
||||
"revision": "dc6b1088d3cc72f1f3a402c56a441a57"
|
||||
},
|
||||
{
|
||||
"url": "index.html",
|
||||
"revision": "577c237555d953d8a22d045212f0a92e"
|
||||
},
|
||||
{
|
||||
"url": "install.html",
|
||||
"revision": "d06af57877e4695ae1a81528e2f128f1"
|
||||
},
|
||||
{
|
||||
"url": "plugins/index.html",
|
||||
"revision": "e578381fed44a65589053470ea33795d"
|
||||
},
|
||||
{
|
||||
"url": "plugins/jessica.html",
|
||||
"revision": "fe406bf63d2d349727c63d6045fd2efa"
|
||||
}
|
||||
].concat(self.__precacheManifest || []);
|
||||
workbox.precaching.suppressWarnings();
|
||||
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
|
Before Width: | Height: | Size: 21 KiB |
@@ -1,19 +0,0 @@
|
||||
<!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.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>Monibuca</title>
|
||||
<script src="jessibuca/ajax.js"></script>
|
||||
<script src="jessibuca/renderer.js"></script>
|
||||
</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>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
@@ -1,535 +0,0 @@
|
||||
// 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;
|
||||
})();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -1,460 +0,0 @@
|
||||
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() })
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div>Monibuca</div>
|
||||
<Menu mode="horizontal" :active-name="selectedMenu" style="position: absolute;top: 0;right: 0;">
|
||||
<MenuItem name="home" to="/">首页</MenuItem>
|
||||
<MenuItem name="docs" to="/docs" target="_blank">
|
||||
文档
|
||||
</MenuItem>
|
||||
<MenuItem name="console" to="console">
|
||||
控制台
|
||||
</MenuItem>
|
||||
<Submenu name="plugins">
|
||||
<template slot="title">
|
||||
内置插件
|
||||
</template>
|
||||
<MenuGroup title="发布者/订阅者">
|
||||
<MenuItem name="cluster">集群</MenuItem>
|
||||
<MenuItem name="rtmp">RTMP</MenuItem>
|
||||
</MenuGroup>
|
||||
<MenuGroup title="订阅者">
|
||||
<MenuItem name="jessica">Jessica</MenuItem>
|
||||
<MenuItem name="HDL">Http-Flv</MenuItem>
|
||||
<MenuItem name="record">录制Flv</MenuItem>
|
||||
</MenuGroup>
|
||||
<MenuGroup title="发布者">
|
||||
<MenuItem name="HLS">HLS</MenuItem>
|
||||
<MenuItem name="TS">TS</MenuItem>
|
||||
</MenuGroup>
|
||||
<MenuGroup title="钩子">
|
||||
<MenuItem name="Auth">验证</MenuItem>
|
||||
<MenuItem name="QoS">QoS</MenuItem>
|
||||
<MenuItem name="gateway">网关</MenuItem>
|
||||
</MenuGroup>
|
||||
</Submenu>
|
||||
<MenuItem name="4" to="about">
|
||||
支持
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<router-view class="content"></router-view>
|
||||
<div>Copyright © 2019-2020 dexter 苏ICP备20001212号</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
data(){
|
||||
return {
|
||||
selectedMenu:"home"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
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;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
#app > div:first-child {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 30px;
|
||||
font-size: x-large;
|
||||
}
|
||||
.content{
|
||||
padding-top: 60px;
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 102 KiB |
@@ -1,50 +0,0 @@
|
||||
<template>
|
||||
<Modal
|
||||
v-bind="$attrs" draggable
|
||||
v-on="$listeners"
|
||||
:title="url"
|
||||
@on-ok="onClosePreview"
|
||||
@on-cancel="onClosePreview">
|
||||
<canvas id="canvas" width="488" height="275" style="background: black"/>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let h5lc = null;
|
||||
export default {
|
||||
name: 'Jessibuca',
|
||||
props: {
|
||||
audioEnabled: Boolean,
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
url:""
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
audioEnabled(value){
|
||||
h5lc.audioEnabled(value)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
h5lc = new window.Jessibuca({
|
||||
canvas: document.getElementById("canvas"),
|
||||
decoder: "jessibuca/ff.js"
|
||||
});
|
||||
},
|
||||
destroyed() {
|
||||
this.onClosePreview()
|
||||
h5lc.destroy()
|
||||
},
|
||||
methods: {
|
||||
play(url){
|
||||
this.url = url
|
||||
h5lc.play(url)
|
||||
},
|
||||
onClosePreview() {
|
||||
h5lc.close();
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -1,18 +0,0 @@
|
||||
<template>
|
||||
<Poptip trigger="hover" :content="'⌚️'+ new Date(value).toLocaleString()">
|
||||
<Time :time="new Date(value)"></Time>
|
||||
</Poptip>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "StartTime",
|
||||
props:{
|
||||
value:String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
@@ -1,13 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import './plugins/iview.js'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
@@ -1,6 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import ViewUI from 'view-design'
|
||||
|
||||
Vue.use(ViewUI)
|
||||
|
||||
import 'view-design/dist/styles/iview.css'
|
@@ -1,32 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import Home from '../views/Home.vue'
|
||||
import About from '../views/About'
|
||||
import Console from '../views/Console'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
component: About
|
||||
}, {
|
||||
path: '/console',
|
||||
name: 'console',
|
||||
component: Console
|
||||
}
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: process.env.BASE_URL,
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
@@ -1,45 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
let summaryES = null
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
summary:{
|
||||
NetWork:[],
|
||||
Rooms:[],
|
||||
Memory:{
|
||||
Used: 0,
|
||||
Usage: 0
|
||||
},
|
||||
CPUUsage:0,
|
||||
HardDisk:{
|
||||
Used: 0,
|
||||
Usage: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
update(state,payload){
|
||||
Object.assign(state,payload)
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
fetchSummary({commit}){
|
||||
summaryES = new EventSource(
|
||||
"//" + location.host + "/api/summary"
|
||||
);
|
||||
summaryES.onmessage = evt=>{
|
||||
if (!evt.data) return
|
||||
let summary = JSON.parse(evt.data)
|
||||
commit("update",{summary})
|
||||
}
|
||||
},
|
||||
stopFetchSummary(){
|
||||
summaryES.close()
|
||||
}
|
||||
},
|
||||
modules: {
|
||||
}
|
||||
})
|
@@ -1,21 +0,0 @@
|
||||
<template>
|
||||
<div class="root">
|
||||
<h1>
|
||||
赞助 Monibuca 的研发
|
||||
</h1>
|
||||
<p>
|
||||
Monibuca 是采用 MIT 许可的开源项目,使用完全免费。 但是随着项目规模的增长,也需要有相应的资金支持才能持续项目的维护的开发。你可以通过下列的方法来赞助 Monibuca 的开发。
|
||||
</p>
|
||||
<img src="../assets/alipay.png">
|
||||
<img src="../assets/wechat.jpg">
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.root{
|
||||
background: lightgray;
|
||||
}
|
||||
.root>img{
|
||||
width: 300px;
|
||||
margin: 30px;
|
||||
}
|
||||
</style>
|
@@ -1,232 +0,0 @@
|
||||
<template>
|
||||
<div class="layout">
|
||||
<ButtonGroup vertical>
|
||||
<Button icon="ios-folder"></Button>
|
||||
<Button icon="md-bug"></Button>
|
||||
<Button icon="md-settings"></Button>
|
||||
</ButtonGroup>
|
||||
<Card v-for="item in Rooms" :key="item.StreamPath" class="room">
|
||||
<p slot="title">
|
||||
{{typeMap[item.Type]||item.Type}}{{item.StreamPath}}
|
||||
</p>
|
||||
<StartTime slot="extra" :value="item.StartTime"></StartTime>
|
||||
<p>
|
||||
{{SoundFormat(item.AudioInfo.SoundFormat)}} {{item.AudioInfo.PacketCount}}
|
||||
{{SoundRate(item.AudioInfo.SoundRate)}} 声道:{{item.AudioInfo.SoundType}}
|
||||
</p>
|
||||
<p>
|
||||
{{CodecID(item.VideoInfo.CodecID)}} {{item.VideoInfo.PacketCount}}
|
||||
{{item.VideoInfo.SPSInfo.Width}}x{{item.VideoInfo.SPSInfo.Height}}
|
||||
</p>
|
||||
<Button @click="onShowDetail(item)">
|
||||
<Icon type="ios-people"/>
|
||||
{{item.SubscriberInfo?item.SubscriberInfo.length:0}}
|
||||
</Button>
|
||||
<Button v-if="item.Type" @click="preview(item)">
|
||||
<Icon type="md-eye"/>
|
||||
Preview
|
||||
</Button>
|
||||
<Button @click="stopRecord(item)" v-if="isRecording(item)">
|
||||
<Icon type="ios-radio-button-on" class="recording"/>
|
||||
Stop Rec
|
||||
</Button>
|
||||
<Button @click="record(item)" v-else>
|
||||
<Icon type="ios-radio-button-on"/>
|
||||
Rec
|
||||
</Button>
|
||||
</Card>
|
||||
<div v-if="Rooms.length==0" class="empty">
|
||||
<Icon type="md-wine" size="50"/>
|
||||
没有任何房间
|
||||
</div>
|
||||
<div class="status">
|
||||
<Alert>
|
||||
带宽消耗 📥:{{totalInNetSpeed}} 📤:{{totalOutNetSpeed}}
|
||||
</Alert>
|
||||
<Alert :type="memoryStatus">
|
||||
内存使用:{{networkFormat(Memory.Used,"M")}} 占比:{{Memory.Usage.toFixed(2)}}%
|
||||
</Alert>
|
||||
<Alert :type="cpuStatus">
|
||||
CPU使用:{{CPUUsage.toFixed(2)}}%
|
||||
</Alert>
|
||||
<Alert :type="hardDiskStatus">
|
||||
磁盘使用:{{networkFormat(HardDisk.Used,"M")}} 占比:{{HardDisk.Usage.toFixed(2)}}%
|
||||
</Alert>
|
||||
</div>
|
||||
<Jessibuca ref="jessibuca" v-model="showPreview"></Jessibuca>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapActions, mapState} from 'vuex'
|
||||
import Jessibuca from "../components/Jessibuca";
|
||||
import StartTime from "../components/StartTime";
|
||||
|
||||
const uintInc = {
|
||||
"": "K",
|
||||
K: "M",
|
||||
M: "G",
|
||||
G: null
|
||||
}
|
||||
const SoundFormat = {
|
||||
0: "Linear PCM, platform endian",
|
||||
1: "ADPCM",
|
||||
2: "MP3",
|
||||
3: "Linear PCM, little endian",
|
||||
4: "Nellymoser 16kHz mono",
|
||||
5: "Nellymoser 8kHz mono",
|
||||
6: "Nellymoser",
|
||||
7: "G.711 A-law logarithmic PCM",
|
||||
8: "G.711 mu-law logarithmic PCM",
|
||||
9: "reserved",
|
||||
10: "AAC",
|
||||
11: "Speex",
|
||||
14: "MP3 8Khz",
|
||||
15: "Device-specific sound"
|
||||
}
|
||||
const CodecID = {
|
||||
1: "JPEG (currently unused)",
|
||||
2: "Sorenson H.263",
|
||||
3: "Screen video",
|
||||
4: "On2 VP6",
|
||||
5: "On2 VP6 with alpha channel",
|
||||
6: "Screen video version 2",
|
||||
7: "AVC",
|
||||
12: "H265"
|
||||
}
|
||||
export default {
|
||||
name: "Console",
|
||||
components: {
|
||||
Jessibuca, StartTime
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPreview: false,
|
||||
typeMap: {
|
||||
TS: "🎬", HLS: "🍎", "": "⏳", Match365: "🏆", RTMP: "📸"
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
Rooms: state => state.summary.Rooms || [],
|
||||
Memory: state => state.summary.Memory,
|
||||
CPUUsage: state => state.summary.CPUUsage,
|
||||
HardDisk: state => state.summary.HardDisk,
|
||||
cpuStatus: state => {
|
||||
if (state.summary.CPUUsage > 99)
|
||||
return "error"
|
||||
return state.summary.CPUUsage > 50 ? "warning" : "success"
|
||||
},
|
||||
memoryStatus(state) {
|
||||
if (state.summary.CPUUsage > 99)
|
||||
return "error"
|
||||
return state.summary.CPUUsage > 50 ? "warning" : "success"
|
||||
},
|
||||
hardDiskStatus(state) {
|
||||
if (state.summary.CPUUsage > 99)
|
||||
return "error"
|
||||
return state.summary.CPUUsage > 50 ? "warning" : "success"
|
||||
},
|
||||
totalInNetSpeed(state) {
|
||||
return this.networkFormat(state.summary.NetWork.reduce((aac, c) => aac + c.ReceiveSpeed, 0)) + "/S"
|
||||
},
|
||||
totalOutNetSpeed(state) {
|
||||
return this.networkFormat(state.summary.NetWork.reduce((aac, c) => aac + c.SentSpeed, 0)) + "/S"
|
||||
}
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
...mapActions([
|
||||
'fetchSummary',
|
||||
'stopFetchSummary'
|
||||
]),
|
||||
preview(item) {
|
||||
this.$refs.jessibuca.play("ws://" + location.hostname + ":8080/" + item.StreamPath)
|
||||
this.showPreview = true
|
||||
}, onShowDetail() {
|
||||
// this.showDetail = true
|
||||
// this.currentSub = item
|
||||
},
|
||||
networkFormat(value, unit = "") {
|
||||
if (value > 1024 && uintInc[unit]) {
|
||||
return this.networkFormat(value / 1024, uintInc[unit])
|
||||
}
|
||||
return value.toFixed(2).replace(".00", "") + unit + "B"
|
||||
},
|
||||
SoundFormat(soundFormat) {
|
||||
return SoundFormat[soundFormat]
|
||||
},
|
||||
CodecID(codec) {
|
||||
return CodecID[codec]
|
||||
},
|
||||
SoundRate(rate) {
|
||||
return rate > 1000 ? (rate / 1000) + "kHz" : rate + "Hz"
|
||||
},
|
||||
record(item) {
|
||||
window.ajax.get("//" + location.host + "/api/record/flv",{streamPath:item.StreamPath})
|
||||
},
|
||||
stopRecord(item){
|
||||
window.ajax.get("//" + location.host + "/api/record/flv/stop",{streamPath:item.StreamPath})
|
||||
},
|
||||
isRecording(item) {
|
||||
return item.SubscriberInfo && item.SubscriberInfo.find(x => x.Type == "FlvRecord")
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.fetchSummary()
|
||||
},
|
||||
destroyed() {
|
||||
this.stopFetchSummary()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@keyframes recording {
|
||||
0% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
.recording {
|
||||
animation: recording 1s infinite;
|
||||
}
|
||||
|
||||
.layout {
|
||||
padding-bottom: 30px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.room {
|
||||
width: 250px;
|
||||
margin: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: #eb5e46;
|
||||
width: 100%;
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
left: 5px;
|
||||
bottom: 10px;
|
||||
}
|
||||
|
||||
.status > div {
|
||||
margin: 0 5px;
|
||||
}
|
||||
</style>
|
@@ -1,53 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<img src="../assets/logo.png">
|
||||
<div>
|
||||
<p>
|
||||
Monibuca 是一个开源的Go语言实现的流媒体服务器开发框架
|
||||
</p>
|
||||
<Button type="success" to="/docs" target="_blank">🚀START</Button>
|
||||
<span style="margin: 0 10px"></span>
|
||||
<Button type="default" target="_blank" to="https://github.com/langhuihui/monibuca">
|
||||
<svg style="vertical-align: text-top" width="16" height="16" aria-labelledby="simpleicons-github-dark-icon" lang="" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title id="simpleicons-github-dark-icon" lang="en">GitHub Dark icon</title><path fill="#7F8C8D" d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"></path></svg>
|
||||
GITHUB</Button>
|
||||
</div>
|
||||
<Row style="margin: 30px;">
|
||||
<Col span="8">
|
||||
<Card :bordered="false" style="margin: 30px">
|
||||
<div slot="title" class="feature-title">⚡高性能</div>
|
||||
<div>针对流媒体服务器独特的性质进行的优化,充分利用Golang的goroutine的性质对大量的连接的读写进行合理的分配计算资源,以及尽可能的减少内存Copy操作。使用对象池减少Golang的GC时间。</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<Card :bordered="false" style="margin: 30px">
|
||||
<div slot="title" class="feature-title">🔧可扩展</div>
|
||||
<div>流媒体服务器的个性化定制变的更简单,基于Golang语言,开发效率更高,独创的插件机制,可以方便用户定制个性化的功能组合,更高效率的利用服务器资源。</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<Card :bordered="false" style="margin: 30px">
|
||||
<div slot="title" class="feature-title">📈可视化</div>
|
||||
<div>功能强大的仪表盘可以直观的看到服务器运行的状态、消耗的资源、以及其他统计信息。用户可以利用控制台对服务器进行配置和控制。点击右上角菜单栏里面的控制台,可以看到演示。</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
||||
<style scoped>
|
||||
.feature-title{
|
||||
color: #eb5e46;
|
||||
font-weight: bold;
|
||||
font-size: larger;
|
||||
}
|
||||
p {
|
||||
margin: 30px;
|
||||
font-size: 20px;
|
||||
}
|
||||
img{
|
||||
margin: 20px;
|
||||
}
|
||||
</style>
|
@@ -1,10 +0,0 @@
|
||||
module.exports = {
|
||||
chainWebpack: config => {
|
||||
config.module
|
||||
.rule('vue')
|
||||
.use('iview-loader')
|
||||
.loader('iview-loader')
|
||||
.tap(()=> ({prefix: false}))
|
||||
.end()
|
||||
}
|
||||
}
|
45
gen.go
Normal file
@@ -0,0 +1,45 @@
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
var debugShim string = `package main
|
||||
|
||||
import "net/http"
|
||||
|
||||
func init() {
|
||||
|
||||
notSupport := func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("not support"))
|
||||
}
|
||||
|
||||
http.HandleFunc("/debug/charts/", notSupport)
|
||||
http.HandleFunc("/debug/charts/data", notSupport)
|
||||
http.HandleFunc("/debug/charts/data-feed", notSupport)
|
||||
}
|
||||
`
|
||||
var debug string = `package main
|
||||
|
||||
import (
|
||||
_ "github.com/mkevac/debugcharts"
|
||||
)
|
||||
`
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Println("usage: go run gen.go <path>")
|
||||
os.Exit(1)
|
||||
}
|
||||
var content string
|
||||
if os.Args[1] == "1" {
|
||||
content = debug
|
||||
} else {
|
||||
content = debugShim
|
||||
}
|
||||
ioutil.WriteFile("debug.go", []byte(content), 0666)
|
||||
}
|
103
go.mod
@@ -1,17 +1,94 @@
|
||||
module github.com/langhuihui/monibuca
|
||||
module monibuca
|
||||
|
||||
go 1.13
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
|
||||
github.com/funny/slab v0.0.0-20180511031532-b1fad5e5d478
|
||||
github.com/funny/utest v0.0.0-20161029064919-43870a374500 // indirect
|
||||
github.com/go-ole/go-ole v1.2.4 // indirect
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
|
||||
github.com/gobwas/pool v0.2.0 // indirect
|
||||
github.com/gobwas/ws v1.0.2
|
||||
github.com/quangngotan95/go-m3u8 v0.1.0
|
||||
github.com/shirou/gopsutil v2.19.12+incompatible
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 // indirect
|
||||
m7s.live/engine/v4 v4.8.11
|
||||
m7s.live/plugin/debug/v4 v4.0.0-20220506113031-34f3a736ceb2
|
||||
m7s.live/plugin/edge/v4 v4.0.2
|
||||
m7s.live/plugin/fmp4/v4 v4.0.0-20221126151227-22a117d1b75e
|
||||
m7s.live/plugin/gb28181/v4 v4.1.5
|
||||
m7s.live/plugin/hdl/v4 v4.0.4
|
||||
m7s.live/plugin/hls/v4 v4.0.5
|
||||
m7s.live/plugin/hook/v4 v4.0.0
|
||||
m7s.live/plugin/jessica/v4 v4.0.0
|
||||
m7s.live/plugin/logrotate/v4 v4.0.3
|
||||
m7s.live/plugin/preview/v4 v4.0.1
|
||||
m7s.live/plugin/record/v4 v4.0.8
|
||||
m7s.live/plugin/room/v4 v4.0.1
|
||||
m7s.live/plugin/rtmp/v4 v4.0.3
|
||||
m7s.live/plugin/rtsp/v4 v4.0.5
|
||||
m7s.live/plugin/snap/v4 v4.0.0
|
||||
m7s.live/plugin/webrtc/v4 v4.0.4
|
||||
m7s.live/plugin/webtransport/v4 v4.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aler9/gortsplib v0.0.0-20221120213348-150f16ae6567 // indirect
|
||||
github.com/cnotch/ipchub v1.1.0 // indirect
|
||||
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca // indirect
|
||||
github.com/edgeware/mp4ff v0.30.1 // indirect
|
||||
github.com/ghettovoice/gosip v0.0.0-20221121090201-9a2ed2233b6d // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.1.0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8 // indirect
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||
github.com/lucas-clemente/quic-go v0.31.0 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c // indirect
|
||||
github.com/marten-seemann/qpack v0.3.0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||
github.com/pion/datachannel v1.5.2 // indirect
|
||||
github.com/pion/dtls/v2 v2.1.5 // indirect
|
||||
github.com/pion/ice/v2 v2.2.12 // indirect
|
||||
github.com/pion/interceptor v0.1.12 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/mdns v0.0.5 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.10 // indirect
|
||||
github.com/pion/rtp v1.7.13 // indirect
|
||||
github.com/pion/rtp/v2 v2.0.0-20220302185659-b3d10fc096b0 // indirect
|
||||
github.com/pion/sctp v1.8.3 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.6 // indirect
|
||||
github.com/pion/srtp/v2 v2.0.10 // indirect
|
||||
github.com/pion/stun v0.3.5 // indirect
|
||||
github.com/pion/transport v0.13.1 // indirect
|
||||
github.com/pion/turn/v2 v2.0.8 // indirect
|
||||
github.com/pion/udp v0.1.1 // indirect
|
||||
github.com/pion/webrtc/v3 v3.1.49 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c // indirect
|
||||
github.com/q191201771/naza v0.30.8 // indirect
|
||||
github.com/quangngotan95/go-m3u8 v0.1.0 // indirect
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.22.10 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/tevino/abool v1.2.0 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
github.com/zhangpeihao/goamf v0.0.0-20140409082417-3ff2c19514a8 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/crypto v0.3.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.2.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/term v0.2.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/tools v0.3.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
400
go.sum
@@ -1,22 +1,384 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/funny/slab v0.0.0-20180511031532-b1fad5e5d478 h1:Db9StoJ6RZN3YttC0Pm0I4Y5izITRYch3RMbT59BYN0=
|
||||
github.com/funny/slab v0.0.0-20180511031532-b1fad5e5d478/go.mod h1:0j1+svBH8ABEIPdUP0AIg4qedsybnXGJBakCEw8cfoo=
|
||||
github.com/funny/utest v0.0.0-20161029064919-43870a374500 h1:Z0r1CZnoIWFB/Uiwh1BU5FYmuFe6L5NPi6XWQEmsTRg=
|
||||
github.com/funny/utest v0.0.0-20161029064919-43870a374500/go.mod h1:mUn39tBov9jKnTWV1RlOYoNzxdBFHiSzXWdY1FoNGGg=
|
||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/aler9/gortsplib v0.0.0-20221120213348-150f16ae6567 h1:x0A9TesnU9HYv1OiyYXrdmgDHNCQkQRRF9XH/+9axHQ=
|
||||
github.com/aler9/gortsplib v0.0.0-20221120213348-150f16ae6567/go.mod h1:BOWNZ/QBkY/eVcRqUzJbPFEsRJshwxaxBT01K260Jeo=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cnotch/apirouter v0.0.0-20200731232942-89e243a791f3/go.mod h1:5deJPLON/x/s2dLOQfuKS0lenhOIT4xX0pvtN/OEIuY=
|
||||
github.com/cnotch/ipchub v1.1.0 h1:hH0lh2mU3AZXPiqMwA0pdtqrwo7PFIMRGush9OobMUs=
|
||||
github.com/cnotch/ipchub v1.1.0/go.mod h1:2PbeBs2q2VxxTVCn1eYCDwpAWuVXbq1+N0FU7GimOH4=
|
||||
github.com/cnotch/loader v0.0.0-20200405015128-d9d964d09439/go.mod h1:oWpDagHB6p+Kqqq7RoRZKyC4XAXft50hR8pbTxdbYYs=
|
||||
github.com/cnotch/queue v0.0.0-20200326024423-6e88bdbf2ad4/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
|
||||
github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
|
||||
github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5/go.mod h1:F4GE3SZkJZ8an1Y0ZCqvSM3jeozNuKzoC67erG1PhIo=
|
||||
github.com/cnotch/xlog v0.0.0-20201208005456-cfda439cd3a0/go.mod h1:RW9oHsR79ffl3sR3yMGgxYupMn2btzdtJUwoxFPUE5E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca h1:cTTdXpkQ1aVbOOmHwdwtYuwUZcQtcMrleD1UXLWhAq8=
|
||||
github.com/discoviking/fsm v0.0.0-20150126104936-f4a273feecca/go.mod h1:W+3LQaEkN8qAwwcw0KC546sUEnX86GIT8CcMLZC4mG0=
|
||||
github.com/edgeware/mp4ff v0.30.1 h1:OV88fQrw8sFPjTCFThsBwubjYPHTdHgb28pSd1y9ozk=
|
||||
github.com/edgeware/mp4ff v0.30.1/go.mod h1:GNUeA6tEFksH2CrjJF2FSGdJolba8yPGmo16qZTXsm8=
|
||||
github.com/emitter-io/address v1.0.0/go.mod h1:GfZb5+S/o8694B1GMGK2imUYQyn2skszMvGNA5D84Ug=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/ghettovoice/gosip v0.0.0-20221121090201-9a2ed2233b6d h1:f1JRfm0MwkluwtUsbYxuVReDMajlc9Wn6zc2orX4sRE=
|
||||
github.com/ghettovoice/gosip v0.0.0-20221121090201-9a2ed2233b6d/go.mod h1:yTr3BEYSFe9As6XM7ldyrVgqsPwlnw8Ahc4N28VFM2g=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.1.0-rc.1/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8 h1:4Jk58quTZmzJcTrLlbB5L1Q6qXu49EIjCReWxcBFWKo=
|
||||
github.com/husanpao/ip v0.0.0-20220711082147-73160bb611a8/go.mod h1:medl9/CfYoQlqAXtAARmMW5dAX2UOdwwkhaszYPk0AM=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/kelindar/process v0.0.0-20170730150328-69a29e249ec3/go.mod h1:+lTCLnZFXOkqwD8sLPl6u4erAc0cP8wFegQHfipz7KE=
|
||||
github.com/kelindar/rate v1.0.0/go.mod h1:AjT4G+hTItNwt30lucEGZIz8y7Uk5zPho6vurIZ+1Es=
|
||||
github.com/kelindar/tcp v1.0.0/go.mod h1:JB5hj1cshLU60XrLij2BBxW3JQ4hOye8vqbyvuKb52k=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lucas-clemente/quic-go v0.31.0 h1:MfNp3fk0wjWRajw6quMFA3ap1AVtlU+2mtwmbVogB2M=
|
||||
github.com/lucas-clemente/quic-go v0.31.0/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c h1:VtwQ41oftZwlMnOEbMWQtSEUgU64U4s+GHk7hZK+jtY=
|
||||
github.com/lufia/plan9stats v0.0.0-20220913051719-115f729f3c8c/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
|
||||
github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
|
||||
github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.5/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
|
||||
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
|
||||
github.com/pion/dtls/v2 v2.1.5 h1:jlh2vtIyUBShchoTDqpCCqiYCyRFJ/lvf/gQ8TALs+c=
|
||||
github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY=
|
||||
github.com/pion/ice/v2 v2.2.12 h1:n3M3lUMKQM5IoofhJo73D3qVla+mJN2nVvbSPq32Nig=
|
||||
github.com/pion/ice/v2 v2.2.12/go.mod h1:z2KXVFyRkmjetRlaVRgjO9U3ShKwzhlUylvxKfHfd5A=
|
||||
github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8=
|
||||
github.com/pion/interceptor v0.1.12 h1:CslaNriCFUItiXS5o+hh5lpL0t0ytQkFnUcbbCs2Zq8=
|
||||
github.com/pion/interceptor v0.1.12/go.mod h1:bDtgAD9dRkBZpWHGKaoKb42FhDHTG2rX8Ii9LRALLVA=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
|
||||
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
|
||||
github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
|
||||
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
|
||||
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
|
||||
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp/v2 v2.0.0-20220302185659-b3d10fc096b0 h1:zyOGxHutZ6IhksQSMtwf3OFXB29W5R18yFQWOQJYWjU=
|
||||
github.com/pion/rtp/v2 v2.0.0-20220302185659-b3d10fc096b0/go.mod h1:Vj+rrFbJCT3yxqE/VSwaOo9DQ2pMKGPxuE7hplGOlOs=
|
||||
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
||||
github.com/pion/sctp v1.8.3 h1:LWcciN2ptLkw9Ugp/Ks2E76fiWy7yk3Wm79D6oFbFNo=
|
||||
github.com/pion/sctp v1.8.3/go.mod h1:OHbDjdk7kg+L+7TJim9q/qGVefdEJohuA2SZyihccgI=
|
||||
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
|
||||
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
|
||||
github.com/pion/srtp/v2 v2.0.10 h1:b8ZvEuI+mrL8hbr/f1YiJFB34UMrOac3R3N1yq2UN0w=
|
||||
github.com/pion/srtp/v2 v2.0.10/go.mod h1:XEeSWaK9PfuMs7zxXyiN252AHPbH12NX5q/CFDWtUuA=
|
||||
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
||||
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
||||
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
|
||||
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
|
||||
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
|
||||
github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA=
|
||||
github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg=
|
||||
github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw=
|
||||
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
|
||||
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
|
||||
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
|
||||
github.com/pion/webrtc/v3 v3.1.49 h1:rbsNGxK9jMYts+xE6zYAJMUQHnGwmk/JYze8yttW+to=
|
||||
github.com/pion/webrtc/v3 v3.1.49/go.mod h1:kHf/o47QW4No1rgpsFux/h7lUhtUnwFnSFDZOXeLapw=
|
||||
github.com/pixelbender/go-sdp v1.1.0/go.mod h1:6IBlz9+BrUHoFTea7gcp4S54khtOhjCW/nVDLhmZBAs=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c h1:NRoLoZvkBTKvR5gQLgA3e0hqjkY9u1wm+iOL45VN/qI=
|
||||
github.com/power-devops/perfstat v0.0.0-20220216144756-c35f1ee13d7c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/q191201771/naza v0.30.8 h1:Lhh29o65C4PmTDj2l+eKfsw9dddpgWZk4bFICtcnSaA=
|
||||
github.com/q191201771/naza v0.30.8/go.mod h1:n+dpJjQSh90PxBwxBNuifOwQttywvSIN5TkWSSYCeBk=
|
||||
github.com/quangngotan95/go-m3u8 v0.1.0 h1:8oseBjJn5IKHQKdRZwSNskkua3NLrRtlvXXtoVgBzMk=
|
||||
github.com/quangngotan95/go-m3u8 v0.1.0/go.mod h1:smzfWHlYpBATVNu1GapKLYiCtEo5JxridIgvvudZ+Wc=
|
||||
github.com/shirou/gopsutil v2.19.12+incompatible h1:WRstheAymn1WOPesh+24+bZKFkqrdCR8JOc77v4xV3Q=
|
||||
github.com/shirou/gopsutil v2.19.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
github.com/shirou/gopsutil/v3 v3.22.10 h1:4KMHdfBRYXGF9skjDWiL4RA2N+E8dRdodU/bOZpPoVg=
|
||||
github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0=
|
||||
github.com/tevino/abool v1.2.0 h1:heAkClL8H6w+mK5md9dzsuohKeXHUpY7Vw0ZCKW+huA=
|
||||
github.com/tevino/abool v1.2.0/go.mod h1:qc66Pna1RiIsPa7O4Egxxs9OqkuxDX55zznh9K07Tzg=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
|
||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/zhangpeihao/goamf v0.0.0-20140409082417-3ff2c19514a8 h1:r1JUI0wuHlgRb8jNd3zPBBkjUdrjpVKr8SdJWc8ntg8=
|
||||
github.com/zhangpeihao/goamf v0.0.0-20140409082417-3ff2c19514a8/go.mod h1:RZd/IqzNpFANwOB9rVmsnAYpo/6KesK4PqrN1a5cRgg=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9 h1:yZNXmy+j/JpX19vZkVktWqAo7Gny4PBWYYK3zskGpx4=
|
||||
golang.org/x/exp v0.0.0-20221126150942-6ab00d035af9/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
|
||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
m7s.live/engine/v4 v4.8.11 h1:ShUejaJgqUUO4Tu8gznl73fvRrLnCTOj8k2cmfFZGFU=
|
||||
m7s.live/engine/v4 v4.8.11/go.mod h1:OgI9lOQ1bE64s9rApdGGop1MBAJIpc/V2MJ190d9ig4=
|
||||
m7s.live/plugin/debug/v4 v4.0.0-20220506113031-34f3a736ceb2 h1:0QWJvozTHy7m+G/lOIGiejQ9okFIDjwzVsgXe6ZaJg8=
|
||||
m7s.live/plugin/debug/v4 v4.0.0-20220506113031-34f3a736ceb2/go.mod h1:A/C1ViacCOK7EPeeCfiwlUrC2TUtRdEqzrR0Yd9b1KQ=
|
||||
m7s.live/plugin/edge/v4 v4.0.2 h1:p1wSOS8qM1JY4Usu1XDR/ghgwDMmR/+3eN9WlPY5BkY=
|
||||
m7s.live/plugin/edge/v4 v4.0.2/go.mod h1:Dhpzmf2dVWWwzb73zdSaKMC4sSOGqWGBkmeUwd2XVuo=
|
||||
m7s.live/plugin/fmp4/v4 v4.0.0-20221126151227-22a117d1b75e h1:/APKrFkujtI17MBwrc/EvsjkeDuO79Uc0kHdZUF+3tg=
|
||||
m7s.live/plugin/fmp4/v4 v4.0.0-20221126151227-22a117d1b75e/go.mod h1:9/DlkfpXuBtZziwARFHZogLRnT+vjXPbO5eTrbGkY+8=
|
||||
m7s.live/plugin/gb28181/v4 v4.1.5 h1:bPtNtfTGubpX/beKciR5W+tdI+mu0OAr2tcBaf1E+Ww=
|
||||
m7s.live/plugin/gb28181/v4 v4.1.5/go.mod h1:B5RDyhiuKYyQG1KCiMUGE0cP3uTbWdEgpEf8jBEuXgo=
|
||||
m7s.live/plugin/hdl/v4 v4.0.4 h1:x2HfE4nQlRDzGr9pC3yk7C/ocT31263TJO+9uKoZ+9E=
|
||||
m7s.live/plugin/hdl/v4 v4.0.4/go.mod h1:lCniPUuWWMsKw6XwwGYnzNeK3ZYBYx/ytDfnEEE+3E8=
|
||||
m7s.live/plugin/hls/v4 v4.0.5 h1:SYrBYTpWkeVKVdu7jdLDVNHrT7YAbvE4RDqBcOAuO48=
|
||||
m7s.live/plugin/hls/v4 v4.0.5/go.mod h1:Qn4dDz5xlyBJwO+eZ3w8CUQ8Hl6KN1nmv0a3IsOjJvw=
|
||||
m7s.live/plugin/hook/v4 v4.0.0 h1:HdkYt+I0IKsLC5SW9hetkrI6LvWA/7JI151OpkVg6+8=
|
||||
m7s.live/plugin/hook/v4 v4.0.0/go.mod h1:ky3FOzCMKSDIiosPOw3wrKrQLM3YERSe5YrQZToJh/I=
|
||||
m7s.live/plugin/jessica/v4 v4.0.0 h1:TWU2NkFLAdrKyF2GQCL1YflBqn0s0Vt1RdtyBUlGaTA=
|
||||
m7s.live/plugin/jessica/v4 v4.0.0/go.mod h1:mJCONeOUeIPPA7Pfgge844l65KzHXa+QwE+AJ64Cf+4=
|
||||
m7s.live/plugin/logrotate/v4 v4.0.3 h1:f+teASc5Y5vDOrxXFc/ri3t7jdi6GIb6V9UMjhacb7I=
|
||||
m7s.live/plugin/logrotate/v4 v4.0.3/go.mod h1:a8hIV59GjpQDE+Ip790CU7yOHaG4+Iweci0sLvo43FU=
|
||||
m7s.live/plugin/preview/v4 v4.0.1 h1:k8iA5/bMiEWSFcy4zaZ8wG93AtJcSwxtgcQG+Y0xX5E=
|
||||
m7s.live/plugin/preview/v4 v4.0.1/go.mod h1:iYhWqFbTvTNDFplbTOrE5X9M6ED7gCKkKMuM5QmBocg=
|
||||
m7s.live/plugin/record/v4 v4.0.8 h1:/f+1hjD7BebWmrd0fdY8QvczHir9eIHBVcCwDdYbcis=
|
||||
m7s.live/plugin/record/v4 v4.0.8/go.mod h1:8fXbmsS+QCQhp136FdqBVEQsbNccWFAYTQDRJW/muQU=
|
||||
m7s.live/plugin/room/v4 v4.0.1 h1:MKcGWKSVc+vWVE4Ygdlz+aMy5KaZvhFx3x2xxT0Onsg=
|
||||
m7s.live/plugin/room/v4 v4.0.1/go.mod h1:s/e+9cyOkJVMAsOVRM08RDvlPikeaeh5R26qk8oekFA=
|
||||
m7s.live/plugin/rtmp/v4 v4.0.3 h1:kH1B3UzD07Q2pWpDIEa8LSAfisoqxmV7tFzy0rK0A/Q=
|
||||
m7s.live/plugin/rtmp/v4 v4.0.3/go.mod h1:Y+1A1ds4GgcoDennFy5DJntiuzeptO7EEqgu32bjJ70=
|
||||
m7s.live/plugin/rtsp/v4 v4.0.5 h1:+YaSafkNztmjWhYu3isHbEOigNX8E9nFgxIoRBsleEs=
|
||||
m7s.live/plugin/rtsp/v4 v4.0.5/go.mod h1:peQMDgSjr7HWex9X4TISZUgvmK/ttqdjHSAHrod42zE=
|
||||
m7s.live/plugin/snap/v4 v4.0.0 h1:qCm3to4bfNzfu2+/ke5pqU1NoheJBFEY6BsifQivH9w=
|
||||
m7s.live/plugin/snap/v4 v4.0.0/go.mod h1:XHggonZ0lIKEX/OP2rXjV2mPpG4urmvMT3foIaFRsus=
|
||||
m7s.live/plugin/webrtc/v4 v4.0.4 h1:PBHthk7lDHSXQNbobh42GD3ipvFyocCcPJR5qnb3gXU=
|
||||
m7s.live/plugin/webrtc/v4 v4.0.4/go.mod h1:s8wpe8MQ1Cmd0QaUgaevUGGPIDWvg0C/avwqjoGd3u4=
|
||||
m7s.live/plugin/webtransport/v4 v4.0.1 h1:ZYgrg9b6u4IBHjz/rXxQ/TLHdgS3iMsyhOHbVAimCn0=
|
||||
m7s.live/plugin/webtransport/v4 v4.0.1/go.mod h1:RtqizBkC2q3QNA+gfYD1mMH6SVK8T/iprvaX+3SQ1B0=
|
||||
|
42
goreleaser.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
project_name: m7s
|
||||
archives:
|
||||
-
|
||||
files:
|
||||
- config.yaml
|
||||
- monibuca.com.key
|
||||
- monibuca.com.pem
|
||||
builds:
|
||||
- id: "with-debug"
|
||||
env: [CGO_ENABLED=0]
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Tag}}
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
- goos: windows
|
||||
goarch: arm64
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
- arm64
|
||||
hooks:
|
||||
pre:
|
||||
- bash -c "debug=1 go generate ./..."
|
||||
- go mod tidy
|
||||
|
||||
- id: "without-debug"
|
||||
env: [CGO_ENABLED=0]
|
||||
ldflags:
|
||||
- -s -w -X main.version={{.Tag}}
|
||||
goos:
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- arm64
|
||||
hooks:
|
||||
pre:
|
||||
- bash -c "debug=0 go generate ./..."
|
||||
- go mod tidy
|
54
main.go
@@ -1,14 +1,54 @@
|
||||
package main
|
||||
|
||||
//go:generate go run gen.go $debug
|
||||
|
||||
/*
|
||||
███ ███ ██████ ███ ██ 👑 ██████ ██ ██ ██████ █████
|
||||
████ ████ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
██ ████ ██ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ███████
|
||||
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
||||
██ ██ ██████ ██ ████ ██ ██████ ██████ ██████ ██ ██
|
||||
|
||||
The live stream server for Go
|
||||
(c) dexter 2019-present
|
||||
*/
|
||||
|
||||
import (
|
||||
. "github.com/langhuihui/monibuca/monica"
|
||||
_ "github.com/langhuihui/monibuca/plugins"
|
||||
"log"
|
||||
"os"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
|
||||
"m7s.live/engine/v4"
|
||||
"m7s.live/engine/v4/util"
|
||||
|
||||
_ "m7s.live/plugin/debug/v4"
|
||||
_ "m7s.live/plugin/gb28181/v4"
|
||||
_ "m7s.live/plugin/hdl/v4"
|
||||
_ "m7s.live/plugin/hls/v4"
|
||||
_ "m7s.live/plugin/hook/v4"
|
||||
_ "m7s.live/plugin/jessica/v4"
|
||||
_ "m7s.live/plugin/logrotate/v4"
|
||||
_ "m7s.live/plugin/preview/v4"
|
||||
_ "m7s.live/plugin/record/v4"
|
||||
_ "m7s.live/plugin/room/v4"
|
||||
_ "m7s.live/plugin/rtmp/v4"
|
||||
_ "m7s.live/plugin/rtsp/v4"
|
||||
_ "m7s.live/plugin/snap/v4"
|
||||
_ "m7s.live/plugin/webrtc/v4"
|
||||
_ "m7s.live/plugin/webtransport/v4"
|
||||
_ "m7s.live/plugin/edge/v4"
|
||||
_ "m7s.live/plugin/fmp4/v4"
|
||||
)
|
||||
|
||||
var (
|
||||
version = "dev"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.SetOutput(os.Stdout)
|
||||
Run("config.toml")
|
||||
select {}
|
||||
fmt.Println("start monibuca version:", version)
|
||||
conf := flag.String("c", "config.yaml", "config file")
|
||||
flag.Parse()
|
||||
ctx, cancel := context.WithCancel(context.WithValue(context.Background(), "version", version))
|
||||
go util.WaitTerm(cancel)
|
||||
engine.Run(ctx, *conf)
|
||||
}
|
||||
|
27
monibuca.com.key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEAsDuh54gI4Flxg+ZrpvxWdmCnvpE1EqNfrV41+yTMZxJko32B
|
||||
6ErSCb/qu6viTqnV+Vf/YY/a7TFCt/NQHFpx3pXRhRFCM5TVaoFqWOYpU8dgACOs
|
||||
nK9cyOlAaE0s8TuPTjo9P9TZAbVyaHobTdEwImu17Nq6vAczFLanqfhKcQ22e7PR
|
||||
mk039f/7vqDUvYJiHtddjACaKfJ9XqfsLjxhKT/fSg/iYjjmD9uEidvUwbK0Uq62
|
||||
M5oTyf1R1A/z+SD4rVUaxN8JyjYsOrELoVYQAP6YY9d5e5V5KrX1JXf+7cjwU0Jy
|
||||
gcieNWvAIzq0oVVqiq43N59//FcoU+n4g2vloQIDAQABAoIBAAc7GySF119lLBwu
|
||||
WyJp3h5TTu6pxJS0MVvKrspUMzLTdV+j6a2fTEjsH/R9U/bITyhA7RCSt3fd+o/T
|
||||
oujW6S8p1IPyNlYpeCw7jSKCpxVx68V1sUJoi5UOxP7Ck+J+AB5Ek3jIAfNo/327
|
||||
7NzfhWsUIk3Kl7jZTsY9zFlT/7HtvZSO9UkNVz0m0wlkoENE7va+SbBgPEIupMqU
|
||||
oR0jZQKAcEwJi7vneLKjUhTr8v2InGYeLybLcw5ZKxYBOjFk2rELPUP26/SgNvsA
|
||||
VPvA9HBTYy9IZFNF/3O3QNnD2/Ix0zGm2LVuYAc4FqE4Zd7NssNBmi25ASZq+rdg
|
||||
YMiNJ7ECgYEA7EbusDzUId4WO8bwB9vW0Glg+8flNJ4uXqbV9eA/B5Vp71jkV9fB
|
||||
led2dmcW5FUG2kktkUNHbUXEer4eM7s74983CAb74hpUXEWY75Fp3FqOCk0eTLqE
|
||||
unke8BaUKdSSYPPWEBNHfii9GkoKRBLvGLnfOsrMB1pZouAhhwdDZu0CgYEAvvGZ
|
||||
0/bhTjdS7k9/5h7FiY1brxpFy/G8yrpZwA+tvxLLGnPNmRBljFDCSQsPliBbURD4
|
||||
T/jt2FOltfBPOJ0wMCNUmEqsnIs2fCiRr1UkEUFZ2SPOcTybk5gaiTKeXKl3i+Zq
|
||||
u1MT+qxr1HfjspuUJ0Ou9N+HIXtrwNMqxb7/DwUCgYAFELw7QQKXO0ikvW4V7Quc
|
||||
6jVvEGkEiMObud3qaIVRZ02fGPvEOlbnHNA4V5txB7We5mS4sYWNfSpqKztAhqoR
|
||||
B48JeATcYw4d8EwIDskDNVnINMEKihEgYkpcgU9p2inNNE0JiTBGLx9mueGgdft0
|
||||
Pz/e5cwb+D7ltAJj/67dPQKBgQCsLv3CcIw3lhgIolP5VaJYKcqVmiF6iWDvhx/L
|
||||
29eXyACyt96cunZ4E5M/fuPtQvxVm/HvW9BPFQ8Hg85MhSKhJhrwwdXpzHezenn1
|
||||
G9fMX5v//RP6dObuL2kucyDu+jq9Q2jXx1Dq6XTLQdlohHcS+SvZ0X/vp3ZBiaq2
|
||||
a0dhaQKBgAV3WUwkqzdmG7yzcUxMMcRO4686UNApNQlqkTieOt3n5+uDEOjxbYQz
|
||||
z8bBLDunDpW5UEQr2UEP/jT6TAZ34xXqMpXyF2BvTPzVbRYlFVzGTLQ6MmOkvykJ
|
||||
BFD6EWH2uAbzNQF1y7TlKTa6CO58+I9tP9+CL6LSfeZ+9ABuRKQ4
|
||||
-----END RSA PRIVATE KEY-----
|
66
monibuca.com.pem
Normal file
@@ -0,0 +1,66 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGdDCCBNygAwIBAgIQNDrmCqWpIXWEcjc+6M1EeDANBgkqhkiG9w0BAQwFADBZ
|
||||
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
|
||||
SW5jLjEjMCEGA1UEAxMaVHJ1c3RBc2lhIFJTQSBEViBUTFMgQ0EgRzIwHhcNMjIw
|
||||
NDA3MDAwMDAwWhcNMjMwNDA3MjM1OTU5WjAXMRUwEwYDVQQDEwxtb25pYnVjYS5j
|
||||
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwO6HniAjgWXGD5mum
|
||||
/FZ2YKe+kTUSo1+tXjX7JMxnEmSjfYHoStIJv+q7q+JOqdX5V/9hj9rtMUK381Ac
|
||||
WnHeldGFEUIzlNVqgWpY5ilTx2AAI6ycr1zI6UBoTSzxO49OOj0/1NkBtXJoehtN
|
||||
0TAia7Xs2rq8BzMUtqep+EpxDbZ7s9GaTTf1//u+oNS9gmIe112MAJop8n1ep+wu
|
||||
PGEpP99KD+JiOOYP24SJ29TBsrRSrrYzmhPJ/VHUD/P5IPitVRrE3wnKNiw6sQuh
|
||||
VhAA/phj13l7lXkqtfUld/7tyPBTQnKByJ41a8AjOrShVWqKrjc3n3/8VyhT6fiD
|
||||
a+WhAgMBAAGjggL4MIIC9DAfBgNVHSMEGDAWgBRfOnwREH4MZ3Fh3IujtQADZ/VX
|
||||
HDAdBgNVHQ4EFgQUXzGOkA4bBluzNCi/v4FoPmbmRkYwDgYDVR0PAQH/BAQDAgWg
|
||||
MAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEkG
|
||||
A1UdIARCMEAwNAYLKwYBBAGyMQECAjEwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9z
|
||||
ZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQIBMH0GCCsGAQUFBwEBBHEwbzBCBggrBgEF
|
||||
BQcwAoY2aHR0cDovL2NydC50cnVzdC1wcm92aWRlci5jbi9UcnVzdEFzaWFSU0FE
|
||||
VlRMU0NBRzIuY3J0MCkGCCsGAQUFBzABhh1odHRwOi8vb2NzcC50cnVzdC1wcm92
|
||||
aWRlci5jbjApBgNVHREEIjAgggxtb25pYnVjYS5jb22CEHd3dy5tb25pYnVjYS5j
|
||||
b20wggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB2AK33vvp8/xDIi509nB4+GGq0
|
||||
Zyldz7EMJMqFhjTr3IKKAAABgAMZ5TAAAAQDAEcwRQIhAOeaZWh1Myi4VcwhZIZ+
|
||||
DnqGBK+j8RgjsxXEKsLsviAUAiAhhdqtOma6qPzjCx8erWmAGALHLW3ksTzLRdiC
|
||||
TZmqegB2AHoyjFTYty22IOo44FIe6YQWcDIThU070ivBOlejUutSAAABgAMZ5OIA
|
||||
AAQDAEcwRQIhALKO6kODma4cvfI6ylGtpkLaBfa6IqoNPIo6iHWqfl0GAiAo0ksX
|
||||
l45X1RxiFCbSS8XMgOgFpXST5rMW9KFZmKNf5gB2AOg+0No+9QY1MudXKLyJa8kD
|
||||
08vREWvs62nhd31tBr1uAAABgAMZ5McAAAQDAEcwRQIgbAiIMrugBC74wShIjEhn
|
||||
6P0RNpddTPiulfQwlK/nPYcCIQC8/i3N8JJ1d8or+FqQulc3eU6PIuzg39MjX9UU
|
||||
GcN4qTANBgkqhkiG9w0BAQwFAAOCAYEAXjyA/d2/Xu1ChRqoaGaDDc4Na1ogvzkM
|
||||
X2ZXhAl0L/fPWiZjMX6DSjQmBFZZLhXC40LhnvuvVByGt0OUWrHRWU2wonH7Avhn
|
||||
IZi1BcrQXwO5vwfA4kmwaMA92PZFQMjySzmd9+44J6HacrbI6j29Tv67qeglE7z2
|
||||
NmzsuaHAW0G08A5A7LlziW53lz+CnPk60iPcNCjV60bPFJPRPhtt/a4ND2jbIALa
|
||||
u8OuFZvlggeCWW8TQlGQFhv4ux7PotHcRfcyW3HigLyNQTjLkzopVufL7BvSR4vW
|
||||
JFfb5LdOfcx5iES4AoNdld8jIxKhOviLlKV0eT25o66SwGGfP+hGcDx+Vf+2/x4n
|
||||
ukHwQVMtidiwxvDTJMPBoTZRCj5AW6A8bF8Ps4gh7Vfr3fvLRJnL+88f6GjUbmfO
|
||||
GlO4h6Za78Vl3TQcBD7296+MrBu0faAtTbd34FqgRXGQ8DHdDNLeKRP8WAzv19/L
|
||||
IhHfarLkL/bhhrGTB9McvA2jmGr4W0jf
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFBzCCA++gAwIBAgIRALIM7VUuMaC/NDp1KHQ76aswDQYJKoZIhvcNAQELBQAw
|
||||
ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV
|
||||
BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0yMjAxMTAwMDAwMDBaFw0y
|
||||
ODEyMzEyMzU5NTlaMFkxCzAJBgNVBAYTAkNOMSUwIwYDVQQKExxUcnVzdEFzaWEg
|
||||
VGVjaG5vbG9naWVzLCBJbmMuMSMwIQYDVQQDExpUcnVzdEFzaWEgUlNBIERWIFRM
|
||||
UyBDQSBHMjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAKjGDe0GSaBs
|
||||
Yl/VhMaTM6GhfR1TAt4mrhN8zfAMwEfLZth+N2ie5ULbW8YvSGzhqkDhGgSBlafm
|
||||
qq05oeESrIJQyz24j7icGeGyIZ/jIChOOvjt4M8EVi3O0Se7E6RAgVYcX+QWVp5c
|
||||
Sy+l7XrrtL/pDDL9Bngnq/DVfjCzm5ZYUb1PpyvYTP7trsV+yYOCNmmwQvB4yVjf
|
||||
IIpHC1OcsPBntMUGeH1Eja4D+qJYhGOxX9kpa+2wTCW06L8T6OhkpJWYn5JYiht5
|
||||
8exjAR7b8Zi3DeG9oZO5o6Qvhl3f8uGU8lK1j9jCUN/18mI/5vZJ76i+hsgdlfZB
|
||||
Rh5lmAQjD80M9TY+oD4MYUqB5XrigPfFAUwXFGehhlwCVw7y6+5kpbq/NpvM5Ba8
|
||||
SeQYUUuMA8RXpTtGlrrTPqJryfa55hTuX/ThhX4gcCVkbyujo0CYr+Uuc14IOyNY
|
||||
1fD0/qORbllbgV41wiy/2ZUWZQUodqHWkjT1CwIMbQOY5jmrSYGBwwIDAQABo4IB
|
||||
JjCCASIwHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYDVR0OBBYE
|
||||
FF86fBEQfgxncWHci6O1AANn9VccMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8E
|
||||
CDAGAQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAiBgNVHSAE
|
||||
GzAZMA0GCysGAQQBsjEBAgIxMAgGBmeBDAECATBDBgNVHR8EPDA6MDigNqA0hjJo
|
||||
dHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNy
|
||||
bDA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmNvbW9k
|
||||
b2NhLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAHMUom5cxIje2IiFU7mOCsBr2F6CY
|
||||
eU5cyfQ/Aep9kAXYUDuWsaT85721JxeXFYkf4D/cgNd9+hxT8ZeDOJrn+ysqR7NO
|
||||
2K9AdqTdIY2uZPKmvgHOkvH2gQD6jc05eSPOwdY/10IPvmpgUKaGOa/tyygL8Og4
|
||||
3tYyoHipMMnS4OiYKakDJny0XVuchIP7ZMKiP07Q3FIuSS4omzR77kmc75/6Q9dP
|
||||
v4wa90UCOn1j6r7WhMmX3eT3Gsdj3WMe9bYD0AFuqa6MDyjIeXq08mVGraXiw73s
|
||||
Zale8OMckn/BU3O/3aFNLHLfET2H2hT6Wb3nwxjpLIfXmSVcVd8A58XH0g==
|
||||
-----END CERTIFICATE-----
|
BIN
monibuca_windows_amd64.syso
Normal file
@@ -1,307 +0,0 @@
|
||||
package avformat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/langhuihui/monibuca/monica/util"
|
||||
)
|
||||
|
||||
const (
|
||||
ADTS_HEADER_SIZE = 7
|
||||
)
|
||||
|
||||
// ISO/IEC 14496-15 11(16)/page
|
||||
//
|
||||
// Advanced Video Coding
|
||||
//
|
||||
|
||||
type AVCDecoderConfigurationRecord struct {
|
||||
ConfigurationVersion byte // 8 bits Version
|
||||
AVCProfileIndication byte // 8 bits
|
||||
ProfileCompatibility byte // 8 bits
|
||||
AVCLevelIndication byte // 8 bits
|
||||
Reserved1 byte // 6 bits
|
||||
LengthSizeMinusOne byte // 2 bits 非常重要,每个NALU包前面都(lengthSizeMinusOne & 3)+1个字节的NAL包长度描述
|
||||
Reserved2 byte // 3 bits
|
||||
NumOfSequenceParameterSets byte // 5 bits SPS 的个数,计算方法是 numOfSequenceParameterSets & 0x1F
|
||||
NumOfPictureParameterSets byte // 8 bits PPS 的个数
|
||||
|
||||
SequenceParameterSetLength uint16 // 16 byte SPS Length
|
||||
SequenceParameterSetNALUnit []byte // n byte SPS
|
||||
PictureParameterSetLength uint16 // 16 byte PPS Length
|
||||
PictureParameterSetNALUnit []byte // n byte PPS
|
||||
}
|
||||
|
||||
//func (p *AVCDecoderConfigurationRecord) Marshal(b []byte) (n int) {
|
||||
// b[0] = 1
|
||||
// b[1] = p.AVCProfileIndication
|
||||
// b[2] = p.ProfileCompatibility
|
||||
// b[3] = p.AVCLevelIndication
|
||||
// b[4] = p.LengthSizeMinusOne | 0xfc
|
||||
// b[5] = uint8(len(p.SPS)) | 0xe0
|
||||
// n += 6
|
||||
//
|
||||
// for _, sps := range p.SPS {
|
||||
// pio.PutU16BE(b[n:], uint16(len(sps)))
|
||||
// n += 2
|
||||
// copy(b[n:], sps)
|
||||
// n += len(sps)
|
||||
// }
|
||||
//
|
||||
// b[n] = uint8(len(p.PPS))
|
||||
// n++
|
||||
//
|
||||
// for _, pps := range p.PPS {
|
||||
// pio.PutU16BE(b[n:], uint16(len(pps)))
|
||||
// n += 2
|
||||
// copy(b[n:], pps)
|
||||
// n += len(pps)
|
||||
// }
|
||||
//
|
||||
// return
|
||||
//}
|
||||
var ErrDecconfInvalid = errors.New("decode error")
|
||||
|
||||
func (p *AVCDecoderConfigurationRecord) Unmarshal(b []byte) (n int, err error) {
|
||||
if len(b) < 7 {
|
||||
err = errors.New("not enough len")
|
||||
return
|
||||
}
|
||||
|
||||
p.AVCProfileIndication = b[1]
|
||||
p.ProfileCompatibility = b[2]
|
||||
p.AVCLevelIndication = b[3]
|
||||
p.LengthSizeMinusOne = b[4] & 0x03
|
||||
spscount := int(b[5] & 0x1f)
|
||||
n += 6
|
||||
var sps, pps [][]byte
|
||||
for i := 0; i < spscount; i++ {
|
||||
if len(b) < n+2 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
spslen := int(util.BigEndian.Uint16(b[n:]))
|
||||
n += 2
|
||||
|
||||
if len(b) < n+spslen {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
sps = append(sps, b[n:n+spslen])
|
||||
n += spslen
|
||||
}
|
||||
p.SequenceParameterSetLength = uint16(len(sps[0]))
|
||||
p.SequenceParameterSetNALUnit = sps[0]
|
||||
if len(b) < n+1 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
ppscount := int(b[n])
|
||||
n++
|
||||
|
||||
for i := 0; i < ppscount; i++ {
|
||||
if len(b) < n+2 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
ppslen := int(util.BigEndian.Uint16(b[n:]))
|
||||
n += 2
|
||||
|
||||
if len(b) < n+ppslen {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
pps = append(pps, b[n:n+ppslen])
|
||||
n += ppslen
|
||||
}
|
||||
p.PictureParameterSetLength = uint16(len(pps[0]))
|
||||
p.PictureParameterSetNALUnit = pps[0]
|
||||
return
|
||||
}
|
||||
|
||||
// ISO/IEC 14496-3 38(52)/page
|
||||
//
|
||||
// Audio
|
||||
//
|
||||
|
||||
type AudioSpecificConfig struct {
|
||||
AudioObjectType byte // 5 bits
|
||||
SamplingFrequencyIndex byte // 4 bits
|
||||
ChannelConfiguration byte // 4 bits
|
||||
GASpecificConfig
|
||||
}
|
||||
|
||||
type GASpecificConfig struct {
|
||||
FrameLengthFlag byte // 1 bit
|
||||
DependsOnCoreCoder byte // 1 bit
|
||||
ExtensionFlag byte // 1 bit
|
||||
}
|
||||
|
||||
//
|
||||
// AudioObjectTypes -> ISO/IEC 14496-3 43(57)/page
|
||||
//
|
||||
// 1 AAC MAIN ISO/IEC 14496-3 subpart 4
|
||||
// 2 AAC LC ISO/IEC 14496-3 subpart 4
|
||||
// 3 AAC SSR ISO/IEC 14496-3 subpart 4
|
||||
// 4 AAC LTP ISO/IEC 14496-3 subpart 4
|
||||
//
|
||||
//
|
||||
|
||||
// ISO/IEC 13838-7 20(25)/page
|
||||
//
|
||||
// Advanced Audio Coding
|
||||
//
|
||||
// AudioDataTransportStream
|
||||
type ADTS struct {
|
||||
ADTSFixedHeader
|
||||
ADTSVariableHeader
|
||||
}
|
||||
|
||||
// 28 bits
|
||||
type ADTSFixedHeader struct {
|
||||
SyncWord uint16 // 12 bits The bit string ‘1111 1111 1111’. See ISO/IEC 11172-3,subclause 2.4.2.3 (Table 8)
|
||||
ID byte // 1 bit MPEG identifier, set to ‘1’. See ISO/IEC 11172-3,subclause 2.4.2.3 (Table 8)
|
||||
Layer byte // 2 bits Indicates which layer is used. Set to ‘00’. See ISO/IEC 11172-3,subclause 2.4.2.3 (Table 8)
|
||||
ProtectionAbsent byte // 1 bit Indicates whether error_check() data is present or not. Same assyntax element ‘protection_bit’ in ISO/IEC 11172-3,subclause 2.4.1 and 2.4.2 (Table 8)
|
||||
Profile byte // 2 bits profile used. See clause 2 (Table 8)
|
||||
SamplingFrequencyIndex byte // 4 bits indicates the sampling frequency used according to the followingtable (Table 8)
|
||||
PrivateBit byte // 1 bit see ISO/IEC 11172-3, subclause 2.4.2.3 (Table 8)
|
||||
ChannelConfiguration byte // 3 bits indicates the channel configuration used. Ifchannel_configuration is greater than 0, the channelconfiguration is given in Table 42, see subclause 8.5.3.1. Ifchannel_configuration equals 0, the channel configuration is notspecified in the header and must be given by aprogram_config_element() following as first syntactic element inthe first raw_data_block() after the header (seesubclause 8.5.3.2), or by the implicit configuration (seesubclause 8.5.3.3) or must be known in the application (Table 8)
|
||||
OriginalCopy byte // 1 bit see ISO/IEC 11172-3, definition of data element copyright
|
||||
Home byte // 1 bit see ISO/IEC 11172-3, definition of data element original/copy
|
||||
}
|
||||
|
||||
// SyncWord, 同步头 总是0xFFF, all bits must be 1,代表着一个ADTS帧的开始
|
||||
// ID, MPEG Version: 0 for MPEG-4, 1 for MPEG-2
|
||||
// Layer, always: '00'
|
||||
// ProtectionAbsent, 表示是否误码校验
|
||||
// Profile, 表示使用哪个级别的AAC,有些芯片只支持AAC LC 。在MPEG-2 AAC中定义了3种.
|
||||
// SamplingFrequencyIndex, 表示使用的采样率下标,通过这个下标在 Sampling Frequencies[ ]数组中查找得知采样率的值
|
||||
// PrivateBit,
|
||||
// ChannelConfiguration, 表示声道数
|
||||
// OriginalCopy,
|
||||
// Home,
|
||||
|
||||
// Profile:
|
||||
//
|
||||
// 0: Main profile
|
||||
// 1: Low Complexity profile(LC)
|
||||
// 2: Scalable Sampling Rate profile(SSR)
|
||||
// 3: Reserved
|
||||
//
|
||||
var SamplingFrequencies = [...]int{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350}
|
||||
|
||||
// Sampling Frequencies[]:
|
||||
//
|
||||
// 0: 96000 Hz
|
||||
// 1: 88200 Hz
|
||||
// 2: 64000 Hz
|
||||
// 3: 48000 Hz
|
||||
// 4: 44100 Hz
|
||||
// 5: 32000 Hz
|
||||
// 6: 24000 Hz
|
||||
// 7: 22050 Hz
|
||||
// 8: 16000 Hz
|
||||
// 9: 12000 Hz
|
||||
// 10: 11025 Hz
|
||||
// 11: 8000 Hz
|
||||
// 12: 7350 Hz
|
||||
// 13: Reserved
|
||||
// 14: Reserved
|
||||
// 15: frequency is written explictly
|
||||
//
|
||||
|
||||
// ChannelConfiguration:
|
||||
//
|
||||
// 0: Defined in AOT Specifc Config
|
||||
// 1: 1 channel: front-center
|
||||
// 2: 2 channels: front-left, front-right
|
||||
// 3: 3 channels: front-center, front-left, front-right
|
||||
// 4: 4 channels: front-center, front-left, front-right, back-center
|
||||
// 5: 5 channels: front-center, front-left, front-right, back-left, back-right
|
||||
// 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
|
||||
// 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
|
||||
// 8-15: Reserved
|
||||
//
|
||||
|
||||
// 28 bits
|
||||
type ADTSVariableHeader struct {
|
||||
CopyrightIdentificationBit byte // 1 bit One bit of the 72-bit copyright identification field (seecopyright_id above). The bits of this field are transmitted frame by frame; the first bit is indicated by the copyright_identification_start bit set to ‘1’. The field consists of an 8-bit copyright_identifier, followed by a 64-bit copyright_number.The copyright identifier is given by a Registration Authority as designated by SC29. The copyright_number is a value which identifies uniquely the copyrighted material. See ISO/IEC 13818-3, subclause 2.5.2.13 (Table 9)
|
||||
CopyrightIdentificationStart byte // 1 bit One bit to indicate that the copyright_identification_bit in this audio frame is the first bit of the 72-bit copyright identification. If no copyright identification is transmitted, this bit should be kept '0'.'0' no start of copyright identification in this audio frame '1' start of copyright identification in this audio frame See ISO/IEC 13818-3, subclause 2.5.2.13 (Table 9)
|
||||
AACFrameLength uint16 // 13 bits Length of the frame including headers and error_check in bytes(Table 9)
|
||||
ADTSBufferFullness uint16 // 11 bits state of the bit reservoir in the course of encoding the ADTS frame, up to and including the first raw_data_block() and the optionally following adts_raw_data_block_error_check(). It is transmitted as the number of available bits in the bit reservoir divided by NCC divided by 32 and truncated to an integer value (Table 9). A value of hexadecimal 7FF signals that the bitstream is a variable rate bitstream. In this case, buffer fullness is not applicable
|
||||
NumberOfRawDataBlockInFrame byte // 2 bits Number of raw_data_block()’s that are multiplexed in the adts_frame() is equal to number_of_raw_data_blocks_in_frame + 1. The minimum value is 0 indicating 1 raw_data_block()(Table 9)
|
||||
}
|
||||
|
||||
// CopyrightIdentificationBit,
|
||||
// CopyrightIdentificationStart,
|
||||
// AACFrameLength, 一个ADTS帧的长度包括ADTS头和raw data block.
|
||||
// ADTSBufferFullness, 0x7FF 说明是码率可变的码流.
|
||||
// NumberOfRawDataBlockInFrame, 表示ADTS帧中有number_of_raw_data_blocks_in_frame + 1个AAC原始帧
|
||||
|
||||
// 所以说number_of_raw_data_blocks_in_frame == 0 表示说ADTS帧中有一个AAC数据块并不是说没有。(一个AAC原始帧包含一段时间内1024个采样及相关数据)
|
||||
func ADTSToAudioSpecificConfig(data []byte) []byte {
|
||||
profile := ((data[2] & 0xc0) >> 6) + 1
|
||||
sampleRate := (data[2] & 0x3c) >> 2
|
||||
channel := ((data[2] & 0x1) << 2) | ((data[3] & 0xc0) >> 6)
|
||||
config1 := (profile << 3) | ((sampleRate & 0xe) >> 1)
|
||||
config2 := ((sampleRate & 0x1) << 7) | (channel << 3)
|
||||
return []byte{0xAF, 0x00, config1, config2}
|
||||
}
|
||||
func AudioSpecificConfigToADTS(asc AudioSpecificConfig, rawDataLength int) (adts ADTS, adtsByte []byte, err error) {
|
||||
if asc.ChannelConfiguration > 8 || asc.FrameLengthFlag > 13 {
|
||||
err = errors.New("Reserved field.")
|
||||
return
|
||||
}
|
||||
|
||||
// ADTSFixedHeader
|
||||
adts.SyncWord = 0xfff
|
||||
adts.ID = 0
|
||||
adts.Layer = 0
|
||||
adts.ProtectionAbsent = 1
|
||||
|
||||
// SyncWord(12) + ID(1) + Layer(2) + ProtectionAbsent(1)
|
||||
adtsByte = append(adtsByte, 0xff)
|
||||
adtsByte = append(adtsByte, 0xf1)
|
||||
|
||||
if asc.AudioObjectType >= 3 || asc.AudioObjectType == 0 {
|
||||
adts.Profile = 1
|
||||
} else {
|
||||
adts.Profile = asc.AudioObjectType - 1
|
||||
}
|
||||
|
||||
adts.SamplingFrequencyIndex = asc.SamplingFrequencyIndex
|
||||
adts.PrivateBit = 0
|
||||
adts.ChannelConfiguration = asc.ChannelConfiguration
|
||||
adts.OriginalCopy = 0
|
||||
adts.Home = 0
|
||||
|
||||
// Profile(2) + SamplingFrequencyIndex(4) + PrivateBit(1) + ChannelConfiguration(3)(取高1位)
|
||||
byte3 := uint8(adts.Profile<<6) + uint8(adts.SamplingFrequencyIndex<<2) + uint8(adts.PrivateBit<<1) + uint8((adts.ChannelConfiguration&0x7)>>2)
|
||||
adtsByte = append(adtsByte, byte3)
|
||||
|
||||
// ADTSVariableHeader
|
||||
adts.CopyrightIdentificationBit = 0
|
||||
adts.CopyrightIdentificationStart = 0
|
||||
adts.AACFrameLength = 7 + uint16(rawDataLength)
|
||||
adts.ADTSBufferFullness = 0x7ff
|
||||
adts.NumberOfRawDataBlockInFrame = 0
|
||||
|
||||
// ChannelConfiguration(3)(取低2位) + OriginalCopy(1) + Home(1) + CopyrightIdentificationBit(1) + CopyrightIdentificationStart(1) + AACFrameLength(13)(取高2位)
|
||||
byte4 := uint8((adts.ChannelConfiguration&0x3)<<6) + uint8((adts.AACFrameLength&0x1fff)>>11)
|
||||
adtsByte = append(adtsByte, byte4)
|
||||
|
||||
// AACFrameLength(13)
|
||||
// xx xxxxxxxx xxx
|
||||
// 取中间的部分
|
||||
byte5 := uint8(((adts.AACFrameLength & 0x1fff) >> 3) & 0x0ff)
|
||||
adtsByte = append(adtsByte, byte5)
|
||||
|
||||
// AACFrameLength(13)(取低3位) + ADTSBufferFullness(11)(取高5位)
|
||||
byte6 := uint8((adts.AACFrameLength&0x0007)<<5) + 0x1f
|
||||
adtsByte = append(adtsByte, byte6)
|
||||
|
||||
// ADTSBufferFullness(11)(取低6位) + NumberOfRawDataBlockInFrame(2)
|
||||
adtsByte = append(adtsByte, 0xfc)
|
||||
|
||||
return
|
||||
}
|