Improve HLS reader
This commit is contained in:
+35
-25
@@ -2,7 +2,6 @@ package hls
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -16,6 +15,7 @@ type reader struct {
|
|||||||
client *http.Client
|
client *http.Client
|
||||||
request *http.Request
|
request *http.Request
|
||||||
|
|
||||||
|
playlist []byte
|
||||||
lastSegment []byte
|
lastSegment []byte
|
||||||
lastTime time.Time
|
lastTime time.Time
|
||||||
|
|
||||||
@@ -28,18 +28,22 @@ func NewReader(u *url.URL, body io.ReadCloser) (io.Reader, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rawURL string
|
||||||
|
|
||||||
re := regexp.MustCompile(`#EXT-X-STREAM-INF.+?\n(\S+)`)
|
re := regexp.MustCompile(`#EXT-X-STREAM-INF.+?\n(\S+)`)
|
||||||
m := re.FindSubmatch(b)
|
m := re.FindSubmatch(b)
|
||||||
if m == nil {
|
if m != nil {
|
||||||
return nil, errors.New("hls: wrong playlist: " + string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
ref, err := url.Parse(string(m[1]))
|
ref, err := url.Parse(string(m[1]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", u.ResolveReference(ref).String(), nil)
|
rawURL = u.ResolveReference(ref).String()
|
||||||
|
} else {
|
||||||
|
rawURL = u.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", rawURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -75,7 +79,8 @@ func (r *reader) Read(dst []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *reader) getSegment() ([]byte, error) {
|
func (r *reader) getSegment() ([]byte, error) {
|
||||||
for {
|
for i := 0; i < 5; i++ {
|
||||||
|
if r.playlist == nil {
|
||||||
if wait := time.Second - time.Since(r.lastTime); wait > 0 {
|
if wait := time.Second - time.Since(r.lastTime); wait > 0 {
|
||||||
time.Sleep(wait)
|
time.Sleep(wait)
|
||||||
}
|
}
|
||||||
@@ -86,37 +91,40 @@ func (r *reader) getSegment() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist, err := io.ReadAll(res.Body)
|
r.playlist, err = io.ReadAll(res.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.lastTime = time.Now()
|
r.lastTime = time.Now()
|
||||||
|
|
||||||
//log.Printf("[hls] load playlist\n%s", playlist)
|
//log.Printf("[hls] load playlist\n%s", r.playlist)
|
||||||
|
}
|
||||||
// 2. Remove all previous segments from playlist
|
|
||||||
if i := bytes.Index(playlist, r.lastSegment); i > 0 {
|
for r.playlist != nil {
|
||||||
playlist = playlist[i:]
|
// 2. Remove all previous segments from playlist
|
||||||
|
if i := bytes.Index(r.playlist, r.lastSegment); i > 0 {
|
||||||
|
r.playlist = r.playlist[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
for playlist != nil {
|
|
||||||
// 3. Get link to new segment
|
// 3. Get link to new segment
|
||||||
var segment []byte
|
segment := getSegment(r.playlist)
|
||||||
if segment, playlist = getSegment(playlist); segment == nil {
|
if segment == nil {
|
||||||
|
r.playlist = nil
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
//log.Printf("[hls] load segment: %s", segment)
|
//log.Printf("[hls] load segment: %s", segment)
|
||||||
|
|
||||||
ref, err2 := url.Parse(string(segment))
|
ref, err := url.Parse(string(segment))
|
||||||
if err2 != nil {
|
if err != nil {
|
||||||
return nil, err2
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ref = r.request.URL.ResolveReference(ref)
|
ref = r.request.URL.ResolveReference(ref)
|
||||||
if res, err2 = r.client.Get(ref.String()); err2 != nil {
|
res, err := r.client.Get(ref.String())
|
||||||
return nil, err2
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.lastSegment = segment
|
r.lastSegment = segment
|
||||||
@@ -124,23 +132,25 @@ func (r *reader) getSegment() ([]byte, error) {
|
|||||||
return io.ReadAll(res.Body)
|
return io.ReadAll(res.Body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil, io.EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSegment(src []byte) (segment, left []byte) {
|
func getSegment(src []byte) []byte {
|
||||||
for ok := false; !ok; {
|
for ok := false; !ok; {
|
||||||
ok = bytes.HasPrefix(src, []byte("#EXTINF"))
|
ok = bytes.HasPrefix(src, []byte("#EXTINF"))
|
||||||
|
|
||||||
i := bytes.IndexByte(src, '\n') + 1
|
i := bytes.IndexByte(src, '\n') + 1
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
src = src[i:]
|
src = src[i:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if i := bytes.IndexByte(src, '\n'); i > 0 {
|
if i := bytes.IndexByte(src, '\n'); i > 0 {
|
||||||
return src[:i], src[i+1:]
|
return src[:i]
|
||||||
}
|
}
|
||||||
|
|
||||||
return src, nil
|
return src
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user