Files
monibuca/plugin/hdl/pkg/pull.go
2024-04-12 17:48:26 +08:00

120 lines
2.7 KiB
Go

package hdl
import (
"bufio"
"errors"
"io"
"net/http"
"net/url"
"os"
"strings"
"m7s.live/m7s/v5"
"m7s.live/m7s/v5/pkg/util"
rtmp "m7s.live/m7s/v5/plugin/rtmp/pkg"
)
type HDLPuller struct {
*bufio.Reader
absTS uint32 //绝对时间戳
pool *util.ScalableMemoryAllocator
}
func NewHDLPuller() *HDLPuller {
return &HDLPuller{
pool: util.NewScalableMemoryAllocator(1024),
}
}
func (puller *HDLPuller) Connect(p *m7s.Puller) (err error) {
if strings.HasPrefix(p.RemoteURL, "http") {
var res *http.Response
client := http.DefaultClient
if proxyConf := p.GetPullConfig().Proxy; proxyConf != "" {
proxy, err := url.Parse(proxyConf)
if err != nil {
return err
}
transport := &http.Transport{Proxy: http.ProxyURL(proxy)}
client = &http.Client{Transport: transport}
}
if res, err = client.Get(p.RemoteURL); err == nil {
if res.StatusCode != http.StatusOK {
return io.EOF
}
p.Closer = res.Body
puller.Reader = bufio.NewReader(res.Body)
}
} else {
var res *os.File
if res, err = os.Open(p.RemoteURL); err == nil {
p.Closer = res
puller.Reader = bufio.NewReader(res)
}
}
if err == nil {
header := puller.pool.Malloc(13)
defer puller.pool.Free(header)
if _, err = io.ReadFull(puller, header); err == nil {
if header[0] != 'F' || header[1] != 'L' || header[2] != 'V' {
err = errors.New("not flv file")
} else {
configCopy := p.GetPublishConfig()
if header[4]&0x04 == 0 {
configCopy.PubAudio = false
}
if header[4]&0x01 == 0 {
configCopy.PubVideo = false
}
}
}
}
return
}
func (puller *HDLPuller) Pull(p *m7s.Puller) (err error) {
var startTs uint32
var buf15 [15]byte
pubaudio, pubvideo := p.GetPublishConfig().PubAudio, p.GetPublishConfig().PubVideo
for offsetTs := puller.absTS; err == nil; _, err = io.ReadFull(puller, buf15[11:]) {
tmp := util.Buffer(buf15[:11])
_, err = io.ReadFull(puller, tmp)
if err != nil {
return
}
t := tmp.ReadByte()
dataSize := tmp.ReadUint24()
timestamp := tmp.ReadUint24() | uint32(tmp.ReadByte())<<24
if startTs == 0 {
startTs = timestamp
}
tmp.ReadUint24()
var frame rtmp.RTMPData
frame.ScalableMemoryAllocator = puller.pool
mem := frame.Malloc(int(dataSize))
_, err = io.ReadFull(puller, mem)
if err != nil {
frame.Recycle()
return
}
frame.ReadFromBytes(mem)
puller.absTS = offsetTs + (timestamp - startTs)
frame.Timestamp = puller.absTS
// fmt.Println(t, offsetTs, timestamp, startTs, puller.absTS)
switch t {
case FLV_TAG_TYPE_AUDIO:
if pubaudio {
p.WriteAudio(&rtmp.RTMPAudio{frame})
}
case FLV_TAG_TYPE_VIDEO:
if pubvideo {
p.WriteVideo(&rtmp.RTMPVideo{frame})
}
case FLV_TAG_TYPE_SCRIPT:
p.Info("script", "data", mem)
frame.Recycle()
}
}
return
}