diff --git a/examples/open_probe_file.go b/examples/open_probe_file.go new file mode 100644 index 0000000..4960fdd --- /dev/null +++ b/examples/open_probe_file.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + "github.com/nareix/joy4/av" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/format" +) + +func init() { + format.RegisterAll() +} + +func main() { + file, _ := avutil.Open("projectindex.flv") + + streams, _ := file.Streams() + for _, stream := range streams { + if stream.Type().IsAudio() { + astream := stream.(av.AudioCodecData) + fmt.Println(astream.Type(), astream.SampleRate(), astream.SampleFormat(), astream.ChannelLayout()) + } else if stream.Type().IsVideo() { + vstream := stream.(av.VideoCodecData) + fmt.Println(vstream.Type(), vstream.Width(), vstream.Height()) + } + } + + for i := 0; i < 10; i++ { + var pkt av.Packet + var err error + if pkt, err = file.ReadPacket(); err != nil { + break + } + fmt.Println("pkt", i, streams[pkt.Idx].Type(), "len", len(pkt.Data), "keyframe", pkt.IsKeyFrame) + } + + file.Close() +} + diff --git a/examples/rtmp_publish.go b/examples/rtmp_publish.go new file mode 100644 index 0000000..4c39af8 --- /dev/null +++ b/examples/rtmp_publish.go @@ -0,0 +1,27 @@ +package main + +import ( + "github.com/nareix/joy4/av/pktque" + "github.com/nareix/joy4/format" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/format/rtmp" +) + +func init() { + format.RegisterAll() +} + +// as same as: ffmpeg -re -i projectindex.flv -c copy -f flv rtmp://localhost:1936/app/publish + +func main() { + file, _ := avutil.Open("projectindex.flv") + conn, _ := rtmp.Dial("rtmp://localhost:1936/app/publish") + // conn, _ := avutil.Create("rtmp://localhost:1936/app/publish") + + demuxer := &pktque.FilterDemuxer{Demuxer: file, Filter: &pktque.Walltime{}} + avutil.CopyFile(conn, demuxer) + + file.Close() + conn.Close() +} + diff --git a/examples/rtmp_server_channels.go b/examples/rtmp_server_channels.go new file mode 100644 index 0000000..dc3be4d --- /dev/null +++ b/examples/rtmp_server_channels.go @@ -0,0 +1,66 @@ +package main + +import ( + "sync" + "github.com/nareix/joy4/format" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/av/pubsub" + "github.com/nareix/joy4/format/rtmp" +) + +func init() { + format.RegisterAll() +} + +func main() { + server := &rtmp.Server{} + + l := &sync.RWMutex{} + type Channel struct { + que *pubsub.Queue + } + channels := map[string]*Channel{} + + server.HandlePlay = func(conn *rtmp.Conn) { + l.RLock() + ch := channels[conn.URL.Path] + l.RUnlock() + + if ch != nil { + cursor := ch.que.Latest() + avutil.CopyFile(conn, cursor) + } + } + + server.HandlePublish = func(conn *rtmp.Conn) { + streams, _ := conn.Streams() + + l.Lock() + ch := channels[conn.URL.Path] + if ch == nil { + ch = &Channel{} + ch.que = pubsub.NewQueue(streams) + channels[conn.URL.Path] = ch + } else { + ch = nil + } + l.Unlock() + if ch == nil { + return + } + + avutil.CopyPackets(ch.que, conn) + + l.Lock() + delete(channels, conn.URL.Path) + l.Unlock() + ch.que.Close() + } + + server.ListenAndServe() + + // ffmpeg -re -i movie.flv -c copy -f flv rtmp://localhost/movie + // ffmpeg -f avfoundation -i "0:0" .... -f flv rtmp://localhost/screen + // ffplay rtmp://localhost/movie + // ffplay rtmp://localhost/screen +} diff --git a/examples/rtmp_server_conv_audio.go b/examples/rtmp_server_conv_audio.go new file mode 100644 index 0000000..3f00b37 --- /dev/null +++ b/examples/rtmp_server_conv_audio.go @@ -0,0 +1,48 @@ +package main + +import ( + "github.com/nareix/joy4/av" + "github.com/nareix/joy4/av/transcode" + "github.com/nareix/joy4/format" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/format/rtmp" + "github.com/nareix/joy4/cgo/ffmpeg" +) + +// need ffmpeg with libspeex and libfdkaac installed +// +// open http://www.wowza.com/resources/4.4.1/examples/WebcamRecording/FlashRTMPPlayer11/player.html +// click connect and recored +// input camera H264/SPEEX will converted H264/AAC and saved in out.ts + +func init() { + format.RegisterAll() +} + +func main() { + server := &rtmp.Server{} + + server.HandlePublish = func(conn *rtmp.Conn) { + file, _ := avutil.Create("out.ts") + + findcodec := func(stream av.AudioCodecData, i int) (need bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) { + need = true + dec, _ = ffmpeg.NewAudioDecoder(stream) + enc, _ = ffmpeg.NewAudioEncoderByName("libfdk_aac") + enc.SetSampleRate(48000) + enc.SetChannelLayout(av.CH_STEREO) + return + } + + trans := &transcode.Demuxer{ + Options: transcode.Options{ + FindAudioDecoderEncoder: findcodec, + }, + Demuxer: conn, + } + + avutil.CopyFile(file, trans) + } + + server.ListenAndServe() +} diff --git a/examples/rtmp_server_gop_cache.go b/examples/rtmp_server_gop_cache.go new file mode 100644 index 0000000..a0143d5 --- /dev/null +++ b/examples/rtmp_server_gop_cache.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "time" + "github.com/nareix/joy4/format" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/av/pktque" + "github.com/nareix/joy4/av/pubsub" + "github.com/nareix/joy4/format/rtmp" +) + +func init() { + format.RegisterAll() +} + +func main() { + server := &rtmp.Server{} + + var que *pubsub.Queue + + go func() { + file, _ := avutil.Open("projectindex.flv") + streams, _ := file.Streams() + que = pubsub.NewQueue(streams) + demuxer := &pktque.FilterDemuxer{Demuxer: file, Filter: &pktque.Walltime{}} + avutil.CopyPackets(que, demuxer) + file.Close() + que.Close() + }() + + server.HandlePlay = func(conn *rtmp.Conn) { + cursor := que.Latest() + query := conn.URL.Query() + if q := query.Get("delaygop"); q != "" { + n := 0 + fmt.Sscanf(q, "%d", &n) + cursor = que.DelayedGopCount(n) + } else if q := query.Get("delaytime"); q != "" { + dur, _ := time.ParseDuration(q) + cursor = que.DelayedTime(dur) + } + demuxer := &pktque.FilterDemuxer{Demuxer: cursor, Filter: &pktque.WaitKeyFrame{}} + avutil.CopyFile(conn, demuxer) + } + + server.ListenAndServe() + + // ffplay rtmp://localhost/test.flv + // ffplay rtmp://localhost/test.flv?delaygop=2 + // ffplay rtmp://localhost/test.flv?delaytime=3s + // ffplay rtmp://localhost/test.flv?delaytime=10s +} + diff --git a/examples/rtmp_server_proxy.go b/examples/rtmp_server_proxy.go new file mode 100644 index 0000000..43fd20d --- /dev/null +++ b/examples/rtmp_server_proxy.go @@ -0,0 +1,29 @@ +package main + +import ( + "fmt" + "strings" + "github.com/nareix/joy4/format" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/format/rtmp" +) + +func init() { + format.RegisterAll() +} + +func main() { + server := &rtmp.Server{} + + server.HandlePlay = func(conn *rtmp.Conn) { + segs := strings.Split(conn.URL.Path, "/") + url := fmt.Sprintf("%s://%s", segs[1], strings.Join(segs[2:], "/")) + src, _ := avutil.Open(url) + avutil.CopyFile(conn, src) + } + + server.ListenAndServe() + + // ffplay rtmp://localhost/rtsp/192.168.1.1/camera1 + // ffplay rtmp://localhost/rtmp/live.hkstv.hk.lxdns.com/live/hks +} diff --git a/examples/transcode.go b/examples/transcode.go new file mode 100644 index 0000000..2910119 --- /dev/null +++ b/examples/transcode.go @@ -0,0 +1,45 @@ +package main + +import ( + "github.com/nareix/joy4/av" + "github.com/nareix/joy4/av/transcode" + "github.com/nareix/joy4/format" + "github.com/nareix/joy4/av/avutil" + "github.com/nareix/joy4/cgo/ffmpeg" +) + +// need ffmpeg with libfdkaac installed + +func init() { + format.RegisterAll() +} + +func main() { + infile, _ := avutil.Open("speex.flv") + + findcodec := func(stream av.AudioCodecData, i int) (need bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) { + need = true + dec, _ = ffmpeg.NewAudioDecoder(stream) + enc, _ = ffmpeg.NewAudioEncoderByName("libfdk_aac") + enc.SetSampleRate(stream.SampleRate()) + enc.SetChannelLayout(av.CH_STEREO) + enc.SetBitrate(12000) + enc.SetOption("profile", "HE-AACv2") + return + } + + trans := &transcode.Demuxer{ + Options: transcode.Options{ + FindAudioDecoderEncoder: findcodec, + }, + Demuxer: infile, + } + + outfile, _ := avutil.Create("out.ts") + avutil.CopyFile(outfile, trans) + + outfile.Close() + infile.Close() + trans.Close() +} +