// Copyright 2020, 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" "time" "github.com/q191201771/lal/pkg/rtmp" "github.com/q191201771/lal/pkg/base" "github.com/q191201771/lal/pkg/remux" "github.com/q191201771/lal/pkg/rtprtcp" "github.com/q191201771/lal/pkg/rtsp" "github.com/q191201771/naza/pkg/nazalog" ) var pushSession *rtmp.PushSession type Observer struct { } func (o *Observer) OnRTPPacket(pkt rtprtcp.RTPPacket) { // noop } func (o *Observer) OnAVConfig(asc, vps, sps, pps []byte) { metadata, ash, vsh, err := remux.AVConfig2RTMPMsg(asc, vps, sps, pps) nazalog.Assert(nil, err) err = pushSession.AsyncWrite(rtmp.Message2Chunks(metadata.Payload, &metadata.Header)) nazalog.Assert(nil, err) if ash != nil { err = pushSession.AsyncWrite(rtmp.Message2Chunks(ash.Payload, &ash.Header)) nazalog.Assert(nil, err) } if vsh != nil { err = pushSession.AsyncWrite(rtmp.Message2Chunks(vsh.Payload, &vsh.Header)) nazalog.Assert(nil, err) } } func (o *Observer) OnAVPacket(pkt base.AVPacket) { msg, err := remux.AVPacket2RTMPMsg(pkt) nazalog.Assert(nil, err) err = pushSession.AsyncWrite(rtmp.Message2Chunks(msg.Payload, &msg.Header)) nazalog.Assert(nil, err) } func main() { _ = nazalog.Init(func(option *nazalog.Option) { option.AssertBehavior = nazalog.AssertFatal }) defer nazalog.Sync() inURL, outURL, overTCP := parseFlag() pushSession = rtmp.NewPushSession(func(option *rtmp.PushSessionOption) { option.PushTimeoutMS = 5000 option.WriteAVTimeoutMS = 5000 }) err := pushSession.Push(outURL) nazalog.Assert(nil, err) defer pushSession.Dispose() o := &Observer{} pullSession := rtsp.NewPullSession(o, func(option *rtsp.PullSessionOption) { option.PullTimeoutMS = 5000 option.OverTCP = overTCP != 0 }) err = pullSession.Pull(inURL) nazalog.Assert(nil, err) defer pullSession.Dispose() go func() { for { pullSession.UpdateStat(1) pullStat := pullSession.GetStat() pushSession.UpdateStat(1) pushStat := pushSession.GetStat() nazalog.Debugf("stat. pull=%+v, push=%+v", pullStat, pushStat) time.Sleep(1 * time.Second) } }() select { case err = <-pullSession.Wait(): nazalog.Infof("< pullSession.Wait(). err=%+v", err) time.Sleep(1 * time.Second) return case err = <-pushSession.Wait(): nazalog.Infof("< pushSession.Wait(). err=%+v", err) time.Sleep(1 * time.Second) return } } func parseFlag() (inURL string, outFilename string, overTCP int) { i := flag.String("i", "", "specify pull rtsp url") o := flag.String("o", "", "specify push rtmp url") t := flag.Int("t", 0, "specify interleaved mode(rtp/rtcp over tcp)") flag.Parse() if *i == "" || *o == "" { flag.Usage() _, _ = fmt.Fprintf(os.Stderr, `Example: %s -i rtsp://localhost:5544/live/test110 -o rtmp://localhost:19350/live/test220 -t 0 %s -i rtsp://localhost:5544/live/test110 -o rtmp://localhost:19350/live/test220 -t 1 `, os.Args[0], os.Args[0]) base.OSExitAndWaitPressIfWindows(1) } return *i, *o, *t }