]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
快速响应 flv播放支持 限定文件才进行流处理
authorqydysky <qydysky@foxmail.com>
Tue, 13 Apr 2021 16:35:04 +0000 (00:35 +0800)
committerqydysky <qydysky@foxmail.com>
Tue, 13 Apr 2021 16:35:04 +0000 (00:35 +0800)
README.md
Reply/F.go
Reply/flvDecode.go

index 3f4baed3d3ebc6d2b346cbef865c3874ea12b179..8ac81e47d818c6a823bd22c63064c08ee02aec3d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -99,7 +99,7 @@ golang go version go1.15 linux/amd64
 ### 说明
 本项目使用github action自动构建,构建过程详见[yml](https://github.com/qydysky/bili_danmu/blob/master/.github/workflows/go.yml)
 
-#### 局域网转直播流服务
+#### 直播流Web服务
 启动Web流服务,为下载的直播流提供局域网内的流服务。
 
 在`demo/config/config_K_v.json`中可找到配置项,默认开启。
@@ -108,7 +108,13 @@ golang go version go1.15 linux/amd64
     "直播保存位置Web服务":true,
 ```
 
-开启之后,启动会显示服务地址,在局域网内打开网址可以取得当前直播流(`dtmp`结尾)的flv流地址。可以在其他设备进行网络串流观看(如安卓mx player)。通过对获取flv直播流进行修改,使得无论何时打开局域网串流,播放的进度与当前直播时刻相同。服务地址也可通过命令行` room`查看。
+开启之后,启动会显示服务地址,在局域网内打开网址可以取得所有直播流的串流地址。
+
+- dtmp结尾:当前正在获取的流,播放此链接时进度将保持当前流进度
+- flv结尾:保存完毕的直播流,播放此链接时将从头开始播放
+- ass结尾:保存完毕的直播流字幕,有些播放器会在播放flv串流时获取此文件
+
+服务地址也可通过命令行` room`查看。
 
 ```
 I: 2021/04/13 20:07:45 命令行操作 [直播Web服务: http://192.168.31.245:38259]
index 5e5e50a2c3c2d4e9735b26d480373c9e224b710e..3e8592e143569ce041fb705f709362d544017326 100644 (file)
@@ -958,7 +958,7 @@ func init() {
                s.Handle(map[string]func(http.ResponseWriter,*http.Request){
                        `/`:func(w http.ResponseWriter,r *http.Request){
                                var path string = r.URL.Path[1:]
-                               if path == `` {
+                               if ext := filepath.Ext(path);ext == `` || ext != `.dtmp` || ext != `.flv` {
                                        http.FileServer(http.Dir(base_dir)).ServeHTTP(w,r)
                                } else {
                                        path = base_dir+path
@@ -968,11 +968,6 @@ func init() {
                                                return
                                        }
 
-                                       w.WriteHeader(200)
-                                       if f, ok := w.(http.Flusher); ok { 
-                                               f.Flush() 
-                                       }
-
                                        byteC := make(chan []byte,1024*1024)
                                        cancel := make(chan struct{})
                                        defer close(cancel)
@@ -983,6 +978,8 @@ func init() {
                                                }
                                        }()
 
+                                       
+                                       var fastRespon = true
                                        for {
                                                buf := <- byteC
                                                if len(buf) == 0 {break}
@@ -990,6 +987,9 @@ func init() {
                                                if _,err := w.Write(buf);err != nil {
                                                        flog.Base_add(`直播Web服务`).L(`T: `,`E: `,err);
                                                        break
+                                               } else if fastRespon {
+                                                       fastRespon = false
+                                                       if flusher, flushSupport := w.(http.Flusher);flushSupport {flusher.Flush()}
                                                }
                                        }
                                }
index 4a2ed33eaf7523d48e5096d274d53ef2d53f1802..c4b541736b37da6ce3fc5b10ed98229555e1d031 100644 (file)
@@ -5,6 +5,7 @@ import (
        "bytes"
        "time"
        "errors"
+       "path/filepath"
 
        c "github.com/qydysky/bili_danmu/CV"
        F "github.com/qydysky/bili_danmu/F"
@@ -21,7 +22,7 @@ const (
 
        //custom define
        eof_tag = byte(0x00)
-       copy_buf_size = 1024*1024
+       copy_buf_size = 1024*1024*10
 )
 
 var (
@@ -40,67 +41,73 @@ func Stream(path string,streamChan chan []byte,cancel chan struct{}) (error) {
        defer f.Close()
        defer close(streamChan)
 
-       //get flv header(9byte) + FirstTagSize(4byte)
-       {
-               f.Seek(0,0)
-               buf := make([]byte, flv_header_size+previou_tag_size)
-               if _,err := f.Read(buf);err != nil {return err}
-               if !bytes.Contains(buf,flv_header_sign) {return errors.New(`no flv`)}
-               streamChan <- buf
-       }
+       living := filepath.Ext(path) == `.dtmp`
+       //living stream ,seed to least
+       if living {
+               //get flv header(9byte) + FirstTagSize(4byte)
+               {
+                       f.Seek(0,0)
+                       buf := make([]byte, flv_header_size+previou_tag_size)
+                       if _,err := f.Read(buf);err != nil {return err}
+                       if !bytes.Contains(buf,flv_header_sign) {return errors.New(`no flv`)}
+                       streamChan <- buf
+               }
 
-       //get tag func
-       var getTag = func(f *os.File)(tag byte,offset int64,buf_p *[]byte,data_p *[]byte){
-               buf := make([]byte, tag_header_size)
-               if _,err := f.Read(buf);err != nil {tag = eof_tag;return}
-               tag = buf[0]
-               size := F.Btoi32(append([]byte{0x00},buf[1:4]...),0)
-
-               data := make([]byte, size+previou_tag_size)
-               if _,err := f.Read(data);err != nil {tag = eof_tag;return}
-               
-               offset,_ = f.Seek(0,1)
-               offset -= tag_header_size+int64(size)+previou_tag_size
-               return tag,offset,&buf,&data
-       }
+               //get tag func
+               var getTag = func(f *os.File)(tag byte,offset int64,buf_p *[]byte,data_p *[]byte){
+                       buf := make([]byte, tag_header_size)
+                       buf_p = &buf
+                       if _,err := f.Read(buf);err != nil {tag = eof_tag;return}
+                       tag = buf[0]
+                       size := F.Btoi32(append([]byte{0x00},buf[1:4]...),0)
+
+                       data := make([]byte, size+previou_tag_size)
+                       data_p = &data
+                       if _,err := f.Read(data);err != nil {tag = eof_tag;return}
+                       
+                       offset,_ = f.Seek(0,1)
+                       offset -= tag_header_size+int64(size)+previou_tag_size
+                       return
+               }
 
-       //get first video and audio tag
-       //find last_keyframe_video_offset
-       var last_keyframe_video_offset int64
-       first_video_tag,first_audio_tag := false,false
-       for {
-               tag,offset,buf_p,data_p := getTag(f)
-               if tag == script_tag {
-                       streamChan <- *buf_p
-                       streamChan <- *data_p
-               } else if tag == video_tag {
-                       if !first_video_tag {
-                               first_video_tag = true
+               //get first video and audio tag
+               //find last_keyframe_video_offset
+               var last_keyframe_video_offset int64
+               first_video_tag,first_audio_tag := false,false
+               for {
+                       tag,offset,buf_p,data_p := getTag(f)
+                       if tag == script_tag {
                                streamChan <- *buf_p
                                streamChan <- *data_p
-                       }
+                       } else if tag == video_tag {
+                               if !first_video_tag {
+                                       first_video_tag = true
+                                       streamChan <- *buf_p
+                                       streamChan <- *data_p
+                               }
 
-                       if (*data_p)[0] & 0xf0 == 0x10 {
-                               last_keyframe_video_offset = offset
-                       }
-               } else if tag == audio_tag {
-                       if !first_audio_tag {
-                               first_audio_tag = true
-                               streamChan <- *buf_p
-                               streamChan <- *data_p
+                               if (*data_p)[0] & 0xf0 == 0x10 {
+                                       last_keyframe_video_offset = offset
+                               }
+                       } else if tag == audio_tag {
+                               if !first_audio_tag {
+                                       first_audio_tag = true
+                                       streamChan <- *buf_p
+                                       streamChan <- *data_p
+                               }
+                       } else {//eof_tag
+                               break;
                        }
-               } else {//eof_tag
-                       break;
                }
-       }
 
-       //seed to last tag
-       f.Seek(last_keyframe_video_offset,0)
+               //seed to last tag
+               f.Seek(last_keyframe_video_offset,0)
+       }
 
        //copy
        {
                buf := make([]byte, copy_buf_size)
-               eof_wait_turn := 3
+               preOffset,_ := f.Seek(0,1)
                for {
 
                        //退出
@@ -113,16 +120,20 @@ func Stream(path string,streamChan chan []byte,cancel chan struct{}) (error) {
                        if err != nil {
                                if err.Error() != `EOF` {
                                        return err
+                               } else if offset,_ := f.Seek(0,1);offset == preOffset {
+                                       break
                                }
-                               if eof_wait_turn < 0 {break}
-                               eof_wait_turn -= 1
                        }
 
                        if size > 0 {
                                streamChan <- buf[:size]
                        }
 
-                       if eof_wait_turn > 0 {time.Sleep(time.Second*3)}
+                       if err != nil {
+                               preOffset,_ = f.Seek(0,1)
+                               time.Sleep(time.Duration(3) * time.Second)
+                       }
+
                }
        }