如何在RTSP协议网页无插件直播流媒体视频平台EasyNVR演示系统内做到自定义断流?

我们在对EasyDSS做功能测试的时候,讲过在EasyDSS演示平台上,为了节省资源占用设置的自动停播问题。基于EasyDSS的成功经验,我们在EasyNVR的官网也做了同样一套机制。

如何在RTSP协议网页无插件直播流媒体视频平台EasyNVR演示系统内做到自定义断流?

分析问题

在EasyNVR的演示平台内设置自动断流机制,限制几分钟后流自动断开,这样客户在浏览的时候就算看了忘了关,系统也会在几分钟就自动断开,耗费流量就会少很多。

解决问题

在获取通过直播链接的时候,在直播链接后面添加一个校验的流的字符串。

func wrapURLWithLiveToken(rawURL string, c *gin.Context) (wrapURL string) {
wrapURL = rawURL
demo := utils.Conf().Section("base_config").Key("demo").MustBool(false)
if !demo {
return
}
if rawURL == "" {
return
}
_url, err := url.Parse(rawURL)
if err != nil {
return
}
q := _url.Query()
//token := utils.MD5(sessions.Default(c).ID() + rawURL)
token := createRandomString(8)
q.Set("token", token)
_url.RawQuery = q.Encode()
wrapURL = _url.String()
liveTokenCache.SetDefault(token, wrapURL)
return
}

func createRandomString(len int) string {
var container string
var str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
b := bytes.NewBufferString(str)
length := b.Len()
bigInt := big.NewInt(int64(length))
for i := 0; i < len; i++ {
randomInt, _ := rand.Int(rand.Reader, bigInt)
container += string(str[randomInt.Int64()])
}
return container
}

这样,直播链接就会有一个校验参数token。

如何在RTSP协议网页无插件直播流媒体视频平台EasyNVR演示系统内做到自定义断流?

针对不同流的特点来进行不同的限制:

1、ws-flv流

func WSFlvHandler() gin.HandlerFunc {
return func(c *gin.Context) {
demo := utils.Conf().Section("base_config").Key("demo").MustBool(false)
demoDuration := utils.Conf().Section("base_config").Key("demo_duration").MustInt(180)
flag := false
path := c.Param("path")
if strings.HasSuffix(path, ".flv") {
target := fmt.Sprintf("127.0.0.1:%v", dss.GetHTTPPort())
//获取nginx里面的真实流地址
flvUrl := "http://" + target + path
upGrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool {
return true
}}
//websocket长连接
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
return
}
defer func() {
//fmt.Println("关闭ws-flv长连接")
ws.Close()
}()
if demo {
go func() {
time.Sleep(time.Duration(demoDuration) * time.Second)
flag = true
}()
}
//发送http请求,将视频流数据循环写入到websocket
req, _ := http.NewRequest("GET", flvUrl, nil)
res, _ := http.DefaultClient.Do(req)
reader := bufio.NewReader(res.Body)
defer res.Body.Close()
//循环遍历
for {
line, err := reader.ReadBytes(' ')
if err != nil {
return
}
ws.WriteMessage(websocket.BinaryMessage, line)
if flag {
return
}
}
}
c.Next()
}
}

至此,ws-flv流就限制成功了。

2、http-flv流

//可关闭 Transport
type ShutDownTransport struct {
Trans *http.Transport
response *http.Response
}

//覆盖上层Transport
func (t *ShutDownTransport) RoundTrip(req *http.Request) (*http.Response, error) {
res, err := t.Trans.RoundTrip(req)
t.response = res
return res, err
}

//实现关闭方法
func (t *ShutDownTransport) ShutDown(d time.Duration) {
time.AfterFunc(d, func() {
res := t.response
if res != nil {
if res.Body != nil {
res.Body.Close()
}
}
})
}

// FlvHandler flv request handler
func FlvHandler() gin.HandlerFunc {
return func(c *gin.Context) {
demo := utils.Conf().Section("base_config").Key("demo").MustBool(false)
demoDuration := utils.Conf().Section("base_config").Key("demo_duration").MustInt(180)
path := c.Param("path")
if strings.HasSuffix(path, ".flv") {
target := fmt.Sprintf("127.0.0.1:%v", dss.GetHTTPPort())
director := func(req *http.Request) {
req.URL.Scheme = "http"
req.URL.Host = target
req.URL.Path = path
}
modifyRes := func(res *http.Response) (err error) {
res.Header.Del("Access-Control-Allow-Credentials")
res.Header.Del("Access-Control-Allow-Headers")
res.Header.Del("Access-Control-Allow-Methods")
res.Header.Del("Access-Control-Allow-Origin")
res.Header.Del("Vary")
res.Header.Del("Server")
return
}
transport := &ShutDownTransport{
Trans: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ResponseHeaderTimeout: 10 * time.Second,
},
}
if demo {
transport.ShutDown(time.Duration(demoDuration) * time.Second)
}
proxy := &httputil.ReverseProxy{
Director: director,
Transport: transport,
ModifyResponse: modifyRes,
}
defer func() {
if p := recover(); p != nil {
log.Println(p)
}
}()
proxy.ServeHTTP(c.Writer, c.Request)
return
}
c.Next()
}
}

至此,http-flv限流就完成了。

3、hls流

因为hls流和ws-flv、http-flv流不同,前端会一直请求这个链接,所以就不用向上面一样限流。

// 检查断流
func checkTime() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Param("path")
demo := utils.Conf().Section("base_config").Key("demo").MustBool(false)
isTS := strings.HasSuffix(path, ".ts")
if demo && !isTS {
token := c.Query("token")
if token == "" {
c.IndentedJSON(401, "Token Not Found")
return
}
if _, ok := liveTokenCache.Get(token); !ok {
c.IndentedJSON(401, "Invalid Token")
return
}
}
c.Next()
}
}

因为播放器又断流自动重连机制,所以在请求的流链接时先要判断一下,请求的这个流地址是不是系统缓存中,不在系统缓存中就不让播放流了。

如何在RTSP协议网页无插件直播流媒体视频平台EasyNVR演示系统内做到自定义断流?

只要有演示平台需求的项目都可以通过该调用方法节省公网的浏览和带宽,大家可以参考《EasyGBS平台如何开启“演示”模式》一文了解一下演示平台的机制和作用。

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

如何在RTSP协议网页无插件直播流媒体视频平台EasyNVR演示系统内做到自定义断流?

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 如何在RTSP协议网页无插件直播流媒体视频平台EasyNVR演示系统内做到自定义断流?
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏