]> 127.0.0.1 Git - bili_danmu/.git/commitdiff
流服务自定义端口
authorqydysky <qydysky@foxmail.com>
Fri, 16 Apr 2021 07:44:57 +0000 (15:44 +0800)
committerqydysky <qydysky@foxmail.com>
Fri, 16 Apr 2021 07:44:57 +0000 (15:44 +0800)
flv数据整tag传输

README.md
Reply/F.go
Reply/flvDecode.go
demo/config/config_K_v.json

index 8ac81e47d818c6a823bd22c63064c08ee02aec3d..2d713b14e9b8b95ee54cf6751789f55637717f5c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -102,10 +102,10 @@ golang go version go1.15 linux/amd64
 #### 直播流Web服务
 启动Web流服务,为下载的直播流提供局域网内的流服务。
 
-在`demo/config/config_K_v.json`中可找到配置项,默认开启
+在`demo/config/config_K_v.json`中可找到配置项,0:随机可用端口 >0:固定可用端口 <0:禁用服务
 
 ```
-    "直播保存位置Web服务":true,
+    "直播保存位置Web服务":0,
 ```
 
 开启之后,启动会显示服务地址,在局域网内打开网址可以取得所有直播流的串流地址。
index 32c75ad012a9ec894594b96c23ec4e6983e15aa8..510b7e9d4b3a353e3a1183f33a9ef7d4c139cd67 100644 (file)
@@ -332,6 +332,10 @@ func Saveflvf(){
                l.L(`I: `,"结束")
                Ass_f("", time.Now())//ass
                p.FileMove(saveflv.path+".flv.dtmp", saveflv.path+".flv")
+
+               //set ro ``
+               saveflv.path = ``
+
                if !saveflv.cancel.Islive() {break}//cancel
                /*
                        Saveflv需要外部组件
@@ -945,15 +949,24 @@ func AutoSend_silver_gift() {
 
 //直播保存位置Web服务
 func init() {
-       if v,ok := c.K_v.LoadV(`直播保存位置Web服务`).(bool);ok && v {
+       if port_f,ok := c.K_v.LoadV(`直播保存位置Web服务`).(float64);ok && port_f >= 0 {
+               port := int(port_f)
+
                base_dir := ""
                if path,ok := c.K_v.LoadV(`直播流保存位置`).(string);ok && path !="" {
                        if path,err := filepath.Abs(path);err == nil{
                                base_dir = path+"/"
                        }
                }
+
+               addr := "0.0.0.0:"
+               if port == 0 {
+                       addr += strconv.Itoa(p.Sys().GetFreePort())
+               } else {
+                       addr += strconv.Itoa(port)
+               }
                s := web.New(&http.Server{
-                       Addr: "0.0.0.0:"+strconv.Itoa(p.Sys().GetFreePort()),
+                       Addr: addr,
                })
                s.Handle(map[string]func(http.ResponseWriter,*http.Request){
                        `/`:func(w http.ResponseWriter,r *http.Request){
@@ -962,37 +975,48 @@ func init() {
                                w.Header().Set("Access-Control-Allow-Origin", "*")
 
                                var path string = r.URL.Path[1:]
-                               if ext := filepath.Ext(path); ext == `.dtmp` {
+                               if filepath.Ext(path) == `.dtmp` || path == `now` {
+                                       //最新直播流
+                                       if path == `now` && saveflv.path != `` {
+                                               path = filepath.Base(saveflv.path)+".flv.dtmp"
+                                       }
+
                                        path = base_dir+path
 
                                        if !p.Checkfile().IsExist(path) {
-                                               w.WriteHeader(404)
+                                               w.WriteHeader(http.StatusNotFound)
                                                return
                                        }
 
-                                       byteC := make(chan []byte,1024*1024)
+                                       w.Header().Set("Connection", "Keep-Alive")
+                                       w.Header().Set("Content-Type", "video/x-flv")
+                                       w.Header().Set("X-Content-Type-Options", "nosniff")
+                                       w.WriteHeader(http.StatusOK)
+
+                                       byteC := make(chan []byte,1024*1024*10)
                                        cancel := make(chan struct{})
                                        defer close(cancel)
-                                       go func() {
+
+                                       go func(){
                                                if err := Stream(path,byteC,cancel);err != nil {
                                                        flog.Base_add(`直播Web服务`).L(`T: `,err);
                                                        return
                                                }
                                        }()
 
-                                       
-                                       var fastRespon = true
-                                       for {
-                                               buf := <- byteC
-                                               if len(buf) == 0 {break}
+                                       flusher, flushSupport := w.(http.Flusher);
+                                       if flushSupport {flusher.Flush()}
 
-                                               if _,err := w.Write(buf);err != nil {
-                                                       flog.Base_add(`直播Web服务`).L(`T: `,err);
+                                       var (
+                                               err error
+                                       )
+                                       for err == nil {
+                                               if b := <- byteC;len(b) != 0 {
+                                                       _,err = w.Write(b)
+                                               } else {
                                                        break
-                                               } else if fastRespon {
-                                                       fastRespon = false
-                                                       if flusher, flushSupport := w.(http.Flusher);flushSupport {flusher.Flush()}
                                                }
+                                               if flushSupport {flusher.Flush()}
                                        }
                                } else {
                                        http.FileServer(http.Dir(base_dir)).ServeHTTP(w,r)
index aacbac86a63d8432e5e4b1942a71693e0f8c7b24..9abdb8ace39f1285de80d0ab1909f0779cc89b9e 100644 (file)
@@ -2,9 +2,11 @@ package reply
 
 import (
        "os"
+       // "fmt"
        "bytes"
        "time"
        "errors"
+       // "math"
 
        c "github.com/qydysky/bili_danmu/CV"
        F "github.com/qydysky/bili_danmu/F"
@@ -21,17 +23,17 @@ const (
 
        //custom define
        eof_tag = byte(0x00)
-       copy_buf_size = 1024*1024*10
 )
 
 var (
        flv_header_sign = []byte{0x46,0x4c,0x56}
        flvlog = c.Log.Base(`flv解码`)
+       send_sign = []byte{0x00}
 )
 
 func Stream(path string,streamChan chan []byte,cancel chan struct{}) (error) {
-       flvlog.L(`I: `,path)
-       defer flvlog.L(`I: `,`退出`)
+       flvlog.L(`T: `,path)
+       defer flvlog.L(`T: `,`退出`)
        //file
        f,err := os.OpenFile(path,os.O_RDONLY,0644)
        if err != nil {
@@ -47,93 +49,161 @@ func Stream(path string,streamChan chan []byte,cancel chan struct{}) (error) {
        {
                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`)}
+               if bytes.Index(buf,flv_header_sign) != 0 {return errors.New(`no flv`)}
                streamChan <- buf
        }
 
+       type flv_tag struct {
+               Tag byte
+               Offset int64
+               Timestamp int32
+               PreSize int32
+               VideoFrame byte
+               Buf *[]byte
+       }
+
+       var seachtag = func(f *os.File)(offset int64){
+               cur_offset,_ := f.Seek(0,1)
+               defer f.Seek(cur_offset,0)
+
+               f.Seek(tag_header_size,1)
+               buf := make([]byte, 1024*1024)
+               for {
+                       if size,_ := f.Read(buf);size == 0 {
+                               return
+                       } else {
+                               for offset=0;offset<int64(size); {
+                                       streamid_loc := bytes.Index(buf[offset:], []byte{0x00,0x00,0x00})
+                                       if streamid_loc == -1 {break}
+                                       offset += int64(streamid_loc)
+
+                                       if tag_type := buf[offset-6];tag_type != video_tag && tag_type != audio_tag && tag_type != script_tag {
+                                               continue
+                                       }
+                                       offset += int64(tag_header_size-6)
+                                       return
+                               }
+                               f.Seek(-5,1)
+                       }
+               }
+       }
+
        //get tag func
-       var getTag = func(f *os.File)(tag byte,offset int64,buf_p *[]byte,data_p *[]byte){
+       var getTag = func(f *os.File)(t flv_tag){
+               t.Offset,_ = f.Seek(0,1)
+               Buf := []byte{}
+               t.Buf = &Buf
+
                buf := make([]byte, tag_header_size)
-               buf_p = &buf
-               if _,err := f.Read(buf);err != nil {tag = eof_tag;return}
-               tag = buf[0]
+               if size,err := f.Read(buf);err != nil || size == 0 {
+                       t.Tag = eof_tag
+                       return
+               }
+               Buf = append(Buf, buf...)
+               t.Tag = buf[0]
+               t.Timestamp = F.Btoi32([]byte{buf[7],buf[4],buf[5],buf[6]},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}
+               data := make([]byte, size)
+               if size,err := f.Read(data);err != nil || size == 0 {
+                       t.Tag = eof_tag
+                       return
+               }
+               t.VideoFrame = data[0]
+
+               pre_tag := make([]byte, previou_tag_size)
+               if size,err := f.Read(pre_tag);err != nil || size == 0 {
+                       t.Tag = eof_tag
+                       return
+               } 
+               t.PreSize = F.Btoi32(pre_tag,0)
                
-               offset,_ = f.Seek(0,1)
-               offset -= tag_header_size+int64(size)+previou_tag_size
+               Buf = append(Buf, append(data, pre_tag...)...)
+               // if t.PreSize == 0{fmt.Println(t.Tag,size,data[size:])}
+
                return
        }
 
        //get first video and audio tag
        //find last_keyframe_video_offset
-       var last_keyframe_video_offsets []int64
-       first_video_tag,first_audio_tag := false,false
+       var (
+               last_keyframe_video_offsets []int64
+               first_video_tag bool
+               first_audio_tag bool
+               // last_timestamps []int32
+       )
        for {
-               tag,offset,buf_p,data_p := getTag(f)
-               if tag == script_tag {
-                       streamChan <- *buf_p
-                       streamChan <- *data_p
-               } else if tag == video_tag {
+               t := getTag(f)
+               if t.Tag == script_tag {
+                       streamChan <- *t.Buf
+               } else if t.Tag == video_tag {
                        if !first_video_tag {
                                first_video_tag = true
-                               streamChan <- *buf_p
-                               streamChan <- *data_p
+                               streamChan <- *t.Buf
                        }
 
-                       if (*data_p)[0] & 0xf0 == 0x10 {
+                       if t.VideoFrame & 0xf0 == 0x10 {
                                if len(last_keyframe_video_offsets) > 2 {
-                                       last_keyframe_video_offsets = append(last_keyframe_video_offsets[1:], offset)
+                                       // last_timestamps = append(last_timestamps[1:], t.Timestamp)
+                                       last_keyframe_video_offsets = append(last_keyframe_video_offsets[1:], t.Offset)
                                } else {
-                                       last_keyframe_video_offsets = append(last_keyframe_video_offsets, offset)
+                                       // last_timestamps = append(last_timestamps, t.Timestamp)
+                                       last_keyframe_video_offsets = append(last_keyframe_video_offsets, t.Offset)
                                }
                        }
-               } else if tag == audio_tag {
+               } else if t.Tag == audio_tag {
                        if !first_audio_tag {
                                first_audio_tag = true
-                               streamChan <- *buf_p
-                               streamChan <- *data_p
+                               streamChan <- *t.Buf
                        }
-               } else {//eof_tag
+               } else {//eof_tag 
                        break;
                }
        }
 
        //seed to the second last tag
+       if len(last_keyframe_video_offsets) == 0 {flvlog.L(`W: `,`no keyframe`);return errors.New(`no keyframe`)}
        f.Seek(last_keyframe_video_offsets[0],0)
 
+
+       // var (
+       //      last_video_keyframe_timestramp int32
+       //      video_keyframe_speed int32
+       // )
        //copy
        {
-               buf := make([]byte, copy_buf_size)
-               preOffset,_ := f.Seek(0,1)
+               last_available_offset := last_keyframe_video_offsets[0]
+               // last_Timestamp := last_timestamps[0]
                for {
-
                        //退出
                        select {
                        case <-cancel:return nil;
                        default:;
                        }
-
-                       size,err := f.Read(buf)
-                       if err != nil {
-                               if err.Error() != `EOF` {
-                                       return err
-                               } else if offset,_ := f.Seek(0,1);offset == preOffset {
-                                       break
-                               }
-                       }
-
-                       if size > 0 {
-                               streamChan <- buf[:size]
-                       }
-
-                       if err != nil {
-                               preOffset,_ = f.Seek(0,1)
-                               time.Sleep(time.Duration(1) * time.Second)
+                       t := getTag(f)
+                       if t.Tag == eof_tag {
+                               f.Seek(last_available_offset,0)
+                               time.Sleep(time.Second)
+                               continue
+                       } else if t.PreSize == 0 {
+                               f.Seek(last_available_offset,0)
+                               f.Seek(seachtag(f),1)
+                               continue
+                       } else if t.Tag == video_tag {
+                               // if t.VideoFrame & 0xf0 == 0x10 {
+                               //      video_keyframe_speed = t.Timestamp - last_video_keyframe_timestramp
+                               //      fmt.Println(`video_keyframe_speed`,video_keyframe_speed)
+                               //      last_video_keyframe_timestramp = t.Timestamp
+                               // }
+                               streamChan <- *t.Buf
+                       } else if t.Tag == audio_tag {
+                               streamChan <- *t.Buf
+                       } else if t.Tag != script_tag {
+                               ;
                        }
+                       
+                       last_available_offset = t.Offset
 
                }
        }
index 2b0c7f0224a5fada112c8d2e01f6122c3ae12fd5..5e02930cc70fb8b13580777340d64e84b377e3dd 100644 (file)
@@ -46,7 +46,7 @@
     "直播流清晰度-help": "清晰度可选-1:不保存 0:默认 10000:原画 800:4K 401:蓝光(杜比) 400:蓝光 250:超清 150:高清 80:流畅,无提供所选清晰度时,使用低一档清晰度",
     "flv直播流清晰度": 150,
     "直播流保存位置": "./live",
-    "直播保存位置Web服务":true,
+    "直播保存位置Web服务":0,
     "ass-help": "只有保存直播流时才考虑生成ass",
     "生成Ass弹幕": true,
     "弹幕处理": "",