|
|
|
@ -13,6 +13,8 @@ import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"os"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/q191201771/lal/pkg/logic"
|
|
|
|
@ -23,28 +25,77 @@ import (
|
|
|
|
|
log "github.com/q191201771/naza/pkg/nazalog"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
//rtmp推流客户端,输入是本地flv文件,文件推送完毕后,可循环推送(rtmp push流并不断开)
|
|
|
|
|
// rtmp 推流客户端,读取本地 flv 文件,使用 rtmp 协议推送出去
|
|
|
|
|
//
|
|
|
|
|
// -r 为1时表示当文件推送完毕后,是否循环推送(rtmp push流并不断开)
|
|
|
|
|
// 支持循环推送:文件推送完毕后,可循环推送(rtmp push 流并不断开)
|
|
|
|
|
// 支持推送多路流:相当于一个 rtmp 推流压测工具
|
|
|
|
|
//
|
|
|
|
|
// Usage:
|
|
|
|
|
// ./bin/flvfile2rtmppush -r 1 -i /tmp/test.flv -o rtmp://push.xxx.com/live/testttt
|
|
|
|
|
// Usage of ./bin/flvfile2rtmppush:
|
|
|
|
|
// -i string
|
|
|
|
|
// specify flv file
|
|
|
|
|
// -n int
|
|
|
|
|
// num of push connection (default 1)
|
|
|
|
|
// -o string
|
|
|
|
|
// specify rtmp push url
|
|
|
|
|
// -r recursive push if reach end of file
|
|
|
|
|
// -v show bin info
|
|
|
|
|
// Example:
|
|
|
|
|
// ./bin/flvfile2rtmppush -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test
|
|
|
|
|
// ./bin/flvfile2rtmppush -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test -r
|
|
|
|
|
// ./bin/flvfile2rtmppush -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test_{i} -r -n 1000
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
var err error
|
|
|
|
|
log.Info(bininfo.StringifySingleLine())
|
|
|
|
|
|
|
|
|
|
flvFileName, rtmpPushURL, isRecursive := parseFlag()
|
|
|
|
|
filename, urlTmpl, num, isRecursive := parseFlag()
|
|
|
|
|
urls := collect(urlTmpl, num)
|
|
|
|
|
|
|
|
|
|
log.Info(bininfo.StringifySingleLine())
|
|
|
|
|
tags := readAllTag(filename)
|
|
|
|
|
log.Debug(urls, num)
|
|
|
|
|
|
|
|
|
|
ps := rtmp.NewPushSession(func(option *rtmp.PushSessionOption) {
|
|
|
|
|
option.ConnectTimeoutMS = 3000
|
|
|
|
|
option.PushTimeoutMS = 5000
|
|
|
|
|
option.WriteAVTimeoutMS = 10000
|
|
|
|
|
})
|
|
|
|
|
err = ps.Push(rtmpPushURL)
|
|
|
|
|
push(tags, urls, isRecursive)
|
|
|
|
|
log.Info("bye.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// readAllTag 预读取 flv 文件中的所有 tag,缓存在内存中
|
|
|
|
|
func readAllTag(filename string) (ret []httpflv.Tag) {
|
|
|
|
|
var ffr httpflv.FLVFileReader
|
|
|
|
|
err := ffr.Open(filename)
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
log.Infof("push succ. url=%s", rtmpPushURL)
|
|
|
|
|
log.Infof("open succ. filename=%s", filename)
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
tag, err := ffr.ReadTag()
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
log.Info("EOF")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
ret = append(ret, tag)
|
|
|
|
|
}
|
|
|
|
|
log.Infof("read all tag done. num=%d", len(ret))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func push(tags []httpflv.Tag, urls []string, isRecursive bool) {
|
|
|
|
|
if len(tags) == 0 || len(urls) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
var psList []*rtmp.PushSession
|
|
|
|
|
|
|
|
|
|
for i := range urls {
|
|
|
|
|
ps := rtmp.NewPushSession(func(option *rtmp.PushSessionOption) {
|
|
|
|
|
option.ConnectTimeoutMS = 3000
|
|
|
|
|
option.PushTimeoutMS = 5000
|
|
|
|
|
option.WriteAVTimeoutMS = 10000
|
|
|
|
|
})
|
|
|
|
|
err = ps.Push(urls[i])
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
log.Infof("push succ. url=%s", urls[i])
|
|
|
|
|
psList = append(psList, ps)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var totalBaseTS uint32
|
|
|
|
|
var prevTS uint32
|
|
|
|
@ -58,21 +109,9 @@ func main() {
|
|
|
|
|
log.Infof(" > round. i=%d, totalBaseTS=%d, prevTS=%d, thisBaseTS=%d",
|
|
|
|
|
i, totalBaseTS, prevTS, thisBaseTS)
|
|
|
|
|
|
|
|
|
|
var ffr httpflv.FLVFileReader
|
|
|
|
|
err = ffr.Open(flvFileName)
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
log.Infof("open succ. filename=%s", flvFileName)
|
|
|
|
|
|
|
|
|
|
hasReadThisBaseTS = false
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
tag, err := ffr.ReadTag()
|
|
|
|
|
if err == io.EOF {
|
|
|
|
|
log.Info("EOF")
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
|
|
|
|
|
for _, tag := range tags {
|
|
|
|
|
h := logic.Trans.FLVTagHeader2RTMPHeader(tag.Header)
|
|
|
|
|
|
|
|
|
|
if tag.IsMetadata() {
|
|
|
|
@ -81,8 +120,10 @@ func main() {
|
|
|
|
|
//log.Debugf("CHEFERASEME write metadata.")
|
|
|
|
|
h.TimestampAbs = 0
|
|
|
|
|
chunks := rtmp.Message2Chunks(tag.Raw[11:11+h.MsgLen], &h)
|
|
|
|
|
err = ps.AsyncWrite(chunks)
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
for _, ps := range psList {
|
|
|
|
|
err = ps.AsyncWrite(chunks)
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// noop
|
|
|
|
|
}
|
|
|
|
@ -122,14 +163,15 @@ func main() {
|
|
|
|
|
hasTraceFirstTagTS = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = ps.AsyncWrite(chunks)
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
for _, ps := range psList {
|
|
|
|
|
err = ps.AsyncWrite(chunks)
|
|
|
|
|
log.FatalIfErrorNotNil(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prevTS = h.TimestampAbs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
totalBaseTS = prevTS + 1
|
|
|
|
|
ffr.Dispose()
|
|
|
|
|
|
|
|
|
|
if !isRecursive {
|
|
|
|
|
break
|
|
|
|
@ -137,11 +179,20 @@ func main() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseFlag() (string, string, bool) {
|
|
|
|
|
func collect(urlTmpl string, num int) (urls []string) {
|
|
|
|
|
for i := 0; i < num; i++ {
|
|
|
|
|
url := strings.Replace(urlTmpl, "{i}", strconv.Itoa(i), -1)
|
|
|
|
|
urls = append(urls, url)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseFlag() (filename string, urlTmpl string, num int, isRecursive bool) {
|
|
|
|
|
v := flag.Bool("v", false, "show bin info")
|
|
|
|
|
i := flag.String("i", "", "specify flv file")
|
|
|
|
|
o := flag.String("o", "", "specify rtmp push url")
|
|
|
|
|
r := flag.Bool("r", false, "recursive push if reach end of file")
|
|
|
|
|
n := flag.Int("n", 1, "num of push connection")
|
|
|
|
|
flag.Parse()
|
|
|
|
|
if *v {
|
|
|
|
|
_, _ = fmt.Fprint(os.Stderr, bininfo.StringifyMultiLine())
|
|
|
|
@ -149,7 +200,12 @@ func parseFlag() (string, string, bool) {
|
|
|
|
|
}
|
|
|
|
|
if *i == "" || *o == "" {
|
|
|
|
|
flag.Usage()
|
|
|
|
|
_, _ = fmt.Fprintf(os.Stderr, `Example:
|
|
|
|
|
./bin/flvfile2rtmppush -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test
|
|
|
|
|
./bin/flvfile2rtmppush -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test -r
|
|
|
|
|
./bin/flvfile2rtmppush -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test_{i} -r -n 1000
|
|
|
|
|
`)
|
|
|
|
|
os.Exit(1)
|
|
|
|
|
}
|
|
|
|
|
return *i, *o, *r
|
|
|
|
|
return *i, *o, *n, *r
|
|
|
|
|
}
|
|
|
|
|