You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/app/demo/pushrtmp/pushrtmp.go

179 lines
4.6 KiB
Go

// Copyright 2019, Chef. All rights reserved.
// https://github.com/q191201771/lal
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package main
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/q191201771/lal/pkg/base"
"github.com/q191201771/lal/pkg/remux"
"github.com/q191201771/lal/pkg/httpflv"
"github.com/q191201771/lal/pkg/rtmp"
"github.com/q191201771/naza/pkg/nazalog"
)
// RTMP推流客户端读取本地FLV文件使用RTMP协议推送出去
//
// 支持匀速推送:按照时间戳的间隔时间推送
// 支持循环推送文件推送完毕后可循环推送RTMP push 流并不断开)
// 支持推送多路流相当于一个RTMP推流压测工具
//
// 连接断开,内部并不做重试。当所有推流连接断开时,程序退出。
//
// Usage of ./bin/pushrtmp:
// -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/pushrtmp -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test
// ./bin/pushrtmp -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test -r
// ./bin/pushrtmp -i testdata/test.flv -o rtmp://127.0.0.1:19350/live/test_{i} -r -n 1000
var aliveSessionCount int32
func main() {
defer nazalog.Sync()
base.LogoutStartInfo()
filename, urlTmpl, num, isRecursive, logfile := parseFlag()
initLog(logfile)
urls := collect(urlTmpl, num)
tags, err := httpflv.ReadAllTagsFromFlvFile(filename)
if err != nil || len(tags) == 0 {
nazalog.Fatalf("read tags from flv file failed. len=%d, err=%+v", len(tags), err)
return
}
nazalog.Infof("read tags from flv file succ. len of tags=%d", len(tags))
go func() {
for {
nazalog.Debugf("alive session:%d", atomic.LoadInt32(&aliveSessionCount))
time.Sleep(1 * time.Second)
}
}()
var wg sync.WaitGroup
wg.Add(len(urls))
for _, url := range urls {
go func(u string) {
push(tags, u, isRecursive)
wg.Done()
atomic.AddInt32(&aliveSessionCount, -1)
}(url)
}
wg.Wait()
time.Sleep(1 * time.Second)
nazalog.Info("< main.")
}
func push(tags []httpflv.Tag, url string, isRecursive bool) {
ps := rtmp.NewPushSession(func(option *rtmp.PushSessionOption) {
option.PushTimeoutMs = 5000
option.WriteAvTimeoutMs = 10000
option.WriteBufSize = 0
option.WriteChanSize = 0
})
if err := ps.Push(url); err != nil {
nazalog.Errorf("push failed. err=%v", err)
return
}
atomic.AddInt32(&aliveSessionCount, 1)
nazalog.Infof("push succ. url=%s", url)
go func() {
flvFilePump := httpflv.NewFlvFilePump(func(option *httpflv.FlvFilePumpOption) {
option.IsRecursive = isRecursive
})
_ = flvFilePump.PumpWithTags(tags, func(tag httpflv.Tag) bool {
chunks := remux.FlvTag2RtmpChunks(tag)
if err := ps.Write(chunks); err != nil {
nazalog.Errorf("write data error. err=%v", err)
return false
}
return true
})
}()
// 临时测试一下主动关闭client session
//go func() {
// time.Sleep(5 * time.Second)
// nazalog.Debugf("> session Dispose.")
// err := ps.Dispose()
// nazalog.Debugf("< session Dispose. err=%+v", err)
//}()
err := <-ps.WaitChan()
nazalog.Infof("< session WaitChan. err=%+v", err)
}
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 initLog(logfile string) {
if logfile != "" {
err := nazalog.Init(func(option *nazalog.Option) {
option.IsRotateDaily = false
option.Filename = logfile
option.IsToStdout = false
})
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "init nazalog failed. err=%+v", err)
os.Exit(1)
}
} else {
_ = nazalog.Init(func(option *nazalog.Option) {
option.AssertBehavior = nazalog.AssertFatal
})
}
}
func parseFlag() (filename string, urlTmpl string, num int, isRecursive bool, logfile string) {
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")
l := flag.String("l", "", "specify log file")
flag.Parse()
if *i == "" || *o == "" {
flag.Usage()
_, _ = fmt.Fprintf(os.Stderr, `Example:
%s -i test.flv -o rtmp://127.0.0.1:1935/live/test
%s -i test.flv -o rtmp://127.0.0.1:1935/live/test -r
%s -i test.flv -o rtmp://127.0.0.1:1935/live/test_{i} -r -n 1000
`, os.Args[0], os.Args[0], os.Args[0])
base.OsExitAndWaitPressIfWindows(1)
}
return *i, *o, *n, *r, *l
}