//header
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Headers", "*")
- w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
+ w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Content-Transfer-Encoding", "binary")
}
if rpath != `/now/` {
- if v, ok := c.C.K_v.LoadV(`直播流保存位置`).(string); ok && v != "" {
+ if v, ok := c.C.K_v.LoadV(`直播流保存位置`).(string); !ok || v == "" {
+ w.Header().Set("Retry-After", "1")
+ w.WriteHeader(http.StatusServiceUnavailable)
+ flog.L(`W: `, `直播流保存位置无效`)
+ return
+ } else {
if strings.HasSuffix(v, "/") || strings.HasSuffix(v, "\\") {
v += rpath[1:]
} else {
}
if file.New(v+"0.flv", 0, true).IsExist() {
v += "0.flv"
+ w.Header().Set("Content-Type", "flv-application/octet-stream")
} else if file.New(v+"0.mp4", 0, true).IsExist() {
v += "0.mp4"
+ w.Header().Set("Content-Type", "video/mp4")
} else {
w.Header().Set("Retry-After", "1")
w.WriteHeader(http.StatusServiceUnavailable)
return
}
+ // 读取区间
var rangeHeaderNum int
- var e error
if rangeHeader := r.Header.Get(`range`); rangeHeader != "" {
+ var e error
if strings.Index(rangeHeader, "bytes=") != 0 {
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
flog.L(`W: `, `请求的范围不合法:仅支持bytes`)
w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)
flog.L(`W: `, `请求的范围不合法:`, e)
return
- } else if rangeHeaderNum != 0 {
- w.WriteHeader(http.StatusPartialContent)
}
}
- f := file.New(v, int64(rangeHeaderNum), false)
- defer f.Close()
-
// 直播流回放速率
var speed, _ = humanize.ParseBytes("1 M")
if rc, ok := c.C.K_v.LoadV(`直播流回放速率`).(string); ok {
if s, e := humanize.ParseBytes(rc); e != nil {
+ w.WriteHeader(http.StatusServiceUnavailable)
flog.L(`W: `, `直播流回放速率不合法:`, e)
+ return
} else {
speed = s
}
}
- go func() {
- flog.L(`T: `, r.RemoteAddr, `接入录播`, v)
- <-r.Context().Done()
- flog.L(`T: `, r.RemoteAddr, `断开录播`, v)
- }()
+ f := file.New(v, int64(rangeHeaderNum), false)
+ defer f.Close()
- if e := f.CopyToIoWriter(w, int64(speed), true); e != nil {
- flog.L(`E: `, e)
+ // 设置当前返回区间,并拷贝
+ if fi, e := f.Stat(); e != nil {
+ w.WriteHeader(http.StatusServiceUnavailable)
+ flog.L(`W: `, e)
+ return
+ } else {
+ var totalSec int64 = 10
+ allSize := fi.Size()
+ targetC := int64(rangeHeaderNum) + int64(speed)*totalSec
+ if allSize < targetC {
+ targetC = allSize
+ }
+ w.Header().Add(`Content-Range`, fmt.Sprintf("bytes %d-%d/%d", rangeHeaderNum, targetC, allSize))
+ w.WriteHeader(http.StatusPartialContent)
+ if e := f.CopyToIoWriterUntil(pweb.WithFlush(w), int64(speed), totalSec, true); e != nil {
+ flog.L(`E: `, e)
+ }
}
- } else {
- w.Header().Set("Retry-After", "1")
- w.WriteHeader(http.StatusServiceUnavailable)
- flog.L(`W: `, `直播流保存位置无效`)
}
return
}
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/qydysky/part v0.28.1-0.20230814074040-f9bfda2de89e h1:6/63PfGwQgzF+jDBVBUiiejRuORWqVsdc/HvN08FE0M=
-github.com/qydysky/part v0.28.1-0.20230814074040-f9bfda2de89e/go.mod h1:iOK6EzUOqdqTyQZm+pf1qxYpKvLmdK+YHZehNN/2J3U=
+github.com/qydysky/part v0.28.1-0.20230815161426-479a1258c761 h1:QF8corbhIb+PtiD0cBab/ejZBI8aflPKpEIK9NhHCyM=
+github.com/qydysky/part v0.28.1-0.20230815161426-479a1258c761/go.mod h1:iOK6EzUOqdqTyQZm+pf1qxYpKvLmdK+YHZehNN/2J3U=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=