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
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)
}
}()
+
+ var fastRespon = true
for {
buf := <- byteC
if len(buf) == 0 {break}
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()}
}
}
}
"bytes"
"time"
"errors"
+ "path/filepath"
c "github.com/qydysky/bili_danmu/CV"
F "github.com/qydysky/bili_danmu/F"
//custom define
eof_tag = byte(0x00)
- copy_buf_size = 1024*1024
+ copy_buf_size = 1024*1024*10
)
var (
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 {
//退出
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)
+ }
+
}
}