mirror of
https://github.com/Monibuca/plugin-jessica.git
synced 2025-10-19 14:24:34 +08:00
适配3.0
This commit is contained in:
15
go.mod
15
go.mod
@@ -1,13 +1,12 @@
|
||||
module github.com/Monibuca/plugin-jessica
|
||||
module github.com/Monibuca/plugin-jessica/v3
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Monibuca/engine/v2 v2.0.0
|
||||
github.com/Monibuca/utils v1.0.0 // 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/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
github.com/Monibuca/engine/v3 v3.0.0-alpha4
|
||||
github.com/Monibuca/utils/v3 v3.0.0-alpha4
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.0.4
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
)
|
||||
|
64
go.sum
64
go.sum
@@ -1,67 +1,39 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Monibuca/engine v1.2.1 h1:TJmC6eZA1lR1MScWgempZLiEZD4T6aY/nn/rlQ9UdK8=
|
||||
github.com/Monibuca/engine v1.2.1/go.mod h1:WbDkXENLjcPjyjCR1Mix1GA+uAlwORkv/+8aMVrDX2g=
|
||||
github.com/Monibuca/engine v1.2.2 h1:hNjsrZpOmui8lYhgCJ5ltJU8g/k0Rrdysx2tHNGGnbI=
|
||||
github.com/Monibuca/engine v1.2.2/go.mod h1:WbDkXENLjcPjyjCR1Mix1GA+uAlwORkv/+8aMVrDX2g=
|
||||
github.com/Monibuca/engine/v2 v2.0.0-alpha2 h1:45yazqnnxEEcfHcOJGuIr1xtnBzQT6cPvhlymeZrDmA=
|
||||
github.com/Monibuca/engine/v2 v2.0.0-alpha2/go.mod h1:34EYjjV15G6myuHOKaJkO7y5tJ1Arq/NfC9Weacr2mc=
|
||||
github.com/Monibuca/engine/v2 v2.0.0 h1:8FjaScrtN8QdbcxO9zZYABMC0Re3I1O1T4p94zAXYb0=
|
||||
github.com/Monibuca/engine/v2 v2.0.0/go.mod h1:34EYjjV15G6myuHOKaJkO7y5tJ1Arq/NfC9Weacr2mc=
|
||||
github.com/Monibuca/utils v1.0.0 h1:hbRvlDAzClTXtIQIeY1PMqkL36TWyRCLNULjY/sOT3w=
|
||||
github.com/Monibuca/utils v1.0.0/go.mod h1:Iw3OnscHv6RFoi9nHdVLdPKkI9UfFmU5TgSQkMf+Yi8=
|
||||
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/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae/go.mod h1:wruC5r2gHdr/JIUs5Rr1V45YtsAzKXZxAnn/5rPC97g=
|
||||
github.com/Monibuca/engine/v3 v3.0.0-alpha3 h1:NtFBMsu1nvEA09q64sW9xNzLdQ9RCKQXJlESM3GmGxU=
|
||||
github.com/Monibuca/engine/v3 v3.0.0-alpha3/go.mod h1:K5FB3wk+iS/nPc+NS4XwObYQV4gtF6klEwDxaVM0BsQ=
|
||||
github.com/Monibuca/engine/v3 v3.0.0-alpha4 h1:kAStDd1p9tlSQeNyAAmb7vrPL2UCz7LFTzw5LdbGxBI=
|
||||
github.com/Monibuca/engine/v3 v3.0.0-alpha4/go.mod h1:V0/kfen6K5O/RLXHPsZj4DF/LboDZ0OqfeCfn35bWMo=
|
||||
github.com/Monibuca/utils/v3 v3.0.0-alpha3 h1:n4Sq7mS1Iz8oBj2BcV4sXgKbZgix0fFLvjAfXYoiXl0=
|
||||
github.com/Monibuca/utils/v3 v3.0.0-alpha3/go.mod h1:3xYmhQbgAZBHLyIMteUCd1va+1z/xnd72B585mCaT3c=
|
||||
github.com/Monibuca/utils/v3 v3.0.0-alpha4 h1:pecYA89kWmtGOeY6R99d4T1epPJ1wc+jFrrJY13VD04=
|
||||
github.com/Monibuca/utils/v3 v3.0.0-alpha4/go.mod h1:3xYmhQbgAZBHLyIMteUCd1va+1z/xnd72B585mCaT3c=
|
||||
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/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.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
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.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/gobwas/ws v1.0.4 h1:5eXU1CZhpQdq5kXbKb+sECH5Ia5KiO6CYzIzdlVx6Bs=
|
||||
github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
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/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/quangngotan95/go-m3u8 v0.1.0/go.mod h1:smzfWHlYpBATVNu1GapKLYiCtEo5JxridIgvvudZ+Wc=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/shirou/gopsutil v2.19.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/gopsutil v2.20.1+incompatible h1:oIq9Cq4i84Hk8uQAUOG3eNdI/29hBawGrD5YRl6JRDY=
|
||||
github.com/shirou/gopsutil v2.20.1+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/yakovlevdmv/Golang-iso8601-duration v0.0.0-20180403125811-e5db0413b903/go.mod h1:9o96byDMk+osDZqiIS2a7E7y0cWmg4rRTjQRWVHpFWE=
|
||||
github.com/yakovlevdmv/WS-Discovery v0.0.0-20180512141937-16170c6c3677/go.mod h1:/VKdrRRbAVE0pvkoPTUlfXw1zxqEpflVsgF25aR5gbk=
|
||||
github.com/yakovlevdmv/goonvif v0.0.0-20180517145634-8181eb3ef2fb/go.mod h1:Os0AToR0I28wSLpS4rQtZdMEcfGKJcSrTaJughAopv4=
|
||||
github.com/yakovlevdmv/gosoap v0.0.0-20180512142237-299a954b1c6d/go.mod h1:NhCpqPG+N2wrLSqEHVG3FKl4uAPvtFHUx7IlCVpW1PU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20200226051749-491c5fce7268/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
27
main.go
27
main.go
@@ -1,15 +1,11 @@
|
||||
package jessica
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
. "github.com/Monibuca/engine/v2"
|
||||
"github.com/Monibuca/utils"
|
||||
. "github.com/Monibuca/engine/v3"
|
||||
"github.com/Monibuca/utils/v3"
|
||||
. "github.com/logrusorgru/aurora"
|
||||
)
|
||||
|
||||
@@ -25,7 +21,6 @@ var publicPath string
|
||||
func init() {
|
||||
plugin := &PluginConfig{
|
||||
Name: "Jessica",
|
||||
Type: PLUGIN_SUBSCRIBER,
|
||||
Config: &config,
|
||||
Run: run,
|
||||
}
|
||||
@@ -33,25 +28,11 @@ func init() {
|
||||
publicPath = filepath.Join(plugin.Dir, "ui", "public")
|
||||
}
|
||||
func run() {
|
||||
http.HandleFunc("/jessibuca/", jessibuca)
|
||||
if config.ListenAddr != "" || config.ListenAddrTLS != "" {
|
||||
Print(Green("Jessica start at"), BrightBlue(config.ListenAddr), BrightBlue(config.ListenAddrTLS))
|
||||
utils.Print(Green("Jessica start at"), BrightBlue(config.ListenAddr), BrightBlue(config.ListenAddrTLS))
|
||||
utils.ListenAddrs(config.ListenAddr, config.ListenAddrTLS, config.CertFile, config.KeyFile, http.HandlerFunc(WsHandler))
|
||||
} else {
|
||||
Print(Green("Jessica start reuse gateway port"))
|
||||
utils.Print(Green("Jessica start reuse gateway port"))
|
||||
http.HandleFunc("/jessica/", WsHandler)
|
||||
}
|
||||
}
|
||||
func jessibuca(w http.ResponseWriter, r *http.Request) {
|
||||
filePath := strings.TrimPrefix(r.URL.Path, "/jessibuca")
|
||||
if mime := mime.TypeByExtension(path.Ext(filePath)); mime != "" {
|
||||
w.Header().Set("Content-Type", mime)
|
||||
}
|
||||
if f, err := ioutil.ReadFile(filepath.Join(publicPath, filePath)); err == nil {
|
||||
if _, err = w.Write(f); err != nil {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(404)
|
||||
}
|
||||
}
|
||||
|
119
subscriber.go
119
subscriber.go
@@ -5,9 +5,9 @@ import (
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
. "github.com/Monibuca/engine/v2"
|
||||
"github.com/Monibuca/engine/v2/avformat"
|
||||
"github.com/Monibuca/engine/v2/pool"
|
||||
. "github.com/Monibuca/engine/v3"
|
||||
"github.com/Monibuca/utils/v3"
|
||||
"github.com/Monibuca/utils/v3/codec"
|
||||
"github.com/gobwas/ws"
|
||||
)
|
||||
|
||||
@@ -16,10 +16,10 @@ var streamPathReg = regexp.MustCompile("/(jessica/)?((.+)(\\.flv)|(.+))")
|
||||
func WsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
sign := r.URL.Query().Get("sign")
|
||||
isFlv := false
|
||||
if err := AuthHooks.Trigger(sign); err != nil {
|
||||
w.WriteHeader(403)
|
||||
return
|
||||
}
|
||||
// if err := AuthHooks.Trigger(sign); err != nil {
|
||||
// w.WriteHeader(403)
|
||||
// return
|
||||
// }
|
||||
parts := streamPathReg.FindStringSubmatch(r.RequestURI)
|
||||
streamPath := parts[3]
|
||||
if streamPath == "" {
|
||||
@@ -31,8 +31,10 @@ func WsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
baseStream := Subscriber{Sign: sign}
|
||||
baseStream.ID = conn.RemoteAddr().String()
|
||||
baseStream := Subscriber{Sign: sign, ID: r.RemoteAddr, Type: "Jessica"}
|
||||
if isFlv {
|
||||
baseStream.Type = "JessicaFlv"
|
||||
}
|
||||
defer conn.Close()
|
||||
go func() {
|
||||
b := []byte{0}
|
||||
@@ -41,55 +43,68 @@ func WsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
baseStream.Close()
|
||||
}()
|
||||
if isFlv {
|
||||
baseStream.Type = "JessicaFlv"
|
||||
baseStream.OnData = func(packet *avformat.SendPacket) error {
|
||||
err := ws.WriteHeader(conn, ws.Header{
|
||||
if baseStream.Subscribe(streamPath) == nil {
|
||||
at := baseStream.GetAudioTrack("aac")
|
||||
vt := baseStream.OriginVideoTrack
|
||||
var writeAV func(byte, uint32, []byte)
|
||||
if isFlv {
|
||||
if err := ws.WriteHeader(conn, ws.Header{
|
||||
Fin: true,
|
||||
OpCode: ws.OpBinary,
|
||||
Length: int64(len(packet.Payload) + 15),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
Length: int64(13),
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = conn.Write(codec.FLVHeader); err != nil {
|
||||
return
|
||||
}
|
||||
writeAV = func(t byte, ts uint32, payload []byte) {
|
||||
ws.WriteHeader(conn, ws.Header{
|
||||
Fin: true,
|
||||
OpCode: ws.OpBinary,
|
||||
Length: int64(len(payload) + 15),
|
||||
})
|
||||
codec.WriteFLVTag(conn, t, ts, payload)
|
||||
}
|
||||
} else {
|
||||
writeAV = func(t byte, ts uint32, payload []byte) {
|
||||
ws.WriteHeader(conn, ws.Header{
|
||||
Fin: true,
|
||||
OpCode: ws.OpBinary,
|
||||
Length: int64(len(payload) + 5),
|
||||
})
|
||||
head := utils.GetSlice(5)
|
||||
defer utils.RecycleSlice(head)
|
||||
head[0] = t - 7
|
||||
binary.BigEndian.PutUint32(head[1:5], ts)
|
||||
if _, err = conn.Write(head); err != nil {
|
||||
return
|
||||
}
|
||||
conn.Write(payload)
|
||||
}
|
||||
return avformat.WriteFLVTag(conn, packet)
|
||||
}
|
||||
if err := ws.WriteHeader(conn, ws.Header{
|
||||
Fin: true,
|
||||
OpCode: ws.OpBinary,
|
||||
Length: int64(13),
|
||||
}); err != nil {
|
||||
return
|
||||
if vt != nil {
|
||||
writeAV(codec.FLV_TAG_TYPE_VIDEO, 0, vt.RtmpTag)
|
||||
baseStream.OnVideo = func(pack VideoPack) {
|
||||
payload := codec.Nalu2RTMPTag(pack.Payload)
|
||||
defer utils.RecycleSlice(payload)
|
||||
writeAV(codec.FLV_TAG_TYPE_VIDEO, pack.Timestamp, payload)
|
||||
}
|
||||
}
|
||||
if _, err = conn.Write(avformat.FLVHeader); err != nil {
|
||||
return
|
||||
if at != nil {
|
||||
writeAV(codec.FLV_TAG_TYPE_AUDIO, 0, at.RtmpTag)
|
||||
baseStream.OnAudio = func(pack AudioPack) {
|
||||
var aac byte
|
||||
if at.SoundFormat == 10 {
|
||||
aac = at.RtmpTag[0]
|
||||
}
|
||||
payload := codec.Audio2RTMPTag(aac, pack.Payload)
|
||||
defer utils.RecycleSlice(payload)
|
||||
writeAV(codec.FLV_TAG_TYPE_AUDIO, pack.Timestamp, payload)
|
||||
}
|
||||
}
|
||||
baseStream.Play(r.Context(), at, vt)
|
||||
} else {
|
||||
baseStream.Type = "Jessica"
|
||||
baseStream.OnData = func(packet *avformat.SendPacket) error {
|
||||
err := ws.WriteHeader(conn, ws.Header{
|
||||
Fin: true,
|
||||
OpCode: ws.OpBinary,
|
||||
Length: int64(len(packet.Payload) + 5),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
head := pool.GetSlice(5)
|
||||
head[0] = packet.Type - 7
|
||||
binary.BigEndian.PutUint32(head[1:5], packet.Timestamp)
|
||||
if _, err = conn.Write(head); err != nil {
|
||||
return err
|
||||
}
|
||||
pool.RecycleSlice(head)
|
||||
//if p.Header[0] == 2 {
|
||||
// fmt.Printf("%6d %X\n", (uint32(p.Packet.Payload[5])<<24)|(uint32(p.Packet.Payload[6])<<16)|(uint32(p.Packet.Payload[7])<<8)|uint32(p.Packet.Payload[8]), p.Packet.Payload[9])
|
||||
//}
|
||||
if _, err = conn.Write(packet.Payload); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
w.WriteHeader(404)
|
||||
}
|
||||
baseStream.Subscribe(streamPath)
|
||||
}
|
||||
|
19
ui/dist/demo.html
vendored
19
ui/dist/demo.html
vendored
@@ -1,19 +0,0 @@
|
||||
<meta charset="utf-8">
|
||||
<title>plugin-jessica demo</title>
|
||||
<script src="https://unpkg.com/vue"></script>
|
||||
<script src="./plugin-jessica.umd.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./plugin-jessica.css">
|
||||
|
||||
|
||||
<div id="app">
|
||||
<demo></demo>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
components: {
|
||||
demo: plugin-jessica
|
||||
}
|
||||
}).$mount('#app')
|
||||
</script>
|
11777
ui/dist/plugin-jessica.common.js
vendored
11777
ui/dist/plugin-jessica.common.js
vendored
File diff suppressed because it is too large
Load Diff
1
ui/dist/plugin-jessica.common.js.map
vendored
1
ui/dist/plugin-jessica.common.js.map
vendored
File diff suppressed because one or more lines are too long
1
ui/dist/plugin-jessica.css
vendored
1
ui/dist/plugin-jessica.css
vendored
@@ -1 +0,0 @@
|
||||
td[data-v-5c6a4048]{padding-left:5px;padding-right:5px}.empty[data-v-5c6a4048]{color:#eb5e46;width:100%;min-height:500px;display:flex;justify-content:center;align-items:center}.demo-spin-icon-load[data-v-5c6a4048]{-webkit-animation:ani-demo-spin 1s linear infinite;animation:ani-demo-spin 1s linear infinite}
|
11787
ui/dist/plugin-jessica.umd.js
vendored
11787
ui/dist/plugin-jessica.umd.js
vendored
File diff suppressed because it is too large
Load Diff
1
ui/dist/plugin-jessica.umd.js.map
vendored
1
ui/dist/plugin-jessica.umd.js.map
vendored
File diff suppressed because one or more lines are too long
10
ui/dist/plugin-jessica.umd.min.js
vendored
10
ui/dist/plugin-jessica.umd.min.js
vendored
File diff suppressed because one or more lines are too long
1
ui/dist/plugin-jessica.umd.min.js.map
vendored
1
ui/dist/plugin-jessica.umd.min.js.map
vendored
File diff suppressed because one or more lines are too long
9625
ui/package-lock.json
generated
9625
ui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "dashboard of jessica plugin for monibuca",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "vue-cli-service build --target lib --name plugin-jessica"
|
||||
},
|
||||
"author": "dexter",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@vue/cli-service": "^4.2.3",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"flv.js": "^1.5.0",
|
||||
"view-design": "^4.1.3"
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,531 +0,0 @@
|
||||
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
function Jessibuca(opt) {
|
||||
this.canvasElement = opt.canvas;
|
||||
this.contextOptions = opt.contextOptions;
|
||||
this.videoBuffer = opt.videoBuffer || 0
|
||||
if (!opt.forceNoGL) this.initContextGL();
|
||||
this.audioContext = new window.AudioContext();
|
||||
if (opt.mute) {
|
||||
this.audioEnabled(true)
|
||||
this.audioEnabled(false)
|
||||
}
|
||||
if (this.contextGL) {
|
||||
this.initProgram();
|
||||
this.initBuffers();
|
||||
this.initTextures();
|
||||
};
|
||||
this.decoderWorker = new Worker(opt.decoder || 'ff.js')
|
||||
var _this = this
|
||||
this.decoderWorker.onmessage = function (event) {
|
||||
var msg = event.data
|
||||
switch (msg.cmd) {
|
||||
case "init":
|
||||
console.log("decoder worker init")
|
||||
this.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)
|
||||
// }
|
||||
if (_this.contextGL) {
|
||||
_this.drawNextOuptutPictureGL(_this.width, _this.height, null, msg.output);
|
||||
// this.postMessage({ cmd: "setBuffer", buffer: msg.output }, [msg.output[0].buffer, msg.output[1].buffer, msg.output[2].buffer])
|
||||
} else {
|
||||
_this.drawNextOuptutPictureRGBA(_this.width, _this.height, null, msg.buffer);
|
||||
}
|
||||
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
|
||||
default:
|
||||
_this[msg.cmd](msg)
|
||||
}
|
||||
}
|
||||
};
|
||||
Jessibuca.prototype.initAudioPlanar = function (msg) {
|
||||
var channels = msg.channels
|
||||
var samplerate = msg.samplerate
|
||||
console.log("initAudioPlanar:","channles:",channels,"samplerate:",samplerate)
|
||||
var context = this.audioContext;
|
||||
var isPlaying = false;
|
||||
var audioBuffers = [];
|
||||
if (!context) return false;
|
||||
var _this = this
|
||||
this.playAudio = function (buffer) {
|
||||
var frameCount = buffer[0][0].length
|
||||
var audioBuffer = context.createBuffer(channels, frameCount*buffer.length, samplerate);
|
||||
var copyToCtxBuffer = function (fromBuffer) {
|
||||
for (var channel = 0; channel < channels; channel++) {
|
||||
var nowBuffering = audioBuffer.getChannelData(channel);
|
||||
for( var j=0;j<buffer.length;j++){
|
||||
for (var i = 0; i < frameCount; i++) {
|
||||
nowBuffering[i+j*frameCount] = fromBuffer[j][channel][i]
|
||||
}
|
||||
//postMessage({ cmd: "setBufferA", buffer: fromBuffer[j] }, '*', fromBuffer[j].map(x => x.buffer))
|
||||
}
|
||||
}
|
||||
}
|
||||
var playNextBuffer = function () {
|
||||
isPlaying = false;
|
||||
//console.log("~", audioBuffers.length)
|
||||
if (audioBuffers.length) {
|
||||
playAudio(audioBuffers.shift());
|
||||
}
|
||||
//if (audioBuffers.length > 1) audioBuffers.shift();
|
||||
};
|
||||
var playAudio = function (fromBuffer) {
|
||||
if(!fromBuffer)return
|
||||
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;
|
||||
source.start();
|
||||
};
|
||||
_this.playAudio = playAudio
|
||||
_this.audioInterval = setInterval(playNextBuffer, audioBuffer.duration * 1000);
|
||||
playAudio(buffer)
|
||||
};
|
||||
}
|
||||
|
||||
function _unlock(context) {
|
||||
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.audioContext)
|
||||
this.audioEnabled = function (flag) {
|
||||
if (flag) {
|
||||
this.audioContext.resume();
|
||||
} else {
|
||||
this.audioContext.suspend();
|
||||
}
|
||||
}
|
||||
} 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 decodeAudio = function () {
|
||||
if (decodeQueue.length) {
|
||||
context.decodeAudioData(decodeQueue.shift(), tryPlay, decodeAudio);
|
||||
} else {
|
||||
isDecoding = false
|
||||
}
|
||||
}
|
||||
var tryPlay = function (buffer) {
|
||||
decodeAudio()
|
||||
if (isPlaying) {
|
||||
audioBuffers.push(buffer);
|
||||
} else {
|
||||
playBuffer(buffer)
|
||||
}
|
||||
}
|
||||
var playAudio = function (data) {
|
||||
decodeQueue.push(...data)
|
||||
if (!isDecoding) {
|
||||
isDecoding = true
|
||||
decodeAudio()
|
||||
}
|
||||
}
|
||||
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 _this = this
|
||||
var resampled = samplerate < 22050;
|
||||
if (resampled) {
|
||||
console.log("resampled!")
|
||||
}
|
||||
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;
|
||||
if (!_this.audioInterval) {
|
||||
_this.audioInterval = setInterval(playNextBuffer, audioBuffer.duration * 1000);
|
||||
}
|
||||
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)
|
||||
}
|
||||
delete this.playAudio
|
||||
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,77 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<stream-table>
|
||||
<template v-slot="scope">
|
||||
<m-button @click="preview(scope)">预览</m-button>
|
||||
<template>
|
||||
</stream-table>
|
||||
<Jessibuca ref="jessibuca" v-model="showPreview"
|
||||
:port="ListenAddr.split(':').pop()"
|
||||
:videoCodec="currentStream && CodecID(currentStream.VideoInfo.CodecID)"
|
||||
:audioCodec="currentStream && SoundFormat(currentStream.AudioInfo.SoundFormat)"></Jessibuca>
|
||||
<!-- <Subscribers :data="currentStream && currentStream.SubscriberInfo || []" v-model="showSubscribers" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Jessibuca from "./components/Jessibuca";
|
||||
// import Subscribers from "./components/Subscribers";
|
||||
let summaryES = null;
|
||||
export default {
|
||||
components: {
|
||||
Jessibuca,
|
||||
// Subscribers,
|
||||
},
|
||||
props: {
|
||||
ListenAddr: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPreview: false,
|
||||
currentStream: null,
|
||||
showSubscribers: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
host() {
|
||||
return location.hostname + ":" + this.ListenAddr.split(":").pop();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
preview({row}) {
|
||||
this.currentStream = row;
|
||||
this.onPlay(this.host + "/" + row.StreamPath);
|
||||
},
|
||||
onPlay(url) {
|
||||
this.showPreview = true;
|
||||
this.$nextTick(() => this.$refs.jessibuca.play(url));
|
||||
},
|
||||
onShowDetail(item) {
|
||||
this.showSubscribers = true;
|
||||
this.currentStream = item;
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
if (this.$refs.jessibuca) this.$refs.jessibuca.destroy();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
td {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.empty {
|
||||
color: #eb5e46;
|
||||
width: 100%;
|
||||
min-height: 500px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.demo-spin-icon-load {
|
||||
animation: ani-demo-spin 1s linear infinite;
|
||||
}
|
||||
</style>
|
@@ -1,149 +0,0 @@
|
||||
<template>
|
||||
<Modal
|
||||
v-bind="$attrs"
|
||||
draggable
|
||||
v-on="$listeners"
|
||||
:title="targetURL"
|
||||
@on-ok="onClosePreview"
|
||||
@on-cancel="onClosePreview"
|
||||
>
|
||||
<video ref="flvjs" v-show="protocol=='flv.js'" style="width:488px;height:275px"></video>
|
||||
<canvas id="canvas" width="488" height="275" style="background: black" v-show="protocol!='flv.js'" />
|
||||
<div slot="footer">
|
||||
<mu-radio value="ws-raw" v-model="protocol" label="ws-raw"></mu-radio>
|
||||
<mu-radio value="ws-flv" v-model="protocol" label="ws-flv"></mu-radio>
|
||||
<mu-radio value="http-flv" v-model="protocol" label="http-flv"></mu-radio>
|
||||
<mu-radio value="flv.js" v-model="protocol" label="flv.js"></mu-radio>
|
||||
<!-- <Button v-if="audioEnabled" @click="turnOff" icon="md-volume-up" />
|
||||
<Button v-else @click="turnOn" icon="md-volume-off"></Button>-->
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
<style scoped>
|
||||
</style>
|
||||
<script>
|
||||
let h5lc = null;
|
||||
let flvPlayer = null;
|
||||
import flvjs from "flv.js";
|
||||
export default {
|
||||
name: "Jessibuca",
|
||||
props: {
|
||||
audioCodec: String,
|
||||
videoCodec: String,
|
||||
port:String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
audioEnabled: true,
|
||||
protocol: "ws-raw",
|
||||
url: "",
|
||||
targetURL: "",
|
||||
decoderTable: {
|
||||
AAC_AVC: "ff",
|
||||
AAC_H265: "hevc_aac",
|
||||
MP3_AVC: "ff_mp3",
|
||||
MP3_H265: "hevc_mp3",
|
||||
AVC: "ff",
|
||||
H265: "hevc_aac"
|
||||
}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
audioEnabled(value) {
|
||||
h5lc.audioEnabled(value);
|
||||
},
|
||||
decoder(value) {
|
||||
if (h5lc) {
|
||||
h5lc.destroy();
|
||||
}
|
||||
h5lc = new window.Jessibuca({
|
||||
canvas: document.getElementById("canvas"),
|
||||
decoder: value,
|
||||
videoBuffer:0.2
|
||||
});
|
||||
},
|
||||
protocol(v) {
|
||||
switch (v) {
|
||||
case "ws-raw":
|
||||
this.targetURL = "ws://" + this.url;
|
||||
break;
|
||||
case "ws-flv":
|
||||
this.targetURL = "ws://" + this.url + ".flv";
|
||||
break;
|
||||
case "http-flv":
|
||||
this.targetURL = "http://" + this.url.replace(this.port,"2020") + ".flv";
|
||||
break;
|
||||
case "flv.js":
|
||||
h5lc.close();
|
||||
this.targetURL = "ws://" + this.url + ".flv"
|
||||
flvPlayer = flvjs.createPlayer(
|
||||
{
|
||||
type: "flv",
|
||||
isLive: true,
|
||||
url: this.targetURL
|
||||
},
|
||||
{
|
||||
fixAudioTimestampGap: false
|
||||
}
|
||||
);
|
||||
flvPlayer.attachMediaElement(this.$refs.flvjs);
|
||||
flvPlayer.load();
|
||||
flvPlayer.play();
|
||||
}
|
||||
if(v!="flv.js"){
|
||||
h5lc.play(this.targetURL);
|
||||
if(flvPlayer) {
|
||||
flvPlayer.destroy();
|
||||
flvPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
decoder() {
|
||||
let js = this.decoderTable[this.audioCodec + "_" + this.videoCodec];
|
||||
if (!js) {
|
||||
js = this.decoderTable[this.videoCodec] || "ff";
|
||||
}
|
||||
return "jessibuca/" + js + ".js";
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let s = document.createElement("script");
|
||||
s.src = "/jessibuca/renderer.js";
|
||||
s.onload = function() {
|
||||
s.onload = null;
|
||||
h5lc = new window.Jessibuca({
|
||||
canvas: document.getElementById("canvas"),
|
||||
decoder: "jessibuca/ff.js"
|
||||
});
|
||||
};
|
||||
this.$root.$el.append(s);
|
||||
},
|
||||
methods: {
|
||||
play(url) {
|
||||
this.url = url;
|
||||
if (this.protocol == "ws-raw") {
|
||||
this.targetURL = "ws://" + url;
|
||||
h5lc.play(this.targetURL);
|
||||
} else {
|
||||
this.protocol = "ws-raw";
|
||||
}
|
||||
},
|
||||
onClosePreview() {
|
||||
h5lc.close();
|
||||
flvPlayer.destroy();
|
||||
},
|
||||
destroy() {
|
||||
h5lc.destroy();
|
||||
},
|
||||
turnOn() {
|
||||
this.audioEnabled = true;
|
||||
},
|
||||
turnOff() {
|
||||
this.audioEnabled = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@@ -1,62 +0,0 @@
|
||||
<template>
|
||||
<Modal v-bind="$attrs" draggable v-on="$listeners" title="查看订阅者">
|
||||
<Table :columns="subtableColumns" :data="data"></Table>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
data: Array
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
subtableColumns: [
|
||||
{
|
||||
title: "类型",
|
||||
key: "Type"
|
||||
},
|
||||
{
|
||||
title: "Name",
|
||||
key: "ID"
|
||||
},
|
||||
{
|
||||
title: "订阅时间",
|
||||
render(h, { row }) {
|
||||
return h(StartTime, {
|
||||
props: {
|
||||
value: row.SubscribeTime
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "丢帧",
|
||||
render(h, { row }) {
|
||||
return h(
|
||||
"span",
|
||||
row.TotalPacket ? row.TotalDrop + "/" + row.TotalPacket : ""
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Buffer",
|
||||
render(h, { row }) {
|
||||
return h("Progress", {
|
||||
props: {
|
||||
percent: Math.floor((row.BufferLength * 99) / 1024),
|
||||
"text-inside": true,
|
||||
"stroke-width": 20,
|
||||
"stroke-color": ["#87d068", "#ff0000"]
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
Reference in New Issue
Block a user