├── go.sum ├── go.mod ├── .gitignore ├── examples ├── rtmpserver │ └── main.go ├── rtmppusher │ └── main.go ├── rtmp-bench │ └── main.go ├── rtmppushplay │ └── main.go ├── rtmp-pull │ └── main.go ├── rtmp-relay │ └── main.go ├── transcode │ └── main.go └── rtmp-to-http-flv │ └── main.go ├── README.md ├── av ├── timeline.go └── av.go ├── pubsub ├── buf.go └── queue.go ├── bits └── bits.go ├── pio └── pio.go ├── flv ├── amf0.go └── flv.go ├── aac └── parser.go ├── h264 └── parser.go ├── audio └── audio.go └── rtmp.go /go.sum: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/notedit/rtmp-lib 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | *.flv 15 | 16 | .vscode/ 17 | 18 | .idea/ 19 | 20 | .DS_Store 21 | -------------------------------------------------------------------------------- /examples/rtmpserver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | rtmp "github.com/notedit/rtmp-lib" 7 | ) 8 | 9 | func main() { 10 | 11 | server := &rtmp.Server{} 12 | 13 | server.HandlePublish = func(conn *rtmp.Conn) { 14 | 15 | for { 16 | packet, err := conn.ReadPacket() 17 | if err != nil { 18 | break 19 | } 20 | fmt.Println(packet.Time) 21 | } 22 | } 23 | 24 | server.ListenAndServe() 25 | 26 | } 27 | -------------------------------------------------------------------------------- /examples/rtmppusher/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | rtmp "github.com/notedit/rtmp-lib" 7 | "github.com/notedit/rtmp-lib/flv" 8 | ) 9 | 10 | func main() { 11 | 12 | file, err := os.Open("test.flv") 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | conn, _ := rtmp.Dial("rtmp://localhost/app/publish") 18 | 19 | demuxer := flv.NewDemuxer(file)Z 20 | 21 | streams, err := demuxer.Streams() 22 | 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | err = conn.WriteHeader(streams) 28 | 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | for { 34 | 35 | packet, err := demuxer.ReadPacket() 36 | 37 | if err != nil { 38 | break 39 | } 40 | conn.WritePacket(packet) 41 | } 42 | 43 | conn.WriteTrailer() 44 | } 45 | -------------------------------------------------------------------------------- /examples/rtmp-bench/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | rtmp "github.com/notedit/rtmp-lib" 7 | ) 8 | 9 | var ( 10 | stream string 11 | number int 12 | ) 13 | 14 | func pullstream(url string, index int) error { 15 | 16 | conn, _ := rtmp.Dial(url) 17 | 18 | _, err := conn.Streams() 19 | 20 | if err != nil { 21 | return err 22 | } 23 | 24 | go func() { 25 | for { 26 | _, err := conn.ReadPacket() 27 | if err != nil { 28 | break 29 | } 30 | } 31 | 32 | fmt.Printf("stream %d finished\n", index) 33 | }() 34 | 35 | return nil 36 | 37 | } 38 | 39 | func main() { 40 | 41 | flag.StringVar(&stream, "stream", "rtmp://localhost/live/live", "stream url") 42 | flag.IntVar(&number, "number", 100, "number stream to play") 43 | flag.Parse() 44 | 45 | for i := 0; i < number; i++ { 46 | pullstream(stream, i) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rtmp-lib 2 | 3 | 4 | make a clean golang rtmp lib 5 | 6 | 7 | 8 | ## Examples 9 | 10 | - [rtmp-to-http-flv](https://github.com/notedit/rtmp-lib/tree/master/examples/rtmp-to-http-flv): rtmp push and http-flv play 11 | - [rtmppusher](https://github.com/notedit/rtmp-lib/tree/master/examples/rtmppusher): push flv time to rtmp server 12 | - [rtmppushplay](https://github.com/notedit/rtmp-lib/tree/master/examples/rtmppushplay): rtmp push and rtmp play 13 | - [rtmpserver](https://github.com/notedit/rtmp-lib/tree/master/examples/rtmpserver): simple rtmp server 14 | - [rtmp-pull](https://github.com/notedit/rtmp-lib/tree/master/examples/rtmp-pull) rtmp pull from remote stream 15 | - [rtmp-relay](https://github.com/notedit/rtmp-lib/tree/master/examples/rtmp-relay) rtmp relay one stream to another stream 16 | - [rtmp-bench](https://github.com/notedit/rtmp-lib/tree/master/examples/rtmp-bench) rtmp bench tools 17 | 18 | 19 | ## Thanks 20 | 21 | - [joy4](https://github.com/nareix/joy4) 22 | 23 | -------------------------------------------------------------------------------- /examples/rtmppushplay/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/notedit/rtmp-lib/av" 6 | "time" 7 | 8 | rtmp "github.com/notedit/rtmp-lib" 9 | ) 10 | 11 | 12 | var pubstream *rtmp.Conn 13 | var playstream *rtmp.Conn 14 | 15 | var start bool 16 | 17 | func main() { 18 | 19 | config := &rtmp.Config{ 20 | ChunkSize: 128, 21 | BufferSize: 0, 22 | } 23 | server := rtmp.NewServer(config) 24 | 25 | //rtmp.Debug = true 26 | 27 | server.HandlePlay = func(conn *rtmp.Conn) { 28 | 29 | playstream = conn 30 | 31 | streams,_ := pubstream.Streams() 32 | playstream.WriteHeader(streams) 33 | 34 | 35 | for { 36 | time.Sleep(time.Second) 37 | } 38 | } 39 | 40 | server.HandlePublish = func(conn *rtmp.Conn) { 41 | 42 | pubstream = conn 43 | 44 | _, err := conn.Streams() 45 | if err != nil { 46 | panic(err) 47 | } 48 | 49 | for { 50 | var pkt av.Packet 51 | if pkt, err = conn.ReadPacket(); err != nil { 52 | break 53 | } 54 | 55 | if playstream != nil { 56 | playstream.WritePacket(pkt) 57 | } 58 | 59 | fmt.Println("publish ", pkt.Time) 60 | } 61 | } 62 | 63 | server.ListenAndServe() 64 | 65 | } 66 | -------------------------------------------------------------------------------- /av/timeline.go: -------------------------------------------------------------------------------- 1 | package av 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | /* 8 | pop push 9 | seg seg seg 10 | |--------| |---------| |---| 11 | 20ms 40ms 5ms 12 | ----------------- time --------------------> 13 | headtm tailtm 14 | */ 15 | 16 | type tlSeg struct { 17 | tm, dur time.Duration 18 | } 19 | 20 | type Timeline struct { 21 | segs []tlSeg 22 | headtm time.Duration 23 | } 24 | 25 | func (self *Timeline) Push(tm time.Duration, dur time.Duration) { 26 | if len(self.segs) > 0 { 27 | tail := self.segs[len(self.segs)-1] 28 | diff := tm-(tail.tm+tail.dur) 29 | if diff < 0 { 30 | tm -= diff 31 | } 32 | } 33 | self.segs = append(self.segs, tlSeg{tm, dur}) 34 | } 35 | 36 | func (self *Timeline) Pop(dur time.Duration) (tm time.Duration) { 37 | if len(self.segs) == 0 { 38 | return self.headtm 39 | } 40 | 41 | tm = self.segs[0].tm 42 | for dur > 0 && len(self.segs) > 0 { 43 | seg := &self.segs[0] 44 | sub := dur 45 | if seg.dur < sub { 46 | sub = seg.dur 47 | } 48 | seg.dur -= sub 49 | dur -= sub 50 | seg.tm += sub 51 | self.headtm += sub 52 | if seg.dur == 0 { 53 | copy(self.segs[0:], self.segs[1:]) 54 | self.segs = self.segs[:len(self.segs)-1] 55 | } 56 | } 57 | 58 | return 59 | } 60 | -------------------------------------------------------------------------------- /pubsub/buf.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "github.com/notedit/rtmp-lib/av" 5 | ) 6 | 7 | type Buf struct { 8 | Head, Tail BufPos 9 | pkts []av.Packet 10 | Size int 11 | Count int 12 | } 13 | 14 | func NewBuf() *Buf { 15 | return &Buf{ 16 | pkts: make([]av.Packet, 64), 17 | } 18 | } 19 | 20 | func (self *Buf) Pop() av.Packet { 21 | if self.Count == 0 { 22 | panic("pktque.Buf: Pop() when count == 0") 23 | } 24 | 25 | i := int(self.Head) & (len(self.pkts) - 1) 26 | pkt := self.pkts[i] 27 | self.pkts[i] = av.Packet{} 28 | self.Size -= len(pkt.Data) 29 | self.Head++ 30 | self.Count-- 31 | 32 | return pkt 33 | } 34 | 35 | func (self *Buf) grow() { 36 | newpkts := make([]av.Packet, len(self.pkts)*2) 37 | for i := self.Head; i.LT(self.Tail); i++ { 38 | newpkts[int(i)&(len(newpkts)-1)] = self.pkts[int(i)&(len(self.pkts)-1)] 39 | } 40 | self.pkts = newpkts 41 | } 42 | 43 | func (self *Buf) Push(pkt av.Packet) { 44 | if self.Count == len(self.pkts) { 45 | self.grow() 46 | } 47 | self.pkts[int(self.Tail)&(len(self.pkts)-1)] = pkt 48 | self.Tail++ 49 | self.Count++ 50 | self.Size += len(pkt.Data) 51 | } 52 | 53 | func (self *Buf) Get(pos BufPos) av.Packet { 54 | return self.pkts[int(pos)&(len(self.pkts)-1)] 55 | } 56 | 57 | func (self *Buf) IsValidPos(pos BufPos) bool { 58 | return pos.GE(self.Head) && pos.LT(self.Tail) 59 | } 60 | 61 | type BufPos int 62 | 63 | func (self BufPos) LT(pos BufPos) bool { 64 | return self-pos < 0 65 | } 66 | 67 | func (self BufPos) GE(pos BufPos) bool { 68 | return self-pos >= 0 69 | } 70 | 71 | func (self BufPos) GT(pos BufPos) bool { 72 | return self-pos > 0 73 | } 74 | -------------------------------------------------------------------------------- /examples/rtmp-pull/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "sync" 7 | 8 | "github.com/notedit/rtmp-lib/av" 9 | 10 | rtmp "github.com/notedit/rtmp-lib" 11 | "github.com/notedit/rtmp-lib/pubsub" 12 | ) 13 | 14 | type Channel struct { 15 | que *pubsub.Queue 16 | } 17 | 18 | var channels = map[string]*Channel{} 19 | 20 | func pullStream(url *url.URL) { 21 | 22 | fmt.Println(url.String()) 23 | 24 | conn, _ := rtmp.Dial(url.String()) 25 | 26 | _, err := conn.Streams() 27 | 28 | if err != nil { 29 | panic("got streams") 30 | } 31 | 32 | for { 33 | packet, err := conn.ReadPacket() 34 | if err != nil { 35 | break 36 | } 37 | fmt.Println("got packet", packet.IsKeyFrame) 38 | } 39 | 40 | } 41 | 42 | func main() { 43 | 44 | l := &sync.RWMutex{} 45 | 46 | server := &rtmp.Server{} 47 | 48 | server.HandlePlay = func(conn *rtmp.Conn) { 49 | 50 | l.RLock() 51 | ch := channels[conn.URL.Path] 52 | l.RUnlock() 53 | 54 | if ch != nil { 55 | 56 | cursor := ch.que.Latest() 57 | 58 | streams, err := cursor.Streams() 59 | 60 | if err != nil { 61 | panic(err) 62 | } 63 | 64 | conn.WriteHeader(streams) 65 | 66 | for { 67 | packet, err := cursor.ReadPacket() 68 | if err != nil { 69 | break 70 | } 71 | conn.WritePacket(packet) 72 | } 73 | } 74 | } 75 | 76 | server.HandlePublish = func(conn *rtmp.Conn) { 77 | 78 | l.Lock() 79 | ch := channels[conn.URL.Path] 80 | 81 | if ch == nil { 82 | ch = &Channel{} 83 | ch.que = pubsub.NewQueue() 84 | ch.que.SetMaxGopCount(1) 85 | channels[conn.URL.Path] = ch 86 | } 87 | l.Unlock() 88 | 89 | var streams []av.CodecData 90 | var err error 91 | 92 | if streams, err = conn.Streams(); err != nil { 93 | panic(err) 94 | } 95 | 96 | ch.que.WriteHeader(streams) 97 | 98 | go pullStream(conn.URL) 99 | 100 | for { 101 | var pkt av.Packet 102 | if pkt, err = conn.ReadPacket(); err != nil { 103 | break 104 | } 105 | 106 | ch.que.WritePacket(pkt) 107 | } 108 | 109 | l.Lock() 110 | delete(channels, conn.URL.Path) 111 | l.Unlock() 112 | 113 | ch.que.Close() 114 | 115 | } 116 | 117 | server.ListenAndServe() 118 | 119 | } 120 | -------------------------------------------------------------------------------- /examples/rtmp-relay/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | 7 | "github.com/notedit/rtmp-lib/av" 8 | 9 | rtmp "github.com/notedit/rtmp-lib" 10 | "github.com/notedit/rtmp-lib/pubsub" 11 | ) 12 | 13 | type Channel struct { 14 | que *pubsub.Queue 15 | } 16 | 17 | var channels = map[string]*Channel{} 18 | 19 | func relay(pullUrl string, conn *rtmp.Conn) { 20 | 21 | fmt.Println(pullUrl) 22 | 23 | pull, _ := rtmp.Dial(pullUrl) 24 | 25 | streams, err := pull.Streams() 26 | 27 | if err != nil { 28 | panic("got streams") 29 | } 30 | 31 | conn.WriteHeader(streams) 32 | 33 | for { 34 | packet, err := pull.ReadPacket() 35 | if err != nil { 36 | break 37 | } 38 | 39 | err = conn.WritePacket(packet) 40 | 41 | if err != nil { 42 | panic(err) 43 | } 44 | } 45 | } 46 | 47 | func main() { 48 | 49 | l := &sync.RWMutex{} 50 | 51 | server := &rtmp.Server{} 52 | 53 | server.HandlePlay = func(conn *rtmp.Conn) { 54 | 55 | l.RLock() 56 | ch := channels[conn.URL.Path] 57 | l.RUnlock() 58 | 59 | // stream1 60 | if ch != nil { 61 | 62 | cursor := ch.que.Latest() 63 | 64 | streams, err := cursor.Streams() 65 | 66 | if err != nil { 67 | panic(err) 68 | } 69 | 70 | conn.WriteHeader(streams) 71 | 72 | for { 73 | packet, err := cursor.ReadPacket() 74 | if err != nil { 75 | break 76 | } 77 | conn.WritePacket(packet) 78 | } 79 | } else { 80 | // stream2 81 | relay("rtmp://localhost/live/stream1", conn) 82 | } 83 | } 84 | 85 | server.HandlePublish = func(conn *rtmp.Conn) { 86 | 87 | l.Lock() 88 | ch := channels[conn.URL.Path] 89 | 90 | if ch == nil { 91 | ch = &Channel{} 92 | ch.que = pubsub.NewQueue() 93 | ch.que.SetMaxGopCount(1) 94 | channels[conn.URL.Path] = ch 95 | } 96 | l.Unlock() 97 | 98 | var streams []av.CodecData 99 | var err error 100 | 101 | if streams, err = conn.Streams(); err != nil { 102 | panic(err) 103 | } 104 | 105 | ch.que.WriteHeader(streams) 106 | 107 | for { 108 | var pkt av.Packet 109 | if pkt, err = conn.ReadPacket(); err != nil { 110 | break 111 | } 112 | 113 | ch.que.WritePacket(pkt) 114 | } 115 | 116 | l.Lock() 117 | delete(channels, conn.URL.Path) 118 | l.Unlock() 119 | 120 | ch.que.Close() 121 | 122 | } 123 | 124 | server.ListenAndServe() 125 | 126 | } 127 | -------------------------------------------------------------------------------- /examples/transcode/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | _ "github.com/notedit/rtmp-lib/aac" 6 | "github.com/notedit/rtmp-lib/audio" 7 | "github.com/notedit/rtmp-lib/av" 8 | "os" 9 | 10 | rtmp "github.com/notedit/rtmp-lib" 11 | ) 12 | 13 | 14 | 15 | 16 | func main() { 17 | 18 | server := &rtmp.Server{} 19 | 20 | server.HandlePublish = func(conn *rtmp.Conn) { 21 | 22 | file, err := os.Create("test.opus") 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | streams,err := conn.Streams() 28 | 29 | 30 | var enc av.AudioEncoder 31 | var dec av.AudioDecoder 32 | 33 | var adecodec av.AudioCodecData 34 | 35 | for _,stream := range streams { 36 | if stream.Type().IsAudio() { 37 | adecodec = stream.(av.AudioCodecData) 38 | dec, _ = audio.NewAudioDecoderByName("aac") 39 | dec.SetSampleRate(adecodec.SampleRate()) 40 | dec.SetSampleFormat(av.S16) 41 | dec.SetChannelLayout(adecodec.ChannelLayout()) 42 | err = dec.Setup() 43 | if err != nil { 44 | fmt.Println(err) 45 | } 46 | enc, err = audio.NewAudioEncoderByName("libopus") 47 | if err != nil { 48 | fmt.Println(err) 49 | } 50 | //enc.SetSampleFormat(av.S16) 51 | enc.SetSampleRate(48000) 52 | enc.SetSampleFormat(av.S16) 53 | enc.SetChannelLayout(av.CH_STEREO) 54 | enc.Setup() 55 | 56 | } 57 | } 58 | 59 | for { 60 | packet, err := conn.ReadPacket() 61 | if err != nil { 62 | break 63 | } 64 | 65 | stream := streams[packet.Idx] 66 | 67 | if stream.Type().IsVideo() { 68 | continue 69 | } 70 | 71 | ok,frame,err := dec.Decode(packet.Data) 72 | if err != nil { 73 | fmt.Println(err) 74 | continue 75 | } 76 | if !ok { 77 | continue 78 | } 79 | 80 | dur,_ := dec.PacketDuration(packet.Data) 81 | fmt.Println("decode dur", dur) 82 | 83 | var _outpkts [][]byte 84 | if _outpkts, err = enc.Encode(frame); err != nil { 85 | fmt.Println(err) 86 | continue 87 | } 88 | 89 | for _,outpkt := range _outpkts { 90 | //adtsbuffer := []byte{} 91 | //adtsheader := make([]byte, 7) 92 | //aac.FillADTSHeader(adtsheader, aencodec.(aac.CodecData).Config, 1024, len(outpkt)) 93 | //adtsbuffer = append(adtsbuffer, adtsheader...) 94 | //adtsbuffer = append(adtsbuffer, outpkt...) 95 | dur,_ := enc.PacketDuration(outpkt) 96 | file.Write(outpkt) 97 | fmt.Println("encode dur", dur) 98 | // 99 | //dur, _:= aencodec.PacketDuration(outpkt) 100 | //fmt.Println("encode dur", outpkt) 101 | 102 | } 103 | 104 | 105 | fmt.Println(packet.Time) 106 | } 107 | } 108 | 109 | server.ListenAndServe() 110 | 111 | } 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /examples/rtmp-to-http-flv/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "sync" 7 | 8 | "github.com/notedit/rtmp-lib/av" 9 | "github.com/notedit/rtmp-lib/flv" 10 | 11 | rtmp "github.com/notedit/rtmp-lib" 12 | "github.com/notedit/rtmp-lib/pubsub" 13 | ) 14 | 15 | type Channel struct { 16 | que *pubsub.Queue 17 | } 18 | 19 | var channels = map[string]*Channel{} 20 | 21 | type writeFlusher struct { 22 | httpflusher http.Flusher 23 | io.Writer 24 | } 25 | 26 | func (self writeFlusher) Flush() error { 27 | self.httpflusher.Flush() 28 | return nil 29 | } 30 | 31 | func main() { 32 | 33 | l := &sync.RWMutex{} 34 | 35 | server := rtmp.NewServer(1024) 36 | 37 | server.HandlePlay = func(conn *rtmp.Conn) { 38 | 39 | l.RLock() 40 | ch := channels[conn.URL.Path] 41 | l.RUnlock() 42 | 43 | if ch != nil { 44 | 45 | cursor := ch.que.Latest() 46 | 47 | streams, err := cursor.Streams() 48 | 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | conn.WriteHeader(streams) 54 | 55 | for { 56 | packet, err := cursor.ReadPacket() 57 | if err != nil { 58 | break 59 | } 60 | conn.WritePacket(packet) 61 | } 62 | } 63 | } 64 | 65 | server.HandlePublish = func(conn *rtmp.Conn) { 66 | 67 | l.Lock() 68 | ch := channels[conn.URL.Path] 69 | 70 | if ch == nil { 71 | ch = &Channel{} 72 | ch.que = pubsub.NewQueue() 73 | ch.que.SetMaxGopCount(1) 74 | channels[conn.URL.Path] = ch 75 | } 76 | l.Unlock() 77 | 78 | var streams []av.CodecData 79 | var err error 80 | 81 | if streams, err = conn.Streams(); err != nil { 82 | panic(err) 83 | } 84 | 85 | ch.que.WriteHeader(streams) 86 | 87 | for { 88 | var pkt av.Packet 89 | if pkt, err = conn.ReadPacket(); err != nil { 90 | break 91 | } 92 | 93 | ch.que.WritePacket(pkt) 94 | } 95 | 96 | l.Lock() 97 | delete(channels, conn.URL.Path) 98 | l.Unlock() 99 | 100 | ch.que.Close() 101 | } 102 | 103 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 104 | 105 | l.RLock() 106 | ch := channels[r.URL.Path] 107 | l.RUnlock() 108 | 109 | if ch != nil { 110 | w.Header().Set("Content-Type", "video/x-flv") 111 | w.Header().Set("Transfer-Encoding", "chunked") 112 | w.Header().Set("Access-Control-Allow-Origin", "*") 113 | w.WriteHeader(200) 114 | flusher := w.(http.Flusher) 115 | flusher.Flush() 116 | 117 | muxer := flv.NewMuxerWriteFlusher(writeFlusher{httpflusher: flusher, Writer: w}) 118 | cursor := ch.que.Latest() 119 | 120 | streams, err := cursor.Streams() 121 | 122 | if err != nil { 123 | panic(err) 124 | } 125 | 126 | muxer.WriteHeader(streams) 127 | 128 | for { 129 | packet, err := cursor.ReadPacket() 130 | if err != nil { 131 | break 132 | } 133 | muxer.WritePacket(packet) 134 | } 135 | } else { 136 | http.NotFound(w, r) 137 | } 138 | }) 139 | 140 | go http.ListenAndServe(":8088", nil) 141 | 142 | server.ListenAndServe() 143 | 144 | } 145 | -------------------------------------------------------------------------------- /bits/bits.go: -------------------------------------------------------------------------------- 1 | package bits 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | type Reader struct { 8 | R io.Reader 9 | n int 10 | bits uint64 11 | } 12 | 13 | func (self *Reader) ReadBits64(n int) (bits uint64, err error) { 14 | if self.n < n { 15 | var b [8]byte 16 | var got int 17 | want := (n - self.n + 7) / 8 18 | if got, err = self.R.Read(b[:want]); err != nil { 19 | return 20 | } 21 | if got < want { 22 | err = io.EOF 23 | return 24 | } 25 | for i := 0; i < got; i++ { 26 | self.bits <<= 8 27 | self.bits |= uint64(b[i]) 28 | } 29 | self.n += got * 8 30 | } 31 | bits = self.bits >> uint(self.n-n) 32 | self.bits ^= bits << uint(self.n-n) 33 | self.n -= n 34 | return 35 | } 36 | 37 | func (self *Reader) ReadBits(n int) (bits uint, err error) { 38 | var bits64 uint64 39 | if bits64, err = self.ReadBits64(n); err != nil { 40 | return 41 | } 42 | bits = uint(bits64) 43 | return 44 | } 45 | 46 | func (self *Reader) Read(p []byte) (n int, err error) { 47 | for n < len(p) { 48 | want := 8 49 | if len(p)-n < want { 50 | want = len(p) - n 51 | } 52 | var bits uint64 53 | if bits, err = self.ReadBits64(want * 8); err != nil { 54 | break 55 | } 56 | for i := 0; i < want; i++ { 57 | p[n+i] = byte(bits >> uint((want-i-1)*8)) 58 | } 59 | n += want 60 | } 61 | return 62 | } 63 | 64 | type Writer struct { 65 | W io.Writer 66 | n int 67 | bits uint64 68 | } 69 | 70 | func (self *Writer) WriteBits64(bits uint64, n int) (err error) { 71 | if self.n+n > 64 { 72 | move := uint(64 - self.n) 73 | mask := bits >> move 74 | self.bits = (self.bits << move) | mask 75 | self.n = 64 76 | if err = self.FlushBits(); err != nil { 77 | return 78 | } 79 | n -= int(move) 80 | bits ^= (mask << move) 81 | } 82 | self.bits = (self.bits << uint(n)) | bits 83 | self.n += n 84 | return 85 | } 86 | 87 | func (self *Writer) WriteBits(bits uint, n int) (err error) { 88 | return self.WriteBits64(uint64(bits), n) 89 | } 90 | 91 | func (self *Writer) Write(p []byte) (n int, err error) { 92 | for n < len(p) { 93 | if err = self.WriteBits64(uint64(p[n]), 8); err != nil { 94 | return 95 | } 96 | n++ 97 | } 98 | return 99 | } 100 | 101 | func (self *Writer) FlushBits() (err error) { 102 | if self.n > 0 { 103 | var b [8]byte 104 | bits := self.bits 105 | if self.n%8 != 0 { 106 | bits <<= uint(8 - (self.n % 8)) 107 | } 108 | want := (self.n + 7) / 8 109 | for i := 0; i < want; i++ { 110 | b[i] = byte(bits >> uint((want-i-1)*8)) 111 | } 112 | if _, err = self.W.Write(b[:want]); err != nil { 113 | return 114 | } 115 | self.n = 0 116 | } 117 | return 118 | } 119 | 120 | type GolombBitReader struct { 121 | R io.Reader 122 | buf [1]byte 123 | left byte 124 | } 125 | 126 | func (self *GolombBitReader) ReadBit() (res uint, err error) { 127 | if self.left == 0 { 128 | if _, err = self.R.Read(self.buf[:]); err != nil { 129 | return 130 | } 131 | self.left = 8 132 | } 133 | self.left-- 134 | res = uint(self.buf[0]>>self.left) & 1 135 | return 136 | } 137 | 138 | func (self *GolombBitReader) ReadBits(n int) (res uint, err error) { 139 | for i := 0; i < n; i++ { 140 | var bit uint 141 | if bit, err = self.ReadBit(); err != nil { 142 | return 143 | } 144 | res |= bit << uint(n-i-1) 145 | } 146 | return 147 | } 148 | 149 | func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) { 150 | i := 0 151 | for { 152 | var bit uint 153 | if bit, err = self.ReadBit(); err != nil { 154 | return 155 | } 156 | if !(bit == 0 && i < 32) { 157 | break 158 | } 159 | i++ 160 | } 161 | if res, err = self.ReadBits(i); err != nil { 162 | return 163 | } 164 | res += (1 << uint(i)) - 1 165 | return 166 | } 167 | 168 | func (self *GolombBitReader) ReadSE() (res uint, err error) { 169 | if res, err = self.ReadExponentialGolombCode(); err != nil { 170 | return 171 | } 172 | if res&0x01 != 0 { 173 | res = (res + 1) / 2 174 | } else { 175 | res = -res / 2 176 | } 177 | return 178 | } 179 | -------------------------------------------------------------------------------- /pio/pio.go: -------------------------------------------------------------------------------- 1 | package pio 2 | 3 | func U8(b []byte) (i uint8) { 4 | return b[0] 5 | } 6 | 7 | func U16BE(b []byte) (i uint16) { 8 | i = uint16(b[0]) 9 | i <<= 8 10 | i |= uint16(b[1]) 11 | return 12 | } 13 | 14 | func I16BE(b []byte) (i int16) { 15 | i = int16(b[0]) 16 | i <<= 8 17 | i |= int16(b[1]) 18 | return 19 | } 20 | 21 | func I24BE(b []byte) (i int32) { 22 | i = int32(int8(b[0])) 23 | i <<= 8 24 | i |= int32(b[1]) 25 | i <<= 8 26 | i |= int32(b[2]) 27 | return 28 | } 29 | 30 | func U24BE(b []byte) (i uint32) { 31 | i = uint32(b[0]) 32 | i <<= 8 33 | i |= uint32(b[1]) 34 | i <<= 8 35 | i |= uint32(b[2]) 36 | return 37 | } 38 | 39 | func I32BE(b []byte) (i int32) { 40 | i = int32(int8(b[0])) 41 | i <<= 8 42 | i |= int32(b[1]) 43 | i <<= 8 44 | i |= int32(b[2]) 45 | i <<= 8 46 | i |= int32(b[3]) 47 | return 48 | } 49 | 50 | func U32LE(b []byte) (i uint32) { 51 | i = uint32(b[3]) 52 | i <<= 8 53 | i |= uint32(b[2]) 54 | i <<= 8 55 | i |= uint32(b[1]) 56 | i <<= 8 57 | i |= uint32(b[0]) 58 | return 59 | } 60 | 61 | func U32BE(b []byte) (i uint32) { 62 | i = uint32(b[0]) 63 | i <<= 8 64 | i |= uint32(b[1]) 65 | i <<= 8 66 | i |= uint32(b[2]) 67 | i <<= 8 68 | i |= uint32(b[3]) 69 | return 70 | } 71 | 72 | func U40BE(b []byte) (i uint64) { 73 | i = uint64(b[0]) 74 | i <<= 8 75 | i |= uint64(b[1]) 76 | i <<= 8 77 | i |= uint64(b[2]) 78 | i <<= 8 79 | i |= uint64(b[3]) 80 | i <<= 8 81 | i |= uint64(b[4]) 82 | return 83 | } 84 | 85 | func U64BE(b []byte) (i uint64) { 86 | i = uint64(b[0]) 87 | i <<= 8 88 | i |= uint64(b[1]) 89 | i <<= 8 90 | i |= uint64(b[2]) 91 | i <<= 8 92 | i |= uint64(b[3]) 93 | i <<= 8 94 | i |= uint64(b[4]) 95 | i <<= 8 96 | i |= uint64(b[5]) 97 | i <<= 8 98 | i |= uint64(b[6]) 99 | i <<= 8 100 | i |= uint64(b[7]) 101 | return 102 | } 103 | 104 | func I64BE(b []byte) (i int64) { 105 | i = int64(int8(b[0])) 106 | i <<= 8 107 | i |= int64(b[1]) 108 | i <<= 8 109 | i |= int64(b[2]) 110 | i <<= 8 111 | i |= int64(b[3]) 112 | i <<= 8 113 | i |= int64(b[4]) 114 | i <<= 8 115 | i |= int64(b[5]) 116 | i <<= 8 117 | i |= int64(b[6]) 118 | i <<= 8 119 | i |= int64(b[7]) 120 | return 121 | } 122 | 123 | func PutU8(b []byte, v uint8) { 124 | b[0] = v 125 | } 126 | 127 | func PutI16BE(b []byte, v int16) { 128 | b[0] = byte(v >> 8) 129 | b[1] = byte(v) 130 | } 131 | 132 | func PutU16BE(b []byte, v uint16) { 133 | b[0] = byte(v >> 8) 134 | b[1] = byte(v) 135 | } 136 | 137 | func PutI24BE(b []byte, v int32) { 138 | b[0] = byte(v >> 16) 139 | b[1] = byte(v >> 8) 140 | b[2] = byte(v) 141 | } 142 | 143 | func PutU24BE(b []byte, v uint32) { 144 | b[0] = byte(v >> 16) 145 | b[1] = byte(v >> 8) 146 | b[2] = byte(v) 147 | } 148 | 149 | func PutI32BE(b []byte, v int32) { 150 | b[0] = byte(v >> 24) 151 | b[1] = byte(v >> 16) 152 | b[2] = byte(v >> 8) 153 | b[3] = byte(v) 154 | } 155 | 156 | func PutU32BE(b []byte, v uint32) { 157 | b[0] = byte(v >> 24) 158 | b[1] = byte(v >> 16) 159 | b[2] = byte(v >> 8) 160 | b[3] = byte(v) 161 | } 162 | 163 | func PutU32LE(b []byte, v uint32) { 164 | b[3] = byte(v >> 24) 165 | b[2] = byte(v >> 16) 166 | b[1] = byte(v >> 8) 167 | b[0] = byte(v) 168 | } 169 | 170 | func PutU40BE(b []byte, v uint64) { 171 | b[0] = byte(v >> 32) 172 | b[1] = byte(v >> 24) 173 | b[2] = byte(v >> 16) 174 | b[3] = byte(v >> 8) 175 | b[4] = byte(v) 176 | } 177 | 178 | func PutU48BE(b []byte, v uint64) { 179 | b[0] = byte(v >> 40) 180 | b[1] = byte(v >> 32) 181 | b[2] = byte(v >> 24) 182 | b[3] = byte(v >> 16) 183 | b[4] = byte(v >> 8) 184 | b[5] = byte(v) 185 | } 186 | 187 | func PutU64BE(b []byte, v uint64) { 188 | b[0] = byte(v >> 56) 189 | b[1] = byte(v >> 48) 190 | b[2] = byte(v >> 40) 191 | b[3] = byte(v >> 32) 192 | b[4] = byte(v >> 24) 193 | b[5] = byte(v >> 16) 194 | b[6] = byte(v >> 8) 195 | b[7] = byte(v) 196 | } 197 | 198 | func PutI64BE(b []byte, v int64) { 199 | b[0] = byte(v >> 56) 200 | b[1] = byte(v >> 48) 201 | b[2] = byte(v >> 40) 202 | b[3] = byte(v >> 32) 203 | b[4] = byte(v >> 24) 204 | b[5] = byte(v >> 16) 205 | b[6] = byte(v >> 8) 206 | b[7] = byte(v) 207 | } 208 | -------------------------------------------------------------------------------- /pubsub/queue.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "io" 5 | "sync" 6 | "time" 7 | 8 | "github.com/notedit/rtmp-lib/av" 9 | ) 10 | 11 | // time 12 | // -----------------> 13 | // 14 | // V-A-V-V-A-V-V-A-V-V 15 | // | | 16 | // 0 5 10 17 | // head tail 18 | // oldest latest 19 | // 20 | 21 | // One publisher and multiple subscribers thread-safe packet buffer queue. 22 | type Queue struct { 23 | buf *Buf 24 | head, tail int 25 | lock *sync.RWMutex 26 | cond *sync.Cond 27 | curgopcount, maxgopcount int 28 | streams []av.CodecData 29 | videoidx int 30 | closed bool 31 | } 32 | 33 | func NewQueue() *Queue { 34 | q := &Queue{} 35 | q.buf = NewBuf() 36 | q.maxgopcount = 0 37 | q.lock = &sync.RWMutex{} 38 | q.cond = sync.NewCond(q.lock.RLocker()) 39 | q.videoidx = -1 40 | return q 41 | } 42 | 43 | func (self *Queue) SetMaxGopCount(n int) { 44 | self.lock.Lock() 45 | self.maxgopcount = n 46 | self.lock.Unlock() 47 | return 48 | } 49 | 50 | func (self *Queue) WriteHeader(streams []av.CodecData) error { 51 | self.lock.Lock() 52 | 53 | self.streams = streams 54 | for i, stream := range streams { 55 | if stream.Type().IsVideo() { 56 | self.videoidx = i 57 | } 58 | } 59 | self.cond.Broadcast() 60 | 61 | self.lock.Unlock() 62 | 63 | return nil 64 | } 65 | 66 | func (self *Queue) WriteTrailer() error { 67 | return nil 68 | } 69 | 70 | // After Close() called, all QueueCursor's ReadPacket will return io.EOF. 71 | func (self *Queue) Close() (err error) { 72 | self.lock.Lock() 73 | 74 | self.closed = true 75 | self.cond.Broadcast() 76 | 77 | self.lock.Unlock() 78 | return 79 | } 80 | 81 | // Put packet into buffer, old packets will be discared. 82 | func (self *Queue) WritePacket(pkt av.Packet) (err error) { 83 | self.lock.Lock() 84 | 85 | self.buf.Push(pkt) 86 | if pkt.Idx == int8(self.videoidx) && pkt.IsKeyFrame { 87 | self.curgopcount++ 88 | } 89 | 90 | for self.curgopcount >= self.maxgopcount && self.buf.Count > 1 { 91 | pkt := self.buf.Pop() 92 | if pkt.Idx == int8(self.videoidx) && pkt.IsKeyFrame { 93 | self.curgopcount-- 94 | } 95 | if self.curgopcount < self.maxgopcount { 96 | break 97 | } 98 | } 99 | //println("shrink", self.curgopcount, self.maxgopcount, self.buf.Head, self.buf.Tail, "count", self.buf.Count, "size", self.buf.Size) 100 | 101 | self.cond.Broadcast() 102 | 103 | self.lock.Unlock() 104 | return 105 | } 106 | 107 | type QueueCursor struct { 108 | que *Queue 109 | pos BufPos 110 | gotpos bool 111 | init func(buf *Buf, videoidx int) BufPos 112 | } 113 | 114 | func (self *Queue) newCursor() *QueueCursor { 115 | return &QueueCursor{ 116 | que: self, 117 | } 118 | } 119 | 120 | // Create cursor position at latest packet. 121 | func (self *Queue) Latest() *QueueCursor { 122 | cursor := self.newCursor() 123 | cursor.init = func(buf *Buf, videoidx int) BufPos { 124 | return buf.Tail 125 | } 126 | return cursor 127 | } 128 | 129 | // Oldest Create cursor position at oldest buffered packet. 130 | func (self *Queue) Oldest() *QueueCursor { 131 | cursor := self.newCursor() 132 | cursor.init = func(buf *Buf, videoidx int) BufPos { 133 | return buf.Head 134 | } 135 | return cursor 136 | } 137 | 138 | // DelayedTime Create cursor position at specific time in buffered packets. 139 | func (self *Queue) DelayedTime(dur time.Duration) *QueueCursor { 140 | cursor := self.newCursor() 141 | cursor.init = func(buf *Buf, videoidx int) BufPos { 142 | i := buf.Tail - 1 143 | if buf.IsValidPos(i) { 144 | end := buf.Get(i) 145 | for buf.IsValidPos(i) { 146 | if end.Time-buf.Get(i).Time > dur { 147 | break 148 | } 149 | i-- 150 | } 151 | } 152 | return i 153 | } 154 | return cursor 155 | } 156 | 157 | // Create cursor position at specific delayed GOP count in buffered packets. 158 | func (self *Queue) DelayedGopCount(n int) *QueueCursor { 159 | cursor := self.newCursor() 160 | cursor.init = func(buf *Buf, videoidx int) BufPos { 161 | i := buf.Tail - 1 162 | if videoidx != -1 { 163 | for gop := 0; buf.IsValidPos(i) && gop < n; i-- { 164 | pkt := buf.Get(i) 165 | if pkt.Idx == int8(self.videoidx) && pkt.IsKeyFrame { 166 | gop++ 167 | } 168 | } 169 | } 170 | return i 171 | } 172 | return cursor 173 | } 174 | 175 | func (self *QueueCursor) Streams() (streams []av.CodecData, err error) { 176 | self.que.cond.L.Lock() 177 | for self.que.streams == nil && !self.que.closed { 178 | self.que.cond.Wait() 179 | } 180 | if self.que.streams != nil { 181 | streams = self.que.streams 182 | } else { 183 | err = io.EOF 184 | } 185 | self.que.cond.L.Unlock() 186 | return 187 | } 188 | 189 | // ReadPacket will not consume packets in Queue, it's just a cursor. 190 | func (self *QueueCursor) ReadPacket() (pkt av.Packet, err error) { 191 | self.que.cond.L.Lock() 192 | buf := self.que.buf 193 | if !self.gotpos { 194 | self.pos = self.init(buf, self.que.videoidx) 195 | self.gotpos = true 196 | } 197 | for { 198 | if self.pos.LT(buf.Head) { 199 | self.pos = buf.Head 200 | } else if self.pos.GT(buf.Tail) { 201 | self.pos = buf.Tail 202 | } 203 | if buf.IsValidPos(self.pos) { 204 | pkt = buf.Get(self.pos) 205 | self.pos++ 206 | break 207 | } 208 | if self.que.closed { 209 | err = io.EOF 210 | break 211 | } 212 | self.que.cond.Wait() 213 | } 214 | self.que.cond.L.Unlock() 215 | return 216 | } 217 | -------------------------------------------------------------------------------- /av/av.go: -------------------------------------------------------------------------------- 1 | // Package av defines basic interfaces and data structures of container demux/mux and audio encode/decode. 2 | package av 3 | 4 | import ( 5 | "fmt" 6 | "time" 7 | ) 8 | 9 | // Audio sample format. 10 | type SampleFormat uint8 11 | 12 | const ( 13 | U8 = SampleFormat(iota + 1) // 8-bit unsigned integer 14 | S16 // signed 16-bit integer 15 | S32 // signed 32-bit integer 16 | FLT // 32-bit float 17 | DBL // 64-bit float 18 | U8P // 8-bit unsigned integer in planar 19 | S16P // signed 16-bit integer in planar 20 | S32P // signed 32-bit integer in planar 21 | FLTP // 32-bit float in planar 22 | DBLP // 64-bit float in planar 23 | U32 // unsigned 32-bit integer 24 | ) 25 | 26 | func (self SampleFormat) BytesPerSample() int { 27 | switch self { 28 | case U8, U8P: 29 | return 1 30 | case S16, S16P: 31 | return 2 32 | case FLT, FLTP, S32, S32P, U32: 33 | return 4 34 | case DBL, DBLP: 35 | return 8 36 | default: 37 | return 0 38 | } 39 | } 40 | 41 | func (self SampleFormat) String() string { 42 | switch self { 43 | case U8: 44 | return "U8" 45 | case S16: 46 | return "S16" 47 | case S32: 48 | return "S32" 49 | case FLT: 50 | return "FLT" 51 | case DBL: 52 | return "DBL" 53 | case U8P: 54 | return "U8P" 55 | case S16P: 56 | return "S16P" 57 | case FLTP: 58 | return "FLTP" 59 | case DBLP: 60 | return "DBLP" 61 | case U32: 62 | return "U32" 63 | default: 64 | return "?" 65 | } 66 | } 67 | 68 | // Check if this sample format is in planar. 69 | func (self SampleFormat) IsPlanar() bool { 70 | switch self { 71 | case S16P, S32P, FLTP, DBLP: 72 | return true 73 | default: 74 | return false 75 | } 76 | } 77 | 78 | // Audio channel layout. 79 | type ChannelLayout uint16 80 | 81 | func (self ChannelLayout) String() string { 82 | return fmt.Sprintf("%dch", self.Count()) 83 | } 84 | 85 | const ( 86 | CH_FRONT_CENTER = ChannelLayout(1 << iota) 87 | CH_FRONT_LEFT 88 | CH_FRONT_RIGHT 89 | CH_BACK_CENTER 90 | CH_BACK_LEFT 91 | CH_BACK_RIGHT 92 | CH_SIDE_LEFT 93 | CH_SIDE_RIGHT 94 | CH_LOW_FREQ 95 | CH_NR 96 | 97 | CH_MONO = ChannelLayout(CH_FRONT_CENTER) 98 | CH_STEREO = ChannelLayout(CH_FRONT_LEFT | CH_FRONT_RIGHT) 99 | CH_2_1 = ChannelLayout(CH_STEREO | CH_BACK_CENTER) 100 | CH_2POINT1 = ChannelLayout(CH_STEREO | CH_LOW_FREQ) 101 | CH_SURROUND = ChannelLayout(CH_STEREO | CH_FRONT_CENTER) 102 | CH_3POINT1 = ChannelLayout(CH_SURROUND | CH_LOW_FREQ) 103 | // TODO: add all channel_layout in ffmpeg 104 | ) 105 | 106 | func (self ChannelLayout) Count() (n int) { 107 | for self != 0 { 108 | n++ 109 | self = (self - 1) & self 110 | } 111 | return 112 | } 113 | 114 | // Video/Audio codec type. can be H264/AAC/SPEEX/... 115 | type CodecType uint32 116 | 117 | var ( 118 | H264 = MakeVideoCodecType(avCodecTypeMagic + 1) 119 | AAC = MakeAudioCodecType(avCodecTypeMagic + 1) 120 | PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2) 121 | PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3) 122 | SPEEX = MakeAudioCodecType(avCodecTypeMagic + 4) 123 | NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 5) 124 | ) 125 | 126 | const codecTypeAudioBit = 0x1 127 | const codecTypeOtherBits = 1 128 | 129 | func (self CodecType) String() string { 130 | switch self { 131 | case H264: 132 | return "H264" 133 | case AAC: 134 | return "AAC" 135 | case PCM_MULAW: 136 | return "PCM_MULAW" 137 | case PCM_ALAW: 138 | return "PCM_ALAW" 139 | case SPEEX: 140 | return "SPEEX" 141 | case NELLYMOSER: 142 | return "NELLYMOSER" 143 | } 144 | return "" 145 | } 146 | 147 | func (self CodecType) IsAudio() bool { 148 | return self&codecTypeAudioBit != 0 149 | } 150 | 151 | func (self CodecType) IsVideo() bool { 152 | return self&codecTypeAudioBit == 0 153 | } 154 | 155 | // Make a new audio codec type. 156 | func MakeAudioCodecType(base uint32) (c CodecType) { 157 | c = CodecType(base)< 1 207 | } 208 | 209 | 210 | func (self AudioFrame) Duration() time.Duration { 211 | return time.Second * time.Duration(self.SampleCount) / time.Duration(self.SampleRate) 212 | } 213 | 214 | // Check this audio frame has same format as other audio frame. 215 | func (self AudioFrame) HasSameFormat(other AudioFrame) bool { 216 | if self.SampleRate != other.SampleRate { 217 | return false 218 | } 219 | if self.ChannelLayout != other.ChannelLayout { 220 | return false 221 | } 222 | if self.SampleFormat != other.SampleFormat { 223 | return false 224 | } 225 | return true 226 | } 227 | 228 | // Split sample audio sample from this frame. 229 | func (self AudioFrame) Slice(start int, end int) (out AudioFrame) { 230 | if start > end { 231 | panic(fmt.Sprintf("av: AudioFrame split failed start=%d end=%d invalid", start, end)) 232 | } 233 | out = self 234 | out.Data = append([][]byte(nil), out.Data...) 235 | out.SampleCount = end - start 236 | size := self.SampleFormat.BytesPerSample() * self.ChannelLayout.Count() 237 | for i := range out.Data { 238 | out.Data[i] = out.Data[i][start*size : end*size] 239 | } 240 | return 241 | } 242 | 243 | // Concat two audio frames. 244 | func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) { 245 | out = self 246 | out.Data = append([][]byte(nil), out.Data...) 247 | out.SampleCount += in.SampleCount 248 | for i := range out.Data { 249 | out.Data[i] = append(out.Data[i], in.Data[i]...) 250 | } 251 | return 252 | } 253 | 254 | 255 | type AudioEncoder interface { 256 | CodecData() (AudioCodecData, error) // encoder's codec data can put into container 257 | Setup() (error) 258 | Encode(AudioFrame) ([][]byte, error) // encode raw audio frame into compressed pakcet(s) 259 | Close() // close encoder, free cgo contexts 260 | SetSampleRate(int) (error) // set encoder sample rate 261 | SetChannelLayout(ChannelLayout) (error) // set encoder channel layout 262 | SetSampleFormat(SampleFormat) (error) // set encoder sample format 263 | SetBitrate(int) (error) // set encoder bitrate 264 | SetOption(string,interface{}) (error) // encoder setopt, in ffmpeg is av_opt_set_dict() 265 | GetOption(string,interface{}) (error) // encoder getopt 266 | 267 | PacketDuration(data []byte) (dur time.Duration, err error) 268 | } 269 | 270 | // AudioDecoder can decode compressed audio packets into raw audio frame. 271 | // use ffmpeg.NewAudioDecoder to create it. 272 | type AudioDecoder interface { 273 | Setup() (error) 274 | Decode([]byte) (bool, AudioFrame, error) // decode one compressed audio packet 275 | Close() // close decode, free cgo contexts 276 | SetSampleRate(int) (error) // set encoder sample rate 277 | SetChannelLayout(ChannelLayout) (error) // set encoder channel layout 278 | SetSampleFormat(SampleFormat) (error) // set encoder sample format 279 | PacketDuration(data []byte) (dur time.Duration, err error) 280 | } 281 | 282 | // AudioResampler can convert raw audio frames in different sample rate/format/channel layout. 283 | type AudioResampler interface { 284 | Resample(AudioFrame) (AudioFrame, error) // convert raw audio frames 285 | } 286 | -------------------------------------------------------------------------------- /flv/amf0.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "strings" 7 | "time" 8 | 9 | "github.com/notedit/rtmp-lib/pio" 10 | ) 11 | 12 | type AMF0ParseError struct { 13 | Offset int 14 | Message string 15 | Next *AMF0ParseError 16 | } 17 | 18 | func (self *AMF0ParseError) Error() string { 19 | s := []string{} 20 | for p := self; p != nil; p = p.Next { 21 | s = append(s, fmt.Sprintf("%s:%d", p.Message, p.Offset)) 22 | } 23 | return "amf0 parse error: " + strings.Join(s, ",") 24 | } 25 | 26 | func amf0ParseErr(message string, offset int, err error) error { 27 | next, _ := err.(*AMF0ParseError) 28 | return &AMF0ParseError{ 29 | Offset: offset, 30 | Message: message, 31 | Next: next, 32 | } 33 | } 34 | 35 | type AMFMap map[string]interface{} 36 | type AMFArray []interface{} 37 | type AMFECMAArray map[string]interface{} 38 | 39 | func parseBEFloat64(b []byte) float64 { 40 | return math.Float64frombits(pio.U64BE(b)) 41 | } 42 | 43 | func fillBEFloat64(b []byte, f float64) int { 44 | pio.PutU64BE(b, math.Float64bits(f)) 45 | return 8 46 | } 47 | 48 | const lenAMF0Number = 9 49 | 50 | func fillAMF0Number(b []byte, f float64) int { 51 | b[0] = numbermarker 52 | fillBEFloat64(b[1:], f) 53 | return lenAMF0Number 54 | } 55 | 56 | const ( 57 | amf3undefinedmarker = iota 58 | amf3nullmarker 59 | amf3falsemarker 60 | amf3truemarker 61 | amf3integermarker 62 | amf3doublemarker 63 | amf3stringmarker 64 | amf3xmldocmarker 65 | amf3datemarker 66 | amf3arraymarker 67 | amf3objectmarker 68 | amf3xmlmarker 69 | amf3bytearraymarker 70 | amf3vectorintmarker 71 | amf3vectoruintmarker 72 | amf3vectordoublemarker 73 | amf3vectorobjectmarker 74 | amf3dictionarymarker 75 | ) 76 | 77 | const ( 78 | numbermarker = iota 79 | booleanmarker 80 | stringmarker 81 | objectmarker 82 | movieclipmarker 83 | nullmarker 84 | undefinedmarker 85 | referencemarker 86 | ecmaarraymarker 87 | objectendmarker 88 | strictarraymarker 89 | datemarker 90 | longstringmarker 91 | unsupportedmarker 92 | recordsetmarker 93 | xmldocumentmarker 94 | typedobjectmarker 95 | avmplusobjectmarker 96 | ) 97 | 98 | func LenAMF0Val(_val interface{}) (n int) { 99 | switch val := _val.(type) { 100 | case int8: 101 | n += lenAMF0Number 102 | case int16: 103 | n += lenAMF0Number 104 | case int32: 105 | n += lenAMF0Number 106 | case int64: 107 | n += lenAMF0Number 108 | case int: 109 | n += lenAMF0Number 110 | case uint8: 111 | n += lenAMF0Number 112 | case uint16: 113 | n += lenAMF0Number 114 | case uint32: 115 | n += lenAMF0Number 116 | case uint64: 117 | n += lenAMF0Number 118 | case uint: 119 | n += lenAMF0Number 120 | case float32: 121 | n += lenAMF0Number 122 | case float64: 123 | n += lenAMF0Number 124 | 125 | case string: 126 | u := len(val) 127 | if u <= 65536 { 128 | n += 3 129 | } else { 130 | n += 5 131 | } 132 | n += int(u) 133 | 134 | case AMFECMAArray: 135 | n += 5 136 | for k, v := range val { 137 | n += 2 + len(k) 138 | n += LenAMF0Val(v) 139 | } 140 | n += 3 141 | 142 | case AMFMap: 143 | n++ 144 | for k, v := range val { 145 | if len(k) > 0 { 146 | n += 2 + len(k) 147 | n += LenAMF0Val(v) 148 | } 149 | } 150 | n += 3 151 | 152 | case AMFArray: 153 | n += 5 154 | for _, v := range val { 155 | n += LenAMF0Val(v) 156 | } 157 | 158 | case time.Time: 159 | n += 1 + 8 + 2 160 | 161 | case bool: 162 | n += 2 163 | 164 | case nil: 165 | n++ 166 | } 167 | 168 | return 169 | } 170 | 171 | func FillAMF0Val(b []byte, _val interface{}) (n int) { 172 | switch val := _val.(type) { 173 | case int8: 174 | n += fillAMF0Number(b[n:], float64(val)) 175 | case int16: 176 | n += fillAMF0Number(b[n:], float64(val)) 177 | case int32: 178 | n += fillAMF0Number(b[n:], float64(val)) 179 | case int64: 180 | n += fillAMF0Number(b[n:], float64(val)) 181 | case int: 182 | n += fillAMF0Number(b[n:], float64(val)) 183 | case uint8: 184 | n += fillAMF0Number(b[n:], float64(val)) 185 | case uint16: 186 | n += fillAMF0Number(b[n:], float64(val)) 187 | case uint32: 188 | n += fillAMF0Number(b[n:], float64(val)) 189 | case uint64: 190 | n += fillAMF0Number(b[n:], float64(val)) 191 | case uint: 192 | n += fillAMF0Number(b[n:], float64(val)) 193 | case float32: 194 | n += fillAMF0Number(b[n:], float64(val)) 195 | case float64: 196 | n += fillAMF0Number(b[n:], float64(val)) 197 | 198 | case string: 199 | u := len(val) 200 | if u <= 65536 { 201 | b[n] = stringmarker 202 | n++ 203 | pio.PutU16BE(b[n:], uint16(u)) 204 | n += 2 205 | } else { 206 | b[n] = longstringmarker 207 | n++ 208 | pio.PutU32BE(b[n:], uint32(u)) 209 | n += 4 210 | } 211 | copy(b[n:], []byte(val)) 212 | n += len(val) 213 | 214 | case AMFECMAArray: 215 | b[n] = ecmaarraymarker 216 | n++ 217 | pio.PutU32BE(b[n:], uint32(len(val))) 218 | n += 4 219 | for k, v := range val { 220 | pio.PutU16BE(b[n:], uint16(len(k))) 221 | n += 2 222 | copy(b[n:], []byte(k)) 223 | n += len(k) 224 | n += FillAMF0Val(b[n:], v) 225 | } 226 | pio.PutU24BE(b[n:], 0x000009) 227 | n += 3 228 | 229 | case AMFMap: 230 | b[n] = objectmarker 231 | n++ 232 | for k, v := range val { 233 | if len(k) > 0 { 234 | pio.PutU16BE(b[n:], uint16(len(k))) 235 | n += 2 236 | copy(b[n:], []byte(k)) 237 | n += len(k) 238 | n += FillAMF0Val(b[n:], v) 239 | } 240 | } 241 | pio.PutU24BE(b[n:], 0x000009) 242 | n += 3 243 | 244 | case AMFArray: 245 | b[n] = strictarraymarker 246 | n++ 247 | pio.PutU32BE(b[n:], uint32(len(val))) 248 | n += 4 249 | for _, v := range val { 250 | n += FillAMF0Val(b[n:], v) 251 | } 252 | 253 | case time.Time: 254 | b[n] = datemarker 255 | n++ 256 | u := val.UnixNano() 257 | f := float64(u / 1000000) 258 | n += fillBEFloat64(b[n:], f) 259 | pio.PutU16BE(b[n:], uint16(0)) 260 | n += 2 261 | 262 | case bool: 263 | b[n] = booleanmarker 264 | n++ 265 | var u uint8 266 | if val { 267 | u = 1 268 | } else { 269 | u = 0 270 | } 271 | b[n] = u 272 | n++ 273 | 274 | case nil: 275 | b[n] = nullmarker 276 | n++ 277 | } 278 | 279 | return 280 | } 281 | 282 | func ParseAMF0Val(b []byte) (val interface{}, n int, err error) { 283 | return parseAMF0Val(b, 0) 284 | } 285 | 286 | func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) { 287 | if len(b) < n+1 { 288 | err = amf0ParseErr("marker", offset+n, err) 289 | return 290 | } 291 | marker := b[n] 292 | n++ 293 | 294 | switch marker { 295 | case numbermarker: 296 | if len(b) < n+8 { 297 | err = amf0ParseErr("number", offset+n, err) 298 | return 299 | } 300 | val = parseBEFloat64(b[n:]) 301 | n += 8 302 | 303 | case booleanmarker: 304 | if len(b) < n+1 { 305 | err = amf0ParseErr("boolean", offset+n, err) 306 | return 307 | } 308 | val = b[n] != 0 309 | n++ 310 | 311 | case stringmarker: 312 | if len(b) < n+2 { 313 | err = amf0ParseErr("string.length", offset+n, err) 314 | return 315 | } 316 | length := int(pio.U16BE(b[n:])) 317 | n += 2 318 | 319 | if len(b) < n+length { 320 | err = amf0ParseErr("string.body", offset+n, err) 321 | return 322 | } 323 | val = string(b[n : n+length]) 324 | n += length 325 | 326 | case objectmarker: 327 | obj := AMFMap{} 328 | for { 329 | if len(b) < n+2 { 330 | err = amf0ParseErr("object.key.length", offset+n, err) 331 | return 332 | } 333 | length := int(pio.U16BE(b[n:])) 334 | n += 2 335 | if length == 0 { 336 | break 337 | } 338 | 339 | if len(b) < n+length { 340 | err = amf0ParseErr("object.key.body", offset+n, err) 341 | return 342 | } 343 | okey := string(b[n : n+length]) 344 | n += length 345 | 346 | var nval int 347 | var oval interface{} 348 | if oval, nval, err = parseAMF0Val(b[n:], offset+n); err != nil { 349 | err = amf0ParseErr("object.val", offset+n, err) 350 | return 351 | } 352 | n += nval 353 | 354 | obj[okey] = oval 355 | } 356 | if len(b) < n+1 { 357 | err = amf0ParseErr("object.end", offset+n, err) 358 | return 359 | } 360 | n++ 361 | val = obj 362 | 363 | case nullmarker: 364 | case undefinedmarker: 365 | 366 | case ecmaarraymarker: 367 | if len(b) < n+4 { 368 | err = amf0ParseErr("array.count", offset+n, err) 369 | return 370 | } 371 | n += 4 372 | 373 | obj := AMFMap{} 374 | for { 375 | if len(b) < n+2 { 376 | err = amf0ParseErr("array.key.length", offset+n, err) 377 | return 378 | } 379 | length := int(pio.U16BE(b[n:])) 380 | n += 2 381 | 382 | if length == 0 { 383 | break 384 | } 385 | 386 | if len(b) < n+length { 387 | err = amf0ParseErr("array.key.body", offset+n, err) 388 | return 389 | } 390 | okey := string(b[n : n+length]) 391 | n += length 392 | 393 | var nval int 394 | var oval interface{} 395 | if oval, nval, err = parseAMF0Val(b[n:], offset+n); err != nil { 396 | err = amf0ParseErr("array.val", offset+n, err) 397 | return 398 | } 399 | n += nval 400 | 401 | obj[okey] = oval 402 | } 403 | if len(b) < n+1 { 404 | err = amf0ParseErr("array.end", offset+n, err) 405 | return 406 | } 407 | n += 1 408 | val = obj 409 | 410 | case objectendmarker: 411 | if len(b) < n+3 { 412 | err = amf0ParseErr("objectend", offset+n, err) 413 | return 414 | } 415 | n += 3 416 | 417 | case strictarraymarker: 418 | if len(b) < n+4 { 419 | err = amf0ParseErr("strictarray.count", offset+n, err) 420 | return 421 | } 422 | count := int(pio.U32BE(b[n:])) 423 | n += 4 424 | 425 | obj := make(AMFArray, count) 426 | for i := 0; i < int(count); i++ { 427 | var nval int 428 | if obj[i], nval, err = parseAMF0Val(b[n:], offset+n); err != nil { 429 | err = amf0ParseErr("strictarray.val", offset+n, err) 430 | return 431 | } 432 | n += nval 433 | } 434 | val = obj 435 | 436 | case datemarker: 437 | if len(b) < n+8+2 { 438 | err = amf0ParseErr("date", offset+n, err) 439 | return 440 | } 441 | ts := parseBEFloat64(b[n:]) 442 | n += 8 + 2 443 | 444 | val = time.Unix(int64(ts/1000), (int64(ts)%1000)*1000000) 445 | 446 | case longstringmarker: 447 | if len(b) < n+4 { 448 | err = amf0ParseErr("longstring.length", offset+n, err) 449 | return 450 | } 451 | length := int(pio.U32BE(b[n:])) 452 | n += 4 453 | 454 | if len(b) < n+length { 455 | err = amf0ParseErr("longstring.body", offset+n, err) 456 | return 457 | } 458 | val = string(b[n : n+length]) 459 | n += length 460 | 461 | default: 462 | err = amf0ParseErr(fmt.Sprintf("invalidmarker=%d", marker), offset+n, err) 463 | return 464 | } 465 | 466 | return 467 | } 468 | -------------------------------------------------------------------------------- /aac/parser.go: -------------------------------------------------------------------------------- 1 | package aac 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "time" 8 | 9 | "github.com/notedit/rtmp-lib/av" 10 | "github.com/notedit/rtmp-lib/bits" 11 | ) 12 | 13 | const ( 14 | AOT_AAC_MAIN = 1 + iota ///< Y Main 15 | AOT_AAC_LC ///< Y Low Complexity 16 | AOT_AAC_SSR ///< N (code in SoC repo) Scalable Sample Rate 17 | AOT_AAC_LTP ///< Y Long Term Prediction 18 | AOT_SBR ///< Y Spectral Band Replication 19 | AOT_AAC_SCALABLE ///< N Scalable 20 | AOT_TWINVQ ///< N Twin Vector Quantizer 21 | AOT_CELP ///< N Code Excited Linear Prediction 22 | AOT_HVXC ///< N Harmonic Vector eXcitation Coding 23 | AOT_TTSI = 12 + iota ///< N Text-To-Speech Interface 24 | AOT_MAINSYNTH ///< N Main Synthesis 25 | AOT_WAVESYNTH ///< N Wavetable Synthesis 26 | AOT_MIDI ///< N General MIDI 27 | AOT_SAFX ///< N Algorithmic Synthesis and Audio Effects 28 | AOT_ER_AAC_LC ///< N Error Resilient Low Complexity 29 | AOT_ER_AAC_LTP = 19 + iota ///< N Error Resilient Long Term Prediction 30 | AOT_ER_AAC_SCALABLE ///< N Error Resilient Scalable 31 | AOT_ER_TWINVQ ///< N Error Resilient Twin Vector Quantizer 32 | AOT_ER_BSAC ///< N Error Resilient Bit-Sliced Arithmetic Coding 33 | AOT_ER_AAC_LD ///< N Error Resilient Low Delay 34 | AOT_ER_CELP ///< N Error Resilient Code Excited Linear Prediction 35 | AOT_ER_HVXC ///< N Error Resilient Harmonic Vector eXcitation Coding 36 | AOT_ER_HILN ///< N Error Resilient Harmonic and Individual Lines plus Noise 37 | AOT_ER_PARAM ///< N Error Resilient Parametric 38 | AOT_SSC ///< N SinuSoidal Coding 39 | AOT_PS ///< N Parametric Stereo 40 | AOT_SURROUND ///< N MPEG Surround 41 | AOT_ESCAPE ///< Y Escape Value 42 | AOT_L1 ///< Y Layer 1 43 | AOT_L2 ///< Y Layer 2 44 | AOT_L3 ///< Y Layer 3 45 | AOT_DST ///< N Direct Stream Transfer 46 | AOT_ALS ///< Y Audio LosslesS 47 | AOT_SLS ///< N Scalable LosslesS 48 | AOT_SLS_NON_CORE ///< N Scalable LosslesS (non core) 49 | AOT_ER_AAC_ELD ///< N Error Resilient Enhanced Low Delay 50 | AOT_SMR_SIMPLE ///< N Symbolic Music Representation Simple 51 | AOT_SMR_MAIN ///< N Symbolic Music Representation Main 52 | AOT_USAC_NOSBR ///< N Unified Speech and Audio Coding (no SBR) 53 | AOT_SAOC ///< N Spatial Audio Object Coding 54 | AOT_LD_SURROUND ///< N Low Delay MPEG Surround 55 | AOT_USAC ///< N Unified Speech and Audio Coding 56 | ) 57 | 58 | type MPEG4AudioConfig struct { 59 | SampleRate int 60 | ChannelLayout av.ChannelLayout 61 | ObjectType uint 62 | SampleRateIndex uint 63 | ChannelConfig uint 64 | } 65 | 66 | var sampleRateTable = []int{ 67 | 96000, 88200, 64000, 48000, 44100, 32000, 68 | 24000, 22050, 16000, 12000, 11025, 8000, 7350, 69 | } 70 | 71 | /* 72 | These are the channel configurations: 73 | 0: Defined in AOT Specifc Config 74 | 1: 1 channel: front-center 75 | 2: 2 channels: front-left, front-right 76 | 3: 3 channels: front-center, front-left, front-right 77 | 4: 4 channels: front-center, front-left, front-right, back-center 78 | 5: 5 channels: front-center, front-left, front-right, back-left, back-right 79 | 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel 80 | 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel 81 | 8-15: Reserved 82 | */ 83 | var chanConfigTable = []av.ChannelLayout{ 84 | 0, 85 | av.CH_FRONT_CENTER, 86 | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT, 87 | av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT, 88 | av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_BACK_CENTER, 89 | av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_BACK_LEFT | av.CH_BACK_RIGHT, 90 | av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_BACK_LEFT | av.CH_BACK_RIGHT | av.CH_LOW_FREQ, 91 | av.CH_FRONT_CENTER | av.CH_FRONT_LEFT | av.CH_FRONT_RIGHT | av.CH_SIDE_LEFT | av.CH_SIDE_RIGHT | av.CH_BACK_LEFT | av.CH_BACK_RIGHT | av.CH_LOW_FREQ, 92 | } 93 | 94 | func ParseADTSHeader(frame []byte) (config MPEG4AudioConfig, hdrlen int, framelen int, samples int, err error) { 95 | if frame[0] != 0xff || frame[1]&0xf6 != 0xf0 { 96 | err = fmt.Errorf("aacparser: not adts header") 97 | return 98 | } 99 | config.ObjectType = uint(frame[2]>>6) + 1 100 | config.SampleRateIndex = uint(frame[2] >> 2 & 0xf) 101 | config.ChannelConfig = uint(frame[2]<<2&0x4 | frame[3]>>6&0x3) 102 | if config.ChannelConfig == uint(0) { 103 | err = fmt.Errorf("aacparser: adts channel count invalid") 104 | return 105 | } 106 | (&config).Complete() 107 | framelen = int(frame[3]&0x3)<<11 | int(frame[4])<<3 | int(frame[5]>>5) 108 | samples = (int(frame[6]&0x3) + 1) * 1024 109 | hdrlen = 7 110 | if frame[1]&0x1 == 0 { 111 | hdrlen = 9 112 | } 113 | if framelen < hdrlen { 114 | err = fmt.Errorf("aacparser: adts framelen < hdrlen") 115 | return 116 | } 117 | return 118 | } 119 | 120 | const ADTSHeaderLength = 7 121 | 122 | func FillADTSHeader(header []byte, config MPEG4AudioConfig, samples int, payloadLength int) { 123 | payloadLength += 7 124 | //AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ) 125 | header[0] = 0xff 126 | header[1] = 0xf1 127 | header[2] = 0x50 128 | header[3] = 0x80 129 | header[4] = 0x43 130 | header[5] = 0xff 131 | header[6] = 0xcd 132 | //config.ObjectType = uint(frames[2]>>6)+1 133 | //config.SampleRateIndex = uint(frames[2]>>2&0xf) 134 | //config.ChannelConfig = uint(frames[2]<<2&0x4|frames[3]>>6&0x3) 135 | header[2] = (byte(config.ObjectType-1)&0x3)<<6 | (byte(config.SampleRateIndex)&0xf)<<2 | byte(config.ChannelConfig>>2)&0x1 136 | header[3] = header[3]&0x3f | byte(config.ChannelConfig&0x3)<<6 137 | header[3] = header[3]&0xfc | byte(payloadLength>>11)&0x3 138 | header[4] = byte(payloadLength >> 3) 139 | header[5] = header[5]&0x1f | (byte(payloadLength)&0x7)<<5 140 | header[6] = header[6]&0xfc | byte(samples/1024-1) 141 | return 142 | } 143 | 144 | func readObjectType(r *bits.Reader) (objectType uint, err error) { 145 | if objectType, err = r.ReadBits(5); err != nil { 146 | return 147 | } 148 | if objectType == AOT_ESCAPE { 149 | var i uint 150 | if i, err = r.ReadBits(6); err != nil { 151 | return 152 | } 153 | objectType = 32 + i 154 | } 155 | return 156 | } 157 | 158 | func writeObjectType(w *bits.Writer, objectType uint) (err error) { 159 | if objectType >= 32 { 160 | if err = w.WriteBits(AOT_ESCAPE, 5); err != nil { 161 | return 162 | } 163 | if err = w.WriteBits(objectType-32, 6); err != nil { 164 | return 165 | } 166 | } else { 167 | if err = w.WriteBits(objectType, 5); err != nil { 168 | return 169 | } 170 | } 171 | return 172 | } 173 | 174 | func readSampleRateIndex(r *bits.Reader) (index uint, err error) { 175 | if index, err = r.ReadBits(4); err != nil { 176 | return 177 | } 178 | if index == 0xf { 179 | if index, err = r.ReadBits(24); err != nil { 180 | return 181 | } 182 | } 183 | return 184 | } 185 | 186 | func writeSampleRateIndex(w *bits.Writer, index uint) (err error) { 187 | if index >= 0xf { 188 | if err = w.WriteBits(0xf, 4); err != nil { 189 | return 190 | } 191 | if err = w.WriteBits(index, 24); err != nil { 192 | return 193 | } 194 | } else { 195 | if err = w.WriteBits(index, 4); err != nil { 196 | return 197 | } 198 | } 199 | return 200 | } 201 | 202 | func (self MPEG4AudioConfig) IsValid() bool { 203 | return self.ObjectType > 0 204 | } 205 | 206 | func (self *MPEG4AudioConfig) Complete() { 207 | if int(self.SampleRateIndex) < len(sampleRateTable) { 208 | self.SampleRate = sampleRateTable[self.SampleRateIndex] 209 | } 210 | if int(self.ChannelConfig) < len(chanConfigTable) { 211 | self.ChannelLayout = chanConfigTable[self.ChannelConfig] 212 | } 213 | return 214 | } 215 | 216 | func ParseMPEG4AudioConfigBytes(data []byte) (config MPEG4AudioConfig, err error) { 217 | // copied from libavcodec/mpeg4audio.c avpriv_mpeg4audio_get_config() 218 | r := bytes.NewReader(data) 219 | br := &bits.Reader{R: r} 220 | if config.ObjectType, err = readObjectType(br); err != nil { 221 | return 222 | } 223 | if config.SampleRateIndex, err = readSampleRateIndex(br); err != nil { 224 | return 225 | } 226 | if config.ChannelConfig, err = br.ReadBits(4); err != nil { 227 | return 228 | } 229 | (&config).Complete() 230 | return 231 | } 232 | 233 | func WriteMPEG4AudioConfig(w io.Writer, config MPEG4AudioConfig) (err error) { 234 | bw := &bits.Writer{W: w} 235 | if err = writeObjectType(bw, config.ObjectType); err != nil { 236 | return 237 | } 238 | 239 | if config.SampleRateIndex == 0 { 240 | for i, rate := range sampleRateTable { 241 | if rate == config.SampleRate { 242 | config.SampleRateIndex = uint(i) 243 | } 244 | } 245 | } 246 | if err = writeSampleRateIndex(bw, config.SampleRateIndex); err != nil { 247 | return 248 | } 249 | 250 | if config.ChannelConfig == 0 { 251 | for i, layout := range chanConfigTable { 252 | if layout == config.ChannelLayout { 253 | config.ChannelConfig = uint(i) 254 | } 255 | } 256 | } 257 | if err = bw.WriteBits(config.ChannelConfig, 4); err != nil { 258 | return 259 | } 260 | 261 | if err = bw.FlushBits(); err != nil { 262 | return 263 | } 264 | return 265 | } 266 | 267 | type CodecData struct { 268 | ConfigBytes []byte 269 | Config MPEG4AudioConfig 270 | } 271 | 272 | func (self CodecData) Type() av.CodecType { 273 | return av.AAC 274 | } 275 | 276 | func (self CodecData) MPEG4AudioConfigBytes() []byte { 277 | return self.ConfigBytes 278 | } 279 | 280 | func (self CodecData) ChannelLayout() av.ChannelLayout { 281 | return self.Config.ChannelLayout 282 | } 283 | 284 | func (self CodecData) SampleRate() int { 285 | return self.Config.SampleRate 286 | } 287 | 288 | func (self CodecData) SampleFormat() av.SampleFormat { 289 | return av.FLTP 290 | } 291 | 292 | func (self CodecData) PacketDuration(data []byte) (dur time.Duration, err error) { 293 | dur = time.Duration(1024) * time.Second / time.Duration(self.Config.SampleRate) 294 | return 295 | } 296 | 297 | func NewCodecDataFromMPEG4AudioConfig(config MPEG4AudioConfig) (self CodecData, err error) { 298 | b := &bytes.Buffer{} 299 | WriteMPEG4AudioConfig(b, config) 300 | return NewCodecDataFromMPEG4AudioConfigBytes(b.Bytes()) 301 | } 302 | 303 | func NewCodecDataFromMPEG4AudioConfigBytes(config []byte) (self CodecData, err error) { 304 | self.ConfigBytes = config 305 | if self.Config, err = ParseMPEG4AudioConfigBytes(config); err != nil { 306 | err = fmt.Errorf("aacparser: parse MPEG4AudioConfig failed(%s)", err) 307 | return 308 | } 309 | return 310 | } 311 | -------------------------------------------------------------------------------- /h264/parser.go: -------------------------------------------------------------------------------- 1 | package h264 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | "github.com/notedit/rtmp-lib/av" 8 | "github.com/notedit/rtmp-lib/bits" 9 | "github.com/notedit/rtmp-lib/pio" 10 | ) 11 | 12 | const ( 13 | NALU_SEI = 6 14 | NALU_PPS = 7 15 | NALU_SPS = 8 16 | NALU_AUD = 9 17 | ) 18 | 19 | const ( 20 | NALU_RAW = iota 21 | NALU_AVCC 22 | NALU_ANNEXB 23 | ) 24 | 25 | func SplitNALUs(b []byte) (nalus [][]byte, typ int) { 26 | if len(b) < 4 { 27 | return [][]byte{b}, NALU_RAW 28 | } 29 | 30 | val3 := pio.U24BE(b) 31 | val4 := pio.U32BE(b) 32 | 33 | // maybe AVCC 34 | if val4 <= uint32(len(b)) { 35 | _val4 := val4 36 | _b := b[4:] 37 | nalus := [][]byte{} 38 | for { 39 | nalus = append(nalus, _b[:_val4]) 40 | _b = _b[_val4:] 41 | if len(_b) < 4 { 42 | break 43 | } 44 | _val4 = pio.U32BE(_b) 45 | _b = _b[4:] 46 | if _val4 > uint32(len(_b)) { 47 | break 48 | } 49 | } 50 | if len(_b) == 0 { 51 | return nalus, NALU_AVCC 52 | } 53 | } 54 | 55 | // is Annex B 56 | if val3 == 1 || val4 == 1 { 57 | _val3 := val3 58 | _val4 := val4 59 | start := 0 60 | pos := 0 61 | for { 62 | if start != pos { 63 | nalus = append(nalus, b[start:pos]) 64 | } 65 | if _val3 == 1 { 66 | pos += 3 67 | } else if _val4 == 1 { 68 | pos += 4 69 | } 70 | start = pos 71 | if start == len(b) { 72 | break 73 | } 74 | _val3 = 0 75 | _val4 = 0 76 | for pos < len(b) { 77 | if pos+2 < len(b) && b[pos] == 0 { 78 | _val3 = pio.U24BE(b[pos:]) 79 | if _val3 == 0 { 80 | if pos+3 < len(b) { 81 | _val4 = uint32(b[pos+3]) 82 | if _val4 == 1 { 83 | break 84 | } 85 | } 86 | } else if _val3 == 1 { 87 | break 88 | } 89 | pos++ 90 | } else { 91 | pos++ 92 | } 93 | } 94 | } 95 | typ = NALU_ANNEXB 96 | return 97 | } 98 | 99 | return [][]byte{b}, NALU_RAW 100 | } 101 | 102 | func IsDataNALU(b []byte) bool { 103 | typ := b[0] & 0x1f 104 | return typ >= 1 && typ <= 5 105 | } 106 | 107 | type SPSInfo struct { 108 | ProfileIdc uint 109 | LevelIdc uint 110 | 111 | MbWidth uint 112 | MbHeight uint 113 | 114 | CropLeft uint 115 | CropRight uint 116 | CropTop uint 117 | CropBottom uint 118 | 119 | Width uint 120 | Height uint 121 | } 122 | 123 | func ParseSPS(data []byte) (self SPSInfo, err error) { 124 | r := &bits.GolombBitReader{R: bytes.NewReader(data)} 125 | 126 | if _, err = r.ReadBits(8); err != nil { 127 | return 128 | } 129 | 130 | if self.ProfileIdc, err = r.ReadBits(8); err != nil { 131 | return 132 | } 133 | 134 | // constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits 135 | if _, err = r.ReadBits(8); err != nil { 136 | return 137 | } 138 | 139 | // level_idc 140 | if self.LevelIdc, err = r.ReadBits(8); err != nil { 141 | return 142 | } 143 | 144 | // seq_parameter_set_id 145 | if _, err = r.ReadExponentialGolombCode(); err != nil { 146 | return 147 | } 148 | 149 | if self.ProfileIdc == 100 || self.ProfileIdc == 110 || 150 | self.ProfileIdc == 122 || self.ProfileIdc == 244 || 151 | self.ProfileIdc == 44 || self.ProfileIdc == 83 || 152 | self.ProfileIdc == 86 || self.ProfileIdc == 118 { 153 | 154 | var chroma_format_idc uint 155 | if chroma_format_idc, err = r.ReadExponentialGolombCode(); err != nil { 156 | return 157 | } 158 | 159 | if chroma_format_idc == 3 { 160 | // residual_colour_transform_flag 161 | if _, err = r.ReadBit(); err != nil { 162 | return 163 | } 164 | } 165 | 166 | // bit_depth_luma_minus8 167 | if _, err = r.ReadExponentialGolombCode(); err != nil { 168 | return 169 | } 170 | // bit_depth_chroma_minus8 171 | if _, err = r.ReadExponentialGolombCode(); err != nil { 172 | return 173 | } 174 | // qpprime_y_zero_transform_bypass_flag 175 | if _, err = r.ReadBit(); err != nil { 176 | return 177 | } 178 | 179 | var seq_scaling_matrix_present_flag uint 180 | if seq_scaling_matrix_present_flag, err = r.ReadBit(); err != nil { 181 | return 182 | } 183 | 184 | if seq_scaling_matrix_present_flag != 0 { 185 | for i := 0; i < 8; i++ { 186 | var seq_scaling_list_present_flag uint 187 | if seq_scaling_list_present_flag, err = r.ReadBit(); err != nil { 188 | return 189 | } 190 | if seq_scaling_list_present_flag != 0 { 191 | var sizeOfScalingList uint 192 | if i < 6 { 193 | sizeOfScalingList = 16 194 | } else { 195 | sizeOfScalingList = 64 196 | } 197 | lastScale := uint(8) 198 | nextScale := uint(8) 199 | for j := uint(0); j < sizeOfScalingList; j++ { 200 | if nextScale != 0 { 201 | var delta_scale uint 202 | if delta_scale, err = r.ReadSE(); err != nil { 203 | return 204 | } 205 | nextScale = (lastScale + delta_scale + 256) % 256 206 | } 207 | if nextScale != 0 { 208 | lastScale = nextScale 209 | } 210 | } 211 | } 212 | } 213 | } 214 | } 215 | 216 | // log2_max_frame_num_minus4 217 | if _, err = r.ReadExponentialGolombCode(); err != nil { 218 | return 219 | } 220 | 221 | var pic_order_cnt_type uint 222 | if pic_order_cnt_type, err = r.ReadExponentialGolombCode(); err != nil { 223 | return 224 | } 225 | if pic_order_cnt_type == 0 { 226 | // log2_max_pic_order_cnt_lsb_minus4 227 | if _, err = r.ReadExponentialGolombCode(); err != nil { 228 | return 229 | } 230 | } else if pic_order_cnt_type == 1 { 231 | // delta_pic_order_always_zero_flag 232 | if _, err = r.ReadBit(); err != nil { 233 | return 234 | } 235 | // offset_for_non_ref_pic 236 | if _, err = r.ReadSE(); err != nil { 237 | return 238 | } 239 | // offset_for_top_to_bottom_field 240 | if _, err = r.ReadSE(); err != nil { 241 | return 242 | } 243 | var num_ref_frames_in_pic_order_cnt_cycle uint 244 | if num_ref_frames_in_pic_order_cnt_cycle, err = r.ReadExponentialGolombCode(); err != nil { 245 | return 246 | } 247 | for i := uint(0); i < num_ref_frames_in_pic_order_cnt_cycle; i++ { 248 | if _, err = r.ReadSE(); err != nil { 249 | return 250 | } 251 | } 252 | } 253 | 254 | // max_num_ref_frames 255 | if _, err = r.ReadExponentialGolombCode(); err != nil { 256 | return 257 | } 258 | 259 | // gaps_in_frame_num_value_allowed_flag 260 | if _, err = r.ReadBit(); err != nil { 261 | return 262 | } 263 | 264 | if self.MbWidth, err = r.ReadExponentialGolombCode(); err != nil { 265 | return 266 | } 267 | self.MbWidth++ 268 | 269 | if self.MbHeight, err = r.ReadExponentialGolombCode(); err != nil { 270 | return 271 | } 272 | self.MbHeight++ 273 | 274 | var frame_mbs_only_flag uint 275 | if frame_mbs_only_flag, err = r.ReadBit(); err != nil { 276 | return 277 | } 278 | if frame_mbs_only_flag == 0 { 279 | // mb_adaptive_frame_field_flag 280 | if _, err = r.ReadBit(); err != nil { 281 | return 282 | } 283 | } 284 | 285 | // direct_8x8_inference_flag 286 | if _, err = r.ReadBit(); err != nil { 287 | return 288 | } 289 | 290 | var frame_cropping_flag uint 291 | if frame_cropping_flag, err = r.ReadBit(); err != nil { 292 | return 293 | } 294 | if frame_cropping_flag != 0 { 295 | if self.CropLeft, err = r.ReadExponentialGolombCode(); err != nil { 296 | return 297 | } 298 | if self.CropRight, err = r.ReadExponentialGolombCode(); err != nil { 299 | return 300 | } 301 | if self.CropTop, err = r.ReadExponentialGolombCode(); err != nil { 302 | return 303 | } 304 | if self.CropBottom, err = r.ReadExponentialGolombCode(); err != nil { 305 | return 306 | } 307 | } 308 | 309 | self.Width = (self.MbWidth * 16) - self.CropLeft*2 - self.CropRight*2 310 | self.Height = ((2 - frame_mbs_only_flag) * self.MbHeight * 16) - self.CropTop*2 - self.CropBottom*2 311 | 312 | return 313 | } 314 | 315 | type CodecData struct { 316 | Record []byte 317 | RecordInfo AVCDecoderConfRecord 318 | SPSInfo SPSInfo 319 | } 320 | 321 | func (self CodecData) Type() av.CodecType { 322 | return av.H264 323 | } 324 | 325 | func (self CodecData) AVCDecoderConfRecordBytes() []byte { 326 | return self.Record 327 | } 328 | 329 | func (self CodecData) SPS() []byte { 330 | return self.RecordInfo.SPS[0] 331 | } 332 | 333 | func (self CodecData) PPS() []byte { 334 | return self.RecordInfo.PPS[0] 335 | } 336 | 337 | func (self CodecData) Width() int { 338 | return int(self.SPSInfo.Width) 339 | } 340 | 341 | func (self CodecData) Height() int { 342 | return int(self.SPSInfo.Height) 343 | } 344 | 345 | func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err error) { 346 | self.Record = record 347 | if _, err = (&self.RecordInfo).Unmarshal(record); err != nil { 348 | return 349 | } 350 | if len(self.RecordInfo.SPS) == 0 { 351 | err = fmt.Errorf("h264parser: no SPS found in AVCDecoderConfRecord") 352 | return 353 | } 354 | if len(self.RecordInfo.PPS) == 0 { 355 | err = fmt.Errorf("h264parser: no PPS found in AVCDecoderConfRecord") 356 | return 357 | } 358 | if self.SPSInfo, err = ParseSPS(self.RecordInfo.SPS[0]); err != nil { 359 | err = fmt.Errorf("h264parser: parse SPS failed(%s)", err) 360 | return 361 | } 362 | return 363 | } 364 | 365 | func NewCodecDataFromSPSAndPPS(sps, pps []byte) (self CodecData, err error) { 366 | recordinfo := AVCDecoderConfRecord{} 367 | recordinfo.AVCProfileIndication = sps[1] 368 | recordinfo.ProfileCompatibility = sps[2] 369 | recordinfo.AVCLevelIndication = sps[3] 370 | recordinfo.SPS = [][]byte{sps} 371 | recordinfo.PPS = [][]byte{pps} 372 | recordinfo.LengthSizeMinusOne = 3 373 | 374 | buf := make([]byte, recordinfo.Len()) 375 | recordinfo.Marshal(buf) 376 | 377 | self.RecordInfo = recordinfo 378 | self.Record = buf 379 | 380 | if self.SPSInfo, err = ParseSPS(sps); err != nil { 381 | return 382 | } 383 | return 384 | } 385 | 386 | type AVCDecoderConfRecord struct { 387 | AVCProfileIndication uint8 388 | ProfileCompatibility uint8 389 | AVCLevelIndication uint8 390 | LengthSizeMinusOne uint8 391 | SPS [][]byte 392 | PPS [][]byte 393 | } 394 | 395 | var ErrDecconfInvalid = fmt.Errorf("h264parser: AVCDecoderConfRecord invalid") 396 | 397 | func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) { 398 | if len(b) < 7 { 399 | err = ErrDecconfInvalid 400 | return 401 | } 402 | 403 | self.AVCProfileIndication = b[1] 404 | self.ProfileCompatibility = b[2] 405 | self.AVCLevelIndication = b[3] 406 | self.LengthSizeMinusOne = b[4] & 0x03 407 | spscount := int(b[5] & 0x1f) 408 | n += 6 409 | 410 | for i := 0; i < spscount; i++ { 411 | if len(b) < n+2 { 412 | err = ErrDecconfInvalid 413 | return 414 | } 415 | spslen := int(pio.U16BE(b[n:])) 416 | n += 2 417 | 418 | if len(b) < n+spslen { 419 | err = ErrDecconfInvalid 420 | return 421 | } 422 | self.SPS = append(self.SPS, b[n:n+spslen]) 423 | n += spslen 424 | } 425 | 426 | if len(b) < n+1 { 427 | err = ErrDecconfInvalid 428 | return 429 | } 430 | ppscount := int(b[n]) 431 | n++ 432 | 433 | for i := 0; i < ppscount; i++ { 434 | if len(b) < n+2 { 435 | err = ErrDecconfInvalid 436 | return 437 | } 438 | ppslen := int(pio.U16BE(b[n:])) 439 | n += 2 440 | 441 | if len(b) < n+ppslen { 442 | err = ErrDecconfInvalid 443 | return 444 | } 445 | self.PPS = append(self.PPS, b[n:n+ppslen]) 446 | n += ppslen 447 | } 448 | 449 | return 450 | } 451 | 452 | func (self AVCDecoderConfRecord) Len() (n int) { 453 | n = 7 454 | for _, sps := range self.SPS { 455 | n += 2 + len(sps) 456 | } 457 | for _, pps := range self.PPS { 458 | n += 2 + len(pps) 459 | } 460 | return 461 | } 462 | 463 | func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) { 464 | b[0] = 1 465 | b[1] = self.AVCProfileIndication 466 | b[2] = self.ProfileCompatibility 467 | b[3] = self.AVCLevelIndication 468 | b[4] = self.LengthSizeMinusOne | 0xfc 469 | b[5] = uint8(len(self.SPS)) | 0xe0 470 | n += 6 471 | 472 | for _, sps := range self.SPS { 473 | pio.PutU16BE(b[n:], uint16(len(sps))) 474 | n += 2 475 | copy(b[n:], sps) 476 | n += len(sps) 477 | } 478 | 479 | b[n] = uint8(len(self.PPS)) 480 | n++ 481 | 482 | for _, pps := range self.PPS { 483 | pio.PutU16BE(b[n:], uint16(len(pps))) 484 | n += 2 485 | copy(b[n:], pps) 486 | n += len(pps) 487 | } 488 | 489 | return 490 | } 491 | -------------------------------------------------------------------------------- /flv/flv.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "time" 8 | 9 | "github.com/notedit/rtmp-lib/aac" 10 | "github.com/notedit/rtmp-lib/av" 11 | "github.com/notedit/rtmp-lib/h264" 12 | "github.com/notedit/rtmp-lib/pio" 13 | ) 14 | 15 | var MaxProbePacketCount = 20 16 | 17 | func TsToTime(ts int32) time.Duration { 18 | return time.Millisecond * time.Duration(ts) 19 | } 20 | 21 | func TimeToTs(tm time.Duration) int32 { 22 | return int32(tm / time.Millisecond) 23 | } 24 | 25 | const MaxTagSubHeaderLength = 16 26 | 27 | const ( 28 | TAG_AUDIO = 8 29 | TAG_VIDEO = 9 30 | TAG_SCRIPTDATA = 18 31 | ) 32 | 33 | const ( 34 | SOUND_MP3 = 2 35 | SOUND_NELLYMOSER_16KHZ_MONO = 4 36 | SOUND_NELLYMOSER_8KHZ_MONO = 5 37 | SOUND_NELLYMOSER = 6 38 | SOUND_ALAW = 7 39 | SOUND_MULAW = 8 40 | SOUND_AAC = 10 41 | SOUND_SPEEX = 11 42 | 43 | SOUND_5_5Khz = 0 44 | SOUND_11Khz = 1 45 | SOUND_22Khz = 2 46 | SOUND_44Khz = 3 47 | 48 | SOUND_8BIT = 0 49 | SOUND_16BIT = 1 50 | 51 | SOUND_MONO = 0 52 | SOUND_STEREO = 1 53 | 54 | AAC_SEQHDR = 0 55 | AAC_RAW = 1 56 | ) 57 | 58 | const ( 59 | AVC_SEQHDR = 0 60 | AVC_NALU = 1 61 | AVC_EOS = 2 62 | 63 | FRAME_KEY = 1 64 | FRAME_INTER = 2 65 | 66 | VIDEO_H264 = 7 67 | ) 68 | 69 | type Tag struct { 70 | Type uint8 71 | 72 | /* 73 | SoundFormat: UB[4] 74 | 0 = Linear PCM, platform endian 75 | 1 = ADPCM 76 | 2 = MP3 77 | 3 = Linear PCM, little endian 78 | 4 = Nellymoser 16-kHz mono 79 | 5 = Nellymoser 8-kHz mono 80 | 6 = Nellymoser 81 | 7 = G.711 A-law logarithmic PCM 82 | 8 = G.711 mu-law logarithmic PCM 83 | 9 = reserved 84 | 10 = AAC 85 | 11 = Speex 86 | 14 = MP3 8-Khz 87 | 15 = Device-specific sound 88 | Formats 7, 8, 14, and 15 are reserved for internal use 89 | AAC is supported in Flash Player 9,0,115,0 and higher. 90 | Speex is supported in Flash Player 10 and higher. 91 | */ 92 | SoundFormat uint8 93 | 94 | /* 95 | SoundRate: UB[2] 96 | Sampling rate 97 | 0 = 5.5-kHz For AAC: always 3 98 | 1 = 11-kHz 99 | 2 = 22-kHz 100 | 3 = 44-kHz 101 | */ 102 | SoundRate uint8 103 | 104 | /* 105 | SoundSize: UB[1] 106 | 0 = snd8Bit 107 | 1 = snd16Bit 108 | Size of each sample. 109 | This parameter only pertains to uncompressed formats. 110 | Compressed formats always decode to 16 bits internally 111 | */ 112 | SoundSize uint8 113 | 114 | /* 115 | SoundType: UB[1] 116 | 0 = sndMono 117 | 1 = sndStereo 118 | Mono or stereo sound For Nellymoser: always 0 119 | For AAC: always 1 120 | */ 121 | SoundType uint8 122 | 123 | /* 124 | 0: AAC sequence header 125 | 1: AAC raw 126 | */ 127 | AACPacketType uint8 128 | 129 | /* 130 | 1: keyframe (for AVC, a seekable frame) 131 | 2: inter frame (for AVC, a non- seekable frame) 132 | 3: disposable inter frame (H.263 only) 133 | 4: generated keyframe (reserved for server use only) 134 | 5: video info/command frame 135 | */ 136 | FrameType uint8 137 | 138 | /* 139 | 1: JPEG (currently unused) 140 | 2: Sorenson H.263 141 | 3: Screen video 142 | 4: On2 VP6 143 | 5: On2 VP6 with alpha channel 144 | 6: Screen video version 2 145 | 7: AVC 146 | */ 147 | CodecID uint8 148 | 149 | /* 150 | 0: AVC sequence header 151 | 1: AVC NALU 152 | 2: AVC end of sequence (lower level NALU sequence ender is not required or supported) 153 | */ 154 | AVCPacketType uint8 155 | 156 | CompositionTime int32 157 | 158 | Data []byte 159 | } 160 | 161 | func (self Tag) ChannelLayout() av.ChannelLayout { 162 | if self.SoundType == SOUND_MONO { 163 | return av.CH_MONO 164 | } else { 165 | return av.CH_STEREO 166 | } 167 | } 168 | 169 | func (self *Tag) audioParseHeader(b []byte) (n int, err error) { 170 | if len(b) < n+1 { 171 | err = fmt.Errorf("audiodata: parse invalid") 172 | return 173 | } 174 | 175 | flags := b[n] 176 | n++ 177 | self.SoundFormat = flags >> 4 178 | self.SoundRate = (flags >> 2) & 0x3 179 | self.SoundSize = (flags >> 1) & 0x1 180 | self.SoundType = flags & 0x1 181 | 182 | switch self.SoundFormat { 183 | case SOUND_AAC: 184 | if len(b) < n+1 { 185 | err = fmt.Errorf("audiodata: parse invalid") 186 | return 187 | } 188 | self.AACPacketType = b[n] 189 | n++ 190 | } 191 | 192 | return 193 | } 194 | 195 | func (self Tag) audioFillHeader(b []byte) (n int) { 196 | var flags uint8 197 | flags |= self.SoundFormat << 4 198 | flags |= self.SoundRate << 2 199 | flags |= self.SoundSize << 1 200 | flags |= self.SoundType 201 | b[n] = flags 202 | n++ 203 | 204 | switch self.SoundFormat { 205 | case SOUND_AAC: 206 | b[n] = self.AACPacketType 207 | n++ 208 | } 209 | 210 | return 211 | } 212 | 213 | func (self *Tag) videoParseHeader(b []byte) (n int, err error) { 214 | if len(b) < n+1 { 215 | err = fmt.Errorf("videodata: parse invalid") 216 | return 217 | } 218 | flags := b[n] 219 | self.FrameType = flags >> 4 220 | self.CodecID = flags & 0xf 221 | n++ 222 | 223 | if self.FrameType == FRAME_INTER || self.FrameType == FRAME_KEY { 224 | if len(b) < n+4 { 225 | err = fmt.Errorf("videodata: parse invalid") 226 | return 227 | } 228 | self.AVCPacketType = b[n] 229 | n++ 230 | 231 | self.CompositionTime = pio.I24BE(b[n:]) 232 | n += 3 233 | } 234 | 235 | return 236 | } 237 | 238 | func (self Tag) videoFillHeader(b []byte) (n int) { 239 | flags := self.FrameType<<4 | self.CodecID 240 | b[n] = flags 241 | n++ 242 | b[n] = self.AVCPacketType 243 | n++ 244 | pio.PutI24BE(b[n:], self.CompositionTime) 245 | n += 3 246 | return 247 | } 248 | 249 | func (self Tag) FillHeader(b []byte) (n int) { 250 | switch self.Type { 251 | case TAG_AUDIO: 252 | return self.audioFillHeader(b) 253 | 254 | case TAG_VIDEO: 255 | return self.videoFillHeader(b) 256 | } 257 | 258 | return 259 | } 260 | 261 | func (self *Tag) ParseHeader(b []byte) (n int, err error) { 262 | switch self.Type { 263 | case TAG_AUDIO: 264 | return self.audioParseHeader(b) 265 | 266 | case TAG_VIDEO: 267 | return self.videoParseHeader(b) 268 | } 269 | 270 | return 271 | } 272 | 273 | const ( 274 | // TypeFlagsReserved UB[5] 275 | // TypeFlagsAudio UB[1] Audio tags are present 276 | // TypeFlagsReserved UB[1] Must be 0 277 | // TypeFlagsVideo UB[1] Video tags are present 278 | FILE_HAS_AUDIO = 0x4 279 | FILE_HAS_VIDEO = 0x1 280 | ) 281 | 282 | const TagHeaderLength = 11 283 | const TagTrailerLength = 4 284 | 285 | func ParseTagHeader(b []byte) (tag Tag, ts int32, datalen int, err error) { 286 | tagtype := b[0] 287 | 288 | switch tagtype { 289 | case TAG_AUDIO, TAG_VIDEO, TAG_SCRIPTDATA: 290 | tag = Tag{Type: tagtype} 291 | 292 | default: 293 | err = fmt.Errorf("flv: ReadTag tagtype=%d invalid", tagtype) 294 | return 295 | } 296 | 297 | datalen = int(pio.U24BE(b[1:4])) 298 | 299 | var tslo uint32 300 | var tshi uint8 301 | tslo = pio.U24BE(b[4:7]) 302 | tshi = b[7] 303 | ts = int32(tslo | uint32(tshi)<<24) 304 | 305 | return 306 | } 307 | 308 | func ReadTag(r io.Reader, b []byte) (tag Tag, ts int32, err error) { 309 | if _, err = io.ReadFull(r, b[:TagHeaderLength]); err != nil { 310 | return 311 | } 312 | var datalen int 313 | if tag, ts, datalen, err = ParseTagHeader(b); err != nil { 314 | return 315 | } 316 | 317 | data := make([]byte, datalen) 318 | if _, err = io.ReadFull(r, data); err != nil { 319 | return 320 | } 321 | 322 | var n int 323 | if n, err = (&tag).ParseHeader(data); err != nil { 324 | return 325 | } 326 | tag.Data = data[n:] 327 | 328 | if _, err = io.ReadFull(r, b[:4]); err != nil { 329 | return 330 | } 331 | return 332 | } 333 | 334 | func FillTagHeader(b []byte, tagtype uint8, datalen int, ts int32) (n int) { 335 | b[n] = tagtype 336 | n++ 337 | pio.PutU24BE(b[n:], uint32(datalen)) 338 | n += 3 339 | pio.PutU24BE(b[n:], uint32(ts&0xffffff)) 340 | n += 3 341 | b[n] = uint8(ts >> 24) 342 | n++ 343 | pio.PutI24BE(b[n:], 0) 344 | n += 3 345 | return 346 | } 347 | 348 | func FillTagTrailer(b []byte, datalen int) (n int) { 349 | pio.PutU32BE(b[n:], uint32(datalen+TagHeaderLength)) 350 | n += 4 351 | return 352 | } 353 | 354 | func WriteTag(w io.Writer, tag Tag, ts int32, b []byte) (err error) { 355 | data := tag.Data 356 | 357 | n := tag.FillHeader(b[TagHeaderLength:]) 358 | datalen := len(data) + n 359 | 360 | n += FillTagHeader(b, tag.Type, datalen, ts) 361 | 362 | if _, err = w.Write(b[:n]); err != nil { 363 | return 364 | } 365 | 366 | if _, err = w.Write(data); err != nil { 367 | return 368 | } 369 | 370 | n = FillTagTrailer(b, datalen) 371 | if _, err = w.Write(b[:n]); err != nil { 372 | return 373 | } 374 | 375 | return 376 | } 377 | 378 | const FileHeaderLength = 9 379 | 380 | func FillFileHeader(b []byte, flags uint8) (n int) { 381 | // 'FLV', version 1 382 | pio.PutU32BE(b[n:], 0x464c5601) 383 | n += 4 384 | 385 | b[n] = flags 386 | n++ 387 | 388 | // DataOffset: UI32 Offset in bytes from start of file to start of body (that is, size of header) 389 | // The DataOffset field usually has a value of 9 for FLV version 1. 390 | pio.PutU32BE(b[n:], 9) 391 | n += 4 392 | 393 | // PreviousTagSize0: UI32 Always 0 394 | pio.PutU32BE(b[n:], 0) 395 | n += 4 396 | 397 | return 398 | } 399 | 400 | func ParseFileHeader(b []byte) (flags uint8, skip int, err error) { 401 | flv := pio.U24BE(b[0:3]) 402 | if flv != 0x464c56 { // 'FLV' 403 | err = fmt.Errorf("flv: file header cc3 invalid") 404 | return 405 | } 406 | 407 | flags = b[4] 408 | 409 | skip = int(pio.U32BE(b[5:9])) - 9 + 4 410 | if skip < 0 { 411 | err = fmt.Errorf("flv: file header datasize invalid") 412 | return 413 | } 414 | 415 | return 416 | } 417 | 418 | func NewMetadataByStreams(streams []av.CodecData) (metadata AMFMap, err error) { 419 | metadata = AMFMap{} 420 | 421 | for _, _stream := range streams { 422 | typ := _stream.Type() 423 | switch { 424 | case typ.IsVideo(): 425 | stream := _stream.(av.VideoCodecData) 426 | switch typ { 427 | case av.H264: 428 | metadata["videocodecid"] = VIDEO_H264 429 | 430 | default: 431 | err = fmt.Errorf("flv: metadata: unsupported video codecType=%v", stream.Type()) 432 | return 433 | } 434 | 435 | metadata["width"] = stream.Width() 436 | metadata["height"] = stream.Height() 437 | metadata["displayWidth"] = stream.Width() 438 | metadata["displayHeight"] = stream.Height() 439 | 440 | case typ.IsAudio(): 441 | stream := _stream.(av.AudioCodecData) 442 | switch typ { 443 | case av.AAC: 444 | metadata["audiocodecid"] = SOUND_AAC 445 | 446 | case av.SPEEX: 447 | metadata["audiocodecid"] = SOUND_SPEEX 448 | 449 | default: 450 | err = fmt.Errorf("flv: metadata: unsupported audio codecType=%v", stream.Type()) 451 | return 452 | } 453 | 454 | metadata["audiosamplerate"] = stream.SampleRate() 455 | } 456 | } 457 | 458 | return 459 | } 460 | 461 | type Prober struct { 462 | HasAudio, HasVideo bool 463 | GotAudio, GotVideo bool 464 | VideoStreamIdx, AudioStreamIdx int 465 | PushedCount int 466 | Streams []av.CodecData 467 | CachedPkts []av.Packet 468 | } 469 | 470 | func (self *Prober) CacheTag(_tag Tag, timestamp int32) { 471 | pkt, _ := self.TagToPacket(_tag, timestamp) 472 | self.CachedPkts = append(self.CachedPkts, pkt) 473 | } 474 | 475 | func (self *Prober) PushTag(tag Tag, timestamp int32) (err error) { 476 | self.PushedCount++ 477 | 478 | if self.PushedCount > MaxProbePacketCount { 479 | err = fmt.Errorf("flv: max probe packet count reached") 480 | return 481 | } 482 | 483 | switch tag.Type { 484 | case TAG_VIDEO: 485 | switch tag.AVCPacketType { 486 | case AVC_SEQHDR: 487 | if !self.GotVideo { 488 | var stream h264.CodecData 489 | if stream, err = h264.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil { 490 | err = fmt.Errorf("flv: h264 seqhdr invalid") 491 | return 492 | } 493 | self.VideoStreamIdx = len(self.Streams) 494 | self.Streams = append(self.Streams, stream) 495 | self.GotVideo = true 496 | } 497 | 498 | case AVC_NALU: 499 | self.CacheTag(tag, timestamp) 500 | } 501 | 502 | case TAG_AUDIO: 503 | switch tag.SoundFormat { 504 | case SOUND_AAC: 505 | switch tag.AACPacketType { 506 | case AAC_SEQHDR: 507 | if !self.GotAudio { 508 | var stream aac.CodecData 509 | if stream, err = aac.NewCodecDataFromMPEG4AudioConfigBytes(tag.Data); err != nil { 510 | err = fmt.Errorf("flv: aac seqhdr invalid") 511 | return 512 | } 513 | self.AudioStreamIdx = len(self.Streams) 514 | self.Streams = append(self.Streams, stream) 515 | self.GotAudio = true 516 | } 517 | 518 | case AAC_RAW: 519 | self.CacheTag(tag, timestamp) 520 | } 521 | } 522 | } 523 | 524 | return 525 | } 526 | 527 | func (self *Prober) Probed() (ok bool) { 528 | if self.HasAudio || self.HasVideo { 529 | if self.HasAudio == self.GotAudio && self.HasVideo == self.GotVideo { 530 | return true 531 | } 532 | } else { 533 | if self.PushedCount == MaxProbePacketCount { 534 | return true 535 | } 536 | } 537 | return 538 | } 539 | 540 | func (self *Prober) TagToPacket(tag Tag, timestamp int32) (pkt av.Packet, ok bool) { 541 | switch tag.Type { 542 | case TAG_VIDEO: 543 | pkt.Idx = int8(self.VideoStreamIdx) 544 | switch tag.AVCPacketType { 545 | case AVC_NALU: 546 | ok = true 547 | pkt.Data = tag.Data 548 | pkt.CompositionTime = TsToTime(tag.CompositionTime) 549 | pkt.IsKeyFrame = tag.FrameType == FRAME_KEY 550 | } 551 | 552 | case TAG_AUDIO: 553 | pkt.Idx = int8(self.AudioStreamIdx) 554 | switch tag.SoundFormat { 555 | case SOUND_AAC: 556 | switch tag.AACPacketType { 557 | case AAC_RAW: 558 | ok = true 559 | pkt.Data = tag.Data 560 | } 561 | 562 | case SOUND_SPEEX: 563 | ok = true 564 | pkt.Data = tag.Data 565 | 566 | case SOUND_NELLYMOSER: 567 | ok = true 568 | pkt.Data = tag.Data 569 | } 570 | } 571 | 572 | pkt.Time = TsToTime(timestamp) 573 | return 574 | } 575 | 576 | func (self *Prober) Empty() bool { 577 | return len(self.CachedPkts) == 0 578 | } 579 | 580 | func (self *Prober) PopPacket() av.Packet { 581 | pkt := self.CachedPkts[0] 582 | self.CachedPkts = self.CachedPkts[1:] 583 | return pkt 584 | } 585 | 586 | func CodecDataToTag(stream av.CodecData) (_tag Tag, ok bool, err error) { 587 | switch stream.Type() { 588 | case av.H264: 589 | codec := stream.(h264.CodecData) 590 | tag := Tag{ 591 | Type: TAG_VIDEO, 592 | AVCPacketType: AVC_SEQHDR, 593 | CodecID: VIDEO_H264, 594 | Data: codec.AVCDecoderConfRecordBytes(), 595 | FrameType: FRAME_KEY, 596 | } 597 | ok = true 598 | _tag = tag 599 | 600 | case av.NELLYMOSER: 601 | case av.SPEEX: 602 | 603 | case av.AAC: 604 | codec := stream.(aac.CodecData) 605 | tag := Tag{ 606 | Type: TAG_AUDIO, 607 | SoundFormat: SOUND_AAC, 608 | SoundRate: SOUND_44Khz, 609 | AACPacketType: AAC_SEQHDR, 610 | Data: codec.MPEG4AudioConfigBytes(), 611 | } 612 | switch codec.SampleFormat().BytesPerSample() { 613 | case 1: 614 | tag.SoundSize = SOUND_8BIT 615 | default: 616 | tag.SoundSize = SOUND_16BIT 617 | } 618 | switch codec.ChannelLayout().Count() { 619 | case 1: 620 | tag.SoundType = SOUND_MONO 621 | case 2: 622 | tag.SoundType = SOUND_STEREO 623 | } 624 | ok = true 625 | _tag = tag 626 | 627 | default: 628 | err = fmt.Errorf("flv: unspported codecType=%v", stream.Type()) 629 | return 630 | } 631 | return 632 | } 633 | 634 | func PacketToTag(pkt av.Packet, stream av.CodecData) (tag Tag, timestamp int32) { 635 | switch stream.Type() { 636 | case av.H264: 637 | tag = Tag{ 638 | Type: TAG_VIDEO, 639 | AVCPacketType: AVC_NALU, 640 | CodecID: VIDEO_H264, 641 | Data: pkt.Data, 642 | CompositionTime: TimeToTs(pkt.CompositionTime), 643 | } 644 | if pkt.IsKeyFrame { 645 | tag.FrameType = FRAME_KEY 646 | } else { 647 | tag.FrameType = FRAME_INTER 648 | } 649 | 650 | case av.AAC: 651 | tag = Tag{ 652 | Type: TAG_AUDIO, 653 | SoundFormat: SOUND_AAC, 654 | SoundRate: SOUND_44Khz, 655 | AACPacketType: AAC_RAW, 656 | Data: pkt.Data, 657 | } 658 | astream := stream.(av.AudioCodecData) 659 | switch astream.SampleFormat().BytesPerSample() { 660 | case 1: 661 | tag.SoundSize = SOUND_8BIT 662 | default: 663 | tag.SoundSize = SOUND_16BIT 664 | } 665 | switch astream.ChannelLayout().Count() { 666 | case 1: 667 | tag.SoundType = SOUND_MONO 668 | case 2: 669 | tag.SoundType = SOUND_STEREO 670 | } 671 | 672 | case av.SPEEX: 673 | tag = Tag{ 674 | Type: TAG_AUDIO, 675 | SoundFormat: SOUND_SPEEX, 676 | Data: pkt.Data, 677 | } 678 | 679 | case av.NELLYMOSER: 680 | tag = Tag{ 681 | Type: TAG_AUDIO, 682 | SoundFormat: SOUND_NELLYMOSER, 683 | Data: pkt.Data, 684 | } 685 | } 686 | 687 | timestamp = TimeToTs(pkt.Time) 688 | return 689 | } 690 | 691 | type Muxer struct { 692 | bufw writeFlusher 693 | b []byte 694 | streams []av.CodecData 695 | } 696 | 697 | type writeFlusher interface { 698 | io.Writer 699 | Flush() error 700 | } 701 | 702 | func NewMuxerWriteFlusher(w writeFlusher) *Muxer { 703 | return &Muxer{ 704 | bufw: w, 705 | b: make([]byte, 256), 706 | } 707 | } 708 | 709 | func NewMuxer(w io.Writer) *Muxer { 710 | return NewMuxerWriteFlusher(bufio.NewWriterSize(w, 1024*64)) 711 | } 712 | 713 | var CodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX} 714 | 715 | func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) { 716 | var flags uint8 717 | for _, stream := range streams { 718 | if stream.Type().IsVideo() { 719 | flags |= FILE_HAS_VIDEO 720 | } else if stream.Type().IsAudio() { 721 | flags |= FILE_HAS_AUDIO 722 | } 723 | } 724 | 725 | n := FillFileHeader(self.b, flags) 726 | if _, err = self.bufw.Write(self.b[:n]); err != nil { 727 | return 728 | } 729 | 730 | for _, stream := range streams { 731 | var tag Tag 732 | var ok bool 733 | if tag, ok, err = CodecDataToTag(stream); err != nil { 734 | return 735 | } 736 | if ok { 737 | if err = WriteTag(self.bufw, tag, 0, self.b); err != nil { 738 | return 739 | } 740 | } 741 | } 742 | 743 | self.streams = streams 744 | return 745 | } 746 | 747 | func (self *Muxer) WritePacket(pkt av.Packet) (err error) { 748 | stream := self.streams[pkt.Idx] 749 | tag, timestamp := PacketToTag(pkt, stream) 750 | 751 | if err = WriteTag(self.bufw, tag, timestamp, self.b); err != nil { 752 | return 753 | } 754 | return 755 | } 756 | 757 | func (self *Muxer) WriteTrailer() (err error) { 758 | if err = self.bufw.Flush(); err != nil { 759 | return 760 | } 761 | return 762 | } 763 | 764 | type Demuxer struct { 765 | prober *Prober 766 | bufr *bufio.Reader 767 | b []byte 768 | stage int 769 | } 770 | 771 | func NewDemuxer(r io.Reader) *Demuxer { 772 | return &Demuxer{ 773 | bufr: bufio.NewReaderSize(r, 1024*10), 774 | prober: &Prober{}, 775 | b: make([]byte, 256), 776 | } 777 | } 778 | 779 | func (self *Demuxer) prepare() (err error) { 780 | for self.stage < 2 { 781 | switch self.stage { 782 | case 0: 783 | if _, err = io.ReadFull(self.bufr, self.b[:FileHeaderLength]); err != nil { 784 | return 785 | } 786 | var flags uint8 787 | var skip int 788 | if flags, skip, err = ParseFileHeader(self.b); err != nil { 789 | return 790 | } 791 | if _, err = self.bufr.Discard(skip); err != nil { 792 | return 793 | } 794 | if flags&FILE_HAS_AUDIO != 0 { 795 | self.prober.HasAudio = true 796 | } 797 | if flags&FILE_HAS_VIDEO != 0 { 798 | self.prober.HasVideo = true 799 | } 800 | self.stage++ 801 | 802 | case 1: 803 | for !self.prober.Probed() { 804 | var tag Tag 805 | var timestamp int32 806 | if tag, timestamp, err = ReadTag(self.bufr, self.b); err != nil { 807 | return 808 | } 809 | if err = self.prober.PushTag(tag, timestamp); err != nil { 810 | return 811 | } 812 | } 813 | self.stage++ 814 | } 815 | } 816 | return 817 | } 818 | 819 | func (self *Demuxer) Streams() (streams []av.CodecData, err error) { 820 | if err = self.prepare(); err != nil { 821 | return 822 | } 823 | streams = self.prober.Streams 824 | return 825 | } 826 | 827 | func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) { 828 | if err = self.prepare(); err != nil { 829 | return 830 | } 831 | 832 | if !self.prober.Empty() { 833 | pkt = self.prober.PopPacket() 834 | return 835 | } 836 | 837 | for { 838 | var tag Tag 839 | var timestamp int32 840 | if tag, timestamp, err = ReadTag(self.bufr, self.b); err != nil { 841 | return 842 | } 843 | 844 | var ok bool 845 | if pkt, ok = self.prober.TagToPacket(tag, timestamp); ok { 846 | return 847 | } 848 | } 849 | 850 | return 851 | } 852 | -------------------------------------------------------------------------------- /audio/audio.go: -------------------------------------------------------------------------------- 1 | package audio 2 | 3 | /* 4 | #cgo LDFLAGS: -lavformat -lavutil -lavcodec -lswresample 5 | #cgo CFLAGS: -Wno-deprecated 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | typedef struct { 14 | AVCodec *codec; 15 | AVCodecContext *codecCtx; 16 | AVFrame *frame; 17 | AVDictionary *options; 18 | int profile; 19 | } FFCtx; 20 | 21 | static inline int avcodec_profile_name_to_int(AVCodec *codec, const char *name) { 22 | const AVProfile *p; 23 | for (p = codec->profiles; p != NULL && p->profile != FF_PROFILE_UNKNOWN; p++) 24 | if (!strcasecmp(p->name, name)) 25 | return p->profile; 26 | return FF_PROFILE_UNKNOWN; 27 | } 28 | 29 | int wrap_avcodec_decode_audio4(AVCodecContext *ctx, AVFrame *frame, void *data, int size, int *got) { 30 | struct AVPacket pkt = {.data = data, .size = size}; 31 | return avcodec_decode_audio4(ctx, frame, got, &pkt); 32 | } 33 | int wrap_swresample_convert(SwrContext *avr, int *out, int outcount, int *in, int incount) { 34 | return swr_convert(avr, (void *)out, outcount, (void *)in, incount); 35 | } 36 | 37 | */ 38 | import "C" 39 | 40 | import ( 41 | "fmt" 42 | "github.com/notedit/rtmp-lib/aac" 43 | "github.com/notedit/rtmp-lib/av" 44 | "runtime" 45 | "time" 46 | "unsafe" 47 | ) 48 | 49 | 50 | type ffctx struct { 51 | ff C.FFCtx 52 | } 53 | 54 | type Resampler struct { 55 | inSampleFormat, OutSampleFormat av.SampleFormat 56 | inChannelLayout, OutChannelLayout av.ChannelLayout 57 | inSampleRate, OutSampleRate int 58 | avr *C.SwrContext 59 | } 60 | 61 | func (self *Resampler) Resample(in av.AudioFrame) (out av.AudioFrame, err error) { 62 | formatChange := in.SampleRate != self.inSampleRate || in.SampleFormat != self.inSampleFormat || in.ChannelLayout != self.inChannelLayout 63 | 64 | var flush av.AudioFrame 65 | 66 | if formatChange { 67 | 68 | self.inSampleFormat = in.SampleFormat 69 | self.inSampleRate = in.SampleRate 70 | self.inChannelLayout = in.ChannelLayout 71 | avr := C.swr_alloc() 72 | C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_channel_layout"), C.int64_t(channelLayoutAV2FF(self.inChannelLayout)), 0) 73 | C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_channel_layout"), C.int64_t(channelLayoutAV2FF(self.OutChannelLayout)), 0) 74 | C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_sample_rate"), C.int64_t(self.inSampleRate), 0) 75 | C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_sample_rate"), C.int64_t(self.OutSampleRate), 0) 76 | C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_sample_fmt"), C.int64_t(sampleFormatAV2FF(self.inSampleFormat)), 0) 77 | C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_sample_fmt"), C.int64_t(sampleFormatAV2FF(self.OutSampleFormat)), 0) 78 | C.swr_init(avr) 79 | self.avr = avr 80 | } 81 | 82 | var inChannels, inLinesize int 83 | inSampleCount := in.SampleCount 84 | if !self.inSampleFormat.IsPlanar() { 85 | inChannels = 1 86 | inLinesize = inSampleCount * in.SampleFormat.BytesPerSample() * self.inChannelLayout.Count() 87 | } else { 88 | inChannels = self.inChannelLayout.Count() 89 | inLinesize = inSampleCount * in.SampleFormat.BytesPerSample() 90 | } 91 | inData := make([]*C.uint8_t, inChannels) 92 | for i := 0; i < inChannels; i++ { 93 | inData[i] = (*C.uint8_t)(unsafe.Pointer(&in.Data[i][0])) 94 | } 95 | 96 | fmt.Println(inLinesize) 97 | 98 | var outChannels, outLinesize, outBytesPerSample int 99 | outSampleCount := int(C.swr_get_out_samples(self.avr, C.int(in.SampleCount))) 100 | if !self.OutSampleFormat.IsPlanar() { 101 | outChannels = 1 102 | outBytesPerSample = self.OutSampleFormat.BytesPerSample() * self.OutChannelLayout.Count() 103 | outLinesize = outSampleCount * outBytesPerSample 104 | } else { 105 | outChannels = self.OutChannelLayout.Count() 106 | outBytesPerSample = self.OutSampleFormat.BytesPerSample() 107 | outLinesize = outSampleCount * outBytesPerSample 108 | } 109 | outData := make([]*C.uint8_t, outChannels) 110 | out.Data = make([][]byte, outChannels) 111 | for i := 0; i < outChannels; i++ { 112 | out.Data[i] = make([]byte, outLinesize) 113 | outData[i] = (*C.uint8_t)(unsafe.Pointer(&out.Data[i][0])) 114 | } 115 | out.ChannelLayout = self.OutChannelLayout 116 | out.SampleFormat = self.OutSampleFormat 117 | out.SampleRate = self.OutSampleRate 118 | 119 | convertSamples := int(C.wrap_swresample_convert( 120 | self.avr, 121 | (*C.int)(unsafe.Pointer(&outData[0])), C.int(outSampleCount), 122 | (*C.int)(unsafe.Pointer(&inData[0])), C.int(inSampleCount), 123 | )) 124 | if convertSamples < 0 { 125 | err = fmt.Errorf("ffmpeg: avresample_convert_frame failed") 126 | return 127 | } 128 | 129 | out.SampleCount = convertSamples 130 | if convertSamples < outSampleCount { 131 | for i := 0; i < outChannels; i++ { 132 | out.Data[i] = out.Data[i][:convertSamples*outBytesPerSample] 133 | } 134 | } 135 | 136 | if flush.SampleCount > 0 { 137 | out = flush.Concat(out) 138 | } 139 | 140 | return 141 | } 142 | 143 | func (self *Resampler) Close() { 144 | C.swr_free(&self.avr) 145 | } 146 | 147 | func newFFCtxByCodec(codec *C.AVCodec) (ff *ffctx, err error) { 148 | ff = &ffctx{} 149 | ff.ff.codec = codec 150 | ff.ff.codecCtx = C.avcodec_alloc_context3(codec) 151 | ff.ff.profile = C.FF_PROFILE_UNKNOWN 152 | runtime.SetFinalizer(ff, freeFFCtx) 153 | return 154 | } 155 | 156 | func freeFFCtx(self *ffctx) { 157 | ff := &self.ff 158 | if ff.frame != nil { 159 | C.av_frame_free(&ff.frame) 160 | } 161 | if ff.codecCtx != nil { 162 | C.avcodec_close(ff.codecCtx) 163 | C.av_free(unsafe.Pointer(ff.codecCtx)) 164 | ff.codecCtx = nil 165 | } 166 | if ff.options != nil { 167 | C.av_dict_free(&ff.options) 168 | } 169 | } 170 | 171 | type AudioEncoder struct { 172 | ff *ffctx 173 | SampleRate int 174 | Bitrate int 175 | ChannelLayout av.ChannelLayout 176 | SampleFormat av.SampleFormat 177 | FrameSampleCount int 178 | framebuf av.AudioFrame 179 | codecData av.AudioCodecData 180 | resampler *Resampler 181 | } 182 | 183 | func sampleFormatAV2FF(sampleFormat av.SampleFormat) (ffsamplefmt int32) { 184 | switch sampleFormat { 185 | case av.U8: 186 | ffsamplefmt = C.AV_SAMPLE_FMT_U8 187 | case av.S16: 188 | ffsamplefmt = C.AV_SAMPLE_FMT_S16 189 | case av.S32: 190 | ffsamplefmt = C.AV_SAMPLE_FMT_S32 191 | case av.FLT: 192 | ffsamplefmt = C.AV_SAMPLE_FMT_FLT 193 | case av.DBL: 194 | ffsamplefmt = C.AV_SAMPLE_FMT_DBL 195 | case av.U8P: 196 | ffsamplefmt = C.AV_SAMPLE_FMT_U8P 197 | case av.S16P: 198 | ffsamplefmt = C.AV_SAMPLE_FMT_S16P 199 | case av.S32P: 200 | ffsamplefmt = C.AV_SAMPLE_FMT_S32P 201 | case av.FLTP: 202 | ffsamplefmt = C.AV_SAMPLE_FMT_FLTP 203 | case av.DBLP: 204 | ffsamplefmt = C.AV_SAMPLE_FMT_DBLP 205 | } 206 | return 207 | } 208 | 209 | func sampleFormatFF2AV(ffsamplefmt int32) (sampleFormat av.SampleFormat) { 210 | switch ffsamplefmt { 211 | case C.AV_SAMPLE_FMT_U8: ///< unsigned 8 bits 212 | sampleFormat = av.U8 213 | case C.AV_SAMPLE_FMT_S16: ///< signed 16 bits 214 | sampleFormat = av.S16 215 | case C.AV_SAMPLE_FMT_S32: ///< signed 32 bits 216 | sampleFormat = av.S32 217 | case C.AV_SAMPLE_FMT_FLT: ///< float 218 | sampleFormat = av.FLT 219 | case C.AV_SAMPLE_FMT_DBL: ///< double 220 | sampleFormat = av.DBL 221 | case C.AV_SAMPLE_FMT_U8P: ///< unsigned 8 bits, planar 222 | sampleFormat = av.U8P 223 | case C.AV_SAMPLE_FMT_S16P: ///< signed 16 bits, planar 224 | sampleFormat = av.S16P 225 | case C.AV_SAMPLE_FMT_S32P: ///< signed 32 bits, planar 226 | sampleFormat = av.S32P 227 | case C.AV_SAMPLE_FMT_FLTP: ///< float, planar 228 | sampleFormat = av.FLTP 229 | case C.AV_SAMPLE_FMT_DBLP: ///< double, planar 230 | sampleFormat = av.DBLP 231 | } 232 | return 233 | } 234 | 235 | func (self *AudioEncoder) SetSampleFormat(fmt av.SampleFormat) (err error) { 236 | self.SampleFormat = fmt 237 | return 238 | } 239 | 240 | func (self *AudioEncoder) SetSampleRate(rate int) (err error) { 241 | self.SampleRate = rate 242 | return 243 | } 244 | 245 | func (self *AudioEncoder) SetChannelLayout(ch av.ChannelLayout) (err error) { 246 | self.ChannelLayout = ch 247 | return 248 | } 249 | 250 | func (self *AudioEncoder) SetBitrate(bitrate int) (err error) { 251 | self.Bitrate = bitrate 252 | return 253 | } 254 | 255 | func (self *AudioEncoder) SetOption(key string, val interface{}) (err error) { 256 | ff := &self.ff.ff 257 | 258 | sval := fmt.Sprint(val) 259 | if key == "profile" { 260 | ff.profile = C.avcodec_profile_name_to_int(ff.codec, C.CString(sval)) 261 | if ff.profile == C.FF_PROFILE_UNKNOWN { 262 | err = fmt.Errorf("ffmpeg: profile `%s` invalid", sval) 263 | return 264 | } 265 | return 266 | } 267 | 268 | C.av_dict_set(&ff.options, C.CString(key), C.CString(sval), 0) 269 | return 270 | } 271 | 272 | func (self *AudioEncoder) GetOption(key string, val interface{}) (err error) { 273 | ff := &self.ff.ff 274 | entry := C.av_dict_get(ff.options, C.CString(key), nil, 0) 275 | if entry == nil { 276 | err = fmt.Errorf("ffmpeg: GetOption failed: `%s` not exists", key) 277 | return 278 | } 279 | switch p := val.(type) { 280 | case *string: 281 | *p = C.GoString(entry.value) 282 | case *int: 283 | fmt.Sscanf(C.GoString(entry.value), "%d", p) 284 | default: 285 | err = fmt.Errorf("ffmpeg: GetOption failed: val must be *string or *int receiver") 286 | return 287 | } 288 | return 289 | } 290 | 291 | func (self *AudioEncoder) Setup() (err error) { 292 | ff := &self.ff.ff 293 | 294 | if self.SampleFormat == av.SampleFormat(0) { 295 | self.SampleFormat = sampleFormatFF2AV(*ff.codec.sample_fmts) 296 | } 297 | 298 | if self.SampleRate == 0 { 299 | self.SampleRate = 44100 300 | } 301 | if self.ChannelLayout == av.ChannelLayout(0) { 302 | self.ChannelLayout = av.CH_STEREO 303 | } 304 | 305 | ff.codecCtx.sample_fmt = sampleFormatAV2FF(self.SampleFormat) 306 | ff.codecCtx.sample_rate = C.int(self.SampleRate) 307 | ff.codecCtx.bit_rate = C.int64_t(self.Bitrate) 308 | ff.codecCtx.channel_layout = channelLayoutAV2FF(self.ChannelLayout) 309 | //ff.codecCtx.strict_std_compliance = C.FF_COMPLIANCE_EXPERIMENTAL 310 | //ff.codecCtx.flags = C.AV_CODEC_FLAG_GLOBAL_HEADER 311 | //ff.codecCtx.profile = ff.profile 312 | 313 | if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 { 314 | err = fmt.Errorf("ffmpeg: encoder: avcodec_open2 failed") 315 | return 316 | } 317 | self.SampleFormat = sampleFormatFF2AV(ff.codecCtx.sample_fmt) 318 | self.FrameSampleCount = int(ff.codecCtx.frame_size) 319 | 320 | extradata := C.GoBytes(unsafe.Pointer(ff.codecCtx.extradata), ff.codecCtx.extradata_size) 321 | 322 | ff.frame = C.av_frame_alloc() 323 | 324 | switch ff.codecCtx.codec_id { 325 | case C.AV_CODEC_ID_AAC: 326 | if self.codecData, err = aac.NewCodecDataFromMPEG4AudioConfigBytes(extradata); err != nil { 327 | return 328 | } 329 | 330 | default: 331 | self.codecData = audioCodecData{ 332 | channelLayout: self.ChannelLayout, 333 | sampleFormat: self.SampleFormat, 334 | sampleRate: self.SampleRate, 335 | codecId: ff.codecCtx.codec_id, 336 | extradata: extradata, 337 | } 338 | } 339 | 340 | return 341 | } 342 | 343 | func (self *AudioEncoder) prepare() (err error) { 344 | ff := &self.ff.ff 345 | 346 | if ff.frame == nil { 347 | if err = self.Setup(); err != nil { 348 | return 349 | } 350 | } 351 | 352 | return 353 | } 354 | 355 | func (self *AudioEncoder) CodecData() (codec av.AudioCodecData, err error) { 356 | if err = self.prepare(); err != nil { 357 | return 358 | } 359 | codec = self.codecData 360 | return 361 | } 362 | 363 | func (self *AudioEncoder) encodeOne(frame av.AudioFrame) (gotpkt bool, pkt []byte, err error) { 364 | if err = self.prepare(); err != nil { 365 | return 366 | } 367 | 368 | ff := &self.ff.ff 369 | 370 | cpkt := C.AVPacket{} 371 | cgotpkt := C.int(0) 372 | audioFrameAssignToFF(frame, ff.frame) 373 | 374 | cerr := C.avcodec_encode_audio2(ff.codecCtx, &cpkt, ff.frame, &cgotpkt) 375 | if cerr < C.int(0) { 376 | err = fmt.Errorf("ffmpeg: avcodec_encode_audio2 failed: %d", cerr) 377 | return 378 | } 379 | 380 | if cgotpkt != 0 { 381 | gotpkt = true 382 | pkt = C.GoBytes(unsafe.Pointer(cpkt.data), cpkt.size) 383 | C.av_packet_unref(&cpkt) 384 | 385 | } 386 | 387 | return 388 | } 389 | 390 | func (self *AudioEncoder) resample(in av.AudioFrame) (out av.AudioFrame, err error) { 391 | if self.resampler == nil { 392 | self.resampler = &Resampler{ 393 | OutSampleFormat: self.SampleFormat, 394 | OutSampleRate: self.SampleRate, 395 | OutChannelLayout: self.ChannelLayout, 396 | } 397 | } 398 | if out, err = self.resampler.Resample(in); err != nil { 399 | return 400 | } 401 | return 402 | } 403 | 404 | func (self *AudioEncoder) Encode(frame av.AudioFrame) (pkts [][]byte, err error) { 405 | var gotpkt bool 406 | var pkt []byte 407 | 408 | if frame.SampleFormat != self.SampleFormat || frame.ChannelLayout != self.ChannelLayout || frame.SampleRate != self.SampleRate { 409 | if frame, err = self.resample(frame); err != nil { 410 | return 411 | } 412 | } 413 | 414 | if self.FrameSampleCount != 0 { 415 | if self.framebuf.SampleCount == 0 { 416 | self.framebuf = frame 417 | } else { 418 | self.framebuf = self.framebuf.Concat(frame) 419 | } 420 | for self.framebuf.SampleCount >= self.FrameSampleCount { 421 | frame := self.framebuf.Slice(0, self.FrameSampleCount) 422 | if gotpkt, pkt, err = self.encodeOne(frame); err != nil { 423 | return 424 | } 425 | if gotpkt { 426 | pkts = append(pkts, pkt) 427 | } 428 | self.framebuf = self.framebuf.Slice(self.FrameSampleCount, self.framebuf.SampleCount) 429 | } 430 | } else { 431 | if gotpkt, pkt, err = self.encodeOne(frame); err != nil { 432 | return 433 | } 434 | if gotpkt { 435 | pkts = append(pkts, pkt) 436 | } 437 | } 438 | 439 | return 440 | } 441 | 442 | func (self *AudioEncoder) PacketDuration(data []byte) (dur time.Duration, err error) { 443 | ff := &self.ff.ff 444 | duration := C.av_get_audio_frame_duration(ff.codecCtx, C.int(len(data))) 445 | dur = time.Duration(int(duration)) * time.Second / time.Duration(self.SampleRate) 446 | return 447 | } 448 | 449 | func (self *AudioEncoder) Close() { 450 | freeFFCtx(self.ff) 451 | if self.resampler != nil { 452 | self.resampler.Close() 453 | self.resampler = nil 454 | } 455 | } 456 | 457 | func audioFrameAssignToAVParams(f *C.AVFrame, frame *av.AudioFrame) { 458 | frame.SampleFormat = sampleFormatFF2AV(int32(f.format)) 459 | frame.ChannelLayout = channelLayoutFF2AV(f.channel_layout) 460 | frame.SampleRate = int(f.sample_rate) 461 | } 462 | 463 | func audioFrameAssignToAVData(f *C.AVFrame, frame *av.AudioFrame) { 464 | frame.SampleCount = int(f.nb_samples) 465 | frame.Data = make([][]byte, int(f.channels)) 466 | for i := 0; i < int(f.channels); i++ { 467 | frame.Data[i] = C.GoBytes(unsafe.Pointer(f.data[i]), f.linesize[0]) 468 | } 469 | } 470 | 471 | func audioFrameAssignToAV(f *C.AVFrame, frame *av.AudioFrame) { 472 | audioFrameAssignToAVParams(f, frame) 473 | audioFrameAssignToAVData(f, frame) 474 | } 475 | 476 | func audioFrameAssignToFFParams(frame av.AudioFrame, f *C.AVFrame) { 477 | f.format = C.int(sampleFormatAV2FF(frame.SampleFormat)) 478 | f.channel_layout = channelLayoutAV2FF(frame.ChannelLayout) 479 | f.sample_rate = C.int(frame.SampleRate) 480 | f.channels = C.int(frame.ChannelLayout.Count()) 481 | } 482 | 483 | func audioFrameAssignToFFData(frame av.AudioFrame, f *C.AVFrame) { 484 | f.nb_samples = C.int(frame.SampleCount) 485 | for i := range frame.Data { 486 | f.data[i] = (*C.uint8_t)(unsafe.Pointer(&frame.Data[i][0])) 487 | f.linesize[i] = C.int(len(frame.Data[i])) 488 | } 489 | } 490 | 491 | func audioFrameAssignToFF(frame av.AudioFrame, f *C.AVFrame) { 492 | audioFrameAssignToFFParams(frame, f) 493 | audioFrameAssignToFFData(frame, f) 494 | } 495 | 496 | func channelLayoutFF2AV(layout C.uint64_t) (channelLayout av.ChannelLayout) { 497 | if layout&C.AV_CH_FRONT_CENTER != 0 { 498 | channelLayout |= av.CH_FRONT_CENTER 499 | } 500 | if layout&C.AV_CH_FRONT_LEFT != 0 { 501 | channelLayout |= av.CH_FRONT_LEFT 502 | } 503 | if layout&C.AV_CH_FRONT_RIGHT != 0 { 504 | channelLayout |= av.CH_FRONT_RIGHT 505 | } 506 | if layout&C.AV_CH_BACK_CENTER != 0 { 507 | channelLayout |= av.CH_BACK_CENTER 508 | } 509 | if layout&C.AV_CH_BACK_LEFT != 0 { 510 | channelLayout |= av.CH_BACK_LEFT 511 | } 512 | if layout&C.AV_CH_BACK_RIGHT != 0 { 513 | channelLayout |= av.CH_BACK_RIGHT 514 | } 515 | if layout&C.AV_CH_SIDE_LEFT != 0 { 516 | channelLayout |= av.CH_SIDE_LEFT 517 | } 518 | if layout&C.AV_CH_SIDE_RIGHT != 0 { 519 | channelLayout |= av.CH_SIDE_RIGHT 520 | } 521 | if layout&C.AV_CH_LOW_FREQUENCY != 0 { 522 | channelLayout |= av.CH_LOW_FREQ 523 | } 524 | return 525 | } 526 | 527 | func channelLayoutAV2FF(channelLayout av.ChannelLayout) (layout C.uint64_t) { 528 | if channelLayout&av.CH_FRONT_CENTER != 0 { 529 | layout |= C.AV_CH_FRONT_CENTER 530 | } 531 | if channelLayout&av.CH_FRONT_LEFT != 0 { 532 | layout |= C.AV_CH_FRONT_LEFT 533 | } 534 | if channelLayout&av.CH_FRONT_RIGHT != 0 { 535 | layout |= C.AV_CH_FRONT_RIGHT 536 | } 537 | if channelLayout&av.CH_BACK_CENTER != 0 { 538 | layout |= C.AV_CH_BACK_CENTER 539 | } 540 | if channelLayout&av.CH_BACK_LEFT != 0 { 541 | layout |= C.AV_CH_BACK_LEFT 542 | } 543 | if channelLayout&av.CH_BACK_RIGHT != 0 { 544 | layout |= C.AV_CH_BACK_RIGHT 545 | } 546 | if channelLayout&av.CH_SIDE_LEFT != 0 { 547 | layout |= C.AV_CH_SIDE_LEFT 548 | } 549 | if channelLayout&av.CH_SIDE_RIGHT != 0 { 550 | layout |= C.AV_CH_SIDE_RIGHT 551 | } 552 | if channelLayout&av.CH_LOW_FREQ != 0 { 553 | layout |= C.AV_CH_LOW_FREQUENCY 554 | } 555 | return 556 | } 557 | 558 | type AudioDecoder struct { 559 | ff *ffctx 560 | ChannelLayout av.ChannelLayout 561 | SampleFormat av.SampleFormat 562 | SampleRate int 563 | Extradata []byte 564 | } 565 | 566 | func (self *AudioDecoder) SetSampleFormat(fmt av.SampleFormat) (err error) { 567 | self.SampleFormat = fmt 568 | return 569 | } 570 | 571 | func (self *AudioDecoder) SetSampleRate(rate int) (err error) { 572 | self.SampleRate = rate 573 | return 574 | } 575 | 576 | func (self *AudioDecoder) SetChannelLayout(ch av.ChannelLayout) (err error) { 577 | self.ChannelLayout = ch 578 | return 579 | } 580 | 581 | func (self *AudioDecoder) Setup() (err error) { 582 | ff := &self.ff.ff 583 | 584 | ff.frame = C.av_frame_alloc() 585 | 586 | if len(self.Extradata) > 0 { 587 | ff.codecCtx.extradata = (*C.uint8_t)(unsafe.Pointer(&self.Extradata[0])) 588 | ff.codecCtx.extradata_size = C.int(len(self.Extradata)) 589 | } 590 | 591 | ff.codecCtx.sample_rate = C.int(self.SampleRate) 592 | ff.codecCtx.channel_layout = channelLayoutAV2FF(self.ChannelLayout) 593 | ff.codecCtx.channels = C.int(self.ChannelLayout.Count()) 594 | if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 { 595 | err = fmt.Errorf("ffmpeg: decoder: avcodec_open2 failed") 596 | return 597 | } 598 | self.SampleFormat = sampleFormatFF2AV(ff.codecCtx.sample_fmt) 599 | self.ChannelLayout = channelLayoutFF2AV(ff.codecCtx.channel_layout) 600 | if self.SampleRate == 0 { 601 | self.SampleRate = int(ff.codecCtx.sample_rate) 602 | } 603 | 604 | return 605 | } 606 | 607 | func (self *AudioDecoder) Decode(pkt []byte) (gotframe bool, frame av.AudioFrame, err error) { 608 | ff := &self.ff.ff 609 | 610 | cgotframe := C.int(0) 611 | cerr := C.wrap_avcodec_decode_audio4(ff.codecCtx, ff.frame, unsafe.Pointer(&pkt[0]), C.int(len(pkt)), &cgotframe) 612 | if cerr < C.int(0) { 613 | err = fmt.Errorf("ffmpeg: avcodec_decode_audio4 failed: %d", cerr) 614 | return 615 | } 616 | 617 | if cgotframe != C.int(0) { 618 | gotframe = true 619 | audioFrameAssignToAV(ff.frame, &frame) 620 | frame.SampleRate = self.SampleRate 621 | 622 | } 623 | 624 | return 625 | } 626 | 627 | func (self *AudioDecoder) PacketDuration(data []byte) (dur time.Duration, err error) { 628 | ff := &self.ff.ff 629 | duration := C.av_get_audio_frame_duration(ff.codecCtx, C.int(len(data))) 630 | dur = time.Duration(int(duration)) * time.Second / time.Duration(self.SampleRate) 631 | return 632 | } 633 | 634 | func (self *AudioDecoder) Close() { 635 | freeFFCtx(self.ff) 636 | } 637 | 638 | func NewAudioEncoderByName(name string) (enc *AudioEncoder, err error) { 639 | _enc := &AudioEncoder{} 640 | 641 | codec := C.avcodec_find_encoder_by_name(C.CString(name)) 642 | if codec == nil || C.avcodec_get_type(codec.id) != C.AVMEDIA_TYPE_AUDIO { 643 | err = fmt.Errorf("ffmpeg: cannot find audio encoder name=%s", name) 644 | return 645 | } 646 | 647 | if _enc.ff, err = newFFCtxByCodec(codec); err != nil { 648 | return 649 | } 650 | enc = _enc 651 | return 652 | } 653 | 654 | func NewAudioDecoderByName(name string) (dec *AudioDecoder, err error) { 655 | _dec := &AudioDecoder{} 656 | 657 | codec := C.avcodec_find_decoder_by_name(C.CString(name)) 658 | if codec == nil || C.avcodec_get_type(codec.id) != C.AVMEDIA_TYPE_AUDIO { 659 | err = fmt.Errorf("ffmpeg: cannot find audio decoder name=%s", name) 660 | return 661 | } 662 | 663 | if _dec.ff, err = newFFCtxByCodec(codec); err != nil { 664 | return 665 | } 666 | 667 | dec = _dec 668 | 669 | return 670 | 671 | } 672 | 673 | func NewAudioDecoder(codec av.AudioCodecData) (dec *AudioDecoder, err error) { 674 | _dec := &AudioDecoder{} 675 | var id uint32 676 | 677 | switch codec.Type() { 678 | case av.AAC: 679 | if aaccodec, ok := codec.(aac.CodecData); ok { 680 | _dec.Extradata = aaccodec.MPEG4AudioConfigBytes() 681 | id = C.AV_CODEC_ID_AAC 682 | } else { 683 | err = fmt.Errorf("ffmpeg: aac CodecData must be aacparser.CodecData") 684 | return 685 | } 686 | 687 | case av.SPEEX: 688 | id = C.AV_CODEC_ID_SPEEX 689 | 690 | case av.PCM_MULAW: 691 | id = C.AV_CODEC_ID_PCM_MULAW 692 | 693 | case av.PCM_ALAW: 694 | id = C.AV_CODEC_ID_PCM_ALAW 695 | 696 | default: 697 | if ffcodec, ok := codec.(audioCodecData); ok { 698 | _dec.Extradata = ffcodec.extradata 699 | id = ffcodec.codecId 700 | } else { 701 | err = fmt.Errorf("ffmpeg: invalid CodecData for ffmpeg to decode") 702 | return 703 | } 704 | } 705 | 706 | c := C.avcodec_find_decoder(id) 707 | if c == nil || C.avcodec_get_type(c.id) != C.AVMEDIA_TYPE_AUDIO { 708 | err = fmt.Errorf("ffmpeg: cannot find audio decoder id=%d", id) 709 | return 710 | } 711 | 712 | if _dec.ff, err = newFFCtxByCodec(c); err != nil { 713 | return 714 | } 715 | 716 | _dec.SampleFormat = codec.SampleFormat() 717 | _dec.SampleRate = codec.SampleRate() 718 | _dec.ChannelLayout = codec.ChannelLayout() 719 | 720 | dec = _dec 721 | return 722 | } 723 | 724 | type audioCodecData struct { 725 | codecId uint32 726 | sampleFormat av.SampleFormat 727 | channelLayout av.ChannelLayout 728 | sampleRate int 729 | extradata []byte 730 | } 731 | 732 | func (self audioCodecData) Type() av.CodecType { 733 | return av.MakeAudioCodecType(self.codecId) 734 | } 735 | 736 | func (self audioCodecData) SampleRate() int { 737 | return self.sampleRate 738 | } 739 | 740 | func (self audioCodecData) SampleFormat() av.SampleFormat { 741 | return self.sampleFormat 742 | } 743 | 744 | func (self audioCodecData) ChannelLayout() av.ChannelLayout { 745 | return self.channelLayout 746 | } 747 | -------------------------------------------------------------------------------- /rtmp.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "crypto/hmac" 7 | "crypto/rand" 8 | "crypto/sha256" 9 | "encoding/hex" 10 | "fmt" 11 | "io" 12 | "net" 13 | "net/url" 14 | "strings" 15 | "time" 16 | 17 | "github.com/notedit/rtmp-lib/av" 18 | "github.com/notedit/rtmp-lib/flv" 19 | "github.com/notedit/rtmp-lib/pio" 20 | ) 21 | 22 | var Debug bool 23 | 24 | func ParseURL(uri string) (u *url.URL, err error) { 25 | if u, err = url.Parse(uri); err != nil { 26 | return 27 | } 28 | if _, _, serr := net.SplitHostPort(u.Host); serr != nil { 29 | u.Host += ":1935" 30 | } 31 | return 32 | } 33 | 34 | func Dial(uri string) (conn *Conn, err error) { 35 | return DialTimeout(uri, 0) 36 | } 37 | 38 | func DialTimeout(uri string, timeout time.Duration) (conn *Conn, err error) { 39 | var u *url.URL 40 | if u, err = ParseURL(uri); err != nil { 41 | return 42 | } 43 | 44 | dailer := net.Dialer{Timeout: timeout} 45 | var netconn net.Conn 46 | if netconn, err = dailer.Dial("tcp", u.Host); err != nil { 47 | return 48 | } 49 | 50 | conn = NewConn(netconn, 1024*100) 51 | conn.URL = u 52 | return 53 | } 54 | 55 | type Config struct { 56 | ChunkSize int 57 | BufferSize int 58 | } 59 | 60 | type Server struct { 61 | config *Config 62 | Addr string 63 | HandlePublish func(*Conn) 64 | HandlePlay func(*Conn) 65 | HandleConn func(*Conn) 66 | } 67 | 68 | func NewServer(config *Config) *Server { 69 | server := &Server{ 70 | config:config, 71 | } 72 | return server 73 | } 74 | 75 | func (self *Server) handleConn(conn *Conn) (err error) { 76 | if self.HandleConn != nil { 77 | self.HandleConn(conn) 78 | } else { 79 | if err = conn.prepare(stageCommandDone, 0); err != nil { 80 | return 81 | } 82 | 83 | if conn.playing { 84 | if self.HandlePlay != nil { 85 | self.HandlePlay(conn) 86 | } 87 | } else if conn.publishing { 88 | if self.HandlePublish != nil { 89 | self.HandlePublish(conn) 90 | } 91 | } 92 | } 93 | 94 | return 95 | } 96 | 97 | func (self *Server) ListenAndServe() (err error) { 98 | addr := self.Addr 99 | if addr == "" { 100 | addr = ":1935" 101 | } 102 | var tcpaddr *net.TCPAddr 103 | if tcpaddr, err = net.ResolveTCPAddr("tcp", addr); err != nil { 104 | err = fmt.Errorf("rtmp: ListenAndServe: %s", err) 105 | return 106 | } 107 | 108 | var listener *net.TCPListener 109 | if listener, err = net.ListenTCP("tcp", tcpaddr); err != nil { 110 | return 111 | } 112 | 113 | if Debug { 114 | fmt.Println("rtmp: server: listening on", addr) 115 | } 116 | 117 | 118 | for { 119 | var netconn net.Conn 120 | if netconn, err = listener.Accept(); err != nil { 121 | return 122 | } 123 | 124 | if Debug { 125 | fmt.Println("rtmp: server: accepted") 126 | } 127 | 128 | conn := NewConn(netconn, self.config.BufferSize) 129 | conn.isserver = true 130 | go func() { 131 | err := self.handleConn(conn) 132 | if Debug { 133 | fmt.Println("rtmp: server: client closed err:", err) 134 | } 135 | }() 136 | } 137 | } 138 | 139 | const ( 140 | stageHandshakeDone = iota + 1 141 | stageCommandDone 142 | stageCodecDataDone 143 | ) 144 | 145 | const ( 146 | prepareReading = iota + 1 147 | prepareWriting 148 | ) 149 | 150 | type Conn struct { 151 | URL *url.URL 152 | OnPlayOrPublish func(string, flv.AMFMap) error 153 | 154 | prober *flv.Prober 155 | streams []av.CodecData 156 | 157 | txbytes uint64 158 | rxbytes uint64 159 | 160 | bufr *bufio.Reader 161 | bufw *bufio.Writer 162 | ackn uint32 163 | 164 | writebuf []byte 165 | readbuf []byte 166 | 167 | netconn net.Conn 168 | txrxcount *txrxcount 169 | 170 | writeMaxChunkSize int 171 | readMaxChunkSize int 172 | readAckSize uint32 173 | readcsmap map[uint32]*chunkStream 174 | 175 | isserver bool 176 | publishing, playing bool 177 | reading, writing bool 178 | stage int 179 | 180 | avmsgsid uint32 181 | 182 | gotcommand bool 183 | commandname string 184 | commandtransid float64 185 | commandobj flv.AMFMap 186 | commandparams []interface{} 187 | 188 | gotmsg bool 189 | timestamp uint32 190 | msgdata []byte 191 | msgtypeid uint8 192 | datamsgvals []interface{} 193 | avtag flv.Tag 194 | 195 | eventtype uint16 196 | } 197 | 198 | type txrxcount struct { 199 | io.ReadWriter 200 | txbytes uint64 201 | rxbytes uint64 202 | } 203 | 204 | func (self *txrxcount) Read(p []byte) (int, error) { 205 | n, err := self.ReadWriter.Read(p) 206 | self.rxbytes += uint64(n) 207 | return n, err 208 | } 209 | 210 | func (self *txrxcount) Write(p []byte) (int, error) { 211 | n, err := self.ReadWriter.Write(p) 212 | self.txbytes += uint64(n) 213 | return n, err 214 | } 215 | 216 | // NewConn buffersize better be > 1024 217 | func NewConn(netconn net.Conn, buffersize int) *Conn { 218 | conn := &Conn{} 219 | conn.prober = &flv.Prober{} 220 | conn.netconn = netconn 221 | conn.readcsmap = make(map[uint32]*chunkStream) 222 | conn.readMaxChunkSize = 128 223 | conn.writeMaxChunkSize = 128 224 | conn.bufr = bufio.NewReaderSize(netconn, buffersize) 225 | conn.bufw = bufio.NewWriterSize(netconn, buffersize) 226 | conn.txrxcount = &txrxcount{ReadWriter: netconn} 227 | conn.writebuf = make([]byte, 4096) 228 | conn.readbuf = make([]byte, 4096) 229 | return conn 230 | } 231 | 232 | type chunkStream struct { 233 | timenow uint32 234 | timedelta uint32 235 | hastimeext bool 236 | msgsid uint32 237 | msgtypeid uint8 238 | msgdatalen uint32 239 | msgdataleft uint32 240 | msghdrtype uint8 241 | msgdata []byte 242 | } 243 | 244 | func (self *chunkStream) Start() { 245 | self.msgdataleft = self.msgdatalen 246 | self.msgdata = make([]byte, self.msgdatalen) 247 | } 248 | 249 | const ( 250 | msgtypeidUserControl = 4 251 | msgtypeidAck = 3 252 | msgtypeidWindowAckSize = 5 253 | msgtypeidSetPeerBandwidth = 6 254 | msgtypeidSetChunkSize = 1 255 | msgtypeidCommandMsgAMF0 = 20 256 | msgtypeidCommandMsgAMF3 = 17 257 | msgtypeidDataMsgAMF0 = 18 258 | msgtypeidDataMsgAMF3 = 15 259 | msgtypeidVideoMsg = 9 260 | msgtypeidAudioMsg = 8 261 | ) 262 | 263 | const ( 264 | eventtypeStreamBegin = 0 265 | eventtypeSetBufferLength = 3 266 | eventtypeStreamIsRecorded = 4 267 | ) 268 | 269 | func (self *Conn) NetConn() net.Conn { 270 | return self.netconn 271 | } 272 | 273 | func (self *Conn) TxBytes() uint64 { 274 | return self.txrxcount.txbytes 275 | } 276 | 277 | func (self *Conn) RxBytes() uint64 { 278 | return self.txrxcount.rxbytes 279 | } 280 | 281 | func (self *Conn) Close() (err error) { 282 | return self.netconn.Close() 283 | } 284 | 285 | func (self *Conn) pollCommand() (err error) { 286 | for { 287 | if err = self.pollMsg(); err != nil { 288 | return 289 | } 290 | if self.gotcommand { 291 | return 292 | } 293 | } 294 | } 295 | 296 | func (self *Conn) pollAVTag() (tag flv.Tag, err error) { 297 | for { 298 | if err = self.pollMsg(); err != nil { 299 | return 300 | } 301 | switch self.msgtypeid { 302 | case msgtypeidVideoMsg, msgtypeidAudioMsg: 303 | tag = self.avtag 304 | return 305 | } 306 | } 307 | } 308 | 309 | func (self *Conn) pollMsg() (err error) { 310 | self.gotmsg = false 311 | self.gotcommand = false 312 | self.datamsgvals = nil 313 | self.avtag = flv.Tag{} 314 | for { 315 | if err = self.readChunk(); err != nil { 316 | return 317 | } 318 | if self.gotmsg { 319 | return 320 | } 321 | } 322 | } 323 | 324 | func SplitPath(u *url.URL) (app, stream string) { 325 | pathsegs := strings.SplitN(u.RequestURI(), "/", 3) 326 | if len(pathsegs) > 1 { 327 | app = pathsegs[1] 328 | } 329 | if len(pathsegs) > 2 { 330 | stream = pathsegs[2] 331 | } 332 | return 333 | } 334 | 335 | func getTcUrl(u *url.URL) string { 336 | app, _ := SplitPath(u) 337 | nu := *u 338 | nu.Path = "/" + app 339 | return nu.String() 340 | } 341 | 342 | func createURL(tcurl, app, play string) (u *url.URL) { 343 | ps := strings.Split(app+"/"+play, "/") 344 | out := []string{""} 345 | for _, s := range ps { 346 | if len(s) > 0 { 347 | out = append(out, s) 348 | } 349 | } 350 | if len(out) < 2 { 351 | out = append(out, "") 352 | } 353 | path := strings.Join(out, "/") 354 | u, _ = url.ParseRequestURI(path) 355 | 356 | if tcurl != "" { 357 | tu, _ := url.Parse(tcurl) 358 | if tu != nil { 359 | u.Host = tu.Host 360 | u.Scheme = tu.Scheme 361 | } 362 | } 363 | return 364 | } 365 | 366 | var CodecTypes = flv.CodecTypes 367 | 368 | func (self *Conn) writeBasicConf() (err error) { 369 | // > SetChunkSize 370 | 371 | if err = self.writeSetChunkSize(1024 * 1024 * 128); err != nil { 372 | return 373 | } 374 | 375 | // > WindowAckSize 376 | if err = self.writeWindowAckSize(5000000); err != nil { 377 | return 378 | } 379 | // > SetPeerBandwidth 380 | if err = self.writeSetPeerBandwidth(5000000, 2); err != nil { 381 | return 382 | } 383 | return 384 | } 385 | 386 | func (self *Conn) readConnect() (err error) { 387 | var connectpath string 388 | 389 | // < connect("app") 390 | if err = self.pollCommand(); err != nil { 391 | return 392 | } 393 | if self.commandname != "connect" { 394 | err = fmt.Errorf("rtmp: first command is not connect") 395 | return 396 | } 397 | if self.commandobj == nil { 398 | err = fmt.Errorf("rtmp: connect command params invalid") 399 | return 400 | } 401 | 402 | var ok bool 403 | var _app, _tcurl interface{} 404 | if _app, ok = self.commandobj["app"]; !ok { 405 | err = fmt.Errorf("rtmp: `connect` params missing `app`") 406 | return 407 | } 408 | connectpath, _ = _app.(string) 409 | 410 | var tcurl string 411 | if _tcurl, ok = self.commandobj["tcUrl"]; !ok { 412 | _tcurl, ok = self.commandobj["tcurl"] 413 | } 414 | if ok { 415 | tcurl, _ = _tcurl.(string) 416 | } 417 | connectparams := self.commandobj 418 | 419 | if err = self.writeBasicConf(); err != nil { 420 | return 421 | } 422 | 423 | // > _result("NetConnection.Connect.Success") 424 | if err = self.writeCommandMsg(3, 0, "_result", self.commandtransid, 425 | flv.AMFMap{ 426 | "fmtVer": "FMS/3,0,1,123", 427 | "capabilities": 31, 428 | }, 429 | flv.AMFMap{ 430 | "level": "status", 431 | "code": "NetConnection.Connect.Success", 432 | "description": "Connection succeeded.", 433 | "objectEncoding": 3, 434 | }, 435 | ); err != nil { 436 | return 437 | } 438 | 439 | if err = self.flushWrite(); err != nil { 440 | return 441 | } 442 | 443 | for { 444 | if err = self.pollMsg(); err != nil { 445 | return 446 | } 447 | if self.gotcommand { 448 | switch self.commandname { 449 | 450 | // < createStream 451 | case "createStream": 452 | self.avmsgsid = uint32(1) 453 | // > _result(streamid) 454 | if err = self.writeCommandMsg(3, 0, "_result", self.commandtransid, nil, self.avmsgsid); err != nil { 455 | return 456 | } 457 | if err = self.flushWrite(); err != nil { 458 | return 459 | } 460 | 461 | // < publish("path") 462 | case "publish": 463 | if Debug { 464 | fmt.Println("rtmp: < publish") 465 | } 466 | 467 | if len(self.commandparams) < 1 { 468 | err = fmt.Errorf("rtmp: publish params invalid") 469 | return 470 | } 471 | publishpath, _ := self.commandparams[0].(string) 472 | 473 | var cberr error 474 | if self.OnPlayOrPublish != nil { 475 | cberr = self.OnPlayOrPublish(self.commandname, connectparams) 476 | } 477 | 478 | // > onStatus() 479 | if err = self.writeCommandMsg(5, self.avmsgsid, 480 | "onStatus", self.commandtransid, nil, 481 | flv.AMFMap{ 482 | "level": "status", 483 | "code": "NetStream.Publish.Start", 484 | "description": "Start publishing", 485 | }, 486 | ); err != nil { 487 | return 488 | } 489 | if err = self.flushWrite(); err != nil { 490 | return 491 | } 492 | 493 | if cberr != nil { 494 | err = fmt.Errorf("rtmp: OnPlayOrPublish check failed") 495 | return 496 | } 497 | 498 | self.URL = createURL(tcurl, connectpath, publishpath) 499 | self.publishing = true 500 | self.reading = true 501 | self.stage++ 502 | return 503 | 504 | // < play("path") 505 | case "play": 506 | if Debug { 507 | fmt.Println("rtmp: < play") 508 | } 509 | 510 | if len(self.commandparams) < 1 { 511 | err = fmt.Errorf("rtmp: command play params invalid") 512 | return 513 | } 514 | playpath, _ := self.commandparams[0].(string) 515 | 516 | // > streamBegin(streamid) 517 | if err = self.writeStreamBegin(self.avmsgsid); err != nil { 518 | return 519 | } 520 | 521 | // > onStatus() 522 | if err = self.writeCommandMsg(5, self.avmsgsid, 523 | "onStatus", self.commandtransid, nil, 524 | flv.AMFMap{ 525 | "level": "status", 526 | "code": "NetStream.Play.Start", 527 | "description": "Start live", 528 | }, 529 | ); err != nil { 530 | return 531 | } 532 | 533 | // > |RtmpSampleAccess() 534 | if err = self.writeDataMsg(5, self.avmsgsid, 535 | "|RtmpSampleAccess", true, true, 536 | ); err != nil { 537 | return 538 | } 539 | 540 | if err = self.flushWrite(); err != nil { 541 | return 542 | } 543 | 544 | self.URL = createURL(tcurl, connectpath, playpath) 545 | self.playing = true 546 | self.writing = true 547 | self.stage++ 548 | return 549 | } 550 | 551 | } 552 | } 553 | 554 | return 555 | } 556 | 557 | func (self *Conn) checkConnectResult() (ok bool, errmsg string) { 558 | if len(self.commandparams) < 1 { 559 | errmsg = "params length < 1" 560 | return 561 | } 562 | 563 | obj, _ := self.commandparams[0].(flv.AMFMap) 564 | if obj == nil { 565 | errmsg = "params[0] not object" 566 | return 567 | } 568 | 569 | _code, _ := obj["code"] 570 | if _code == nil { 571 | errmsg = "code invalid" 572 | return 573 | } 574 | 575 | code, _ := _code.(string) 576 | if code != "NetConnection.Connect.Success" { 577 | errmsg = "code != NetConnection.Connect.Success" 578 | return 579 | } 580 | 581 | ok = true 582 | return 583 | } 584 | 585 | func (self *Conn) checkCreateStreamResult() (ok bool, avmsgsid uint32) { 586 | if len(self.commandparams) < 1 { 587 | return 588 | } 589 | 590 | ok = true 591 | _avmsgsid, _ := self.commandparams[0].(float64) 592 | avmsgsid = uint32(_avmsgsid) 593 | return 594 | } 595 | 596 | func (self *Conn) probe() (err error) { 597 | for !self.prober.Probed() { 598 | var tag flv.Tag 599 | if tag, err = self.pollAVTag(); err != nil { 600 | return 601 | } 602 | if err = self.prober.PushTag(tag, int32(self.timestamp)); err != nil { 603 | return 604 | } 605 | } 606 | 607 | self.streams = self.prober.Streams 608 | self.stage++ 609 | return 610 | } 611 | 612 | func (self *Conn) writeConnect(path string) (err error) { 613 | if err = self.writeBasicConf(); err != nil { 614 | return 615 | } 616 | 617 | // > connect("app") 618 | if Debug { 619 | fmt.Printf("rtmp: > connect('%s') host=%s\n", path, self.URL.Host) 620 | } 621 | if err = self.writeCommandMsg(3, 0, "connect", 1, 622 | flv.AMFMap{ 623 | "app": path, 624 | "flashVer": "MAC 22,0,0,192", 625 | "tcUrl": getTcUrl(self.URL), 626 | "fpad": false, 627 | "capabilities": 15, 628 | "audioCodecs": 4071, 629 | "videoCodecs": 252, 630 | "videoFunction": 1, 631 | }, 632 | ); err != nil { 633 | return 634 | } 635 | 636 | if err = self.flushWrite(); err != nil { 637 | return 638 | } 639 | 640 | for { 641 | if err = self.pollMsg(); err != nil { 642 | return 643 | } 644 | if self.gotcommand { 645 | // < _result("NetConnection.Connect.Success") 646 | if self.commandname == "_result" { 647 | var ok bool 648 | var errmsg string 649 | if ok, errmsg = self.checkConnectResult(); !ok { 650 | err = fmt.Errorf("rtmp: command connect failed: %s", errmsg) 651 | return 652 | } 653 | if Debug { 654 | fmt.Printf("rtmp: < _result() of connect\n") 655 | } 656 | break 657 | } 658 | } else { 659 | if self.msgtypeid == msgtypeidWindowAckSize { 660 | if len(self.msgdata) == 4 { 661 | self.readAckSize = pio.U32BE(self.msgdata) 662 | } 663 | if err = self.writeWindowAckSize(0xffffffff); err != nil { 664 | return 665 | } 666 | } 667 | } 668 | } 669 | 670 | return 671 | } 672 | 673 | func (self *Conn) connectPublish() (err error) { 674 | connectpath, publishpath := SplitPath(self.URL) 675 | 676 | if err = self.writeConnect(connectpath); err != nil { 677 | return 678 | } 679 | 680 | transid := 2 681 | 682 | // > createStream() 683 | if Debug { 684 | fmt.Printf("rtmp: > createStream()\n") 685 | } 686 | if err = self.writeCommandMsg(3, 0, "createStream", transid, nil); err != nil { 687 | return 688 | } 689 | transid++ 690 | 691 | if err = self.flushWrite(); err != nil { 692 | return 693 | } 694 | 695 | for { 696 | if err = self.pollMsg(); err != nil { 697 | return 698 | } 699 | if self.gotcommand { 700 | // < _result(avmsgsid) of createStream 701 | if self.commandname == "_result" { 702 | var ok bool 703 | if ok, self.avmsgsid = self.checkCreateStreamResult(); !ok { 704 | err = fmt.Errorf("rtmp: createStream command failed") 705 | return 706 | } 707 | break 708 | } 709 | } 710 | } 711 | 712 | // > publish('app') 713 | if Debug { 714 | fmt.Printf("rtmp: > publish('%s')\n", publishpath) 715 | } 716 | if err = self.writeCommandMsg(8, self.avmsgsid, "publish", transid, nil, publishpath); err != nil { 717 | return 718 | } 719 | transid++ 720 | 721 | if err = self.flushWrite(); err != nil { 722 | return 723 | } 724 | 725 | self.writing = true 726 | self.publishing = true 727 | self.stage++ 728 | return 729 | } 730 | 731 | func (self *Conn) connectPlay() (err error) { 732 | connectpath, playpath := SplitPath(self.URL) 733 | 734 | if err = self.writeConnect(connectpath); err != nil { 735 | return 736 | } 737 | 738 | // > createStream() 739 | if Debug { 740 | fmt.Printf("rtmp: > createStream()\n") 741 | } 742 | if err = self.writeCommandMsg(3, 0, "createStream", 2, nil); err != nil { 743 | return 744 | } 745 | 746 | // > SetBufferLength 0,100ms 747 | if err = self.writeSetBufferLength(0, 100); err != nil { 748 | return 749 | } 750 | 751 | if err = self.flushWrite(); err != nil { 752 | return 753 | } 754 | 755 | for { 756 | if err = self.pollMsg(); err != nil { 757 | return 758 | } 759 | if self.gotcommand { 760 | // < _result(avmsgsid) of createStream 761 | if self.commandname == "_result" { 762 | var ok bool 763 | if ok, self.avmsgsid = self.checkCreateStreamResult(); !ok { 764 | err = fmt.Errorf("rtmp: createStream command failed") 765 | return 766 | } 767 | break 768 | } 769 | } 770 | } 771 | 772 | // > play('app') 773 | if Debug { 774 | fmt.Printf("rtmp: > play('%s')\n", playpath) 775 | } 776 | if err = self.writeCommandMsg(8, self.avmsgsid, "play", 0, nil, playpath); err != nil { 777 | return 778 | } 779 | if err = self.flushWrite(); err != nil { 780 | return 781 | } 782 | 783 | self.reading = true 784 | self.playing = true 785 | self.stage++ 786 | return 787 | } 788 | 789 | func (self *Conn) ReadPacket() (pkt av.Packet, err error) { 790 | if err = self.prepare(stageCodecDataDone, prepareReading); err != nil { 791 | return 792 | } 793 | 794 | if !self.prober.Empty() { 795 | pkt = self.prober.PopPacket() 796 | return 797 | } 798 | 799 | for { 800 | var tag flv.Tag 801 | if tag, err = self.pollAVTag(); err != nil { 802 | return 803 | } 804 | 805 | var ok bool 806 | if pkt, ok = self.prober.TagToPacket(tag, int32(self.timestamp)); ok { 807 | return 808 | } 809 | } 810 | 811 | return 812 | } 813 | 814 | func (self *Conn) Prepare() (err error) { 815 | return self.prepare(stageCommandDone, 0) 816 | } 817 | 818 | func (self *Conn) prepare(stage int, flags int) (err error) { 819 | for self.stage < stage { 820 | switch self.stage { 821 | case 0: 822 | if self.isserver { 823 | if err = self.handshakeServer(); err != nil { 824 | return 825 | } 826 | } else { 827 | if err = self.handshakeClient(); err != nil { 828 | return 829 | } 830 | } 831 | 832 | case stageHandshakeDone: 833 | if self.isserver { 834 | if err = self.readConnect(); err != nil { 835 | return 836 | } 837 | } else { 838 | if flags == prepareReading { 839 | if err = self.connectPlay(); err != nil { 840 | return 841 | } 842 | } else { 843 | if err = self.connectPublish(); err != nil { 844 | return 845 | } 846 | } 847 | } 848 | 849 | case stageCommandDone: 850 | if flags == prepareReading { 851 | if err = self.probe(); err != nil { 852 | return 853 | } 854 | } else { 855 | err = fmt.Errorf("rtmp: call WriteHeader() before WritePacket()") 856 | return 857 | } 858 | } 859 | } 860 | return 861 | } 862 | 863 | func (self *Conn) Streams() (streams []av.CodecData, err error) { 864 | if err = self.prepare(stageCodecDataDone, prepareReading); err != nil { 865 | return 866 | } 867 | streams = self.streams 868 | return 869 | } 870 | 871 | func (self *Conn) WritePacket(pkt av.Packet) (err error) { 872 | if err = self.prepare(stageCodecDataDone, prepareWriting); err != nil { 873 | return 874 | } 875 | 876 | stream := self.streams[pkt.Idx] 877 | tag, timestamp := flv.PacketToTag(pkt, stream) 878 | 879 | if Debug { 880 | fmt.Println("rtmp: WritePacket", pkt.Idx, pkt.Time, pkt.CompositionTime) 881 | } 882 | 883 | if err = self.writeAVTag(tag, int32(timestamp)); err != nil { 884 | return 885 | } 886 | 887 | return 888 | } 889 | 890 | func (self *Conn) WriteTrailer() (err error) { 891 | if err = self.flushWrite(); err != nil { 892 | return 893 | } 894 | return 895 | } 896 | 897 | func (self *Conn) WriteHeader(streams []av.CodecData) (err error) { 898 | if err = self.prepare(stageCommandDone, prepareWriting); err != nil { 899 | return 900 | } 901 | 902 | var metadata flv.AMFMap 903 | if metadata, err = flv.NewMetadataByStreams(streams); err != nil { 904 | return 905 | } 906 | 907 | // > onMetaData() 908 | if err = self.writeDataMsg(5, self.avmsgsid, "onMetaData", metadata); err != nil { 909 | return 910 | } 911 | 912 | // > Videodata(decoder config) 913 | // > Audiodata(decoder config) 914 | for _, stream := range streams { 915 | var ok bool 916 | var tag flv.Tag 917 | if tag, ok, err = flv.CodecDataToTag(stream); err != nil { 918 | return 919 | } 920 | if ok { 921 | if err = self.writeAVTag(tag, 0); err != nil { 922 | return 923 | } 924 | } 925 | } 926 | 927 | self.streams = streams 928 | self.stage++ 929 | return 930 | } 931 | 932 | func (self *Conn) tmpwbuf(n int) []byte { 933 | if len(self.writebuf) < n { 934 | self.writebuf = make([]byte, n) 935 | fmt.Println("write buf ==== ", n) 936 | } 937 | return self.writebuf 938 | } 939 | 940 | func (self *Conn) writeSetChunkSize(size int) (err error) { 941 | self.writeMaxChunkSize = size 942 | b := self.tmpwbuf(chunkHeaderLength + 4) 943 | n := self.fillChunkHeader(b, 2, 0, msgtypeidSetChunkSize, 0, 4) 944 | pio.PutU32BE(b[n:], uint32(size)) 945 | n += 4 946 | _, err = self.bufw.Write(b[:n]) 947 | return 948 | } 949 | 950 | func (self *Conn) writeAck(seqnum uint32) (err error) { 951 | b := self.tmpwbuf(chunkHeaderLength + 4) 952 | n := self.fillChunkHeader(b, 2, 0, msgtypeidAck, 0, 4) 953 | pio.PutU32BE(b[n:], seqnum) 954 | n += 4 955 | _, err = self.bufw.Write(b[:n]) 956 | return 957 | } 958 | 959 | func (self *Conn) writeWindowAckSize(size uint32) (err error) { 960 | b := self.tmpwbuf(chunkHeaderLength + 4) 961 | n := self.fillChunkHeader(b, 2, 0, msgtypeidWindowAckSize, 0, 4) 962 | pio.PutU32BE(b[n:], size) 963 | n += 4 964 | _, err = self.bufw.Write(b[:n]) 965 | return 966 | } 967 | 968 | func (self *Conn) writeSetPeerBandwidth(acksize uint32, limittype uint8) (err error) { 969 | b := self.tmpwbuf(chunkHeaderLength + 5) 970 | n := self.fillChunkHeader(b, 2, 0, msgtypeidSetPeerBandwidth, 0, 5) 971 | pio.PutU32BE(b[n:], acksize) 972 | n += 4 973 | b[n] = limittype 974 | n++ 975 | _, err = self.bufw.Write(b[:n]) 976 | return 977 | } 978 | 979 | func (self *Conn) writeCommandMsg(csid, msgsid uint32, args ...interface{}) (err error) { 980 | return self.writeAMF0Msg(msgtypeidCommandMsgAMF0, csid, msgsid, args...) 981 | } 982 | 983 | func (self *Conn) writeDataMsg(csid, msgsid uint32, args ...interface{}) (err error) { 984 | return self.writeAMF0Msg(msgtypeidDataMsgAMF0, csid, msgsid, args...) 985 | } 986 | 987 | func (self *Conn) writeAMF0Msg(msgtypeid uint8, csid, msgsid uint32, args ...interface{}) (err error) { 988 | size := 0 989 | for _, arg := range args { 990 | size += flv.LenAMF0Val(arg) 991 | } 992 | 993 | b := self.tmpwbuf(chunkHeaderLength + size) 994 | n := self.fillChunkHeader(b, csid, 0, msgtypeid, msgsid, size) 995 | for _, arg := range args { 996 | n += flv.FillAMF0Val(b[n:], arg) 997 | } 998 | 999 | _, err = self.bufw.Write(b[:n]) 1000 | return 1001 | } 1002 | 1003 | func (self *Conn) writeAVTag(tag flv.Tag, ts int32) (err error) { 1004 | var msgtypeid uint8 1005 | var csid uint32 1006 | var data []byte 1007 | 1008 | switch tag.Type { 1009 | case flv.TAG_AUDIO: 1010 | msgtypeid = msgtypeidAudioMsg 1011 | csid = 6 1012 | data = tag.Data 1013 | 1014 | case flv.TAG_VIDEO: 1015 | msgtypeid = msgtypeidVideoMsg 1016 | csid = 7 1017 | data = tag.Data 1018 | } 1019 | 1020 | actualChunkHeaderLength := chunkHeaderLength 1021 | if uint32(ts) > FlvTimestampMax { 1022 | actualChunkHeaderLength += 4 1023 | } 1024 | 1025 | b := self.tmpwbuf(actualChunkHeaderLength + flv.MaxTagSubHeaderLength) 1026 | hdrlen := tag.FillHeader(b[actualChunkHeaderLength:]) 1027 | self.fillChunkHeader(b, csid, ts, msgtypeid, self.avmsgsid, hdrlen+len(data)) 1028 | n := hdrlen + actualChunkHeaderLength 1029 | 1030 | if n+len(data) > self.writeMaxChunkSize { 1031 | if err = self.writeSetChunkSize(n + len(data)); err != nil { 1032 | return 1033 | } 1034 | } 1035 | 1036 | if _, err = self.bufw.Write(b[:n]); err != nil { 1037 | return 1038 | } 1039 | _, err = self.bufw.Write(data) 1040 | return 1041 | } 1042 | 1043 | func (self *Conn) writeStreamBegin(msgsid uint32) (err error) { 1044 | b := self.tmpwbuf(chunkHeaderLength + 6) 1045 | n := self.fillChunkHeader(b, 2, 0, msgtypeidUserControl, 0, 6) 1046 | pio.PutU16BE(b[n:], eventtypeStreamBegin) 1047 | n += 2 1048 | pio.PutU32BE(b[n:], msgsid) 1049 | n += 4 1050 | _, err = self.bufw.Write(b[:n]) 1051 | return 1052 | } 1053 | 1054 | func (self *Conn) writeSetBufferLength(msgsid uint32, timestamp uint32) (err error) { 1055 | b := self.tmpwbuf(chunkHeaderLength + 10) 1056 | n := self.fillChunkHeader(b, 2, 0, msgtypeidUserControl, 0, 10) 1057 | pio.PutU16BE(b[n:], eventtypeSetBufferLength) 1058 | n += 2 1059 | pio.PutU32BE(b[n:], msgsid) 1060 | n += 4 1061 | pio.PutU32BE(b[n:], timestamp) 1062 | n += 4 1063 | _, err = self.bufw.Write(b[:n]) 1064 | return 1065 | } 1066 | 1067 | const chunkHeaderLength = 12 1068 | const FlvTimestampMax = 0xFFFFFF 1069 | 1070 | func (self *Conn) fillChunkHeader(b []byte, csid uint32, timestamp int32, msgtypeid uint8, msgsid uint32, msgdatalen int) (n int) { 1071 | // 0 1 2 3 1072 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 1073 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1074 | // | timestamp |message length | 1075 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1076 | // | message length (cont) |message type id| msg stream id | 1077 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1078 | // | message stream id (cont) | 1079 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1080 | // 1081 | // Figure 9 Chunk Message Header – Type 0 1082 | 1083 | b[n] = byte(csid) & 0x3f 1084 | n++ 1085 | if uint32(timestamp) <= FlvTimestampMax { 1086 | pio.PutU24BE(b[n:], uint32(timestamp)) 1087 | } else { 1088 | pio.PutU24BE(b[n:], FlvTimestampMax) 1089 | } 1090 | n += 3 1091 | pio.PutU24BE(b[n:], uint32(msgdatalen)) 1092 | n += 3 1093 | b[n] = msgtypeid 1094 | n++ 1095 | pio.PutU32LE(b[n:], msgsid) 1096 | n += 4 1097 | if uint32(timestamp) > FlvTimestampMax { 1098 | pio.PutU32BE(b[n:], uint32(timestamp)) 1099 | n += 4 1100 | } 1101 | 1102 | if Debug { 1103 | fmt.Printf("rtmp: write chunk msgdatalen=%d msgsid=%d\n", msgdatalen, msgsid) 1104 | } 1105 | 1106 | return 1107 | } 1108 | 1109 | func (self *Conn) flushWrite() (err error) { 1110 | if err = self.bufw.Flush(); err != nil { 1111 | return 1112 | } 1113 | return 1114 | } 1115 | 1116 | func (self *Conn) readChunk() (err error) { 1117 | b := self.readbuf 1118 | n := 0 1119 | if _, err = io.ReadFull(self.bufr, b[:1]); err != nil { 1120 | return 1121 | } 1122 | header := b[0] 1123 | n += 1 1124 | 1125 | var msghdrtype uint8 1126 | var csid uint32 1127 | 1128 | msghdrtype = header >> 6 1129 | 1130 | csid = uint32(header) & 0x3f 1131 | switch csid { 1132 | default: // Chunk basic header 1 1133 | case 0: // Chunk basic header 2 1134 | if _, err = io.ReadFull(self.bufr, b[:1]); err != nil { 1135 | return 1136 | } 1137 | n += 1 1138 | csid = uint32(b[0]) + 64 1139 | case 1: // Chunk basic header 3 1140 | if _, err = io.ReadFull(self.bufr, b[:2]); err != nil { 1141 | return 1142 | } 1143 | n += 2 1144 | csid = uint32(pio.U16BE(b)) + 64 1145 | } 1146 | 1147 | cs := self.readcsmap[csid] 1148 | if cs == nil { 1149 | cs = &chunkStream{} 1150 | self.readcsmap[csid] = cs 1151 | } 1152 | 1153 | var timestamp uint32 1154 | 1155 | switch msghdrtype { 1156 | case 0: 1157 | // 0 1 2 3 1158 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 1159 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1160 | // | timestamp |message length | 1161 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1162 | // | message length (cont) |message type id| msg stream id | 1163 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1164 | // | message stream id (cont) | 1165 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1166 | // 1167 | // Figure 9 Chunk Message Header – Type 0 1168 | if cs.msgdataleft != 0 { 1169 | err = fmt.Errorf("rtmp: chunk msgdataleft=%d invalid", cs.msgdataleft) 1170 | return 1171 | } 1172 | h := b[:11] 1173 | if _, err = io.ReadFull(self.bufr, h); err != nil { 1174 | return 1175 | } 1176 | n += len(h) 1177 | timestamp = pio.U24BE(h[0:3]) 1178 | cs.msghdrtype = msghdrtype 1179 | cs.msgdatalen = pio.U24BE(h[3:6]) 1180 | cs.msgtypeid = h[6] 1181 | cs.msgsid = pio.U32LE(h[7:11]) 1182 | if timestamp == 0xffffff { 1183 | if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { 1184 | return 1185 | } 1186 | n += 4 1187 | timestamp = pio.U32BE(b) 1188 | cs.hastimeext = true 1189 | } else { 1190 | cs.hastimeext = false 1191 | } 1192 | cs.timenow = timestamp 1193 | cs.Start() 1194 | 1195 | case 1: 1196 | // 0 1 2 3 1197 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 1198 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1199 | // | timestamp delta |message length | 1200 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1201 | // | message length (cont) |message type id| 1202 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1203 | // 1204 | // Figure 10 Chunk Message Header – Type 1 1205 | if cs.msgdataleft != 0 { 1206 | err = fmt.Errorf("rtmp: chunk msgdataleft=%d invalid", cs.msgdataleft) 1207 | return 1208 | } 1209 | h := b[:7] 1210 | if _, err = io.ReadFull(self.bufr, h); err != nil { 1211 | return 1212 | } 1213 | n += len(h) 1214 | timestamp = pio.U24BE(h[0:3]) 1215 | cs.msghdrtype = msghdrtype 1216 | cs.msgdatalen = pio.U24BE(h[3:6]) 1217 | cs.msgtypeid = h[6] 1218 | if timestamp == 0xffffff { 1219 | if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { 1220 | return 1221 | } 1222 | n += 4 1223 | timestamp = pio.U32BE(b) 1224 | cs.hastimeext = true 1225 | } else { 1226 | cs.hastimeext = false 1227 | } 1228 | cs.timedelta = timestamp 1229 | cs.timenow += timestamp 1230 | cs.Start() 1231 | 1232 | case 2: 1233 | // 0 1 2 1234 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 1235 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1236 | // | timestamp delta | 1237 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1238 | // 1239 | // Figure 11 Chunk Message Header – Type 2 1240 | if cs.msgdataleft != 0 { 1241 | err = fmt.Errorf("rtmp: chunk msgdataleft=%d invalid", cs.msgdataleft) 1242 | return 1243 | } 1244 | h := b[:3] 1245 | if _, err = io.ReadFull(self.bufr, h); err != nil { 1246 | return 1247 | } 1248 | n += len(h) 1249 | cs.msghdrtype = msghdrtype 1250 | timestamp = pio.U24BE(h[0:3]) 1251 | if timestamp == 0xffffff { 1252 | if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { 1253 | return 1254 | } 1255 | n += 4 1256 | timestamp = pio.U32BE(b) 1257 | cs.hastimeext = true 1258 | } else { 1259 | cs.hastimeext = false 1260 | } 1261 | cs.timedelta = timestamp 1262 | cs.timenow += timestamp 1263 | cs.Start() 1264 | 1265 | case 3: 1266 | if cs.msgdataleft == 0 { 1267 | switch cs.msghdrtype { 1268 | case 0: 1269 | if cs.hastimeext { 1270 | if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { 1271 | return 1272 | } 1273 | n += 4 1274 | timestamp = pio.U32BE(b) 1275 | cs.timenow = timestamp 1276 | } 1277 | case 1, 2: 1278 | if cs.hastimeext { 1279 | if _, err = io.ReadFull(self.bufr, b[:4]); err != nil { 1280 | return 1281 | } 1282 | n += 4 1283 | timestamp = pio.U32BE(b) 1284 | } else { 1285 | timestamp = cs.timedelta 1286 | } 1287 | cs.timenow += timestamp 1288 | } 1289 | cs.Start() 1290 | } 1291 | 1292 | default: 1293 | err = fmt.Errorf("rtmp: invalid chunk msg header type=%d", msghdrtype) 1294 | return 1295 | } 1296 | 1297 | size := int(cs.msgdataleft) 1298 | if size > self.readMaxChunkSize { 1299 | size = self.readMaxChunkSize 1300 | } 1301 | off := cs.msgdatalen - cs.msgdataleft 1302 | buf := cs.msgdata[off : int(off)+size] 1303 | if _, err = io.ReadFull(self.bufr, buf); err != nil { 1304 | return 1305 | } 1306 | n += len(buf) 1307 | cs.msgdataleft -= uint32(size) 1308 | 1309 | if Debug { 1310 | fmt.Printf("rtmp: chunk msgsid=%d msgtypeid=%d msghdrtype=%d len=%d left=%d\n", 1311 | cs.msgsid, cs.msgtypeid, cs.msghdrtype, cs.msgdatalen, cs.msgdataleft) 1312 | } 1313 | 1314 | if cs.msgdataleft == 0 { 1315 | if Debug { 1316 | fmt.Println("rtmp: chunk data") 1317 | fmt.Print(hex.Dump(cs.msgdata)) 1318 | } 1319 | 1320 | if err = self.handleMsg(cs.timenow, cs.msgsid, cs.msgtypeid, cs.msgdata); err != nil { 1321 | return 1322 | } 1323 | } 1324 | 1325 | self.ackn += uint32(n) 1326 | if self.readAckSize != 0 && self.ackn > self.readAckSize { 1327 | if err = self.writeAck(self.ackn); err != nil { 1328 | return 1329 | } 1330 | self.ackn = 0 1331 | } 1332 | 1333 | return 1334 | } 1335 | 1336 | func (self *Conn) handleCommandMsgAMF0(b []byte) (n int, err error) { 1337 | var name, transid, obj interface{} 1338 | var size int 1339 | 1340 | if name, size, err = flv.ParseAMF0Val(b[n:]); err != nil { 1341 | return 1342 | } 1343 | n += size 1344 | if transid, size, err = flv.ParseAMF0Val(b[n:]); err != nil { 1345 | return 1346 | } 1347 | n += size 1348 | if obj, size, err = flv.ParseAMF0Val(b[n:]); err != nil { 1349 | return 1350 | } 1351 | n += size 1352 | 1353 | var ok bool 1354 | if self.commandname, ok = name.(string); !ok { 1355 | err = fmt.Errorf("rtmp: CommandMsgAMF0 command is not string") 1356 | return 1357 | } 1358 | self.commandtransid, _ = transid.(float64) 1359 | self.commandobj, _ = obj.(flv.AMFMap) 1360 | self.commandparams = []interface{}{} 1361 | 1362 | for n < len(b) { 1363 | if obj, size, err = flv.ParseAMF0Val(b[n:]); err != nil { 1364 | return 1365 | } 1366 | n += size 1367 | self.commandparams = append(self.commandparams, obj) 1368 | } 1369 | if n < len(b) { 1370 | err = fmt.Errorf("rtmp: CommandMsgAMF0 left bytes=%d", len(b)-n) 1371 | return 1372 | } 1373 | 1374 | self.gotcommand = true 1375 | return 1376 | } 1377 | 1378 | func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, msgdata []byte) (err error) { 1379 | self.msgdata = msgdata 1380 | self.msgtypeid = msgtypeid 1381 | self.timestamp = timestamp 1382 | 1383 | switch msgtypeid { 1384 | case msgtypeidCommandMsgAMF0: 1385 | if _, err = self.handleCommandMsgAMF0(msgdata); err != nil { 1386 | return 1387 | } 1388 | 1389 | case msgtypeidCommandMsgAMF3: 1390 | if len(msgdata) < 1 { 1391 | err = fmt.Errorf("rtmp: short packet of CommandMsgAMF3") 1392 | return 1393 | } 1394 | // skip first byte 1395 | if _, err = self.handleCommandMsgAMF0(msgdata[1:]); err != nil { 1396 | return 1397 | } 1398 | 1399 | case msgtypeidUserControl: 1400 | if len(msgdata) < 2 { 1401 | err = fmt.Errorf("rtmp: short packet of UserControl") 1402 | return 1403 | } 1404 | self.eventtype = pio.U16BE(msgdata) 1405 | 1406 | case msgtypeidDataMsgAMF0: 1407 | b := msgdata 1408 | n := 0 1409 | for n < len(b) { 1410 | var obj interface{} 1411 | var size int 1412 | if obj, size, err = flv.ParseAMF0Val(b[n:]); err != nil { 1413 | return 1414 | } 1415 | n += size 1416 | self.datamsgvals = append(self.datamsgvals, obj) 1417 | } 1418 | if n < len(b) { 1419 | err = fmt.Errorf("rtmp: DataMsgAMF0 left bytes=%d", len(b)-n) 1420 | return 1421 | } 1422 | 1423 | case msgtypeidVideoMsg: 1424 | if len(msgdata) == 0 { 1425 | return 1426 | } 1427 | tag := flv.Tag{Type: flv.TAG_VIDEO} 1428 | var n int 1429 | if n, err = (&tag).ParseHeader(msgdata); err != nil { 1430 | return 1431 | } 1432 | if !(tag.FrameType == flv.FRAME_INTER || tag.FrameType == flv.FRAME_KEY) { 1433 | return 1434 | } 1435 | tag.Data = msgdata[n:] 1436 | self.avtag = tag 1437 | 1438 | case msgtypeidAudioMsg: 1439 | if len(msgdata) == 0 { 1440 | return 1441 | } 1442 | tag := flv.Tag{Type: flv.TAG_AUDIO} 1443 | var n int 1444 | if n, err = (&tag).ParseHeader(msgdata); err != nil { 1445 | return 1446 | } 1447 | tag.Data = msgdata[n:] 1448 | self.avtag = tag 1449 | 1450 | case msgtypeidSetChunkSize: 1451 | if len(msgdata) < 4 { 1452 | err = fmt.Errorf("rtmp: short packet of SetChunkSize") 1453 | return 1454 | } 1455 | self.readMaxChunkSize = int(pio.U32BE(msgdata)) 1456 | return 1457 | } 1458 | 1459 | self.gotmsg = true 1460 | return 1461 | } 1462 | 1463 | var ( 1464 | hsClientFullKey = []byte{ 1465 | 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', 1466 | 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', 1467 | '0', '0', '1', 1468 | 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 1469 | 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 1470 | 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE, 1471 | } 1472 | hsServerFullKey = []byte{ 1473 | 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', 1474 | 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ', 1475 | 'S', 'e', 'r', 'v', 'e', 'r', ' ', 1476 | '0', '0', '1', 1477 | 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 1478 | 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 1479 | 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE, 1480 | } 1481 | hsClientPartialKey = hsClientFullKey[:30] 1482 | hsServerPartialKey = hsServerFullKey[:36] 1483 | ) 1484 | 1485 | func hsMakeDigest(key []byte, src []byte, gap int) (dst []byte) { 1486 | h := hmac.New(sha256.New, key) 1487 | if gap <= 0 { 1488 | h.Write(src) 1489 | } else { 1490 | h.Write(src[:gap]) 1491 | h.Write(src[gap+32:]) 1492 | } 1493 | return h.Sum(nil) 1494 | } 1495 | 1496 | func hsCalcDigestPos(p []byte, base int) (pos int) { 1497 | for i := 0; i < 4; i++ { 1498 | pos += int(p[base+i]) 1499 | } 1500 | pos = (pos % 728) + base + 4 1501 | return 1502 | } 1503 | 1504 | func hsFindDigest(p []byte, key []byte, base int) int { 1505 | gap := hsCalcDigestPos(p, base) 1506 | digest := hsMakeDigest(key, p, gap) 1507 | if bytes.Compare(p[gap:gap+32], digest) != 0 { 1508 | return -1 1509 | } 1510 | return gap 1511 | } 1512 | 1513 | func hsParse1(p []byte, peerkey []byte, key []byte) (ok bool, digest []byte) { 1514 | var pos int 1515 | if pos = hsFindDigest(p, peerkey, 772); pos == -1 { 1516 | if pos = hsFindDigest(p, peerkey, 8); pos == -1 { 1517 | return 1518 | } 1519 | } 1520 | ok = true 1521 | digest = hsMakeDigest(key, p[pos:pos+32], -1) 1522 | return 1523 | } 1524 | 1525 | func hsCreate01(p []byte, time uint32, ver uint32, key []byte) { 1526 | p[0] = 3 1527 | p1 := p[1:] 1528 | rand.Read(p1[8:]) 1529 | pio.PutU32BE(p1[0:4], time) 1530 | pio.PutU32BE(p1[4:8], ver) 1531 | gap := hsCalcDigestPos(p1, 8) 1532 | digest := hsMakeDigest(key, p1, gap) 1533 | copy(p1[gap:], digest) 1534 | } 1535 | 1536 | func hsCreate2(p []byte, key []byte) { 1537 | rand.Read(p) 1538 | gap := len(p) - 32 1539 | digest := hsMakeDigest(key, p, gap) 1540 | copy(p[gap:], digest) 1541 | } 1542 | 1543 | func (self *Conn) handshakeClient() (err error) { 1544 | var random [(1 + 1536*2) * 2]byte 1545 | 1546 | C0C1C2 := random[:1536*2+1] 1547 | C0 := C0C1C2[:1] 1548 | //C1 := C0C1C2[1:1536+1] 1549 | C0C1 := C0C1C2[:1536+1] 1550 | C2 := C0C1C2[1536+1:] 1551 | 1552 | S0S1S2 := random[1536*2+1:] 1553 | //S0 := S0S1S2[:1] 1554 | S1 := S0S1S2[1 : 1536+1] 1555 | //S0S1 := S0S1S2[:1536+1] 1556 | //S2 := S0S1S2[1536+1:] 1557 | 1558 | C0[0] = 3 1559 | //hsCreate01(C0C1, hsClientFullKey) 1560 | 1561 | // > C0C1 1562 | if _, err = self.bufw.Write(C0C1); err != nil { 1563 | return 1564 | } 1565 | if err = self.bufw.Flush(); err != nil { 1566 | return 1567 | } 1568 | 1569 | // < S0S1S2 1570 | if _, err = io.ReadFull(self.bufr, S0S1S2); err != nil { 1571 | return 1572 | } 1573 | 1574 | if Debug { 1575 | fmt.Println("rtmp: handshakeClient: server version", S1[4], S1[5], S1[6], S1[7]) 1576 | } 1577 | 1578 | if ver := pio.U32BE(S1[4:8]); ver != 0 { 1579 | C2 = S1 1580 | } else { 1581 | C2 = S1 1582 | } 1583 | 1584 | // > C2 1585 | if _, err = self.bufw.Write(C2); err != nil { 1586 | return 1587 | } 1588 | 1589 | self.stage++ 1590 | return 1591 | } 1592 | 1593 | func (self *Conn) handshakeServer() (err error) { 1594 | var random [(1 + 1536*2) * 2]byte 1595 | 1596 | C0C1C2 := random[:1536*2+1] 1597 | C0 := C0C1C2[:1] 1598 | C1 := C0C1C2[1 : 1536+1] 1599 | C0C1 := C0C1C2[:1536+1] 1600 | C2 := C0C1C2[1536+1:] 1601 | 1602 | S0S1S2 := random[1536*2+1:] 1603 | S0 := S0S1S2[:1] 1604 | S1 := S0S1S2[1 : 1536+1] 1605 | S0S1 := S0S1S2[:1536+1] 1606 | S2 := S0S1S2[1536+1:] 1607 | 1608 | // < C0C1 1609 | if _, err = io.ReadFull(self.bufr, C0C1); err != nil { 1610 | return 1611 | } 1612 | if C0[0] != 3 { 1613 | err = fmt.Errorf("rtmp: handshake version=%d invalid", C0[0]) 1614 | return 1615 | } 1616 | 1617 | S0[0] = 3 1618 | 1619 | clitime := pio.U32BE(C1[0:4]) 1620 | srvtime := clitime 1621 | srvver := uint32(0x0d0e0a0d) 1622 | cliver := pio.U32BE(C1[4:8]) 1623 | 1624 | if cliver != 0 { 1625 | var ok bool 1626 | var digest []byte 1627 | if ok, digest = hsParse1(C1, hsClientPartialKey, hsServerFullKey); !ok { 1628 | err = fmt.Errorf("rtmp: handshake server: C1 invalid") 1629 | return 1630 | } 1631 | hsCreate01(S0S1, srvtime, srvver, hsServerPartialKey) 1632 | hsCreate2(S2, digest) 1633 | } else { 1634 | copy(S1, C1) 1635 | copy(S2, C2) 1636 | } 1637 | 1638 | // > S0S1S2 1639 | if _, err = self.bufw.Write(S0S1S2); err != nil { 1640 | return 1641 | } 1642 | if err = self.bufw.Flush(); err != nil { 1643 | return 1644 | } 1645 | 1646 | // < C2 1647 | if _, err = io.ReadFull(self.bufr, C2); err != nil { 1648 | return 1649 | } 1650 | 1651 | self.stage++ 1652 | return 1653 | } 1654 | --------------------------------------------------------------------------------