Compare commits

...

3 Commits

Author SHA1 Message Date
langhuihui
655170cb24 修复中止拉流的操作 2020-05-20 09:55:39 +08:00
李宇翔
55bd2ce785 增加中止操作 2020-05-19 19:25:44 +08:00
李宇翔
2004a6afc1 删除错误引用StartTime 2020-05-11 11:25:45 +08:00
12 changed files with 437 additions and 355 deletions

174
client.go
View File

@@ -5,9 +5,8 @@ import (
"bytes" "bytes"
"crypto/md5" "crypto/md5"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
. "github.com/Monibuca/engine/v2"
"github.com/pixelbender/go-sdp/sdp"
"io" "io"
"net" "net"
"net/url" "net/url"
@@ -15,11 +14,13 @@ import (
"strconv" "strconv"
"strings" "strings"
"time" "time"
. "github.com/Monibuca/engine/v2"
) )
// PullStream 从外部拉流 // PullStream 从外部拉流
func (rtsp *RTSP) PullStream(streamPath string, rtspUrl string) (result bool) { func (rtsp *RTSP) PullStream(streamPath string, rtspUrl string) (err error) {
if result = rtsp.Publisher.Publish(streamPath); result { if result := rtsp.Publisher.Publish(streamPath); result {
rtsp.Stream.Type = "RTSP" rtsp.Stream.Type = "RTSP"
rtsp.RTSPInfo.StreamInfo = &rtsp.Stream.StreamInfo rtsp.RTSPInfo.StreamInfo = &rtsp.Stream.StreamInfo
rtsp.TransType = TRANS_TYPE_TCP rtsp.TransType = TRANS_TYPE_TCP
@@ -28,15 +29,16 @@ func (rtsp *RTSP) PullStream(streamPath string, rtspUrl string) (result bool) {
rtsp.aRTPChannel = 2 rtsp.aRTPChannel = 2
rtsp.aRTPControlChannel = 3 rtsp.aRTPControlChannel = 3
rtsp.URL = rtspUrl rtsp.URL = rtspUrl
if err := rtsp.requestStream();err != nil { if err = rtsp.requestStream(); err != nil {
Println(err)
rtsp.Close() rtsp.Close()
return false return
} }
go rtsp.startStream() go rtsp.startStream()
collection.Store(streamPath, rtsp) collection.Store(streamPath, rtsp)
// go rtsp.run() return
} }
return return errors.New("publish badname")
} }
func DigestAuth(authLine string, method string, URL string) (string, error) { func DigestAuth(authLine string, method string, URL string) (string, error) {
l, err := url.Parse(URL) l, err := url.Parse(URL)
@@ -184,104 +186,94 @@ func (client *RTSP) requestStream() (err error) {
return err return err
} }
} }
_sdp, err := sdp.ParseString(resp.Body)
if err != nil {
return err
}
client.Sdp = _sdp
client.SDPRaw = resp.Body client.SDPRaw = resp.Body
client.SDPMap = ParseSDP(client.SDPRaw) client.SDPMap = ParseSDP(client.SDPRaw)
session := "" session := ""
for _, media := range _sdp.Media { if videoInfo, ok := client.SDPMap["video"]; ok {
switch media.Type { client.VControl = videoInfo.Control
case "video": client.VCodec = videoInfo.Codec
client.VControl = media.Attributes.Get("control") client.SPS = videoInfo.SpropParameterSets[0]
client.VCodec = media.Format[0].Name client.PPS = videoInfo.SpropParameterSets[1]
client.SPS = client.SDPMap["video"].SpropParameterSets[0] var _url = ""
client.PPS = client.SDPMap["video"].SpropParameterSets[1] if strings.Index(strings.ToLower(client.VControl), "rtsp://") == 0 {
var _url = "" _url = client.VControl
if strings.Index(strings.ToLower(client.VControl), "rtsp://") == 0 { } else {
_url = client.VControl _url = strings.TrimRight(client.URL, "/") + "/" + strings.TrimLeft(client.VControl, "/")
} else {
_url = strings.TrimRight(client.URL, "/") + "/" + strings.TrimLeft(client.VControl, "/")
}
headers = make(map[string]string)
if client.TransType == TRANS_TYPE_TCP {
headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.vRTPChannel, client.vRTPControlChannel)
} else {
if client.UDPServer == nil {
client.UDPServer = &UDPServer{Session: client}
}
//RTP/AVP;unicast;client_port=64864-64865
err = client.UDPServer.SetupVideo()
if err != nil {
Printf("Setup video err.%v", err)
return err
}
headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.VPort, client.UDPServer.VControlPort)
client.Conn.timeout = 0 // UDP ignore timeout
}
if session != "" {
headers["Session"] = session
}
Printf("Parse DESCRIBE response, VIDEO VControl:%s, VCode:%s, url:%s,Session:%s,vRTPChannel:%d,vRTPControlChannel:%d", client.VControl, client.VCodec, _url, session, client.vRTPChannel, client.vRTPControlChannel)
resp, err = client.RequestWithPath("SETUP", _url, headers, true)
if err != nil {
return err
}
session, _ = resp.Header["Session"].(string)
case "audio":
client.AControl = media.Attributes.Get("control")
client.ACodec = media.Format[0].Name
client.AudioSpecificConfig = client.SDPMap["audio"].Config
var _url = ""
if strings.Index(strings.ToLower(client.AControl), "rtsp://") == 0 {
_url = client.AControl
} else {
_url = strings.TrimRight(client.URL, "/") + "/" + strings.TrimLeft(client.AControl, "/")
}
headers = make(map[string]string)
if client.TransType == TRANS_TYPE_TCP {
headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.aRTPChannel, client.aRTPControlChannel)
} else {
if client.UDPServer == nil {
client.UDPServer = &UDPServer{Session: client}
}
err = client.UDPServer.SetupAudio()
if err != nil {
Printf("Setup audio err.%v", err)
return err
}
headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.APort, client.UDPServer.AControlPort)
client.Conn.timeout = 0 // UDP ignore timeout
}
if session != "" {
headers["Session"] = session
}
Printf("Parse DESCRIBE response, AUDIO AControl:%s, ACodec:%s, url:%s,Session:%s, aRTPChannel:%d,aRTPControlChannel:%d", client.AControl, client.ACodec, _url, session, client.aRTPChannel, client.aRTPControlChannel)
resp, err = client.RequestWithPath("SETUP", _url, headers, true)
if err != nil {
return err
}
session, _ = resp.Header["Session"].(string)
} }
headers = make(map[string]string)
if client.TransType == TRANS_TYPE_TCP {
headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.vRTPChannel, client.vRTPControlChannel)
} else {
if client.UDPServer == nil {
client.UDPServer = &UDPServer{Session: client}
}
//RTP/AVP;unicast;client_port=64864-64865
err = client.UDPServer.SetupVideo()
if err != nil {
Printf("Setup video err.%v", err)
return err
}
headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.VPort, client.UDPServer.VControlPort)
client.Conn.timeout = 0 // UDP ignore timeout
}
if session != "" {
headers["Session"] = session
}
Printf("Parse DESCRIBE response, VIDEO VControl:%s, VCode:%s, url:%s,Session:%s,vRTPChannel:%d,vRTPControlChannel:%d", client.VControl, client.VCodec, _url, session, client.vRTPChannel, client.vRTPControlChannel)
if resp, err = client.RequestWithPath("SETUP", _url, headers, true); err != nil {
return err
}
session, _ = resp.Header["Session"].(string)
session = strings.Split(session, ";")[0]
}
if audioInfo, ok := client.SDPMap["audio"]; ok {
client.AControl = audioInfo.Control
client.ACodec = audioInfo.Codec
client.AudioSpecificConfig = audioInfo.Config
var _url = ""
if strings.Index(strings.ToLower(client.AControl), "rtsp://") == 0 {
_url = client.AControl
} else {
_url = strings.TrimRight(client.URL, "/") + "/" + strings.TrimLeft(client.AControl, "/")
}
headers = make(map[string]string)
if client.TransType == TRANS_TYPE_TCP {
headers["Transport"] = fmt.Sprintf("RTP/AVP/TCP;unicast;interleaved=%d-%d", client.aRTPChannel, client.aRTPControlChannel)
} else {
if client.UDPServer == nil {
client.UDPServer = &UDPServer{Session: client}
}
err = client.UDPServer.SetupAudio()
if err != nil {
Printf("Setup audio err.%v", err)
return err
}
headers["Transport"] = fmt.Sprintf("RTP/AVP/UDP;unicast;client_port=%d-%d", client.UDPServer.APort, client.UDPServer.AControlPort)
client.Conn.timeout = 0 // UDP ignore timeout
}
if session != "" {
headers["Session"] = session
}
Printf("Parse DESCRIBE response, AUDIO AControl:%s, ACodec:%s, url:%s,Session:%s, aRTPChannel:%d,aRTPControlChannel:%d", client.AControl, client.ACodec, _url, session, client.aRTPChannel, client.aRTPControlChannel)
if resp, err = client.RequestWithPath("SETUP", _url, headers, true); err != nil {
return err
}
session, _ = resp.Header["Session"].(string)
session = strings.Split(session, ";")[0]
} }
headers = make(map[string]string) headers = make(map[string]string)
if session != "" { if session != "" {
headers["Session"] = session headers["Session"] = session
} }
resp, err = client.Request("PLAY", headers) resp, err = client.Request("PLAY", headers)
if err != nil { return err
return err
}
return nil
} }
func (client *RTSP) startStream() { func (client *RTSP) startStream() {
//startTime := time.Now() //startTime := time.Now()
//loggerTime := time.Now().Add(-10 * time.Second) //loggerTime := time.Now().Add(-10 * time.Second)
defer client.Stop() defer client.Stop()
for { for client.Err() == nil {
//if client.OptionIntervalMillis > 0 { //if client.OptionIntervalMillis > 0 {
// if time.Since(startTime) > time.Duration(client.OptionIntervalMillis)*time.Millisecond { // if time.Since(startTime) > time.Duration(client.OptionIntervalMillis)*time.Millisecond {
// startTime = time.Now() // startTime = time.Now()
@@ -371,7 +363,7 @@ func (client *RTSP) startStream() {
builder := bytes.Buffer{} builder := bytes.Buffer{}
builder.WriteByte(b) builder.WriteByte(b)
contentLen := 0 contentLen := 0
for { for client.Err() == nil {
line, prefix, err := client.connRW.ReadLine() line, prefix, err := client.connRW.ReadLine()
if err != nil { if err != nil {
Printf("client.connRW.ReadLine err:%v", err) Printf("client.connRW.ReadLine err:%v", err)

4
go.mod
View File

@@ -3,8 +3,10 @@ module github.com/Monibuca/plugin-rtsp
go 1.13 go 1.13
require ( require (
github.com/EasyDarwin/EasyDarwin v8.1.0+incompatible // indirect
github.com/Monibuca/engine/v2 v2.0.0 github.com/Monibuca/engine/v2 v2.0.0
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
github.com/gobwas/pool v0.2.0 // indirect
github.com/gobwas/ws v1.0.3 // indirect
github.com/jinzhu/gorm v1.9.12 // indirect github.com/jinzhu/gorm v1.9.12 // indirect
github.com/pixelbender/go-sdp v1.0.0 github.com/pixelbender/go-sdp v1.0.0
github.com/reactivex/rxgo v1.0.0 // indirect github.com/reactivex/rxgo v1.0.0 // indirect

6
go.sum
View File

@@ -25,6 +25,12 @@ 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/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
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.3 h1:ZOigqf7iBxkA4jdQ3am7ATzdlOFp9YzA6NmuvEEZc9g=
github.com/gobwas/ws v1.0.3/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=

59
main.go
View File

@@ -14,18 +14,16 @@ import (
. "github.com/Monibuca/engine/v2" . "github.com/Monibuca/engine/v2"
. "github.com/Monibuca/engine/v2/avformat" . "github.com/Monibuca/engine/v2/avformat"
"github.com/Monibuca/engine/v2/util" "github.com/Monibuca/engine/v2/util"
"github.com/pixelbender/go-sdp/sdp"
"github.com/teris-io/shortid" "github.com/teris-io/shortid"
) )
var collection = sync.Map{} var collection = sync.Map{}
var config = struct { var config = struct {
ListenAddr string ListenAddr string
BufferLength int AutoPull bool
AutoPull bool RemoteAddr string
RemoteAddr string Timeout int
Timeout int }{":554", false, "rtsp://localhost/${streamPath}", 0}
}{":554", 2048, true, "rtsp://localhost/${streamPath}", 0}
func init() { func init() {
InstallPlugin(&PluginConfig{ InstallPlugin(&PluginConfig{
@@ -54,7 +52,6 @@ func runPlugin() {
collection.Range(func(key, value interface{}) bool { collection.Range(func(key, value interface{}) bool {
rtsp := value.(*RTSP) rtsp := value.(*RTSP)
pinfo := &rtsp.RTSPInfo pinfo := &rtsp.RTSPInfo
//pinfo.BufferRate = len(rtsp.OutGoing) * 100 / config.BufferLength
info = append(info, pinfo) info = append(info, pinfo)
return true return true
}) })
@@ -64,9 +61,7 @@ func runPlugin() {
http.HandleFunc("/rtsp/pull", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/rtsp/pull", func(w http.ResponseWriter, r *http.Request) {
targetURL := r.URL.Query().Get("target") targetURL := r.URL.Query().Get("target")
streamPath := r.URL.Query().Get("streamPath") streamPath := r.URL.Query().Get("streamPath")
var err error if err := new(RTSP).PullStream(streamPath, targetURL); err == nil {
if err == nil {
new(RTSP).PullStream(streamPath, targetURL)
w.Write([]byte(`{"code":0}`)) w.Write([]byte(`{"code":0}`))
} else { } else {
w.Write([]byte(fmt.Sprintf(`{"code":1,"msg":"%s"}`, err.Error()))) w.Write([]byte(fmt.Sprintf(`{"code":1,"msg":"%s"}`, err.Error())))
@@ -132,17 +127,17 @@ type RTSP struct {
connWLock sync.RWMutex connWLock sync.RWMutex
Type SessionType Type SessionType
TransType TransType TransType TransType
SDPRaw string
SDPMap map[string]*SDPInfo SDPMap map[string]*SDPInfo
nonce string nonce string
closeOld bool closeOld bool
AControl string AControl string
VControl string VControl string
ACodec string ACodec string
VCodec string VCodec string
avcsent bool avcsent bool
aacsent bool aacsent bool
Timeout int Timeout int
// stats info // stats info
fuBuffer []byte fuBuffer []byte
//tcp channels //tcp channels
@@ -158,19 +153,17 @@ type RTSP struct {
Auth func(string) string Auth func(string) string
} }
type RTSPClientInfo struct { type RTSPClientInfo struct {
Agent string Agent string
Session string Session string
Sdp *sdp.Session authLine string
authLine string Seq int
Seq int
} }
type RTSPInfo struct { type RTSPInfo struct {
URL string URL string
SyncCount int64 SyncCount int64
Header *string SDPRaw string
BufferRate int InBytes int
InBytes int OutBytes int
OutBytes int
StreamInfo *StreamInfo StreamInfo *StreamInfo
} }

View File

@@ -99,9 +99,11 @@ func (session *RTSP) Stop() {
session.UDPServer = nil session.UDPServer = nil
} }
if session.Running() { if session.Running() {
collection.Delete(session.StreamPath)
session.Cancel() session.Cancel()
} }
if session.Stream != nil {
collection.Delete(session.StreamPath)
}
} }
// AcceptPush 接受推流 // AcceptPush 接受推流
@@ -350,7 +352,7 @@ func (session *RTSP) handleRequest(req *Request) {
res.Status = "Invalid URL" res.Status = "Invalid URL"
return return
} }
streamPath := strings.TrimPrefix(url.Path,"/") streamPath := strings.TrimPrefix(url.Path, "/")
session.SDPRaw = req.Body session.SDPRaw = req.Body
session.SDPMap = ParseSDP(req.Body) session.SDPMap = ParseSDP(req.Body)
@@ -361,7 +363,7 @@ func (session *RTSP) handleRequest(req *Request) {
session.AudioSpecificConfig = sdp.Config session.AudioSpecificConfig = sdp.Config
Printf("audio codec[%s]\n", session.ACodec) Printf("audio codec[%s]\n", session.ACodec)
} }
if sdp, ok = session.SDPMap["video"];ok { if sdp, ok = session.SDPMap["video"]; ok {
session.VControl = sdp.Control session.VControl = sdp.Control
session.VCodec = sdp.Codec session.VCodec = sdp.Codec
session.SPS = sdp.SpropParameterSets[0] session.SPS = sdp.SpropParameterSets[0]

View File

@@ -172,14 +172,14 @@ if (typeof window !== 'undefined') {
// Indicate to webpack that this file can be concatenated // Indicate to webpack that this file can be concatenated
/* harmony default export */ var setPublicPath = (null); /* harmony default export */ var setPublicPath = (null);
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"29918b3a-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=template&id=0225c7f1& // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"29918b3a-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=template&id=de44c72c&
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('mu-data-table',{attrs:{"data":_vm.Streams,"columns":_vm.columns},scopedSlots:_vm._u([{key:"default",fn:function(ref){ var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('mu-data-table',{attrs:{"data":_vm.Streams,"columns":_vm.columns},scopedSlots:_vm._u([{key:"default",fn:function(ref){
var item = ref.row; var item = ref.row;
return [_c('td',[_vm._v(_vm._s(item.StreamInfo.StreamPath))]),_c('td',[_c('StartTime',{attrs:{"value":item.StreamInfo.StartTime}})],1),_c('td',[_c('Progress',{attrs:{"stroke-width":20,"percent":Math.ceil(item.BufferRate),"text-inside":""}})],1),_c('td',[_vm._v(_vm._s(item.SyncCount))]),_c('td',[_c('mu-button',{attrs:{"flat":""},on:{"click":function($event){return _vm.showHeader(item)}}},[_vm._v("头信息")])],1)]}}])}),_c('mu-dialog',{attrs:{"title":"拉流转发","width":"360","open":_vm.openPull},on:{"update:open":function($event){_vm.openPull=$event}}},[_c('mu-text-field',{attrs:{"label":"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:(_vm.remoteAddr),callback:function ($$v) {_vm.remoteAddr=$$v},expression:"remoteAddr"}}),_c('mu-text-field',{attrs:{"label":"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),_c('mu-button',{attrs:{"slot":"actions","flat":"","color":"primary"},on:{"click":_vm.addPull},slot:"actions"},[_vm._v("确定")])],1)],1)} return [_c('td',[_vm._v(_vm._s(item.StreamInfo.StreamPath))]),_c('td',[_c('StartTime',{attrs:{"value":item.StreamInfo.StartTime}})],1),_c('td',[_vm._v(_vm._s(_vm.unitFormat(item.InBytes)))]),_c('td',[_vm._v(_vm._s(_vm.unitFormat(item.OutBytes)))]),_c('td',[_c('mu-button',{attrs:{"flat":""},on:{"click":function($event){return _vm.showHeader(item)}}},[_vm._v("头信息")]),_c('mu-button',{attrs:{"flat":""},on:{"click":function($event){return _vm.stop(item)}}},[_vm._v("中止")])],1)]}}])}),_c('mu-dialog',{attrs:{"title":"拉流转发","width":"360","open":_vm.openPull},on:{"update:open":function($event){_vm.openPull=$event}}},[_c('mu-text-field',{attrs:{"label":"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:(_vm.remoteAddr),callback:function ($$v) {_vm.remoteAddr=$$v},expression:"remoteAddr"}}),_c('mu-text-field',{attrs:{"label":"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),_c('mu-button',{attrs:{"slot":"actions","flat":"","color":"primary"},on:{"click":_vm.addPull},slot:"actions"},[_vm._v("确定")])],1)],1)}
var staticRenderFns = [] var staticRenderFns = []
// CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=0225c7f1& // CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=de44c72c&
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js&
// //
@@ -203,75 +203,104 @@ var staticRenderFns = []
// //
// //
// //
//
//
//
//
//
//
//
//
//
//
//
//
//
let listES = null; let listES = null;
/* harmony default export */ var Appvue_type_script_lang_js_ = ({ /* harmony default export */ var Appvue_type_script_lang_js_ = ({
components: { data() {
StartTime return {
}, currentStream: null,
data() { Streams: null,
return { remoteAddr: "",
currentStream: null, streamPath: "",
Streams: null, openPull: false,
remoteAddr: "", columns: [
streamPath: "", "StreamPath",
openPull: false, "开始时间",
columns:["StreamPath","开始时间","缓冲","同步数","操作" ].map(title=>({title})) "总接收",
}; "总发送",
}, "操作"
].map(title => ({ title }))
};
},
methods: { methods: {
fetchlist() { fetchlist() {
listES = new EventSource(this.apiHost + "/rtsp/list"); listES = new EventSource(this.apiHost + "/rtsp/list");
listES.onmessage = evt => { listES.onmessage = evt => {
if (!evt.data) return; if (!evt.data) return;
this.Streams = JSON.parse(evt.data) || []; this.Streams = JSON.parse(evt.data) || [];
this.Streams.sort((a, b) => this.Streams.sort((a, b) =>
a.StreamInfo.StreamPath > b.StreamInfo.StreamPath ? 1 : -1 a.StreamInfo.StreamPath > b.StreamInfo.StreamPath ? 1 : -1
); );
}; };
},
showHeader(item) {
this.$Modal.info({
title: "RTSP Header",
width: "1000px",
scrollable: true,
content: item.Header
});
},
addPull() {
this.openPull = false;
this.ajax
.getJSON(this.apiHost + "/rtsp/pull", {
target: this.remoteAddr,
streamPath: this.streamPath
})
.then(x => {
if (x.code == 0) {
this.$toast.success("已启动拉流");
} else {
this.$toast.error(x.msg);
}
});
}
}, },
mounted() { showHeader(item) {
this.fetchlist(); this.$Modal.info({
let _this = this; title: "RTSP SDPRaw",
this.$parent.titleOps = [ width: "1000px",
{ scrollable: true,
template:'<m-button @click="onClick">拉流转发</m-button>', content: item.SDPRaw
methods:{ });
onClick(){
_this.openPull = true;
}
}
}
]
}, },
destroyed() { addPull() {
listES.close(); this.openPull = false;
this.ajax
.getJSON(this.apiHost + "/rtsp/pull", {
target: this.remoteAddr,
streamPath: this.streamPath
})
.then(x => {
if (x.code == 0) {
this.$toast.success("已启动拉流");
} else {
this.$toast.error(x.msg);
}
});
},
stop(item) {
this.ajax
.get(this.apiHost + "/api/stop", {
stream: item.StreamInfo.StreamPath
})
.then(x => {
if (x == "success") {
this.$toast.success("已停止拉流");
} else {
this.$toast.error(x.msg);
}
});
} }
},
mounted() {
this.fetchlist();
let _this = this;
this.$parent.titleOps = [
{
template: '<m-button @click="onClick">拉流转发</m-button>',
methods: {
onClick() {
_this.openPull = true;
}
}
}
];
},
destroyed() {
listES.close();
}
}); });
// CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js&

File diff suppressed because one or more lines are too long

View File

@@ -181,14 +181,14 @@ if (typeof window !== 'undefined') {
// Indicate to webpack that this file can be concatenated // Indicate to webpack that this file can be concatenated
/* harmony default export */ var setPublicPath = (null); /* harmony default export */ var setPublicPath = (null);
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"29918b3a-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=template&id=0225c7f1& // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"29918b3a-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=template&id=de44c72c&
var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('mu-data-table',{attrs:{"data":_vm.Streams,"columns":_vm.columns},scopedSlots:_vm._u([{key:"default",fn:function(ref){ var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('mu-data-table',{attrs:{"data":_vm.Streams,"columns":_vm.columns},scopedSlots:_vm._u([{key:"default",fn:function(ref){
var item = ref.row; var item = ref.row;
return [_c('td',[_vm._v(_vm._s(item.StreamInfo.StreamPath))]),_c('td',[_c('StartTime',{attrs:{"value":item.StreamInfo.StartTime}})],1),_c('td',[_c('Progress',{attrs:{"stroke-width":20,"percent":Math.ceil(item.BufferRate),"text-inside":""}})],1),_c('td',[_vm._v(_vm._s(item.SyncCount))]),_c('td',[_c('mu-button',{attrs:{"flat":""},on:{"click":function($event){return _vm.showHeader(item)}}},[_vm._v("头信息")])],1)]}}])}),_c('mu-dialog',{attrs:{"title":"拉流转发","width":"360","open":_vm.openPull},on:{"update:open":function($event){_vm.openPull=$event}}},[_c('mu-text-field',{attrs:{"label":"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:(_vm.remoteAddr),callback:function ($$v) {_vm.remoteAddr=$$v},expression:"remoteAddr"}}),_c('mu-text-field',{attrs:{"label":"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),_c('mu-button',{attrs:{"slot":"actions","flat":"","color":"primary"},on:{"click":_vm.addPull},slot:"actions"},[_vm._v("确定")])],1)],1)} return [_c('td',[_vm._v(_vm._s(item.StreamInfo.StreamPath))]),_c('td',[_c('StartTime',{attrs:{"value":item.StreamInfo.StartTime}})],1),_c('td',[_vm._v(_vm._s(_vm.unitFormat(item.InBytes)))]),_c('td',[_vm._v(_vm._s(_vm.unitFormat(item.OutBytes)))]),_c('td',[_c('mu-button',{attrs:{"flat":""},on:{"click":function($event){return _vm.showHeader(item)}}},[_vm._v("头信息")]),_c('mu-button',{attrs:{"flat":""},on:{"click":function($event){return _vm.stop(item)}}},[_vm._v("中止")])],1)]}}])}),_c('mu-dialog',{attrs:{"title":"拉流转发","width":"360","open":_vm.openPull},on:{"update:open":function($event){_vm.openPull=$event}}},[_c('mu-text-field',{attrs:{"label":"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:(_vm.remoteAddr),callback:function ($$v) {_vm.remoteAddr=$$v},expression:"remoteAddr"}}),_c('mu-text-field',{attrs:{"label":"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:(_vm.streamPath),callback:function ($$v) {_vm.streamPath=$$v},expression:"streamPath"}}),_c('mu-button',{attrs:{"slot":"actions","flat":"","color":"primary"},on:{"click":_vm.addPull},slot:"actions"},[_vm._v("确定")])],1)],1)}
var staticRenderFns = [] var staticRenderFns = []
// CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=0225c7f1& // CONCATENATED MODULE: ./src/App.vue?vue&type=template&id=de44c72c&
// CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js&
// //
@@ -212,75 +212,104 @@ var staticRenderFns = []
// //
// //
// //
//
//
//
//
//
//
//
//
//
//
//
//
//
let listES = null; let listES = null;
/* harmony default export */ var Appvue_type_script_lang_js_ = ({ /* harmony default export */ var Appvue_type_script_lang_js_ = ({
components: { data() {
StartTime return {
}, currentStream: null,
data() { Streams: null,
return { remoteAddr: "",
currentStream: null, streamPath: "",
Streams: null, openPull: false,
remoteAddr: "", columns: [
streamPath: "", "StreamPath",
openPull: false, "开始时间",
columns:["StreamPath","开始时间","缓冲","同步数","操作" ].map(title=>({title})) "总接收",
}; "总发送",
}, "操作"
].map(title => ({ title }))
};
},
methods: { methods: {
fetchlist() { fetchlist() {
listES = new EventSource(this.apiHost + "/rtsp/list"); listES = new EventSource(this.apiHost + "/rtsp/list");
listES.onmessage = evt => { listES.onmessage = evt => {
if (!evt.data) return; if (!evt.data) return;
this.Streams = JSON.parse(evt.data) || []; this.Streams = JSON.parse(evt.data) || [];
this.Streams.sort((a, b) => this.Streams.sort((a, b) =>
a.StreamInfo.StreamPath > b.StreamInfo.StreamPath ? 1 : -1 a.StreamInfo.StreamPath > b.StreamInfo.StreamPath ? 1 : -1
); );
}; };
},
showHeader(item) {
this.$Modal.info({
title: "RTSP Header",
width: "1000px",
scrollable: true,
content: item.Header
});
},
addPull() {
this.openPull = false;
this.ajax
.getJSON(this.apiHost + "/rtsp/pull", {
target: this.remoteAddr,
streamPath: this.streamPath
})
.then(x => {
if (x.code == 0) {
this.$toast.success("已启动拉流");
} else {
this.$toast.error(x.msg);
}
});
}
}, },
mounted() { showHeader(item) {
this.fetchlist(); this.$Modal.info({
let _this = this; title: "RTSP SDPRaw",
this.$parent.titleOps = [ width: "1000px",
{ scrollable: true,
template:'<m-button @click="onClick">拉流转发</m-button>', content: item.SDPRaw
methods:{ });
onClick(){
_this.openPull = true;
}
}
}
]
}, },
destroyed() { addPull() {
listES.close(); this.openPull = false;
this.ajax
.getJSON(this.apiHost + "/rtsp/pull", {
target: this.remoteAddr,
streamPath: this.streamPath
})
.then(x => {
if (x.code == 0) {
this.$toast.success("已启动拉流");
} else {
this.$toast.error(x.msg);
}
});
},
stop(item) {
this.ajax
.get(this.apiHost + "/api/stop", {
stream: item.StreamInfo.StreamPath
})
.then(x => {
if (x == "success") {
this.$toast.success("已停止拉流");
} else {
this.$toast.error(x.msg);
}
});
} }
},
mounted() {
this.fetchlist();
let _this = this;
this.$parent.titleOps = [
{
template: '<m-button @click="onClick">拉流转发</m-button>',
methods: {
onClick() {
_this.openPull = true;
}
}
}
];
},
destroyed() {
listES.close();
}
}); });
// CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js& // CONCATENATED MODULE: ./src/App.vue?vue&type=script&lang=js&

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
(function(t,e){"object"===typeof exports&&"object"===typeof module?module.exports=e():"function"===typeof define&&define.amd?define([],e):"object"===typeof exports?exports["plugin-rtsp"]=e():t["plugin-rtsp"]=e()})("undefined"!==typeof self?self:this,(function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)r.d(n,o,function(e){return t[e]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s="fb15")}({"034f":function(t,e,r){"use strict";var n=r("85ec"),o=r.n(n);o.a},"85ec":function(t,e,r){},f6fd:function(t,e){(function(t){var e="currentScript",r=t.getElementsByTagName("script");e in t||Object.defineProperty(t,e,{get:function(){try{throw new Error}catch(n){var t,e=(/.*at [^\(]*\((.*):.+:.+\)$/gi.exec(n.stack)||[!1])[1];for(t in r)if(r[t].src==e||"interactive"==r[t].readyState)return r[t];return null}}})})(document)},fb15:function(t,e,r){"use strict";var n;(r.r(e),"undefined"!==typeof window)&&(r("f6fd"),(n=window.document.currentScript)&&(n=n.src.match(/(.+\/)[^/]+\.js(\?.*)?$/))&&(r.p=n[1]));var o=function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("div",[r("mu-data-table",{attrs:{data:t.Streams,columns:t.columns},scopedSlots:t._u([{key:"default",fn:function(e){var n=e.row;return[r("td",[t._v(t._s(n.StreamInfo.StreamPath))]),r("td",[r("StartTime",{attrs:{value:n.StreamInfo.StartTime}})],1),r("td",[r("Progress",{attrs:{"stroke-width":20,percent:Math.ceil(n.BufferRate),"text-inside":""}})],1),r("td",[t._v(t._s(n.SyncCount))]),r("td",[r("mu-button",{attrs:{flat:""},on:{click:function(e){return t.showHeader(n)}}},[t._v("头信息")])],1)]}}])}),r("mu-dialog",{attrs:{title:"拉流转发",width:"360",open:t.openPull},on:{"update:open":function(e){t.openPull=e}}},[r("mu-text-field",{attrs:{label:"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:t.remoteAddr,callback:function(e){t.remoteAddr=e},expression:"remoteAddr"}}),r("mu-text-field",{attrs:{label:"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:t.streamPath,callback:function(e){t.streamPath=e},expression:"streamPath"}}),r("mu-button",{attrs:{slot:"actions",flat:"",color:"primary"},on:{click:t.addPull},slot:"actions"},[t._v("确定")])],1)],1)},a=[];let s=null;var i={components:{StartTime:StartTime},data(){return{currentStream:null,Streams:null,remoteAddr:"",streamPath:"",openPull:!1,columns:["StreamPath","开始时间","缓冲","同步数","操作"].map(t=>({title:t}))}},methods:{fetchlist(){s=new EventSource(this.apiHost+"/rtsp/list"),s.onmessage=t=>{t.data&&(this.Streams=JSON.parse(t.data)||[],this.Streams.sort((t,e)=>t.StreamInfo.StreamPath>e.StreamInfo.StreamPath?1:-1))}},showHeader(t){this.$Modal.info({title:"RTSP Header",width:"1000px",scrollable:!0,content:t.Header})},addPull(){this.openPull=!1,this.ajax.getJSON(this.apiHost+"/rtsp/pull",{target:this.remoteAddr,streamPath:this.streamPath}).then(t=>{0==t.code?this.$toast.success("已启动拉流"):this.$toast.error(t.msg)})}},mounted(){this.fetchlist();let t=this;this.$parent.titleOps=[{template:'<m-button @click="onClick">拉流转发</m-button>',methods:{onClick(){t.openPull=!0}}}]},destroyed(){s.close()}},l=i;r("034f");function u(t,e,r,n,o,a,s,i){var l,u="function"===typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=r,u._compiled=!0),n&&(u.functional=!0),a&&(u._scopeId="data-v-"+a),s?(l=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"===typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(s)},u._ssrRegister=l):o&&(l=i?function(){o.call(this,this.$root.$options.shadowRoot)}:o),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(t,e){return l.call(e),c(t,e)}}else{var d=u.beforeCreate;u.beforeCreate=d?[].concat(d,l):[l]}return{exports:t,options:u}}var c=u(l,o,a,!1,null,null,null),d=c.exports;e["default"]=d}})["default"]})); (function(t,e){"object"===typeof exports&&"object"===typeof module?module.exports=e():"function"===typeof define&&define.amd?define([],e):"object"===typeof exports?exports["plugin-rtsp"]=e():t["plugin-rtsp"]=e()})("undefined"!==typeof self?self:this,(function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)r.d(n,o,function(e){return t[e]}.bind(null,o));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s="fb15")}({"034f":function(t,e,r){"use strict";var n=r("85ec"),o=r.n(n);o.a},"85ec":function(t,e,r){},f6fd:function(t,e){(function(t){var e="currentScript",r=t.getElementsByTagName("script");e in t||Object.defineProperty(t,e,{get:function(){try{throw new Error}catch(n){var t,e=(/.*at [^\(]*\((.*):.+:.+\)$/gi.exec(n.stack)||[!1])[1];for(t in r)if(r[t].src==e||"interactive"==r[t].readyState)return r[t];return null}}})})(document)},fb15:function(t,e,r){"use strict";var n;(r.r(e),"undefined"!==typeof window)&&(r("f6fd"),(n=window.document.currentScript)&&(n=n.src.match(/(.+\/)[^/]+\.js(\?.*)?$/))&&(r.p=n[1]));var o=function(){var t=this,e=t.$createElement,r=t._self._c||e;return r("div",[r("mu-data-table",{attrs:{data:t.Streams,columns:t.columns},scopedSlots:t._u([{key:"default",fn:function(e){var n=e.row;return[r("td",[t._v(t._s(n.StreamInfo.StreamPath))]),r("td",[r("StartTime",{attrs:{value:n.StreamInfo.StartTime}})],1),r("td",[t._v(t._s(t.unitFormat(n.InBytes)))]),r("td",[t._v(t._s(t.unitFormat(n.OutBytes)))]),r("td",[r("mu-button",{attrs:{flat:""},on:{click:function(e){return t.showHeader(n)}}},[t._v("头信息")]),r("mu-button",{attrs:{flat:""},on:{click:function(e){return t.stop(n)}}},[t._v("中止")])],1)]}}])}),r("mu-dialog",{attrs:{title:"拉流转发",width:"360",open:t.openPull},on:{"update:open":function(e){t.openPull=e}}},[r("mu-text-field",{attrs:{label:"rtsp url","label-float":"","help-text":"Please enter URL of rtsp..."},model:{value:t.remoteAddr,callback:function(e){t.remoteAddr=e},expression:"remoteAddr"}}),r("mu-text-field",{attrs:{label:"streamPath","label-float":"","help-text":"Please enter streamPath to publish."},model:{value:t.streamPath,callback:function(e){t.streamPath=e},expression:"streamPath"}}),r("mu-button",{attrs:{slot:"actions",flat:"",color:"primary"},on:{click:t.addPull},slot:"actions"},[t._v("确定")])],1)],1)},a=[];let s=null;var i={data(){return{currentStream:null,Streams:null,remoteAddr:"",streamPath:"",openPull:!1,columns:["StreamPath","开始时间","总接收","总发送","操作"].map(t=>({title:t}))}},methods:{fetchlist(){s=new EventSource(this.apiHost+"/rtsp/list"),s.onmessage=t=>{t.data&&(this.Streams=JSON.parse(t.data)||[],this.Streams.sort((t,e)=>t.StreamInfo.StreamPath>e.StreamInfo.StreamPath?1:-1))}},showHeader(t){this.$Modal.info({title:"RTSP SDPRaw",width:"1000px",scrollable:!0,content:t.SDPRaw})},addPull(){this.openPull=!1,this.ajax.getJSON(this.apiHost+"/rtsp/pull",{target:this.remoteAddr,streamPath:this.streamPath}).then(t=>{0==t.code?this.$toast.success("已启动拉流"):this.$toast.error(t.msg)})},stop(t){this.ajax.get(this.apiHost+"/api/stop",{stream:t.StreamInfo.StreamPath}).then(t=>{"success"==t?this.$toast.success("已停止拉流"):this.$toast.error(t.msg)})}},mounted(){this.fetchlist();let t=this;this.$parent.titleOps=[{template:'<m-button @click="onClick">拉流转发</m-button>',methods:{onClick(){t.openPull=!0}}}]},destroyed(){s.close()}},l=i;r("034f");function u(t,e,r,n,o,a,s,i){var l,u="function"===typeof t?t.options:t;if(e&&(u.render=e,u.staticRenderFns=r,u._compiled=!0),n&&(u.functional=!0),a&&(u._scopeId="data-v-"+a),s?(l=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"===typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),o&&o.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(s)},u._ssrRegister=l):o&&(l=i?function(){o.call(this,this.$root.$options.shadowRoot)}:o),l)if(u.functional){u._injectStyles=l;var c=u.render;u.render=function(t,e){return l.call(e),c(t,e)}}else{var f=u.beforeCreate;u.beforeCreate=f?[].concat(f,l):[l]}return{exports:t,options:u}}var c=u(l,o,a,!1,null,null,null),f=c.exports;e["default"]=f}})["default"]}));
//# sourceMappingURL=plugin-rtsp.umd.min.js.map //# sourceMappingURL=plugin-rtsp.umd.min.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,118 +1,147 @@
<template> <template>
<div> <div>
<mu-data-table :data="Streams" :columns="columns"> <mu-data-table :data="Streams" :columns="columns">
<template #default="{row:item}"> <template #default="{row:item}">
<td>{{item.StreamInfo.StreamPath}}</td> <td>{{item.StreamInfo.StreamPath}}</td>
<td><StartTime :value="item.StreamInfo.StartTime"></StartTime></td> <td>
<td><Progress :stroke-width="20" :percent="Math.ceil(item.BufferRate)" text-inside /></td> <StartTime :value="item.StreamInfo.StartTime"></StartTime>
<td>{{item.SyncCount}}</td> </td>
<td><mu-button flat @click="showHeader(item)">头信息</mu-button></td> <td>{{unitFormat(item.InBytes)}}</td>
</template> <td>{{unitFormat(item.OutBytes)}}</td>
</mu-data-table> <td>
<mu-dialog title="拉流转发" width="360" :open.sync="openPull"> <mu-button flat @click="showHeader(item)">头信息</mu-button>
<mu-text-field v-model="remoteAddr" label="rtsp url" label-float help-text="Please enter URL of rtsp..."> <mu-button flat @click="stop(item)">中止</mu-button>
</mu-text-field> </td>
<mu-text-field v-model="streamPath" label="streamPath" label-float </template>
help-text="Please enter streamPath to publish."></mu-text-field> </mu-data-table>
<mu-button slot="actions" flat color="primary" @click="addPull">确定</mu-button> <mu-dialog title="拉流转发" width="360" :open.sync="openPull">
</mu-dialog> <mu-text-field
</div> v-model="remoteAddr"
label="rtsp url"
label-float
help-text="Please enter URL of rtsp..."
></mu-text-field>
<mu-text-field
v-model="streamPath"
label="streamPath"
label-float
help-text="Please enter streamPath to publish."
></mu-text-field>
<mu-button slot="actions" flat color="primary" @click="addPull">确定</mu-button>
</mu-dialog>
</div>
</template> </template>
<script> <script>
let listES = null; let listES = null;
export default { export default {
components: { data() {
StartTime return {
}, currentStream: null,
data() { Streams: null,
return { remoteAddr: "",
currentStream: null, streamPath: "",
Streams: null, openPull: false,
remoteAddr: "", columns: [
streamPath: "", "StreamPath",
openPull: false, "开始时间",
columns:["StreamPath","开始时间","缓冲","同步数","操作" ].map(title=>({title})) "总接收",
}; "总发送",
}, "操作"
].map(title => ({ title }))
};
},
methods: { methods: {
fetchlist() { fetchlist() {
listES = new EventSource(this.apiHost + "/rtsp/list"); listES = new EventSource(this.apiHost + "/rtsp/list");
listES.onmessage = evt => { listES.onmessage = evt => {
if (!evt.data) return; if (!evt.data) return;
this.Streams = JSON.parse(evt.data) || []; this.Streams = JSON.parse(evt.data) || [];
this.Streams.sort((a, b) => this.Streams.sort((a, b) =>
a.StreamInfo.StreamPath > b.StreamInfo.StreamPath ? 1 : -1 a.StreamInfo.StreamPath > b.StreamInfo.StreamPath ? 1 : -1
); );
}; };
},
showHeader(item) {
this.$Modal.info({
title: "RTSP Header",
width: "1000px",
scrollable: true,
content: item.Header
});
},
addPull() {
this.openPull = false;
this.ajax
.getJSON(this.apiHost + "/rtsp/pull", {
target: this.remoteAddr,
streamPath: this.streamPath
})
.then(x => {
if (x.code == 0) {
this.$toast.success("已启动拉流");
} else {
this.$toast.error(x.msg);
}
});
}
}, },
mounted() { showHeader(item) {
this.fetchlist(); this.$Modal.info({
let _this = this; title: "RTSP SDPRaw",
this.$parent.titleOps = [ width: "1000px",
{ scrollable: true,
template:'<m-button @click="onClick">拉流转发</m-button>', content: item.SDPRaw
methods:{ });
onClick(){
_this.openPull = true;
}
}
}
]
}, },
destroyed() { addPull() {
listES.close(); this.openPull = false;
this.ajax
.getJSON(this.apiHost + "/rtsp/pull", {
target: this.remoteAddr,
streamPath: this.streamPath
})
.then(x => {
if (x.code == 0) {
this.$toast.success("已启动拉流");
} else {
this.$toast.error(x.msg);
}
});
},
stop(item) {
this.ajax
.get(this.apiHost + "/api/stop", {
stream: item.StreamInfo.StreamPath
})
.then(x => {
if (x == "success") {
this.$toast.success("已停止拉流");
} else {
this.$toast.error(x.msg);
}
});
} }
},
mounted() {
this.fetchlist();
let _this = this;
this.$parent.titleOps = [
{
template: '<m-button @click="onClick">拉流转发</m-button>',
methods: {
onClick() {
_this.openPull = true;
}
}
}
];
},
destroyed() {
listES.close();
}
}; };
</script> </script>
<style> <style>
.empty { .empty {
color: #eb5e46; color: #eb5e46;
width: 100%; width: 100%;
min-height: 500px; min-height: 500px;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.layout { .layout {
padding-bottom: 30px; padding-bottom: 30px;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
} }
.ts-info { .ts-info {
width: 300px; width: 300px;
} }
.hls-info { .hls-info {
width: 350px; width: 350px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
</style> </style>