├── README.md ├── build.sh ├── doc ├── Readme_cn.md └── mytarget.md └── src ├── main ├── main.go └── pid.go ├── research ├── json.go ├── map_len │ └── map_len.go └── panic │ └── panic.go ├── test ├── pull │ └── play.go └── push │ └── push.go └── vendor └── sheepbao.com ├── glog ├── glog.go └── glog_file.go └── media ├── av ├── av.go └── rwbase.go ├── container ├── flv │ ├── demuxer.go │ ├── muxer.go │ └── tag.go ├── mp4 │ └── muxer.go └── ts │ ├── crc32.go │ ├── muxer.go │ └── muxer_test.go ├── parser ├── aac │ └── parser.go ├── h264 │ ├── parser.go │ └── parser_test.go ├── mp3 │ └── parser.go └── parser.go ├── protocol ├── amf │ ├── amf.go │ ├── amf_test.go │ ├── const.go │ ├── decoder_amf0.go │ ├── decoder_amf0_test.go │ ├── decoder_amf3.go │ ├── decoder_amf3_external.go │ ├── decoder_amf3_test.go │ ├── encoder_amf0.go │ ├── encoder_amf0_test.go │ ├── encoder_amf3.go │ ├── encoder_amf3_test.go │ ├── metadata.go │ └── util.go ├── dash │ └── dash.go ├── hls │ ├── align.go │ ├── audio_cache.go │ ├── hls.go │ ├── status.go │ └── ts_cache.go ├── httpflv │ └── httpflv.go ├── httpopera │ └── httpopera.go ├── kcpts │ └── kcp-ts.go ├── private │ └── protocol.go ├── rtmp │ ├── cache │ │ ├── cache.go │ │ ├── gop.go │ │ └── special.go │ ├── core │ │ ├── chunk_stream.go │ │ ├── chunk_stream_test.go │ │ ├── conn.go │ │ ├── conn_client.go │ │ ├── conn_server.go │ │ ├── conn_test.go │ │ ├── handshake.go │ │ ├── read_writer.go │ │ └── read_writer_test.go │ ├── rtmp.go │ └── stream.go ├── rtp │ └── rtp.go ├── rtsp │ ├── protocol.go │ └── rtsp.go └── webrtc │ └── webrtc.go └── utils ├── cmap └── cmap.go ├── pio ├── pio.go ├── reader.go └── writer.go ├── pool └── pool.go ├── queue └── queue.go └── uid └── uuid.go /README.md: -------------------------------------------------------------------------------- 1 | # sms 2 | xstrive media server and super media server whith golang. 3 | 4 | ## Features 5 | * modularization, expansibility 6 | * high performance, easy deployment, cross-platform 7 | * support rtmp 8 | * support http-flv 9 | * support hls 10 | 11 | ## Build 12 | 13 | ``` 14 | git clone https://github.com/xsw9527/sms.git 15 | cd sms 16 | ./build.sh 17 | ``` 18 | 19 | ## Run 20 | ./bin/sms 21 | 22 | ##Push and play 23 | #Push rtmp stream to sms 24 | ffmpeg -r 30 -f avfoundation -i "0:0" -vcodec libx264 -s 320*240 -b:v 100k -preset ultrafast -acodec libvo_aacenc -f flv rtmp://127.0.0.1/live/test 25 | #Play rtmp streams 26 | ffplay rtmp://127.0.0.1/live/test 27 | #Play hls streams 28 | ffplay http://127.0.0.1:8080/live/test.m3u8 29 | #Play flv streams 30 | ffplay http://127.0.0.1:8081/live/test.flv 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | export GOPATH=`pwd` 2 | os=$1 3 | arch=$2 4 | GOOS=$os GOARCH=$arch go build -o bin/sms${os}${arch} -ldflags \ 5 | "-X main.buildTime=`date +%Y-%m-%d/%H:%M:%S`" src/main/*.go 6 | 7 | -------------------------------------------------------------------------------- /doc/Readme_cn.md: -------------------------------------------------------------------------------- 1 | # sms 2 | 用golang实现的流媒体服务器 3 | 4 | ## 特性 5 | * 模块化,易扩展 6 | * 高性能,易部署,跨平台 7 | * 支持rtmp推拉流 8 | * 支持http-flv分发 9 | * 支持hls分发 10 | 11 | ## 源码编译 12 | 13 | ``` 14 | git clone https://github.com/sheepbao/sms.git 15 | cd sms 16 | ./build.sh 17 | ``` 18 | 19 | ## 运行 20 | ``` 21 | ./bin/sms 22 | ``` -------------------------------------------------------------------------------- /doc/mytarget.md: -------------------------------------------------------------------------------- 1 | * 目标: 2 | 功能最强大的流媒体服务器 3 | 4 | * 支持的协议: 5 | rtmp 6 | http 7 | hls 8 | rtp 9 | rtsp 10 | webrtc 11 | dash 12 | 13 | * 功能: 14 | 第一阶段实现支持协议的推流。 15 | 16 | * 理念: 17 | 模块化设计,自定义组合流媒体协议 18 | 19 | * 设计: 20 | 顶层设计,分模块实现。 21 | 实现的功能的顺序有上到下。 22 | 23 | * 计划: 24 | rtmp(2m) 25 | http(2m) 26 | hls(2m) 27 | rtp(1m) 28 | rtsp(1m) 29 | webrtc(2m) 30 | dash(2m) 31 | 第一阶段实现各个协议的支持。 -------------------------------------------------------------------------------- /src/main/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "net" 7 | "net/http" 8 | _ "net/http/pprof" 9 | "os" 10 | "os/signal" 11 | "syscall" 12 | 13 | "time" 14 | 15 | _ "net/http/pprof" 16 | 17 | "sheepbao.com/glog" 18 | "sheepbao.com/media/protocol/hls" 19 | "sheepbao.com/media/protocol/httpflv" 20 | "sheepbao.com/media/protocol/httpopera" 21 | "sheepbao.com/media/protocol/rtmp" 22 | ) 23 | 24 | const ( 25 | programName = "SMS" 26 | VERSION = "1.1.1" 27 | ) 28 | 29 | var ( 30 | buildTime string 31 | prof = flag.String("pprofAddr", "", "golang pprof debug address.") 32 | rtmpAddr = flag.String("rtmpAddr", ":1935", "The rtmp server address to bind.") 33 | flvAddr = flag.String("flvAddr", ":8081", "the http-flv server address to bind.") 34 | hlsAddr = flag.String("hlsAddr", ":8080", "the hls server address to bind.") 35 | operaAddr = flag.String("operaAddr", "", "the http operation or config address to bind: 8082.") 36 | ) 37 | 38 | func BuildTime() string { 39 | return buildTime 40 | } 41 | 42 | func init() { 43 | flag.Usage = func() { 44 | fmt.Fprintf(os.Stderr, "%s Version[%s]\r\nUsage: %s [OPTIONS]\r\n", programName, VERSION, os.Args[0]) 45 | flag.PrintDefaults() 46 | } 47 | flag.Parse() 48 | } 49 | 50 | func catchSignal() { 51 | sig := make(chan os.Signal) 52 | signal.Notify(sig, syscall.SIGSTOP, syscall.SIGTERM) 53 | <-sig 54 | glog.Println("recieved signal!") 55 | } 56 | 57 | func main() { 58 | defer func() { 59 | if r := recover(); r != nil { 60 | glog.Errorln("main panic: ", r) 61 | time.Sleep(1 * time.Second) 62 | } 63 | }() 64 | 65 | stream := rtmp.NewRtmpStream() 66 | // hls 67 | h := startHls() 68 | // rtmp 69 | startRtmp(stream, h) 70 | // http-flv 71 | startHTTPFlv(stream) 72 | // http-opera 73 | startHTTPOpera(stream) 74 | // pprof 75 | startPprof() 76 | // my log 77 | mylog() 78 | // block 79 | catchSignal() 80 | } 81 | 82 | func startHls() *hls.Server { 83 | hlsListen, err := net.Listen("tcp", *hlsAddr) 84 | if err != nil { 85 | glog.Fatal(err) 86 | } 87 | 88 | hlsServer := hls.NewServer() 89 | go func() { 90 | defer func() { 91 | if r := recover(); r != nil { 92 | glog.Errorln("hls server panic: ", r) 93 | } 94 | }() 95 | hlsServer.Serve(hlsListen) 96 | }() 97 | return hlsServer 98 | } 99 | 100 | func startRtmp(stream *rtmp.RtmpStream, hlsServer *hls.Server) { 101 | rtmplisten, err := net.Listen("tcp", *rtmpAddr) 102 | if err != nil { 103 | glog.Fatal(err) 104 | } 105 | 106 | rtmpServer := rtmp.NewRtmpServer(stream, hlsServer) 107 | go func() { 108 | defer func() { 109 | if r := recover(); r != nil { 110 | glog.Errorln("hls server panic: ", r) 111 | } 112 | }() 113 | rtmpServer.Serve(rtmplisten) 114 | }() 115 | } 116 | 117 | func startHTTPFlv(stream *rtmp.RtmpStream) { 118 | flvListen, err := net.Listen("tcp", *flvAddr) 119 | if err != nil { 120 | glog.Fatal(err) 121 | } 122 | 123 | hdlServer := httpflv.NewServer(stream) 124 | go func() { 125 | defer func() { 126 | if r := recover(); r != nil { 127 | glog.Errorln("hls server panic: ", r) 128 | } 129 | }() 130 | hdlServer.Serve(flvListen) 131 | }() 132 | } 133 | 134 | func startHTTPOpera(stream *rtmp.RtmpStream) { 135 | if *operaAddr != "" { 136 | opListen, err := net.Listen("tcp", *operaAddr) 137 | if err != nil { 138 | glog.Fatal(err) 139 | } 140 | opServer := httpopera.NewServer(stream) 141 | go func() { 142 | defer func() { 143 | if r := recover(); r != nil { 144 | glog.Errorln("hls server panic: ", r) 145 | } 146 | }() 147 | opServer.Serve(opListen) 148 | }() 149 | } 150 | } 151 | 152 | func startPprof() { 153 | if *prof != "" { 154 | go func() { 155 | if err := http.ListenAndServe(*prof, nil); err != nil { 156 | glog.Fatal("enanle pprog failed: ", err) 157 | } 158 | }() 159 | } 160 | } 161 | 162 | func mylog() { 163 | fmt.Println("") 164 | glog.Printf("SMS Version: %s\tBuildTime: %s\n", VERSION, BuildTime()) 165 | glog.Printf("SMS Start, Rtmp Listen On %s\n", *rtmpAddr) 166 | glog.Printf("SMS Start, Hls Listen On %s\n", *hlsAddr) 167 | glog.Printf("SMS Start, HTTP-flv Listen On %s\n", *flvAddr) 168 | if *operaAddr != "" { 169 | glog.Printf("SMS Start, HTTP-Operation Listen On %s\n", *operaAddr) 170 | } 171 | if *prof != "" { 172 | glog.Printf("SMS Start, Pprof Server Listen On %s\n", *prof) 173 | } 174 | SavePid() 175 | } 176 | -------------------------------------------------------------------------------- /src/main/pid.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "path/filepath" 7 | "strconv" 8 | "strings" 9 | 10 | "sheepbao.com/glog" 11 | ) 12 | 13 | // save pid 14 | var CurDir string 15 | 16 | func init() { 17 | CurDir = getParentDirectory(getCurrentDirectory()) 18 | } 19 | func getParentDirectory(dirctory string) string { 20 | return substr(dirctory, 0, strings.LastIndex(dirctory, "/")) 21 | } 22 | func getCurrentDirectory() string { 23 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 24 | if err != nil { 25 | glog.Fatal(err) 26 | } 27 | return strings.Replace(dir, "\\", "/", -1) 28 | } 29 | func substr(s string, pos, length int) string { 30 | runes := []rune(s) 31 | l := pos + length 32 | if l > len(runes) { 33 | l = len(runes) 34 | } 35 | return string(runes[pos:l]) 36 | } 37 | func SavePid() error { 38 | pidFilename := CurDir + "/pid/" + filepath.Base(os.Args[0]) + ".pid" 39 | pid := os.Getpid() 40 | return ioutil.WriteFile(pidFilename, []byte(strconv.Itoa(pid)), 0755) 41 | } 42 | -------------------------------------------------------------------------------- /src/research/json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type Conf struct { 9 | Rtmp struct { 10 | ListenAddr string `json:"listenAddr"` 11 | ReadTimeout int `json:"readTimeoutSec"` 12 | WriteTimeout int `json:"writeTimeoutSec"` 13 | ConnBuffSize int `json:"connBufferSize"` 14 | GOPNum int `json:"gopNum"` 15 | } `json:"rtmp"` 16 | Flv struct { 17 | ListenAddr string `json:"listenAddr"` 18 | } `json:"flv"` 19 | Hls struct { 20 | ListenAddr string `json:"listenAddr"` 21 | MaxBufferSize int `json:"maxBufferSizeKB"` 22 | } `json:"hls"` 23 | 24 | MaxSubGroupNum int `json:"maxSubGroupNum"` 25 | MaxSubGroupWorkers int `json:"maxSubGroupWorkers"` 26 | MaxBufferSize int `json:"maxBufferSizeKB"` 27 | } 28 | 29 | func main() { 30 | conf := &Conf{} 31 | conf.Rtmp.ListenAddr = ":1935" 32 | conf.Rtmp.ReadTimeout = 30 33 | conf.Rtmp.WriteTimeout = 30 34 | conf.Rtmp.ConnBuffSize = 1024 35 | conf.Rtmp.GOPNum = 1 36 | 37 | b, err := json.Marshal(conf) 38 | if err != nil { 39 | fmt.Println(err) 40 | } 41 | fmt.Println(string(b)) 42 | } 43 | -------------------------------------------------------------------------------- /src/research/map_len/map_len.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | test := make(map[string]int) 9 | test["a"] = 1 10 | test["b"] = 2 11 | fmt.Println(len(test)) 12 | } 13 | -------------------------------------------------------------------------------- /src/research/panic/panic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "flag" 7 | 8 | "sheepbao.com/glog" 9 | ) 10 | 11 | func main() { 12 | flag.Parse() 13 | glog.Infoln("start") 14 | time.Sleep(5 * time.Second) 15 | p() 16 | time.Sleep(1) 17 | glog.Infoln("22222222") 18 | } 19 | 20 | func p() { 21 | panic("test") 22 | } 23 | -------------------------------------------------------------------------------- /src/test/pull/play.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "net/url" 6 | "os/signal" 7 | "strings" 8 | "syscall" 9 | 10 | "os" 11 | "strconv" 12 | 13 | "time" 14 | 15 | "sheepbao.com/glog" 16 | "sheepbao.com/media/av" 17 | "sheepbao.com/media/container/flv" 18 | "sheepbao.com/media/protocol/rtmp" 19 | "sheepbao.com/media/utils/uid" 20 | ) 21 | 22 | var ( 23 | host = flag.String("h", "rtmp://127.0.0.1/live/test", "rtmp server url") 24 | saveFlv = flag.Bool("saveFlv", false, "enable save stream to flv file") 25 | clientNum = flag.Int("num", 1, "the client num") 26 | ) 27 | 28 | func main() { 29 | flag.Parse() 30 | 31 | stream := rtmp.NewRtmpStream() 32 | rtmpClient := rtmp.NewRtmpClient(stream, nil) 33 | 34 | for i := 1; i <= *clientNum; i++ { 35 | play(rtmpClient, i) 36 | time.Sleep(200 * time.Millisecond) 37 | } 38 | 39 | catchSignal() 40 | } 41 | 42 | func play(rtmpClient *rtmp.Client, num int) { 43 | glog.Infof("dial to [%s]", *host) 44 | err := rtmpClient.Dial(*host, "play") 45 | if err != nil { 46 | glog.Errorf("dial [%s] error: %v", *host, err) 47 | return 48 | } 49 | if *saveFlv { 50 | info := parseURL(*host) 51 | paths := strings.Split(info.Key, "/") 52 | err := os.MkdirAll(paths[0], 0755) 53 | if err != nil { 54 | glog.Errorln(err) 55 | return 56 | } 57 | numStr := strconv.Itoa(num) 58 | filename := info.Key + "_" + numStr + ".flv" 59 | file, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0644) 60 | if err != nil { 61 | glog.Errorln(err) 62 | return 63 | } 64 | flvWriter := flv.NewFLVWriter(paths[0], paths[1], *host, file) 65 | rtmpClient.GetHandle().HandleWriter(flvWriter) 66 | glog.Infof("save [%s] to [%s]\n\n", *host, filename) 67 | } 68 | } 69 | 70 | func parseURL(URL string) (ret av.Info) { 71 | ret.UID = uid.NEWID() 72 | ret.URL = URL 73 | _url, err := url.Parse(URL) 74 | if err != nil { 75 | glog.Errorln(err) 76 | } 77 | ret.Key = strings.TrimLeft(_url.Path, "/") 78 | ret.Inter = true 79 | return 80 | } 81 | 82 | func catchSignal() { 83 | sig := make(chan os.Signal) 84 | signal.Notify(sig, syscall.SIGUSR1) 85 | <-sig 86 | glog.Println("recieved signal!") 87 | } 88 | -------------------------------------------------------------------------------- /src/test/push/push.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "net/url" 6 | "os/signal" 7 | "strings" 8 | "syscall" 9 | 10 | "os" 11 | 12 | "time" 13 | 14 | "sheepbao.com/glog" 15 | "sheepbao.com/media/av" 16 | "sheepbao.com/media/protocol/rtmp" 17 | "sheepbao.com/media/utils/uid" 18 | ) 19 | 20 | var ( 21 | host = flag.String("h", "127.0.0.1", "rtmp server host") 22 | filename = flag.String("f", "./source/test.flv", "source mdeia file") 23 | clientNum = flag.Int("num", 1, "the client num") 24 | ) 25 | 26 | func main() { 27 | flag.Parse() 28 | 29 | stream := rtmp.NewRtmpStream() 30 | rtmpClient := rtmp.NewRtmpClient(stream, nil) 31 | 32 | for i := 1; i <= *clientNum; i++ { 33 | play(rtmpClient, i) 34 | time.Sleep(200 * time.Millisecond) 35 | } 36 | 37 | catchSignal() 38 | } 39 | 40 | func play(rtmpClient *rtmp.Client, num int) { 41 | glog.Infof("dial to [%s]", *host) 42 | err := rtmpClient.Dial(*host, "publish") 43 | if err != nil { 44 | glog.Errorf("dial [%s] error: %v", *host, err) 45 | return 46 | } 47 | // if *saveFlv { 48 | // info := parseURL(*host) 49 | // paths := strings.Split(info.Key, "/") 50 | // err := os.MkdirAll(paths[0], 0755) 51 | // if err != nil { 52 | // glog.Errorln(err) 53 | // return 54 | // } 55 | // numStr := strconv.Itoa(num) 56 | // filename := info.Key + "_" + numStr + ".flv" 57 | // file, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0644) 58 | // if err != nil { 59 | // glog.Errorln(err) 60 | // return 61 | // } 62 | // flvWriter := flv.NewFLVWriter(paths[0], paths[1], *host, file) 63 | // rtmpClient.GetHandle().HandleWriter(flvWriter) 64 | // glog.Infof("save [%s] to [%s]\n\n", *host, filename) 65 | // } 66 | } 67 | 68 | func parseURL(URL string) (ret av.Info) { 69 | ret.UID = uid.NEWID() 70 | ret.URL = URL 71 | _url, err := url.Parse(URL) 72 | if err != nil { 73 | glog.Errorln(err) 74 | } 75 | ret.Key = strings.TrimLeft(_url.Path, "/") 76 | ret.Inter = true 77 | return 78 | } 79 | 80 | func catchSignal() { 81 | sig := make(chan os.Signal) 82 | signal.Notify(sig, syscall.SIGUSR1) 83 | <-sig 84 | glog.Println("recieved signal!") 85 | } 86 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/glog/glog_file.go: -------------------------------------------------------------------------------- 1 | // Go support for leveled logs, analogous to https://code.google.com/p/google-glog/ 2 | // 3 | // Copyright 2013 Google Inc. All Rights Reserved. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // File I/O for logs. 18 | 19 | package glog 20 | 21 | import ( 22 | "errors" 23 | "flag" 24 | "fmt" 25 | "os" 26 | "os/user" 27 | "path/filepath" 28 | "strings" 29 | "sync" 30 | "time" 31 | ) 32 | 33 | // MaxSize is the maximum size of a log file in bytes. 34 | var MaxSize uint64 = 1024 * 1024 * 1800 35 | 36 | // logDirs lists the candidate directories for new log files. 37 | var logDirs []string 38 | 39 | // If non-empty, overrides the choice of directory in which to write logs. 40 | // See createLogDirs for the full list of possible destinations. 41 | var logDir = flag.String("log_dir", "", "If non-empty, write log files in this directory") 42 | 43 | func createLogDirs() { 44 | if *logDir != "" { 45 | logDirs = append(logDirs, *logDir) 46 | } 47 | logDirs = append(logDirs, os.TempDir()) 48 | } 49 | 50 | var ( 51 | pid = os.Getpid() 52 | program = filepath.Base(os.Args[0]) 53 | host = "unknownhost" 54 | userName = "unknownuser" 55 | ) 56 | 57 | func init() { 58 | h, err := os.Hostname() 59 | if err == nil { 60 | host = shortHostname(h) 61 | } 62 | 63 | current, err := user.Current() 64 | if err == nil { 65 | userName = current.Username 66 | } 67 | 68 | // Sanitize userName since it may contain filepath separators on Windows. 69 | userName = strings.Replace(userName, `\`, "_", -1) 70 | } 71 | 72 | // shortHostname returns its argument, truncating at the first period. 73 | // For instance, given "www.google.com" it returns "www". 74 | func shortHostname(hostname string) string { 75 | if i := strings.Index(hostname, "."); i >= 0 { 76 | return hostname[:i] 77 | } 78 | return hostname 79 | } 80 | 81 | // logName returns a new log file name containing tag, with start time t, and 82 | // the name for the symlink for tag. 83 | func logName(tag string, t time.Time) (name, link string) { 84 | name = fmt.Sprintf("%s.%s.%s.log.%s.%04d%02d%02d-%02d%02d%02d.%d", 85 | program, 86 | host, 87 | userName, 88 | tag, 89 | t.Year(), 90 | t.Month(), 91 | t.Day(), 92 | t.Hour(), 93 | t.Minute(), 94 | t.Second(), 95 | pid) 96 | return name, program + "." + tag 97 | } 98 | 99 | var onceLogDirs sync.Once 100 | 101 | // create creates a new log file and returns the file and its filename, which 102 | // contains tag ("INFO", "FATAL", etc.) and t. If the file is created 103 | // successfully, create also attempts to update the symlink for that tag, ignoring 104 | // errors. 105 | func create(tag string, t time.Time) (f *os.File, filename string, err error) { 106 | onceLogDirs.Do(createLogDirs) 107 | if len(logDirs) == 0 { 108 | return nil, "", errors.New("log: no log dirs") 109 | } 110 | name, link := logName(tag, t) 111 | var lastErr error 112 | for _, dir := range logDirs { 113 | fname := filepath.Join(dir, name) 114 | f, err := os.Create(fname) 115 | if err == nil { 116 | symlink := filepath.Join(dir, link) 117 | os.Remove(symlink) // ignore err 118 | os.Symlink(name, symlink) // ignore err 119 | return f, fname, nil 120 | } 121 | lastErr = err 122 | } 123 | return nil, "", fmt.Errorf("log: cannot create log: %v", lastErr) 124 | } 125 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/av/av.go: -------------------------------------------------------------------------------- 1 | package av 2 | 3 | import "io" 4 | import "fmt" 5 | 6 | const ( 7 | TAG_AUDIO = 8 8 | TAG_VIDEO = 9 9 | TAG_SCRIPTDATAAMF0 = 18 10 | TAG_SCRIPTDATAAMF3 = 0xf 11 | ) 12 | 13 | const ( 14 | MetadatAMF0 = 0x12 15 | MetadataAMF3 = 0xf 16 | ) 17 | 18 | const ( 19 | SOUND_MP3 = 2 20 | SOUND_NELLYMOSER_16KHZ_MONO = 4 21 | SOUND_NELLYMOSER_8KHZ_MONO = 5 22 | SOUND_NELLYMOSER = 6 23 | SOUND_ALAW = 7 24 | SOUND_MULAW = 8 25 | SOUND_AAC = 10 26 | SOUND_SPEEX = 11 27 | 28 | SOUND_5_5Khz = 0 29 | SOUND_11Khz = 1 30 | SOUND_22Khz = 2 31 | SOUND_44Khz = 3 32 | 33 | SOUND_8BIT = 0 34 | SOUND_16BIT = 1 35 | 36 | SOUND_MONO = 0 37 | SOUND_STEREO = 1 38 | 39 | AAC_SEQHDR = 0 40 | AAC_RAW = 1 41 | ) 42 | 43 | const ( 44 | AVC_SEQHDR = 0 45 | AVC_NALU = 1 46 | AVC_EOS = 2 47 | 48 | FRAME_KEY = 1 49 | FRAME_INTER = 2 50 | 51 | VIDEO_H264 = 7 52 | ) 53 | 54 | var ( 55 | PUBLISH = "publish" 56 | PLAY = "play" 57 | ) 58 | 59 | // Header can be converted to AudioHeaderInfo or VideoHeaderInfo 60 | type Packet struct { 61 | IsAudio bool 62 | IsVideo bool 63 | IsMetadata bool 64 | TimeStamp uint32 // dts 65 | Header PacketHeader 66 | Data []byte 67 | } 68 | 69 | type PacketHeader interface { 70 | } 71 | 72 | type AudioPacketHeader interface { 73 | PacketHeader 74 | SoundFormat() uint8 75 | AACPacketType() uint8 76 | } 77 | 78 | type VideoPacketHeader interface { 79 | PacketHeader 80 | IsKeyFrame() bool 81 | IsSeq() bool 82 | CodecID() uint8 83 | CompositionTime() int32 84 | } 85 | 86 | type Demuxer interface { 87 | Demux(*Packet) (ret *Packet, err error) 88 | } 89 | 90 | type Muxer interface { 91 | Mux(*Packet, io.Writer) error 92 | } 93 | 94 | type SampleRater interface { 95 | SampleRate() (int, error) 96 | } 97 | 98 | type CodecParser interface { 99 | SampleRater 100 | Parse(*Packet, io.Writer) error 101 | } 102 | 103 | type GetWriter interface { 104 | GetWriter(Info) WriteCloser 105 | } 106 | 107 | type Handler interface { 108 | HandleReader(ReadCloser) 109 | HandleWriter(WriteCloser) 110 | } 111 | 112 | type Alive interface { 113 | Alive() bool 114 | } 115 | 116 | type Closer interface { 117 | Info() Info 118 | Close(error) 119 | } 120 | 121 | type CalcTime interface { 122 | CalcBaseTimestamp() 123 | } 124 | 125 | type Info struct { 126 | Key string 127 | URL string 128 | UID string 129 | Inter bool 130 | } 131 | 132 | func (self Info) IsInterval() bool { 133 | return self.Inter 134 | } 135 | 136 | func (i Info) String() string { 137 | return fmt.Sprintf("", 138 | i.Key, i.URL, i.UID, i.Inter) 139 | } 140 | 141 | type ReadCloser interface { 142 | Closer 143 | Alive 144 | Read(*Packet) error 145 | } 146 | 147 | type WriteCloser interface { 148 | Closer 149 | Alive 150 | CalcTime 151 | Write(Packet) error 152 | } 153 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/av/rwbase.go: -------------------------------------------------------------------------------- 1 | package av 2 | 3 | import "time" 4 | import "sync" 5 | 6 | type RWBaser struct { 7 | lock sync.Mutex 8 | timeout time.Duration 9 | PreTime time.Time 10 | BaseTimestamp uint32 11 | LastVideoTimestamp uint32 12 | LastAudioTimestamp uint32 13 | } 14 | 15 | func NewRWBaser(duration time.Duration) RWBaser { 16 | return RWBaser{ 17 | timeout: duration, 18 | PreTime: time.Now(), 19 | } 20 | } 21 | 22 | func (self *RWBaser) BaseTimeStamp() uint32 { 23 | return self.BaseTimestamp 24 | } 25 | 26 | func (self *RWBaser) CalcBaseTimestamp() { 27 | if self.LastAudioTimestamp > self.LastVideoTimestamp { 28 | self.BaseTimestamp = self.LastAudioTimestamp 29 | } else { 30 | self.BaseTimestamp = self.LastVideoTimestamp 31 | } 32 | } 33 | 34 | func (self *RWBaser) RecTimeStamp(timestamp, typeID uint32) { 35 | if typeID == TAG_VIDEO { 36 | self.LastVideoTimestamp = timestamp 37 | } else if typeID == TAG_AUDIO { 38 | self.LastAudioTimestamp = timestamp 39 | } 40 | } 41 | 42 | func (self *RWBaser) SetPreTime() { 43 | self.lock.Lock() 44 | self.PreTime = time.Now() 45 | self.lock.Unlock() 46 | } 47 | 48 | func (self *RWBaser) Alive() bool { 49 | self.lock.Lock() 50 | b := !(time.Now().Sub(self.PreTime) >= self.timeout) 51 | self.lock.Unlock() 52 | return b 53 | } 54 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/container/flv/demuxer.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | import ( 4 | "errors" 5 | 6 | "sheepbao.com/media/av" 7 | ) 8 | 9 | var ( 10 | ErrAvcEndSEQ = errors.New("avc end sequence") 11 | ) 12 | 13 | type Demuxer struct { 14 | } 15 | 16 | func NewDemuxer() *Demuxer { 17 | return &Demuxer{} 18 | } 19 | 20 | func (self *Demuxer) DemuxH(p *av.Packet) error { 21 | var tag Tag 22 | _, err := tag.ParseMeidaTagHeader(p.Data, p.IsVideo) 23 | if err != nil { 24 | return err 25 | } 26 | p.Header = &tag 27 | 28 | return nil 29 | } 30 | 31 | func (self *Demuxer) Demux(p *av.Packet) error { 32 | var tag Tag 33 | n, err := tag.ParseMeidaTagHeader(p.Data, p.IsVideo) 34 | if err != nil { 35 | return err 36 | } 37 | if tag.CodecID() == av.VIDEO_H264 && 38 | p.Data[0] == 0x17 && p.Data[1] == 0x02 { 39 | return ErrAvcEndSEQ 40 | } 41 | p.Header = &tag 42 | p.Data = p.Data[n:] 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/container/flv/muxer.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | import ( 4 | "strings" 5 | "time" 6 | 7 | "flag" 8 | 9 | "os" 10 | 11 | "sheepbao.com/glog" 12 | "sheepbao.com/media/av" 13 | "sheepbao.com/media/protocol/amf" 14 | "sheepbao.com/media/utils/pio" 15 | "sheepbao.com/media/utils/uid" 16 | ) 17 | 18 | var ( 19 | flvFile = flag.String("filFile", "./out.flv", "output flv file name") 20 | ) 21 | 22 | func NewFlv(handler av.Handler, info av.Info) { 23 | patths := strings.SplitN(info.Key, "/", 2) 24 | 25 | if len(patths) != 2 { 26 | glog.Errorln("invalid info") 27 | return 28 | } 29 | 30 | w, err := os.OpenFile(*flvFile, os.O_CREATE|os.O_RDWR, 0755) 31 | if err != nil { 32 | glog.Errorln("open file error: ", err) 33 | } 34 | 35 | writer := NewFLVWriter(patths[0], patths[1], info.URL, w) 36 | 37 | handler.HandleWriter(writer) 38 | 39 | writer.Wait() 40 | // close flv file 41 | glog.Infoln("close flv file") 42 | writer.ctx.Close() 43 | } 44 | 45 | const ( 46 | headerLen = 11 47 | ) 48 | 49 | type FLVWriter struct { 50 | Uid string 51 | av.RWBaser 52 | app, title, url string 53 | buf []byte 54 | closed chan struct{} 55 | ctx *os.File 56 | } 57 | 58 | func NewFLVWriter(app, title, url string, ctx *os.File) *FLVWriter { 59 | ret := &FLVWriter{ 60 | Uid: uid.NEWID(), 61 | app: app, 62 | title: title, 63 | url: url, 64 | ctx: ctx, 65 | RWBaser: av.NewRWBaser(time.Second * 10), 66 | closed: make(chan struct{}), 67 | buf: make([]byte, headerLen), 68 | } 69 | 70 | ret.ctx.Write([]byte{0x46, 0x4c, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, 0x09}) 71 | pio.PutI32BE(ret.buf[:4], 0) 72 | ret.ctx.Write(ret.buf[:4]) 73 | 74 | return ret 75 | } 76 | 77 | func (self *FLVWriter) Write(p av.Packet) error { 78 | self.RWBaser.SetPreTime() 79 | h := self.buf[:headerLen] 80 | typeID := av.TAG_VIDEO 81 | if !p.IsVideo { 82 | if p.IsMetadata { 83 | var err error 84 | typeID = av.TAG_SCRIPTDATAAMF0 85 | p.Data, err = amf.MetaDataReform(p.Data, amf.DEL) 86 | if err != nil { 87 | return err 88 | } 89 | } else { 90 | typeID = av.TAG_AUDIO 91 | } 92 | } 93 | dataLen := len(p.Data) 94 | timestamp := p.TimeStamp 95 | timestamp += self.BaseTimeStamp() 96 | self.RWBaser.RecTimeStamp(timestamp, uint32(typeID)) 97 | 98 | preDataLen := dataLen + headerLen 99 | timestampbase := timestamp & 0xffffff 100 | timestampExt := timestamp >> 24 & 0xff 101 | 102 | pio.PutU8(h[0:1], uint8(typeID)) 103 | pio.PutI24BE(h[1:4], int32(dataLen)) 104 | pio.PutI24BE(h[4:7], int32(timestampbase)) 105 | pio.PutU8(h[7:8], uint8(timestampExt)) 106 | 107 | if _, err := self.ctx.Write(h); err != nil { 108 | return err 109 | } 110 | 111 | if _, err := self.ctx.Write(p.Data); err != nil { 112 | return err 113 | } 114 | 115 | pio.PutI32BE(h[:4], int32(preDataLen)) 116 | if _, err := self.ctx.Write(h[:4]); err != nil { 117 | return err 118 | } 119 | 120 | return nil 121 | } 122 | 123 | func (self *FLVWriter) Wait() { 124 | select { 125 | case <-self.closed: 126 | return 127 | } 128 | } 129 | 130 | func (self *FLVWriter) Close(error) { 131 | self.ctx.Close() 132 | close(self.closed) 133 | } 134 | 135 | func (self *FLVWriter) Info() (ret av.Info) { 136 | ret.UID = self.Uid 137 | ret.URL = self.url 138 | ret.Key = self.app + "/" + self.title 139 | return 140 | } 141 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/container/flv/tag.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | import ( 4 | "fmt" 5 | 6 | "sheepbao.com/media/av" 7 | ) 8 | 9 | type flvTag struct { 10 | fType uint8 11 | dataSize uint32 12 | timeStamp uint32 13 | streamID uint32 // always 0 14 | } 15 | 16 | type mediaTag struct { 17 | /* 18 | SoundFormat: UB[4] 19 | 0 = Linear PCM, platform endian 20 | 1 = ADPCM 21 | 2 = MP3 22 | 3 = Linear PCM, little endian 23 | 4 = Nellymoser 16-kHz mono 24 | 5 = Nellymoser 8-kHz mono 25 | 6 = Nellymoser 26 | 7 = G.711 A-law logarithmic PCM 27 | 8 = G.711 mu-law logarithmic PCM 28 | 9 = reserved 29 | 10 = AAC 30 | 11 = Speex 31 | 14 = MP3 8-Khz 32 | 15 = Device-specific sound 33 | Formats 7, 8, 14, and 15 are reserved for internal use 34 | AAC is supported in Flash Player 9,0,115,0 and higher. 35 | Speex is supported in Flash Player 10 and higher. 36 | */ 37 | soundFormat uint8 38 | 39 | /* 40 | SoundRate: UB[2] 41 | Sampling rate 42 | 0 = 5.5-kHz For AAC: always 3 43 | 1 = 11-kHz 44 | 2 = 22-kHz 45 | 3 = 44-kHz 46 | */ 47 | soundRate uint8 48 | 49 | /* 50 | SoundSize: UB[1] 51 | 0 = snd8Bit 52 | 1 = snd16Bit 53 | Size of each sample. 54 | This parameter only pertains to uncompressed formats. 55 | Compressed formats always decode to 16 bits internally 56 | */ 57 | soundSize uint8 58 | 59 | /* 60 | SoundType: UB[1] 61 | 0 = sndMono 62 | 1 = sndStereo 63 | Mono or stereo sound For Nellymoser: always 0 64 | For AAC: always 1 65 | */ 66 | soundType uint8 67 | 68 | /* 69 | 0: AAC sequence header 70 | 1: AAC raw 71 | */ 72 | aacPacketType uint8 73 | 74 | /* 75 | 1: keyframe (for AVC, a seekable frame) 76 | 2: inter frame (for AVC, a non- seekable frame) 77 | 3: disposable inter frame (H.263 only) 78 | 4: generated keyframe (reserved for server use only) 79 | 5: video info/command frame 80 | */ 81 | frameType uint8 82 | 83 | /* 84 | 1: JPEG (currently unused) 85 | 2: Sorenson H.263 86 | 3: Screen video 87 | 4: On2 VP6 88 | 5: On2 VP6 with alpha channel 89 | 6: Screen video version 2 90 | 7: AVC 91 | */ 92 | codecID uint8 93 | 94 | /* 95 | 0: AVC sequence header 96 | 1: AVC NALU 97 | 2: AVC end of sequence (lower level NALU sequence ender is not required or supported) 98 | */ 99 | avcPacketType uint8 100 | 101 | compositionTime int32 102 | } 103 | 104 | type Tag struct { 105 | flvt flvTag 106 | mediat mediaTag 107 | } 108 | 109 | func (self *Tag) SoundFormat() uint8 { 110 | return self.mediat.soundFormat 111 | } 112 | 113 | func (self *Tag) AACPacketType() uint8 { 114 | return self.mediat.aacPacketType 115 | } 116 | 117 | func (self *Tag) IsKeyFrame() bool { 118 | return self.mediat.frameType == av.FRAME_KEY 119 | } 120 | 121 | func (self *Tag) IsSeq() bool { 122 | return self.mediat.frameType == av.FRAME_KEY && 123 | self.mediat.avcPacketType == av.AVC_SEQHDR 124 | } 125 | 126 | func (self *Tag) CodecID() uint8 { 127 | return self.mediat.codecID 128 | } 129 | 130 | func (self *Tag) CompositionTime() int32 { 131 | return self.mediat.compositionTime 132 | } 133 | 134 | // ParseMeidaTagHeader, parse video, audio, tag header 135 | func (self *Tag) ParseMeidaTagHeader(b []byte, isVideo bool) (n int, err error) { 136 | switch isVideo { 137 | case false: 138 | n, err = self.parseAudioHeader(b) 139 | case true: 140 | n, err = self.parseVideoHeader(b) 141 | } 142 | return 143 | } 144 | 145 | func (self *Tag) parseAudioHeader(b []byte) (n int, err error) { 146 | if len(b) < n+1 { 147 | err = fmt.Errorf("invalid audiodata len=%d", len(b)) 148 | return 149 | } 150 | flags := b[0] 151 | self.mediat.soundFormat = flags >> 4 152 | self.mediat.soundRate = (flags >> 2) & 0x3 153 | self.mediat.soundSize = (flags >> 1) & 0x1 154 | self.mediat.soundType = flags & 0x1 155 | n++ 156 | switch self.mediat.soundFormat { 157 | case av.SOUND_AAC: 158 | self.mediat.aacPacketType = b[1] 159 | n++ 160 | } 161 | return 162 | } 163 | 164 | func (self *Tag) parseVideoHeader(b []byte) (n int, err error) { 165 | if len(b) < n+5 { 166 | err = fmt.Errorf("invalid videodata len=%d", len(b)) 167 | return 168 | } 169 | flags := b[0] 170 | self.mediat.frameType = flags >> 4 171 | self.mediat.codecID = flags & 0xf 172 | n++ 173 | if self.mediat.frameType == av.FRAME_INTER || self.mediat.frameType == av.FRAME_KEY { 174 | self.mediat.avcPacketType = b[1] 175 | for i := 2; i < 5; i++ { 176 | self.mediat.compositionTime = self.mediat.compositionTime<<8 + int32(b[i]) 177 | } 178 | n += 4 179 | } 180 | return 181 | } 182 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/container/mp4/muxer.go: -------------------------------------------------------------------------------- 1 | package mp4 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/container/ts/crc32.go: -------------------------------------------------------------------------------- 1 | package ts 2 | 3 | func GenCrc32(src []byte) uint32 { 4 | crcTable := []uint32{ 5 | 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 6 | 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 7 | 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 8 | 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 9 | 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 10 | 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 11 | 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 12 | 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 13 | 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 14 | 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 15 | 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 16 | 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 17 | 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 18 | 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 19 | 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 20 | 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 21 | 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 22 | 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 23 | 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 24 | 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 25 | 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 26 | 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 27 | 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 28 | 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 29 | 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 30 | 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 31 | 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 32 | 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 33 | 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 34 | 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 35 | 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 36 | 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 37 | 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 38 | 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 39 | 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 40 | 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 41 | 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 42 | 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 43 | 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 44 | 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 45 | 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 46 | 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 47 | 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 48 | 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 49 | 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 50 | 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 51 | 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 52 | 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 53 | 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 54 | 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 55 | 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 56 | 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 57 | 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 58 | 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 59 | 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 60 | 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 61 | 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 62 | 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 63 | 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 64 | 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 65 | 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 66 | 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 67 | 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 68 | 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4} 69 | 70 | j := byte(0) 71 | crc32 := uint32(0xFFFFFFFF) 72 | for i := 0; i < len(src); i++ { 73 | j = ((byte(crc32>>24) ^ src[i]) & 0xff) 74 | crc32 = uint32(uint32(crc32<<8) ^ uint32(crcTable[j])) 75 | } 76 | 77 | return crc32 78 | } 79 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/container/ts/muxer.go: -------------------------------------------------------------------------------- 1 | package ts 2 | 3 | import ( 4 | "io" 5 | 6 | "sheepbao.com/media/av" 7 | ) 8 | 9 | const ( 10 | tsDefaultDataLen = 184 11 | tsPacketLen = 188 12 | h264DefaultHZ = 90 13 | ) 14 | 15 | const ( 16 | videoPID = 0x100 17 | audioPID = 0x101 18 | videoSID = 0xe0 19 | audioSID = 0xc0 20 | ) 21 | 22 | type Muxer struct { 23 | videoCc byte 24 | audioCc byte 25 | patCc byte 26 | pmtCc byte 27 | pat [tsPacketLen]byte 28 | pmt [tsPacketLen]byte 29 | tsPacket [tsPacketLen]byte 30 | } 31 | 32 | func NewMuxer() *Muxer { 33 | return &Muxer{} 34 | } 35 | 36 | func (self *Muxer) Mux(p *av.Packet, w io.Writer) error { 37 | first := true 38 | wBytes := 0 39 | pesIndex := 0 40 | tmpLen := byte(0) 41 | dataLen := byte(0) 42 | 43 | var pes pesHeader 44 | dts := int64(p.TimeStamp) * int64(h264DefaultHZ) 45 | pts := dts 46 | pid := audioPID 47 | var videoH av.VideoPacketHeader 48 | if p.IsVideo { 49 | pid = videoPID 50 | videoH, _ = p.Header.(av.VideoPacketHeader) 51 | pts = dts + int64(videoH.CompositionTime())*int64(h264DefaultHZ) 52 | } 53 | err := pes.packet(p, pts, dts) 54 | if err != nil { 55 | return err 56 | } 57 | pesHeaderLen := pes.len 58 | packetBytesLen := len(p.Data) + int(pesHeaderLen) 59 | 60 | for { 61 | if packetBytesLen <= 0 { 62 | break 63 | } 64 | if p.IsVideo { 65 | self.videoCc++ 66 | if self.videoCc > 0xf { 67 | self.videoCc = 0 68 | } 69 | } else { 70 | self.audioCc++ 71 | if self.audioCc > 0xf { 72 | self.audioCc = 0 73 | } 74 | } 75 | 76 | i := byte(0) 77 | 78 | //sync byte 79 | self.tsPacket[i] = 0x47 80 | i++ 81 | 82 | //error indicator, unit start indicator,ts priority,pid 83 | self.tsPacket[i] = byte(pid >> 8) //pid high 5 bits 84 | if first { 85 | self.tsPacket[i] = self.tsPacket[i] | 0x40 //unit start indicator 86 | } 87 | i++ 88 | 89 | //pid low 8 bits 90 | self.tsPacket[i] = byte(pid) 91 | i++ 92 | 93 | //scram control, adaptation control, counter 94 | if p.IsVideo { 95 | self.tsPacket[i] = 0x10 | byte(self.videoCc&0x0f) 96 | } else { 97 | self.tsPacket[i] = 0x10 | byte(self.audioCc&0x0f) 98 | } 99 | i++ 100 | 101 | //关键帧需要加pcr 102 | if first && p.IsVideo && videoH.IsKeyFrame() { 103 | self.tsPacket[3] |= 0x20 104 | self.tsPacket[i] = 7 105 | i++ 106 | self.tsPacket[i] = 0x50 107 | i++ 108 | self.writePcr(self.tsPacket[0:], i, dts) 109 | i += 6 110 | } 111 | 112 | //frame data 113 | if packetBytesLen >= tsDefaultDataLen { 114 | dataLen = tsDefaultDataLen 115 | if first { 116 | dataLen -= (i - 4) 117 | } 118 | } else { 119 | self.tsPacket[3] |= 0x20 //have adaptation 120 | remainBytes := byte(0) 121 | dataLen = byte(packetBytesLen) 122 | if first { 123 | remainBytes = tsDefaultDataLen - dataLen - (i - 4) 124 | } else { 125 | remainBytes = tsDefaultDataLen - dataLen 126 | } 127 | self.adaptationBufInit(self.tsPacket[i:], byte(remainBytes)) 128 | i += remainBytes 129 | } 130 | if first && i < tsPacketLen && pesHeaderLen > 0 { 131 | tmpLen = tsPacketLen - i 132 | if pesHeaderLen <= tmpLen { 133 | tmpLen = pesHeaderLen 134 | } 135 | copy(self.tsPacket[i:], pes.data[pesIndex:pesIndex+int(tmpLen)]) 136 | i += tmpLen 137 | packetBytesLen -= int(tmpLen) 138 | dataLen -= tmpLen 139 | pesHeaderLen -= tmpLen 140 | pesIndex += int(tmpLen) 141 | } 142 | 143 | if i < tsPacketLen { 144 | tmpLen = tsPacketLen - i 145 | if tmpLen <= dataLen { 146 | dataLen = tmpLen 147 | } 148 | copy(self.tsPacket[i:], p.Data[wBytes:wBytes+int(dataLen)]) 149 | wBytes += int(dataLen) 150 | packetBytesLen -= int(dataLen) 151 | } 152 | if w != nil { 153 | if _, err := w.Write(self.tsPacket[0:]); err != nil { 154 | return err 155 | } 156 | } 157 | first = false 158 | } 159 | 160 | return nil 161 | } 162 | 163 | //PAT return pat data 164 | func (self *Muxer) PAT() []byte { 165 | i := 0 166 | remainByte := 0 167 | tsHeader := []byte{0x47, 0x40, 0x00, 0x10, 0x00} 168 | patHeader := []byte{0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x01} 169 | 170 | if self.patCc > 0xf { 171 | self.patCc = 0 172 | } 173 | tsHeader[3] |= self.patCc & 0x0f 174 | self.patCc++ 175 | 176 | copy(self.pat[i:], tsHeader) 177 | i += len(tsHeader) 178 | 179 | copy(self.pat[i:], patHeader) 180 | i += len(patHeader) 181 | 182 | crc32Value := GenCrc32(patHeader) 183 | self.pat[i] = byte(crc32Value >> 24) 184 | i++ 185 | self.pat[i] = byte(crc32Value >> 16) 186 | i++ 187 | self.pat[i] = byte(crc32Value >> 8) 188 | i++ 189 | self.pat[i] = byte(crc32Value) 190 | i++ 191 | 192 | remainByte = int(tsPacketLen - i) 193 | for j := 0; j < remainByte; j++ { 194 | self.pat[i+j] = 0xff 195 | } 196 | 197 | return self.pat[0:] 198 | } 199 | 200 | // PMT return pmt data 201 | func (self *Muxer) PMT(soundFormat byte, hasVideo bool) []byte { 202 | i := int(0) 203 | j := int(0) 204 | var progInfo []byte 205 | remainBytes := int(0) 206 | tsHeader := []byte{0x47, 0x50, 0x01, 0x10, 0x00} 207 | pmtHeader := []byte{0x02, 0xb0, 0xff, 0x00, 0x01, 0xc1, 0x00, 0x00, 0xe1, 0x00, 0xf0, 0x00} 208 | if !hasVideo { 209 | pmtHeader[9] = 0x01 210 | progInfo = []byte{0x0f, 0xe1, 0x01, 0xf0, 0x00} 211 | } else { 212 | progInfo = []byte{0x1b, 0xe1, 0x00, 0xf0, 0x00, //h264 or h265* 213 | 0x0f, 0xe1, 0x01, 0xf0, 0x00, //mp3 or aac 214 | } 215 | } 216 | pmtHeader[2] = byte(len(progInfo) + 9 + 4) 217 | 218 | if self.pmtCc > 0xf { 219 | self.pmtCc = 0 220 | } 221 | tsHeader[3] |= self.pmtCc & 0x0f 222 | self.pmtCc++ 223 | 224 | if soundFormat == 2 || 225 | soundFormat == 14 { 226 | if hasVideo { 227 | progInfo[5] = 0x4 228 | } else { 229 | progInfo[0] = 0x4 230 | } 231 | } 232 | 233 | copy(self.pmt[i:], tsHeader) 234 | i += len(tsHeader) 235 | 236 | copy(self.pmt[i:], pmtHeader) 237 | i += len(pmtHeader) 238 | 239 | copy(self.pmt[i:], progInfo[0:]) 240 | i += len(progInfo) 241 | 242 | crc32Value := GenCrc32(self.pmt[5 : 5+len(pmtHeader)+len(progInfo)]) 243 | self.pmt[i] = byte(crc32Value >> 24) 244 | i++ 245 | self.pmt[i] = byte(crc32Value >> 16) 246 | i++ 247 | self.pmt[i] = byte(crc32Value >> 8) 248 | i++ 249 | self.pmt[i] = byte(crc32Value) 250 | i++ 251 | 252 | remainBytes = int(tsPacketLen - i) 253 | for j = 0; j < remainBytes; j++ { 254 | self.pmt[i+j] = 0xff 255 | } 256 | 257 | return self.pmt[0:] 258 | } 259 | 260 | func (self *Muxer) adaptationBufInit(src []byte, remainBytes byte) { 261 | src[0] = byte(remainBytes - 1) 262 | if remainBytes == 1 { 263 | } else { 264 | src[1] = 0x00 265 | for i := 2; i < len(src); i++ { 266 | src[i] = 0xff 267 | } 268 | } 269 | return 270 | } 271 | 272 | func (self *Muxer) writePcr(b []byte, i byte, pcr int64) error { 273 | b[i] = byte(pcr >> 25) 274 | i++ 275 | b[i] = byte((pcr >> 17) & 0xff) 276 | i++ 277 | b[i] = byte((pcr >> 9) & 0xff) 278 | i++ 279 | b[i] = byte((pcr >> 1) & 0xff) 280 | i++ 281 | b[i] = byte(((pcr & 0x1) << 7) | 0x7e) 282 | i++ 283 | b[i] = 0x00 284 | 285 | return nil 286 | } 287 | 288 | type pesHeader struct { 289 | len byte 290 | data [tsPacketLen]byte 291 | } 292 | 293 | //pesPacket return pes packet 294 | func (self *pesHeader) packet(p *av.Packet, pts, dts int64) error { 295 | //PES header 296 | i := 0 297 | self.data[i] = 0x00 298 | i++ 299 | self.data[i] = 0x00 300 | i++ 301 | self.data[i] = 0x01 302 | i++ 303 | 304 | sid := audioSID 305 | if p.IsVideo { 306 | sid = videoSID 307 | } 308 | self.data[i] = byte(sid) 309 | i++ 310 | 311 | flag := 0x80 312 | ptslen := 5 313 | dtslen := ptslen 314 | headerSize := ptslen 315 | if p.IsVideo && pts != dts { 316 | flag |= 0x40 317 | headerSize += 5 //add dts 318 | } 319 | size := len(p.Data) + headerSize + 3 320 | if size > 0xffff { 321 | size = 0 322 | } 323 | self.data[i] = byte(size >> 8) 324 | i++ 325 | self.data[i] = byte(size) 326 | i++ 327 | 328 | self.data[i] = 0x80 329 | i++ 330 | self.data[i] = byte(flag) 331 | i++ 332 | self.data[i] = byte(headerSize) 333 | i++ 334 | 335 | self.writeTs(self.data[0:], i, flag>>6, pts) 336 | i += ptslen 337 | if p.IsVideo && pts != dts { 338 | self.writeTs(self.data[0:], i, 1, dts) 339 | i += dtslen 340 | } 341 | 342 | self.len = byte(i) 343 | 344 | return nil 345 | } 346 | 347 | func (self *pesHeader) writeTs(src []byte, i int, fb int, ts int64) { 348 | val := uint32(0) 349 | if ts > 0x1ffffffff { 350 | ts -= 0x1ffffffff 351 | } 352 | val = uint32(fb<<4) | ((uint32(ts>>30) & 0x07) << 1) | 1 353 | src[i] = byte(val) 354 | i++ 355 | 356 | val = ((uint32(ts>>15) & 0x7fff) << 1) | 1 357 | src[i] = byte(val >> 8) 358 | i++ 359 | src[i] = byte(val) 360 | i++ 361 | 362 | val = (uint32(ts&0x7fff) << 1) | 1 363 | src[i] = byte(val >> 8) 364 | i++ 365 | src[i] = byte(val) 366 | } 367 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/container/ts/muxer_test.go: -------------------------------------------------------------------------------- 1 | package ts 2 | 3 | import ( 4 | "testing" 5 | 6 | "sheepbao.com/media/av" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | type TestWriter struct { 12 | buf []byte 13 | count int 14 | } 15 | 16 | //Write write p to w.buf 17 | func (w *TestWriter) Write(p []byte) (int, error) { 18 | w.count++ 19 | w.buf = p 20 | return len(p), nil 21 | } 22 | 23 | func TestTSEncoder(t *testing.T) { 24 | at := assert.New(t) 25 | m := NewMuxer() 26 | 27 | w := &TestWriter{} 28 | data := []byte{0xaf, 0x01, 0x21, 0x19, 0xd3, 0x40, 0x7d, 0x0b, 0x6d, 0x44, 0xae, 0x81, 29 | 0x08, 0x00, 0x89, 0xa0, 0x3e, 0x85, 0xb6, 0x92, 0x57, 0x04, 0x80, 0x00, 0x5b, 0xb7, 30 | 0x78, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x30, 0x00, 0x06, 0x00, 0x38, 31 | } 32 | p := av.Packet{ 33 | IsVideo: false, 34 | Data: data, 35 | } 36 | err := m.Mux(&p, w) 37 | at.Equal(err, nil) 38 | at.Equal(w.count, 1) 39 | at.Equal(w.buf, []byte{0x47, 0x41, 0x01, 0x31, 0x81, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 40 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 41 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 42 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 43 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 44 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 45 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 46 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 47 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 48 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x30, 49 | 0x80, 0x80, 0x05, 0x21, 0x00, 0x01, 0x00, 0x01, 0xaf, 0x01, 0x21, 0x19, 0xd3, 0x40, 0x7d, 50 | 0x0b, 0x6d, 0x44, 0xae, 0x81, 0x08, 0x00, 0x89, 0xa0, 0x3e, 0x85, 0xb6, 0x92, 0x57, 0x04, 51 | 0x80, 0x00, 0x5b, 0xb7, 0x78, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x30, 0x00, 52 | 0x06, 0x00, 0x38}) 53 | } 54 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/parser/aac/parser.go: -------------------------------------------------------------------------------- 1 | package aac 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | 7 | "sheepbao.com/media/av" 8 | ) 9 | 10 | type mpegExtension struct { 11 | objectType byte 12 | sampleRate byte 13 | } 14 | 15 | type mpegCfgInfo struct { 16 | objectType byte 17 | sampleRate byte 18 | channel byte 19 | sbr byte 20 | ps byte 21 | frameLen byte 22 | exceptionLogTs int64 23 | extension *mpegExtension 24 | } 25 | 26 | var aacRates = []int{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350} 27 | 28 | var ( 29 | specificBufInvalid = errors.New("audio mpegspecific error") 30 | audioBufInvalid = errors.New("audiodata invalid") 31 | ) 32 | 33 | const ( 34 | adtsHeaderLen = 7 35 | ) 36 | 37 | type Parser struct { 38 | gettedSpecific bool 39 | adtsHeader []byte 40 | cfgInfo *mpegCfgInfo 41 | } 42 | 43 | func NewParser() *Parser { 44 | return &Parser{ 45 | gettedSpecific: false, 46 | cfgInfo: &mpegCfgInfo{}, 47 | adtsHeader: make([]byte, adtsHeaderLen), 48 | } 49 | } 50 | 51 | func (self *Parser) specificInfo(src []byte) error { 52 | if len(src) < 2 { 53 | return specificBufInvalid 54 | } 55 | self.gettedSpecific = true 56 | self.cfgInfo.objectType = (src[0] >> 3) & 0xff 57 | self.cfgInfo.sampleRate = ((src[0] & 0x07) << 1) | src[1]>>7 58 | self.cfgInfo.channel = (src[1] >> 3) & 0x0f 59 | return nil 60 | } 61 | 62 | func (self *Parser) adts(src []byte, w io.Writer) error { 63 | if len(src) <= 0 || !self.gettedSpecific { 64 | return audioBufInvalid 65 | } 66 | 67 | frameLen := uint16(len(src)) + 7 68 | 69 | //first write adts header 70 | self.adtsHeader[0] = 0xff 71 | self.adtsHeader[1] = 0xf1 72 | 73 | self.adtsHeader[2] &= 0x00 74 | self.adtsHeader[2] = self.adtsHeader[2] | (self.cfgInfo.objectType-1)<<6 75 | self.adtsHeader[2] = self.adtsHeader[2] | (self.cfgInfo.sampleRate)<<2 76 | 77 | self.adtsHeader[3] &= 0x00 78 | self.adtsHeader[3] = self.adtsHeader[3] | (self.cfgInfo.channel<<2)<<4 79 | self.adtsHeader[3] = self.adtsHeader[3] | byte((frameLen<<3)>>14) 80 | 81 | self.adtsHeader[4] &= 0x00 82 | self.adtsHeader[4] = self.adtsHeader[4] | byte((frameLen<<5)>>8) 83 | 84 | self.adtsHeader[5] &= 0x00 85 | self.adtsHeader[5] = self.adtsHeader[5] | byte(((frameLen<<13)>>13)<<5) 86 | self.adtsHeader[5] = self.adtsHeader[5] | (0x7C<<1)>>3 87 | self.adtsHeader[6] = 0xfc 88 | 89 | if _, err := w.Write(self.adtsHeader[0:]); err != nil { 90 | return err 91 | } 92 | if _, err := w.Write(src); err != nil { 93 | return err 94 | } 95 | return nil 96 | } 97 | 98 | func (self *Parser) SampleRate() int { 99 | rate := 44100 100 | if self.cfgInfo.sampleRate <= byte(len(aacRates)-1) { 101 | rate = aacRates[self.cfgInfo.sampleRate] 102 | } 103 | return rate 104 | } 105 | 106 | func (self *Parser) Parse(b []byte, packetType uint8, w io.Writer) (err error) { 107 | switch packetType { 108 | case av.AAC_SEQHDR: 109 | err = self.specificInfo(b) 110 | case av.AAC_RAW: 111 | err = self.adts(b, w) 112 | } 113 | return 114 | } 115 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/parser/h264/parser.go: -------------------------------------------------------------------------------- 1 | package h264 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "io" 7 | ) 8 | 9 | const ( 10 | i_frame byte = 0 11 | p_frame byte = 1 12 | b_frame byte = 2 13 | ) 14 | 15 | const ( 16 | nalu_type_not_define byte = 0 17 | nalu_type_slice byte = 1 //slice_layer_without_partioning_rbsp() sliceheader 18 | nalu_type_dpa byte = 2 // slice_data_partition_a_layer_rbsp( ), slice_header 19 | nalu_type_dpb byte = 3 // slice_data_partition_b_layer_rbsp( ) 20 | nalu_type_dpc byte = 4 // slice_data_partition_c_layer_rbsp( ) 21 | nalu_type_idr byte = 5 // slice_layer_without_partitioning_rbsp( ),sliceheader 22 | nalu_type_sei byte = 6 //sei_rbsp( ) 23 | nalu_type_sps byte = 7 //seq_parameter_set_rbsp( ) 24 | nalu_type_pps byte = 8 //pic_parameter_set_rbsp( ) 25 | nalu_type_aud byte = 9 // access_unit_delimiter_rbsp( ) 26 | nalu_type_eoesq byte = 10 //end_of_seq_rbsp( ) 27 | nalu_type_eostream byte = 11 //end_of_stream_rbsp( ) 28 | nalu_type_filler byte = 12 //filler_data_rbsp( ) 29 | ) 30 | 31 | const ( 32 | naluBytesLen int = 4 33 | maxSpsPpsLen int = 2 * 1024 34 | ) 35 | 36 | var ( 37 | decDataNil = errors.New("dec buf is nil") 38 | spsDataError = errors.New("sps data error") 39 | ppsHeaderError = errors.New("pps header error") 40 | ppsDataError = errors.New("pps data error") 41 | naluHeaderInvalid = errors.New("nalu header invalid") 42 | videoDataInvalid = errors.New("video data not match") 43 | dataSizeNotMatch = errors.New("data size not match") 44 | naluBodyLenError = errors.New("nalu body len error") 45 | ) 46 | 47 | var startCode = []byte{0x00, 0x00, 0x00, 0x01} 48 | var naluAud = []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xf0} 49 | 50 | type Parser struct { 51 | frameType byte 52 | specificInfo []byte 53 | pps *bytes.Buffer 54 | } 55 | 56 | type sequenceHeader struct { 57 | configVersion byte //8bits 58 | avcProfileIndication byte //8bits 59 | profileCompatility byte //8bits 60 | avcLevelIndication byte //8bits 61 | reserved1 byte //6bits 62 | naluLen byte //2bits 63 | reserved2 byte //3bits 64 | spsNum byte //5bits 65 | ppsNum byte //8bits 66 | spsLen int 67 | ppsLen int 68 | } 69 | 70 | func NewParser() *Parser { 71 | return &Parser{ 72 | pps: bytes.NewBuffer(make([]byte, maxSpsPpsLen)), 73 | } 74 | } 75 | 76 | //return value 1:sps, value2 :pps 77 | func (self *Parser) parseSpecificInfo(src []byte) error { 78 | if len(src) < 9 { 79 | return decDataNil 80 | } 81 | sps := []byte{} 82 | pps := []byte{} 83 | 84 | var seq sequenceHeader 85 | seq.configVersion = src[0] 86 | seq.avcProfileIndication = src[1] 87 | seq.profileCompatility = src[2] 88 | seq.avcLevelIndication = src[3] 89 | seq.reserved1 = src[4] & 0xfc 90 | seq.naluLen = src[4]&0x03 + 1 91 | seq.reserved2 = src[5] >> 5 92 | 93 | //get sps 94 | seq.spsNum = src[5] & 0x1f 95 | seq.spsLen = int(src[6])<<8 | int(src[7]) 96 | 97 | if len(src[8:]) < seq.spsLen || seq.spsLen <= 0 { 98 | return spsDataError 99 | } 100 | sps = append(sps, startCode...) 101 | sps = append(sps, src[8:(8+seq.spsLen)]...) 102 | 103 | //get pps 104 | tmpBuf := src[(8 + seq.spsLen):] 105 | if len(tmpBuf) < 4 { 106 | return ppsHeaderError 107 | } 108 | seq.ppsNum = tmpBuf[0] 109 | seq.ppsLen = int(0)<<16 | int(tmpBuf[1])<<8 | int(tmpBuf[2]) 110 | if len(tmpBuf[3:]) < seq.ppsLen || seq.ppsLen <= 0 { 111 | return ppsDataError 112 | } 113 | 114 | pps = append(pps, startCode...) 115 | pps = append(pps, tmpBuf[3:]...) 116 | 117 | self.specificInfo = append(self.specificInfo, sps...) 118 | self.specificInfo = append(self.specificInfo, pps...) 119 | 120 | return nil 121 | } 122 | 123 | func (self *Parser) isNaluHeader(src []byte) bool { 124 | if len(src) < naluBytesLen { 125 | return false 126 | } 127 | return src[0] == 0x00 && 128 | src[1] == 0x00 && 129 | src[2] == 0x00 && 130 | src[3] == 0x01 131 | } 132 | 133 | func (self *Parser) naluSize(src []byte) (int, error) { 134 | if len(src) < naluBytesLen { 135 | return 0, errors.New("nalusizedata invalid") 136 | } 137 | buf := src[:naluBytesLen] 138 | size := int(0) 139 | for i := 0; i < len(buf); i++ { 140 | size = size<<8 + int(buf[i]) 141 | } 142 | return size, nil 143 | } 144 | 145 | func (self *Parser) getAnnexbH264(src []byte, w io.Writer) error { 146 | dataSize := len(src) 147 | if dataSize < naluBytesLen { 148 | return videoDataInvalid 149 | } 150 | self.pps.Reset() 151 | _, err := w.Write(naluAud) 152 | if err != nil { 153 | return err 154 | } 155 | 156 | index := 0 157 | nalLen := 0 158 | hasSpsPps := false 159 | hasWriteSpsPps := false 160 | 161 | for dataSize > 0 { 162 | nalLen, err = self.naluSize(src[index:]) 163 | if err != nil { 164 | return dataSizeNotMatch 165 | } 166 | index += naluBytesLen 167 | dataSize -= naluBytesLen 168 | if dataSize >= nalLen && len(src[index:]) >= nalLen && nalLen > 0 { 169 | nalType := src[index] & 0x1f 170 | switch nalType { 171 | case nalu_type_aud: 172 | case nalu_type_idr: 173 | if !hasWriteSpsPps { 174 | hasWriteSpsPps = true 175 | if !hasSpsPps { 176 | if _, err := w.Write(self.specificInfo); err != nil { 177 | return err 178 | } 179 | } else { 180 | if _, err := w.Write(self.pps.Bytes()); err != nil { 181 | return err 182 | } 183 | } 184 | } 185 | fallthrough 186 | case nalu_type_slice: 187 | fallthrough 188 | case nalu_type_sei: 189 | _, err := w.Write(startCode) 190 | if err != nil { 191 | return err 192 | } 193 | _, err = w.Write(src[index : index+nalLen]) 194 | if err != nil { 195 | return err 196 | } 197 | case nalu_type_sps: 198 | fallthrough 199 | case nalu_type_pps: 200 | hasSpsPps = true 201 | _, err := self.pps.Write(startCode) 202 | if err != nil { 203 | return err 204 | } 205 | _, err = self.pps.Write(src[index : index+nalLen]) 206 | if err != nil { 207 | return err 208 | } 209 | } 210 | index += nalLen 211 | dataSize -= nalLen 212 | } else { 213 | return naluBodyLenError 214 | } 215 | } 216 | return nil 217 | } 218 | 219 | func (self *Parser) Parse(b []byte, isSeq bool, w io.Writer) (err error) { 220 | switch isSeq { 221 | case true: 222 | err = self.parseSpecificInfo(b) 223 | case false: 224 | // is annexb 225 | if self.isNaluHeader(b) { 226 | _, err = w.Write(b) 227 | } else { 228 | err = self.getAnnexbH264(b, w) 229 | } 230 | } 231 | return 232 | } 233 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/parser/h264/parser_test.go: -------------------------------------------------------------------------------- 1 | package h264 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestH264SeqDemux(t *testing.T) { 12 | at := assert.New(t) 13 | seq := []byte{ 14 | 0x01, 0x4d, 0x00, 0x1e, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x4d, 0x00, 15 | 0x1e, 0xab, 0x40, 0x5a, 0x12, 0x6c, 0x09, 0x28, 0x28, 0x28, 0x2f, 16 | 0x80, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x61, 0xa8, 0x4a, 0x01, 0x00, 17 | 0x04, 0x68, 0xde, 0x31, 0x12, 18 | } 19 | d := NewParser() 20 | w := bytes.NewBuffer(nil) 21 | err := d.Parse(seq, true, w) 22 | at.Equal(err, nil) 23 | at.Equal(d.specificInfo, []byte{0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x00, 24 | 0x1e, 0xab, 0x40, 0x5a, 0x12, 0x6c, 0x09, 0x28, 0x28, 0x28, 0x2f, 25 | 0x80, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x61, 0xa8, 0x4a, 0x00, 0x00, 0x00, 0x01, 0x68, 0xde, 0x31, 0x12}) 26 | } 27 | 28 | func TestH264AnnexbDemux(t *testing.T) { 29 | at := assert.New(t) 30 | nalu := []byte{ 31 | 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x00, 0x1e, 0xab, 0x40, 0x5a, 0x12, 0x6c, 0x09, 0x28, 0x28, 32 | 0x28, 0x2f, 0x80, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x61, 0xa8, 0x4a, 0x00, 0x00, 0x00, 0x01, 0x68, 33 | 0xde, 0x31, 0x12, 0x00, 0x00, 0x00, 0x01, 0x65, 0x23, 34 | } 35 | d := NewParser() 36 | w := bytes.NewBuffer(nil) 37 | err := d.Parse(nalu, false, w) 38 | at.Equal(err, nil) 39 | at.Equal(w.Len(), 41) 40 | } 41 | 42 | func TestH264NalueSizeException(t *testing.T) { 43 | at := assert.New(t) 44 | nalu := []byte{ 45 | 0x00, 0x00, 0x10, 46 | } 47 | d := NewParser() 48 | w := bytes.NewBuffer(nil) 49 | err := d.Parse(nalu, false, w) 50 | at.Equal(err, errors.New("video data not match")) 51 | } 52 | 53 | func TestH264Mp4Demux(t *testing.T) { 54 | at := assert.New(t) 55 | nalu := []byte{ 56 | 0x00, 0x00, 0x00, 0x17, 0x67, 0x4d, 0x00, 0x1e, 0xab, 0x40, 0x5a, 0x12, 0x6c, 0x09, 0x28, 0x28, 57 | 0x28, 0x2f, 0x80, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x61, 0xa8, 0x4a, 0x00, 0x00, 0x00, 0x04, 0x68, 58 | 0xde, 0x31, 0x12, 0x00, 0x00, 0x00, 0x02, 0x65, 0x23, 59 | } 60 | d := NewParser() 61 | w := bytes.NewBuffer(nil) 62 | err := d.Parse(nalu, false, w) 63 | at.Equal(err, nil) 64 | at.Equal(w.Len(), 47) 65 | at.Equal(w.Bytes(), []byte{0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x00, 0x1e, 0xab, 0x40, 0x5a, 0x12, 0x6c, 0x09, 0x28, 0x28, 66 | 0x28, 0x2f, 0x80, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x61, 0xa8, 0x4a, 0x00, 0x00, 0x00, 0x01, 0x68, 67 | 0xde, 0x31, 0x12, 0x00, 0x00, 0x00, 0x01, 0x65, 0x23}) 68 | } 69 | 70 | func TestH264Mp4DemuxException1(t *testing.T) { 71 | at := assert.New(t) 72 | nalu := []byte{ 73 | 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 74 | } 75 | d := NewParser() 76 | w := bytes.NewBuffer(nil) 77 | 78 | err := d.Parse(nalu, false, w) 79 | at.Equal(err, naluBodyLenError) 80 | } 81 | 82 | func TestH264Mp4DemuxException2(t *testing.T) { 83 | at := assert.New(t) 84 | nalu := []byte{ 85 | 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x17, 0x67, 0x4d, 0x00, 0x1e, 0xab, 0x40, 0x5a, 0x12, 0x6c, 0x09, 0x28, 0x28, 86 | 0x28, 0x2f, 0x80, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x61, 0xa8, 0x4a, 0x00, 0x00, 0x00, 87 | } 88 | d := NewParser() 89 | w := bytes.NewBuffer(nil) 90 | err := d.Parse(nalu, false, w) 91 | at.Equal(err, naluBodyLenError) 92 | } 93 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/parser/mp3/parser.go: -------------------------------------------------------------------------------- 1 | package mp3 2 | 3 | import "errors" 4 | 5 | type Parser struct { 6 | samplingFrequency int 7 | } 8 | 9 | func NewParser() *Parser { 10 | return &Parser{} 11 | } 12 | 13 | // sampling_frequency - indicates the sampling frequency, according to the following table. 14 | // '00' 44.1 kHz 15 | // '01' 48 kHz 16 | // '10' 32 kHz 17 | // '11' reserved 18 | var mp3Rates = []int{44100, 48000, 32000} 19 | var ( 20 | errMp3DataInvalid = errors.New("mp3data invalid") 21 | errIndexInvalid = errors.New("invalid rate index") 22 | ) 23 | 24 | func (self *Parser) Parse(src []byte) error { 25 | if len(src) < 3 { 26 | return errMp3DataInvalid 27 | } 28 | index := (src[2] >> 2) & 0x3 29 | if index <= byte(len(mp3Rates)-1) { 30 | self.samplingFrequency = mp3Rates[index] 31 | return nil 32 | } 33 | return errIndexInvalid 34 | } 35 | 36 | func (self *Parser) SampleRate() int { 37 | if self.samplingFrequency == 0 { 38 | self.samplingFrequency = 44100 39 | } 40 | return self.samplingFrequency 41 | } 42 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | 7 | "sheepbao.com/media/av" 8 | "sheepbao.com/media/parser/aac" 9 | "sheepbao.com/media/parser/h264" 10 | "sheepbao.com/media/parser/mp3" 11 | ) 12 | 13 | var ( 14 | errNoAudio = errors.New("demuxer no audio") 15 | ) 16 | 17 | type CodecParser struct { 18 | aac *aac.Parser 19 | mp3 *mp3.Parser 20 | h264 *h264.Parser 21 | } 22 | 23 | func NewCodecParser() *CodecParser { 24 | return &CodecParser{} 25 | } 26 | 27 | func (self *CodecParser) SampleRate() (int, error) { 28 | if self.aac == nil && self.mp3 == nil { 29 | return 0, errNoAudio 30 | } 31 | if self.aac != nil { 32 | return self.aac.SampleRate(), nil 33 | } 34 | return self.mp3.SampleRate(), nil 35 | } 36 | 37 | func (self *CodecParser) Parse(p *av.Packet, w io.Writer) (err error) { 38 | 39 | switch p.IsVideo { 40 | case true: 41 | f, ok := p.Header.(av.VideoPacketHeader) 42 | if ok { 43 | if f.CodecID() == av.VIDEO_H264 { 44 | if self.h264 == nil { 45 | self.h264 = h264.NewParser() 46 | } 47 | err = self.h264.Parse(p.Data, f.IsSeq(), w) 48 | } 49 | } 50 | case false: 51 | f, ok := p.Header.(av.AudioPacketHeader) 52 | if ok { 53 | switch f.SoundFormat() { 54 | case av.SOUND_AAC: 55 | if self.aac == nil { 56 | self.aac = aac.NewParser() 57 | } 58 | err = self.aac.Parse(p.Data, f.AACPacketType(), w) 59 | case av.SOUND_MP3: 60 | if self.mp3 == nil { 61 | self.mp3 = mp3.NewParser() 62 | } 63 | err = self.mp3.Parse(p.Data) 64 | } 65 | } 66 | 67 | } 68 | return 69 | } 70 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/amf.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | ) 8 | 9 | func (d *Decoder) DecodeBatch(r io.Reader, ver Version) (ret []interface{}, err error) { 10 | var v interface{} 11 | for { 12 | v, err = d.Decode(r, ver) 13 | if err != nil { 14 | break 15 | } 16 | ret = append(ret, v) 17 | } 18 | return 19 | } 20 | 21 | func (d *Decoder) Decode(r io.Reader, ver Version) (interface{}, error) { 22 | switch ver { 23 | case 0: 24 | return d.DecodeAmf0(r) 25 | case 3: 26 | return d.DecodeAmf3(r) 27 | } 28 | 29 | return nil, errors.New(fmt.Sprintf("decode amf: unsupported version %d", ver)) 30 | } 31 | 32 | func (e *Encoder) EncodeBatch(w io.Writer, ver Version, val ...interface{}) (int, error) { 33 | for _, v := range val { 34 | if _, err := e.Encode(w, v, ver); err != nil { 35 | return 0, err 36 | } 37 | } 38 | return 0, nil 39 | } 40 | 41 | func (e *Encoder) Encode(w io.Writer, val interface{}, ver Version) (int, error) { 42 | switch ver { 43 | case AMF0: 44 | return e.EncodeAmf0(w, val) 45 | case AMF3: 46 | return e.EncodeAmf3(w, val) 47 | } 48 | 49 | return 0, Error("encode amf: unsupported version %d", ver) 50 | } 51 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/amf_test.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func EncodeAndDecode(val interface{}, ver Version) (result interface{}, err error) { 13 | enc := new(Encoder) 14 | dec := new(Decoder) 15 | 16 | buf := new(bytes.Buffer) 17 | 18 | _, err = enc.Encode(buf, val, ver) 19 | if err != nil { 20 | return nil, errors.New(fmt.Sprintf("error in encode: %s", err)) 21 | } 22 | 23 | result, err = dec.Decode(buf, ver) 24 | if err != nil { 25 | return nil, errors.New(fmt.Sprintf("error in decode: %s", err)) 26 | } 27 | 28 | return 29 | } 30 | 31 | func Compare(val interface{}, ver Version, name string, t *testing.T) { 32 | result, err := EncodeAndDecode(val, ver) 33 | if err != nil { 34 | t.Errorf("%s: %s", name, err) 35 | } 36 | 37 | if !reflect.DeepEqual(val, result) { 38 | val_v := reflect.ValueOf(val) 39 | result_v := reflect.ValueOf(result) 40 | 41 | t.Errorf("%s: comparison failed between %+v (%s) and %+v (%s)", name, val, val_v.Type(), result, result_v.Type()) 42 | 43 | Dump("expected", val) 44 | Dump("got", result) 45 | } 46 | 47 | // if val != result { 48 | // t.Errorf("%s: comparison failed between %+v and %+v", name, val, result) 49 | // } 50 | } 51 | 52 | func TestAmf0Number(t *testing.T) { 53 | Compare(float64(3.14159), 0, "amf0 number float", t) 54 | Compare(float64(124567890), 0, "amf0 number high", t) 55 | Compare(float64(-34.2), 0, "amf0 number negative", t) 56 | } 57 | 58 | func TestAmf0String(t *testing.T) { 59 | Compare("a pup!", 0, "amf0 string simple", t) 60 | Compare("日本語", 0, "amf0 string utf8", t) 61 | } 62 | 63 | func TestAmf0Boolean(t *testing.T) { 64 | Compare(true, 0, "amf0 boolean true", t) 65 | Compare(false, 0, "amf0 boolean false", t) 66 | } 67 | 68 | func TestAmf0Null(t *testing.T) { 69 | Compare(nil, 0, "amf0 boolean nil", t) 70 | } 71 | 72 | func TestAmf0Object(t *testing.T) { 73 | obj := make(Object) 74 | obj["dog"] = "alfie" 75 | obj["coffee"] = true 76 | obj["drugs"] = false 77 | obj["pi"] = 3.14159 78 | 79 | res, err := EncodeAndDecode(obj, 0) 80 | if err != nil { 81 | t.Errorf("amf0 object: %s", err) 82 | } 83 | 84 | result, ok := res.(Object) 85 | if ok != true { 86 | t.Errorf("amf0 object conversion failed") 87 | } 88 | 89 | if result["dog"] != "alfie" { 90 | t.Errorf("amf0 object string: comparison failed") 91 | } 92 | 93 | if result["coffee"] != true { 94 | t.Errorf("amf0 object true: comparison failed") 95 | } 96 | 97 | if result["drugs"] != false { 98 | t.Errorf("amf0 object false: comparison failed") 99 | } 100 | 101 | if result["pi"] != float64(3.14159) { 102 | t.Errorf("amf0 object float: comparison failed") 103 | } 104 | } 105 | 106 | func TestAmf0Array(t *testing.T) { 107 | arr := [5]float64{1, 2, 3, 4, 5} 108 | 109 | res, err := EncodeAndDecode(arr, 0) 110 | if err != nil { 111 | t.Error("amf0 object: %s", err) 112 | } 113 | 114 | result, ok := res.(Array) 115 | if ok != true { 116 | t.Errorf("amf0 array conversion failed") 117 | } 118 | 119 | for i := 0; i < len(arr); i++ { 120 | if arr[i] != result[i] { 121 | t.Errorf("amf0 array %d comparison failed: %v / %v", i, arr[i], result[i]) 122 | } 123 | } 124 | } 125 | 126 | func TestAmf3Integer(t *testing.T) { 127 | Compare(int32(0), 3, "amf3 integer zero", t) 128 | Compare(int32(1245), 3, "amf3 integer low", t) 129 | Compare(int32(123456), 3, "amf3 integer high", t) 130 | } 131 | 132 | func TestAmf3Double(t *testing.T) { 133 | Compare(float64(3.14159), 3, "amf3 double float", t) 134 | Compare(float64(1234567890), 3, "amf3 double high", t) 135 | Compare(float64(-12345), 3, "amf3 double negative", t) 136 | } 137 | 138 | func TestAmf3String(t *testing.T) { 139 | Compare("a pup!", 0, "amf0 string simple", t) 140 | Compare("日本語", 0, "amf0 string utf8", t) 141 | } 142 | 143 | func TestAmf3Boolean(t *testing.T) { 144 | Compare(true, 3, "amf3 boolean true", t) 145 | Compare(false, 3, "amf3 boolean false", t) 146 | } 147 | 148 | func TestAmf3Null(t *testing.T) { 149 | Compare(nil, 3, "amf3 boolean nil", t) 150 | } 151 | 152 | func TestAmf3Date(t *testing.T) { 153 | t1 := time.Unix(time.Now().Unix(), 0).UTC() // nanoseconds discarded 154 | t2 := time.Date(1983, 9, 4, 12, 4, 8, 0, time.UTC) 155 | 156 | Compare(t1, 3, "amf3 date now", t) 157 | Compare(t2, 3, "amf3 date earlier", t) 158 | } 159 | 160 | func TestAmf3Array(t *testing.T) { 161 | obj := make(Object) 162 | obj["key"] = "val" 163 | 164 | var arr Array 165 | arr = append(arr, "amf") 166 | arr = append(arr, float64(2)) 167 | arr = append(arr, -34.95) 168 | arr = append(arr, true) 169 | arr = append(arr, false) 170 | 171 | res, err := EncodeAndDecode(arr, 3) 172 | if err != nil { 173 | t.Error("amf3 object: %s", err) 174 | } 175 | 176 | result, ok := res.(Array) 177 | if ok != true { 178 | t.Errorf("amf3 array conversion failed: %+v", res) 179 | } 180 | 181 | for i := 0; i < len(arr); i++ { 182 | if arr[i] != result[i] { 183 | t.Errorf("amf3 array %d comparison failed: %v / %v", i, arr[i], result[i]) 184 | } 185 | } 186 | } 187 | 188 | func TestAmf3ByteArray(t *testing.T) { 189 | enc := new(Encoder) 190 | dec := new(Decoder) 191 | 192 | buf := new(bytes.Buffer) 193 | 194 | expect := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x00} 195 | 196 | enc.EncodeAmf3ByteArray(buf, expect, true) 197 | 198 | result, err := dec.DecodeAmf3ByteArray(buf, true) 199 | if err != nil { 200 | t.Errorf("err: %s", err) 201 | } 202 | 203 | if bytes.Compare(result, expect) != 0 { 204 | t.Errorf("expected: %+v, got %+v", expect, buf) 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/const.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | const ( 8 | AMF0 = 0x00 9 | AMF3 = 0x03 10 | ) 11 | 12 | const ( 13 | AMF0_NUMBER_MARKER = 0x00 14 | AMF0_BOOLEAN_MARKER = 0x01 15 | AMF0_STRING_MARKER = 0x02 16 | AMF0_OBJECT_MARKER = 0x03 17 | AMF0_MOVIECLIP_MARKER = 0x04 18 | AMF0_NULL_MARKER = 0x05 19 | AMF0_UNDEFINED_MARKER = 0x06 20 | AMF0_REFERENCE_MARKER = 0x07 21 | AMF0_ECMA_ARRAY_MARKER = 0x08 22 | AMF0_OBJECT_END_MARKER = 0x09 23 | AMF0_STRICT_ARRAY_MARKER = 0x0a 24 | AMF0_DATE_MARKER = 0x0b 25 | AMF0_LONG_STRING_MARKER = 0x0c 26 | AMF0_UNSUPPORTED_MARKER = 0x0d 27 | AMF0_RECORDSET_MARKER = 0x0e 28 | AMF0_XML_DOCUMENT_MARKER = 0x0f 29 | AMF0_TYPED_OBJECT_MARKER = 0x10 30 | AMF0_ACMPLUS_OBJECT_MARKER = 0x11 31 | ) 32 | 33 | const ( 34 | AMF0_BOOLEAN_FALSE = 0x00 35 | AMF0_BOOLEAN_TRUE = 0x01 36 | AMF0_STRING_MAX = 65535 37 | AMF3_INTEGER_MAX = 536870911 38 | ) 39 | 40 | const ( 41 | AMF3_UNDEFINED_MARKER = 0x00 42 | AMF3_NULL_MARKER = 0x01 43 | AMF3_FALSE_MARKER = 0x02 44 | AMF3_TRUE_MARKER = 0x03 45 | AMF3_INTEGER_MARKER = 0x04 46 | AMF3_DOUBLE_MARKER = 0x05 47 | AMF3_STRING_MARKER = 0x06 48 | AMF3_XMLDOC_MARKER = 0x07 49 | AMF3_DATE_MARKER = 0x08 50 | AMF3_ARRAY_MARKER = 0x09 51 | AMF3_OBJECT_MARKER = 0x0a 52 | AMF3_XMLSTRING_MARKER = 0x0b 53 | AMF3_BYTEARRAY_MARKER = 0x0c 54 | ) 55 | 56 | type ExternalHandler func(*Decoder, io.Reader) (interface{}, error) 57 | 58 | type Decoder struct { 59 | refCache []interface{} 60 | stringRefs []string 61 | objectRefs []interface{} 62 | traitRefs []Trait 63 | externalHandlers map[string]ExternalHandler 64 | } 65 | 66 | func NewDecoder() *Decoder { 67 | return &Decoder{ 68 | externalHandlers: make(map[string]ExternalHandler), 69 | } 70 | } 71 | 72 | func (d *Decoder) RegisterExternalHandler(name string, f ExternalHandler) { 73 | d.externalHandlers[name] = f 74 | } 75 | 76 | type Encoder struct { 77 | } 78 | 79 | type Version uint8 80 | 81 | type Array []interface{} 82 | type Object map[string]interface{} 83 | 84 | type TypedObject struct { 85 | Type string 86 | Object Object 87 | } 88 | 89 | type Trait struct { 90 | Type string 91 | Externalizable bool 92 | Dynamic bool 93 | Properties []string 94 | } 95 | 96 | func NewTrait() *Trait { 97 | return &Trait{} 98 | } 99 | 100 | func NewTypedObject() *TypedObject { 101 | return &TypedObject{ 102 | Type: "", 103 | Object: make(Object), 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/decoder_amf0.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | // amf0 polymorphic router 9 | func (d *Decoder) DecodeAmf0(r io.Reader) (interface{}, error) { 10 | marker, err := ReadMarker(r) 11 | if err != nil { 12 | return nil, err 13 | } 14 | 15 | switch marker { 16 | case AMF0_NUMBER_MARKER: 17 | return d.DecodeAmf0Number(r, false) 18 | case AMF0_BOOLEAN_MARKER: 19 | return d.DecodeAmf0Boolean(r, false) 20 | case AMF0_STRING_MARKER: 21 | return d.DecodeAmf0String(r, false) 22 | case AMF0_OBJECT_MARKER: 23 | return d.DecodeAmf0Object(r, false) 24 | case AMF0_MOVIECLIP_MARKER: 25 | return nil, Error("decode amf0: unsupported type movieclip") 26 | case AMF0_NULL_MARKER: 27 | return d.DecodeAmf0Null(r, false) 28 | case AMF0_UNDEFINED_MARKER: 29 | return d.DecodeAmf0Undefined(r, false) 30 | case AMF0_REFERENCE_MARKER: 31 | return nil, Error("decode amf0: unsupported type reference") 32 | case AMF0_ECMA_ARRAY_MARKER: 33 | return d.DecodeAmf0EcmaArray(r, false) 34 | case AMF0_STRICT_ARRAY_MARKER: 35 | return d.DecodeAmf0StrictArray(r, false) 36 | case AMF0_DATE_MARKER: 37 | return d.DecodeAmf0Date(r, false) 38 | case AMF0_LONG_STRING_MARKER: 39 | return d.DecodeAmf0LongString(r, false) 40 | case AMF0_UNSUPPORTED_MARKER: 41 | return d.DecodeAmf0Unsupported(r, false) 42 | case AMF0_RECORDSET_MARKER: 43 | return nil, Error("decode amf0: unsupported type recordset") 44 | case AMF0_XML_DOCUMENT_MARKER: 45 | return d.DecodeAmf0XmlDocument(r, false) 46 | case AMF0_TYPED_OBJECT_MARKER: 47 | return d.DecodeAmf0TypedObject(r, false) 48 | case AMF0_ACMPLUS_OBJECT_MARKER: 49 | return d.DecodeAmf3(r) 50 | } 51 | 52 | return nil, Error("decode amf0: unsupported type %d", marker) 53 | } 54 | 55 | // marker: 1 byte 0x00 56 | // format: 8 byte big endian float64 57 | func (d *Decoder) DecodeAmf0Number(r io.Reader, decodeMarker bool) (result float64, err error) { 58 | if err = AssertMarker(r, decodeMarker, AMF0_NUMBER_MARKER); err != nil { 59 | return 60 | } 61 | 62 | err = binary.Read(r, binary.BigEndian, &result) 63 | if err != nil { 64 | return float64(0), Error("amf0 decode: unable to read number: %s", err) 65 | } 66 | 67 | return 68 | } 69 | 70 | // marker: 1 byte 0x01 71 | // format: 1 byte, 0x00 = false, 0x01 = true 72 | func (d *Decoder) DecodeAmf0Boolean(r io.Reader, decodeMarker bool) (result bool, err error) { 73 | if err = AssertMarker(r, decodeMarker, AMF0_BOOLEAN_MARKER); err != nil { 74 | return 75 | } 76 | 77 | var b byte 78 | if b, err = ReadByte(r); err != nil { 79 | return 80 | } 81 | 82 | if b == AMF0_BOOLEAN_FALSE { 83 | return false, nil 84 | } else if b == AMF0_BOOLEAN_TRUE { 85 | return true, nil 86 | } 87 | 88 | return false, Error("decode amf0: unexpected value %v for boolean", b) 89 | } 90 | 91 | // marker: 1 byte 0x02 92 | // format: 93 | // - 2 byte big endian uint16 header to determine size 94 | // - n (size) byte utf8 string 95 | func (d *Decoder) DecodeAmf0String(r io.Reader, decodeMarker bool) (result string, err error) { 96 | if err = AssertMarker(r, decodeMarker, AMF0_STRING_MARKER); err != nil { 97 | return 98 | } 99 | 100 | var length uint16 101 | err = binary.Read(r, binary.BigEndian, &length) 102 | if err != nil { 103 | return "", Error("decode amf0: unable to decode string length: %s", err) 104 | } 105 | 106 | var bytes = make([]byte, length) 107 | if bytes, err = ReadBytes(r, int(length)); err != nil { 108 | return "", Error("decode amf0: unable to decode string value: %s", err) 109 | } 110 | 111 | return string(bytes), nil 112 | } 113 | 114 | // marker: 1 byte 0x03 115 | // format: 116 | // - loop encoded string followed by encoded value 117 | // - terminated with empty string followed by 1 byte 0x09 118 | func (d *Decoder) DecodeAmf0Object(r io.Reader, decodeMarker bool) (Object, error) { 119 | if err := AssertMarker(r, decodeMarker, AMF0_OBJECT_MARKER); err != nil { 120 | return nil, err 121 | } 122 | 123 | result := make(Object) 124 | d.refCache = append(d.refCache, result) 125 | 126 | for { 127 | key, err := d.DecodeAmf0String(r, false) 128 | if err != nil { 129 | return nil, err 130 | } 131 | 132 | if key == "" { 133 | if err = AssertMarker(r, true, AMF0_OBJECT_END_MARKER); err != nil { 134 | return nil, Error("decode amf0: expected object end marker: %s", err) 135 | } 136 | 137 | break 138 | } 139 | 140 | value, err := d.DecodeAmf0(r) 141 | if err != nil { 142 | return nil, Error("decode amf0: unable to decode object value: %s", err) 143 | } 144 | 145 | result[key] = value 146 | } 147 | 148 | return result, nil 149 | 150 | } 151 | 152 | // marker: 1 byte 0x05 153 | // no additional data 154 | func (d *Decoder) DecodeAmf0Null(r io.Reader, decodeMarker bool) (result interface{}, err error) { 155 | err = AssertMarker(r, decodeMarker, AMF0_NULL_MARKER) 156 | return 157 | } 158 | 159 | // marker: 1 byte 0x06 160 | // no additional data 161 | func (d *Decoder) DecodeAmf0Undefined(r io.Reader, decodeMarker bool) (result interface{}, err error) { 162 | err = AssertMarker(r, decodeMarker, AMF0_UNDEFINED_MARKER) 163 | return 164 | } 165 | 166 | // marker: 1 byte 0x07 167 | // format: 2 byte big endian uint16 168 | /* 169 | func (d *Decoder) DecodeAmf0Reference(r io.Reader, decodeMarker bool) (interface{}, error) { 170 | if err := AssertMarker(r, decodeMarker, AMF0_REFERENCE_MARKER); err != nil { 171 | return nil, err 172 | } 173 | 174 | var err error 175 | var ref uint16 176 | 177 | err = binary.Read(r, binary.BigEndian, &ref) 178 | if err != nil { 179 | return nil, Error("decode amf0: unable to decode reference id: %s", err) 180 | } 181 | 182 | if int(ref) > len(d.refCache) { 183 | return nil, Error("decode amf0: bad reference %d (current length %d)", ref, len(d.refCache)) 184 | } 185 | 186 | result := d.refCache[ref] 187 | 188 | return result, nil 189 | } 190 | */ 191 | 192 | // marker: 1 byte 0x08 193 | // format: 194 | // - 4 byte big endian uint32 with length of associative array 195 | // - normal object format: 196 | // - loop encoded string followed by encoded value 197 | // - terminated with empty string followed by 1 byte 0x09 198 | func (d *Decoder) DecodeAmf0EcmaArray(r io.Reader, decodeMarker bool) (Object, error) { 199 | if err := AssertMarker(r, decodeMarker, AMF0_ECMA_ARRAY_MARKER); err != nil { 200 | return nil, err 201 | } 202 | 203 | var length uint32 204 | err := binary.Read(r, binary.BigEndian, &length) 205 | 206 | result, err := d.DecodeAmf0Object(r, false) 207 | if err != nil { 208 | return nil, Error("decode amf0: unable to decode ecma array object: %s", err) 209 | } 210 | 211 | return result, nil 212 | } 213 | 214 | // marker: 1 byte 0x0a 215 | // format: 216 | // - 4 byte big endian uint32 to determine length of associative array 217 | // - n (length) encoded values 218 | func (d *Decoder) DecodeAmf0StrictArray(r io.Reader, decodeMarker bool) (result Array, err error) { 219 | if err := AssertMarker(r, decodeMarker, AMF0_STRICT_ARRAY_MARKER); err != nil { 220 | return nil, err 221 | } 222 | 223 | var length uint32 224 | err = binary.Read(r, binary.BigEndian, &length) 225 | if err != nil { 226 | return nil, Error("decode amf0: unable to decode strict array length: %s", err) 227 | } 228 | 229 | d.refCache = append(d.refCache, result) 230 | 231 | for i := uint32(0); i < length; i++ { 232 | tmp, err := d.DecodeAmf0(r) 233 | if err != nil { 234 | return nil, Error("decode amf0: unable to decode strict array object: %s", err) 235 | } 236 | result = append(result, tmp) 237 | } 238 | 239 | return result, nil 240 | } 241 | 242 | // marker: 1 byte 0x0b 243 | // format: 244 | // - normal number format: 245 | // - 8 byte big endian float64 246 | // - 2 byte unused 247 | func (d *Decoder) DecodeAmf0Date(r io.Reader, decodeMarker bool) (result float64, err error) { 248 | if err = AssertMarker(r, decodeMarker, AMF0_DATE_MARKER); err != nil { 249 | return 250 | } 251 | 252 | if result, err = d.DecodeAmf0Number(r, false); err != nil { 253 | return float64(0), Error("decode amf0: unable to decode float in date: %s", err) 254 | } 255 | 256 | if _, err = ReadBytes(r, 2); err != nil { 257 | return float64(0), Error("decode amf0: unable to read 2 trail bytes in date: %s", err) 258 | } 259 | 260 | return 261 | } 262 | 263 | // marker: 1 byte 0x0c 264 | // format: 265 | // - 4 byte big endian uint32 header to determine size 266 | // - n (size) byte utf8 string 267 | func (d *Decoder) DecodeAmf0LongString(r io.Reader, decodeMarker bool) (result string, err error) { 268 | if err = AssertMarker(r, decodeMarker, AMF0_LONG_STRING_MARKER); err != nil { 269 | return 270 | } 271 | 272 | var length uint32 273 | err = binary.Read(r, binary.BigEndian, &length) 274 | if err != nil { 275 | return "", Error("decode amf0: unable to decode long string length: %s", err) 276 | } 277 | 278 | var bytes = make([]byte, length) 279 | if bytes, err = ReadBytes(r, int(length)); err != nil { 280 | return "", Error("decode amf0: unable to decode long string value: %s", err) 281 | } 282 | 283 | return string(bytes), nil 284 | } 285 | 286 | // marker: 1 byte 0x0d 287 | // no additional data 288 | func (d *Decoder) DecodeAmf0Unsupported(r io.Reader, decodeMarker bool) (result interface{}, err error) { 289 | err = AssertMarker(r, decodeMarker, AMF0_UNSUPPORTED_MARKER) 290 | return 291 | } 292 | 293 | // marker: 1 byte 0x0f 294 | // format: 295 | // - normal long string format 296 | // - 4 byte big endian uint32 header to determine size 297 | // - n (size) byte utf8 string 298 | func (d *Decoder) DecodeAmf0XmlDocument(r io.Reader, decodeMarker bool) (result string, err error) { 299 | if err = AssertMarker(r, decodeMarker, AMF0_XML_DOCUMENT_MARKER); err != nil { 300 | return 301 | } 302 | 303 | return d.DecodeAmf0LongString(r, false) 304 | } 305 | 306 | // marker: 1 byte 0x10 307 | // format: 308 | // - normal string format: 309 | // - 2 byte big endian uint16 header to determine size 310 | // - n (size) byte utf8 string 311 | // - normal object format: 312 | // - loop encoded string followed by encoded value 313 | // - terminated with empty string followed by 1 byte 0x09 314 | func (d *Decoder) DecodeAmf0TypedObject(r io.Reader, decodeMarker bool) (TypedObject, error) { 315 | result := *new(TypedObject) 316 | 317 | err := AssertMarker(r, decodeMarker, AMF0_TYPED_OBJECT_MARKER) 318 | if err != nil { 319 | return result, err 320 | } 321 | 322 | d.refCache = append(d.refCache, result) 323 | 324 | result.Type, err = d.DecodeAmf0String(r, false) 325 | if err != nil { 326 | return result, Error("decode amf0: typed object unable to determine type: %s", err) 327 | } 328 | 329 | result.Object, err = d.DecodeAmf0Object(r, false) 330 | if err != nil { 331 | return result, Error("decode amf0: typed object unable to determine object: %s", err) 332 | } 333 | 334 | return result, nil 335 | } 336 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/decoder_amf3_external.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "math" 7 | ) 8 | 9 | // Abstract external boilerplate 10 | func (d *Decoder) decodeAbstractMessage(r io.Reader) (result Object, err error) { 11 | result = make(Object) 12 | 13 | if err = d.decodeExternal(r, &result, 14 | []string{"body", "clientId", "destination", "headers", "messageId", "timeStamp", "timeToLive"}, 15 | []string{"clientIdBytes", "messageIdBytes"}); err != nil { 16 | return result, Error("unable to decode abstract external: %s", err) 17 | } 18 | 19 | return 20 | } 21 | 22 | // DSA 23 | func (d *Decoder) decodeAsyncMessageExt(r io.Reader) (result Object, err error) { 24 | return d.decodeAsyncMessage(r) 25 | } 26 | func (d *Decoder) decodeAsyncMessage(r io.Reader) (result Object, err error) { 27 | result, err = d.decodeAbstractMessage(r) 28 | if err != nil { 29 | return result, Error("unable to decode abstract for async: %s", err) 30 | } 31 | 32 | if err = d.decodeExternal(r, &result, []string{"correlationId", "correlationIdBytes"}); err != nil { 33 | return result, Error("unable to decode async external: %s", err) 34 | } 35 | 36 | return 37 | } 38 | 39 | // DSK 40 | func (d *Decoder) decodeAcknowledgeMessageExt(r io.Reader) (result Object, err error) { 41 | return d.decodeAcknowledgeMessage(r) 42 | } 43 | func (d *Decoder) decodeAcknowledgeMessage(r io.Reader) (result Object, err error) { 44 | result, err = d.decodeAsyncMessage(r) 45 | if err != nil { 46 | return result, Error("unable to decode async for ack: %s", err) 47 | } 48 | 49 | if err = d.decodeExternal(r, &result); err != nil { 50 | return result, Error("unable to decode ack external: %s", err) 51 | } 52 | 53 | return 54 | } 55 | 56 | // flex.messaging.io.ArrayCollection 57 | func (d *Decoder) decodeArrayCollection(r io.Reader) (interface{}, error) { 58 | result, err := d.DecodeAmf3(r) 59 | if err != nil { 60 | return result, Error("cannot decode child of array collection: %s", err) 61 | } 62 | 63 | return result, nil 64 | } 65 | 66 | func (d *Decoder) decodeExternal(r io.Reader, obj *Object, fieldSets ...[]string) (err error) { 67 | var flagSet []uint8 68 | var reservedPosition uint8 69 | var fieldNames []string 70 | 71 | flagSet, err = readFlags(r) 72 | if err != nil { 73 | return Error("unable to read flags: %s", err) 74 | } 75 | 76 | for i, flags := range flagSet { 77 | if i < len(fieldSets) { 78 | fieldNames = fieldSets[i] 79 | } else { 80 | fieldNames = []string{} 81 | } 82 | 83 | reservedPosition = uint8(len(fieldNames)) 84 | 85 | for p, field := range fieldNames { 86 | flagBit := uint8(math.Exp2(float64(p))) 87 | if (flags & flagBit) != 0 { 88 | tmp, err := d.DecodeAmf3(r) 89 | if err != nil { 90 | return Error("unable to decode external field %s %d %d (%#v): %s", field, i, p, flagSet, err) 91 | } 92 | (*obj)[field] = tmp 93 | } 94 | } 95 | 96 | if (flags >> reservedPosition) != 0 { 97 | for j := reservedPosition; j < 6; j++ { 98 | if ((flags >> j) & 0x01) != 0 { 99 | field := fmt.Sprintf("extra_%d_%d", i, j) 100 | tmp, err := d.DecodeAmf3(r) 101 | if err != nil { 102 | return Error("unable to decode post-external field %d %d (%#v): %s", i, j, flagSet, err) 103 | } 104 | (*obj)[field] = tmp 105 | } 106 | } 107 | } 108 | } 109 | 110 | return 111 | } 112 | 113 | func readFlags(r io.Reader) (result []uint8, err error) { 114 | for { 115 | flag, err := ReadByte(r) 116 | if err != nil { 117 | return result, Error("unable to read flags: %s", err) 118 | } 119 | 120 | result = append(result, flag) 121 | if (flag & 0x80) == 0 { 122 | break 123 | } 124 | } 125 | 126 | return 127 | } 128 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/decoder_amf3_test.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | type u29TestCase struct { 9 | value uint32 10 | expect []byte 11 | } 12 | 13 | var u29TestCases = []u29TestCase{ 14 | {1, []byte{0x01}}, 15 | {2, []byte{0x02}}, 16 | {127, []byte{0x7F}}, 17 | {128, []byte{0x81, 0x00}}, 18 | {255, []byte{0x81, 0x7F}}, 19 | {256, []byte{0x82, 0x00}}, 20 | {0x3FFF, []byte{0xFF, 0x7F}}, 21 | {0x4000, []byte{0x81, 0x80, 0x00}}, 22 | {0x7FFF, []byte{0x81, 0xFF, 0x7F}}, 23 | {0x8000, []byte{0x82, 0x80, 0x00}}, 24 | {0x1FFFFF, []byte{0xFF, 0xFF, 0x7F}}, 25 | {0x200000, []byte{0x80, 0xC0, 0x80, 0x00}}, 26 | {0x3FFFFF, []byte{0x80, 0xFF, 0xFF, 0xFF}}, 27 | {0x400000, []byte{0x81, 0x80, 0x80, 0x00}}, 28 | {0x0FFFFFFF, []byte{0xBF, 0xFF, 0xFF, 0xFF}}, 29 | } 30 | 31 | func TestDecodeAmf3Undefined(t *testing.T) { 32 | buf := bytes.NewReader([]byte{0x00}) 33 | 34 | dec := new(Decoder) 35 | 36 | got, err := dec.DecodeAmf3(buf) 37 | if err != nil { 38 | t.Errorf("%s", err) 39 | } 40 | if got != nil { 41 | t.Errorf("expect nil got %v", got) 42 | } 43 | } 44 | 45 | func TestDecodeAmf3Null(t *testing.T) { 46 | buf := bytes.NewReader([]byte{0x01}) 47 | 48 | dec := new(Decoder) 49 | 50 | got, err := dec.DecodeAmf3(buf) 51 | if err != nil { 52 | t.Errorf("%s", err) 53 | } 54 | if got != nil { 55 | t.Errorf("expect nil got %v", got) 56 | } 57 | } 58 | 59 | func TestDecodeAmf3False(t *testing.T) { 60 | buf := bytes.NewReader([]byte{0x02}) 61 | expect := false 62 | 63 | dec := new(Decoder) 64 | 65 | got, err := dec.DecodeAmf3(buf) 66 | if err != nil { 67 | t.Errorf("%s", err) 68 | } 69 | if expect != got { 70 | t.Errorf("expect %v got %v", expect, got) 71 | } 72 | } 73 | 74 | func TestDecodeAmf3True(t *testing.T) { 75 | buf := bytes.NewReader([]byte{0x03}) 76 | expect := true 77 | 78 | dec := new(Decoder) 79 | 80 | got, err := dec.DecodeAmf3(buf) 81 | if err != nil { 82 | t.Errorf("%s", err) 83 | } 84 | if expect != got { 85 | t.Errorf("expect %v got %v", expect, got) 86 | } 87 | } 88 | 89 | func TestDecodeU29(t *testing.T) { 90 | dec := new(Decoder) 91 | 92 | for _, tc := range u29TestCases { 93 | buf := bytes.NewBuffer(tc.expect) 94 | n, err := dec.decodeU29(buf) 95 | if err != nil { 96 | t.Errorf("DecodeAmf3Integer error: %s", err) 97 | } 98 | if n != tc.value { 99 | t.Errorf("DecodeAmf3Integer expect n %x got %x", tc.value, n) 100 | } 101 | } 102 | } 103 | 104 | func TestDecodeAmf3Integer(t *testing.T) { 105 | dec := new(Decoder) 106 | 107 | buf := bytes.NewReader([]byte{0x04, 0xFF, 0xFF, 0x7F}) 108 | expect := int32(2097151) 109 | 110 | got, err := dec.DecodeAmf3(buf) 111 | if err != nil { 112 | t.Errorf("%s", err) 113 | } 114 | if expect != got { 115 | t.Errorf("expect %v got %v", expect, got) 116 | } 117 | 118 | buf.Seek(0, 0) 119 | got, err = dec.DecodeAmf3Integer(buf, true) 120 | if err != nil { 121 | t.Errorf("%s", err) 122 | } 123 | if expect != got { 124 | t.Errorf("expect %v got %v", expect, got) 125 | } 126 | 127 | buf.Seek(1, 0) 128 | got, err = dec.DecodeAmf3Integer(buf, false) 129 | if err != nil { 130 | t.Errorf("%s", err) 131 | } 132 | if expect != got { 133 | t.Errorf("expect %v got %v", expect, got) 134 | } 135 | } 136 | 137 | func TestDecodeAmf3Double(t *testing.T) { 138 | buf := bytes.NewReader([]byte{0x05, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33}) 139 | expect := float64(1.2) 140 | 141 | dec := new(Decoder) 142 | 143 | got, err := dec.DecodeAmf3(buf) 144 | if err != nil { 145 | t.Errorf("%s", err) 146 | } 147 | if expect != got { 148 | t.Errorf("expect %v got %v", expect, got) 149 | } 150 | } 151 | 152 | func TestDecodeAmf3String(t *testing.T) { 153 | buf := bytes.NewReader([]byte{0x06, 0x07, 'f', 'o', 'o'}) 154 | expect := "foo" 155 | 156 | dec := new(Decoder) 157 | 158 | got, err := dec.DecodeAmf3(buf) 159 | if err != nil { 160 | t.Errorf("%s", err) 161 | } 162 | if expect != got { 163 | t.Errorf("expect %v got %v", expect, got) 164 | } 165 | } 166 | 167 | func TestDecodeAmf3Array(t *testing.T) { 168 | buf := bytes.NewReader([]byte{0x09, 0x13, 0x01, 169 | 0x06, 0x03, '1', 170 | 0x06, 0x03, '2', 171 | 0x06, 0x03, '3', 172 | 0x06, 0x03, '4', 173 | 0x06, 0x03, '5', 174 | 0x06, 0x03, '6', 175 | 0x06, 0x03, '7', 176 | 0x06, 0x03, '8', 177 | 0x06, 0x03, '9', 178 | }) 179 | 180 | dec := new(Decoder) 181 | expect := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9"} 182 | got, err := dec.DecodeAmf3Array(buf, true) 183 | if err != nil { 184 | t.Errorf("err: %s", err) 185 | } 186 | 187 | for i, v := range expect { 188 | if got[i] != v { 189 | t.Error("expected array element %d to be %v, got %v", i, v, got[i]) 190 | } 191 | } 192 | } 193 | 194 | func TestDecodeAmf3Object(t *testing.T) { 195 | buf := bytes.NewReader([]byte{ 196 | 0x0a, 0x23, 0x1f, 'o', 'r', 'g', '.', 'a', 197 | 'm', 'f', '.', 'A', 'S', 'C', 'l', 'a', 198 | 's', 's', 0x07, 'b', 'a', 'z', 0x07, 'f', 199 | 'o', 'o', 0x01, 0x06, 0x07, 'b', 'a', 'r', 200 | }) 201 | 202 | dec := new(Decoder) 203 | got, err := dec.DecodeAmf3(buf) 204 | if err != nil { 205 | t.Errorf("err: %s", err) 206 | } 207 | 208 | to, ok := got.(Object) 209 | if ok != true { 210 | t.Error("unable to cast object as typed object") 211 | } 212 | 213 | if to["foo"] != "bar" { 214 | t.Error("expected foo to be bar, got: %+v", to["foo"]) 215 | } 216 | 217 | if to["baz"] != nil { 218 | t.Error("expected baz to be nil, got: %+v", to["baz"]) 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/encoder_amf0.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | "reflect" 7 | ) 8 | 9 | // amf0 polymorphic router 10 | func (e *Encoder) EncodeAmf0(w io.Writer, val interface{}) (int, error) { 11 | if val == nil { 12 | return e.EncodeAmf0Null(w, true) 13 | } 14 | 15 | v := reflect.ValueOf(val) 16 | if !v.IsValid() { 17 | return e.EncodeAmf0Null(w, true) 18 | } 19 | 20 | switch v.Kind() { 21 | case reflect.String: 22 | str := v.String() 23 | if len(str) <= AMF0_STRING_MAX { 24 | return e.EncodeAmf0String(w, str, true) 25 | } else { 26 | return e.EncodeAmf0LongString(w, str, true) 27 | } 28 | case reflect.Bool: 29 | return e.EncodeAmf0Boolean(w, v.Bool(), true) 30 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 31 | return e.EncodeAmf0Number(w, float64(v.Int()), true) 32 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 33 | return e.EncodeAmf0Number(w, float64(v.Uint()), true) 34 | case reflect.Float32, reflect.Float64: 35 | return e.EncodeAmf0Number(w, float64(v.Float()), true) 36 | case reflect.Array, reflect.Slice: 37 | length := v.Len() 38 | arr := make(Array, length) 39 | for i := 0; i < length; i++ { 40 | arr[i] = v.Index(int(i)).Interface() 41 | } 42 | return e.EncodeAmf0StrictArray(w, arr, true) 43 | case reflect.Map: 44 | obj, ok := val.(Object) 45 | if ok != true { 46 | return 0, Error("encode amf0: unable to create object from map") 47 | } 48 | return e.EncodeAmf0Object(w, obj, true) 49 | } 50 | 51 | if _, ok := val.(TypedObject); ok { 52 | return 0, Error("encode amf0: unsupported type typed object") 53 | } 54 | 55 | return 0, Error("encode amf0: unsupported type %s", v.Type()) 56 | } 57 | 58 | // marker: 1 byte 0x00 59 | // format: 8 byte big endian float64 60 | func (e *Encoder) EncodeAmf0Number(w io.Writer, val float64, encodeMarker bool) (n int, err error) { 61 | if encodeMarker { 62 | if err = WriteMarker(w, AMF0_NUMBER_MARKER); err != nil { 63 | return 64 | } 65 | n += 1 66 | } 67 | 68 | err = binary.Write(w, binary.BigEndian, &val) 69 | if err != nil { 70 | return 71 | } 72 | n += 8 73 | 74 | return 75 | } 76 | 77 | // marker: 1 byte 0x01 78 | // format: 1 byte, 0x00 = false, 0x01 = true 79 | func (e *Encoder) EncodeAmf0Boolean(w io.Writer, val bool, encodeMarker bool) (n int, err error) { 80 | if encodeMarker { 81 | if err = WriteMarker(w, AMF0_BOOLEAN_MARKER); err != nil { 82 | return 83 | } 84 | n += 1 85 | } 86 | 87 | var m int 88 | buf := make([]byte, 1) 89 | if val { 90 | buf[0] = AMF0_BOOLEAN_TRUE 91 | } else { 92 | buf[0] = AMF0_BOOLEAN_FALSE 93 | } 94 | 95 | m, err = w.Write(buf) 96 | if err != nil { 97 | return 98 | } 99 | n += m 100 | 101 | return 102 | } 103 | 104 | // marker: 1 byte 0x02 105 | // format: 106 | // - 2 byte big endian uint16 header to determine size 107 | // - n (size) byte utf8 string 108 | func (e *Encoder) EncodeAmf0String(w io.Writer, val string, encodeMarker bool) (n int, err error) { 109 | if encodeMarker { 110 | if err = WriteMarker(w, AMF0_STRING_MARKER); err != nil { 111 | return 112 | } 113 | n += 1 114 | } 115 | 116 | var m int 117 | length := uint16(len(val)) 118 | err = binary.Write(w, binary.BigEndian, length) 119 | if err != nil { 120 | return n, Error("encode amf0: unable to encode string length: %s", err) 121 | } 122 | n += 2 123 | 124 | m, err = w.Write([]byte(val)) 125 | if err != nil { 126 | return n, Error("encode amf0: unable to encode string value: %s", err) 127 | } 128 | n += m 129 | 130 | return 131 | } 132 | 133 | // marker: 1 byte 0x03 134 | // format: 135 | // - loop encoded string followed by encoded value 136 | // - terminated with empty string followed by 1 byte 0x09 137 | func (e *Encoder) EncodeAmf0Object(w io.Writer, val Object, encodeMarker bool) (n int, err error) { 138 | if encodeMarker { 139 | if err = WriteMarker(w, AMF0_OBJECT_MARKER); err != nil { 140 | return 141 | } 142 | n += 1 143 | } 144 | 145 | var m int 146 | for k, v := range val { 147 | m, err = e.EncodeAmf0String(w, k, false) 148 | if err != nil { 149 | return n, Error("encode amf0: unable to encode object key: %s", err) 150 | } 151 | n += m 152 | 153 | m, err = e.EncodeAmf0(w, v) 154 | if err != nil { 155 | return n, Error("encode amf0: unable to encode object value: %s", err) 156 | } 157 | n += m 158 | } 159 | 160 | m, err = e.EncodeAmf0String(w, "", false) 161 | if err != nil { 162 | return n, Error("encode amf0: unable to encode object empty string: %s", err) 163 | } 164 | n += m 165 | 166 | err = WriteMarker(w, AMF0_OBJECT_END_MARKER) 167 | if err != nil { 168 | return n, Error("encode amf0: unable to object end marker: %s", err) 169 | } 170 | n += 1 171 | 172 | return 173 | } 174 | 175 | // marker: 1 byte 0x05 176 | // no additional data 177 | func (e *Encoder) EncodeAmf0Null(w io.Writer, encodeMarker bool) (n int, err error) { 178 | if encodeMarker { 179 | if err = WriteMarker(w, AMF0_NULL_MARKER); err != nil { 180 | return 181 | } 182 | n += 1 183 | } 184 | 185 | return 186 | } 187 | 188 | // marker: 1 byte 0x06 189 | // no additional data 190 | func (e *Encoder) EncodeAmf0Undefined(w io.Writer, encodeMarker bool) (n int, err error) { 191 | if encodeMarker { 192 | if err = WriteMarker(w, AMF0_UNDEFINED_MARKER); err != nil { 193 | return 194 | } 195 | n += 1 196 | } 197 | 198 | return 199 | } 200 | 201 | // marker: 1 byte 0x08 202 | // format: 203 | // - 4 byte big endian uint32 with length of associative array 204 | // - normal object format: 205 | // - loop encoded string followed by encoded value 206 | // - terminated with empty string followed by 1 byte 0x09 207 | func (e *Encoder) EncodeAmf0EcmaArray(w io.Writer, val Object, encodeMarker bool) (n int, err error) { 208 | if encodeMarker { 209 | if err = WriteMarker(w, AMF0_ECMA_ARRAY_MARKER); err != nil { 210 | return 211 | } 212 | n += 1 213 | } 214 | 215 | var m int 216 | length := uint32(len(val)) 217 | err = binary.Write(w, binary.BigEndian, length) 218 | if err != nil { 219 | return n, Error("encode amf0: unable to encode ecma array length: %s", err) 220 | } 221 | n += 4 222 | 223 | m, err = e.EncodeAmf0Object(w, val, false) 224 | if err != nil { 225 | return n, Error("encode amf0: unable to encode ecma array object: %s", err) 226 | } 227 | n += m 228 | 229 | return 230 | } 231 | 232 | // marker: 1 byte 0x0a 233 | // format: 234 | // - 4 byte big endian uint32 to determine length of associative array 235 | // - n (length) encoded values 236 | func (e *Encoder) EncodeAmf0StrictArray(w io.Writer, val Array, encodeMarker bool) (n int, err error) { 237 | if encodeMarker { 238 | if err = WriteMarker(w, AMF0_STRICT_ARRAY_MARKER); err != nil { 239 | return 240 | } 241 | n += 1 242 | } 243 | 244 | var m int 245 | length := uint32(len(val)) 246 | err = binary.Write(w, binary.BigEndian, length) 247 | if err != nil { 248 | return n, Error("encode amf0: unable to encode strict array length: %s", err) 249 | } 250 | n += 4 251 | 252 | for _, v := range val { 253 | m, err = e.EncodeAmf0(w, v) 254 | if err != nil { 255 | return n, Error("encode amf0: unable to encode strict array element: %s", err) 256 | } 257 | n += m 258 | } 259 | 260 | return 261 | } 262 | 263 | // marker: 1 byte 0x0c 264 | // format: 265 | // - 4 byte big endian uint32 header to determine size 266 | // - n (size) byte utf8 string 267 | func (e *Encoder) EncodeAmf0LongString(w io.Writer, val string, encodeMarker bool) (n int, err error) { 268 | if encodeMarker { 269 | if err = WriteMarker(w, AMF0_LONG_STRING_MARKER); err != nil { 270 | return 271 | } 272 | n += 1 273 | } 274 | 275 | var m int 276 | length := uint32(len(val)) 277 | err = binary.Write(w, binary.BigEndian, length) 278 | if err != nil { 279 | return n, Error("encode amf0: unable to encode long string length: %s", err) 280 | } 281 | n += 4 282 | 283 | m, err = w.Write([]byte(val)) 284 | if err != nil { 285 | return n, Error("encode amf0: unable to encode long string value: %s", err) 286 | } 287 | n += m 288 | 289 | return 290 | } 291 | 292 | // marker: 1 byte 0x0d 293 | // no additional data 294 | func (e *Encoder) EncodeAmf0Unsupported(w io.Writer, encodeMarker bool) (n int, err error) { 295 | if encodeMarker { 296 | if err = WriteMarker(w, AMF0_UNSUPPORTED_MARKER); err != nil { 297 | return 298 | } 299 | n += 1 300 | } 301 | 302 | return 303 | } 304 | 305 | // marker: 1 byte 0x11 306 | func (e *Encoder) EncodeAmf0Amf3Marker(w io.Writer) error { 307 | return WriteMarker(w, AMF0_ACMPLUS_OBJECT_MARKER) 308 | } 309 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/encoder_amf0_test.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "testing" 7 | ) 8 | 9 | func TestEncodeAmf0Number(t *testing.T) { 10 | buf := new(bytes.Buffer) 11 | expect := []byte{0x00, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33} 12 | 13 | enc := new(Encoder) 14 | 15 | n, err := enc.EncodeAmf0(buf, float64(1.2)) 16 | if err != nil { 17 | t.Errorf("%s", err) 18 | } 19 | if n != 9 { 20 | t.Errorf("expected to write 9 bytes, actual %d", n) 21 | } 22 | if bytes.Compare(buf.Bytes(), expect) != 0 { 23 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 24 | } 25 | } 26 | 27 | func TestEncodeAmf0BooleanTrue(t *testing.T) { 28 | buf := new(bytes.Buffer) 29 | expect := []byte{0x01, 0x01} 30 | 31 | enc := new(Encoder) 32 | 33 | n, err := enc.EncodeAmf0(buf, true) 34 | if err != nil { 35 | t.Errorf("%s", err) 36 | } 37 | if n != 2 { 38 | t.Errorf("expected to write 2 bytes, actual %d", n) 39 | } 40 | if bytes.Compare(buf.Bytes(), expect) != 0 { 41 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 42 | } 43 | } 44 | 45 | func TestEncodeAmf0BooleanFalse(t *testing.T) { 46 | buf := new(bytes.Buffer) 47 | expect := []byte{0x01, 0x00} 48 | 49 | enc := new(Encoder) 50 | 51 | n, err := enc.EncodeAmf0(buf, false) 52 | if err != nil { 53 | t.Errorf("%s", err) 54 | } 55 | if n != 2 { 56 | t.Errorf("expected to write 2 bytes, actual %d", n) 57 | } 58 | if bytes.Compare(buf.Bytes(), expect) != 0 { 59 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 60 | } 61 | } 62 | 63 | func TestEncodeAmf0String(t *testing.T) { 64 | buf := new(bytes.Buffer) 65 | expect := []byte{0x02, 0x00, 0x03, 0x66, 0x6f, 0x6f} 66 | 67 | enc := new(Encoder) 68 | 69 | n, err := enc.EncodeAmf0(buf, "foo") 70 | if err != nil { 71 | t.Errorf("%s", err) 72 | } 73 | if n != 6 { 74 | t.Errorf("expected to write 6 bytes, actual %d", n) 75 | } 76 | if bytes.Compare(buf.Bytes(), expect) != 0 { 77 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 78 | } 79 | } 80 | 81 | func TestEncodeAmf0Object(t *testing.T) { 82 | buf := new(bytes.Buffer) 83 | expect := []byte{0x03, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x00, 0x03, 0x62, 0x61, 0x72, 0x00, 0x00, 0x09} 84 | 85 | enc := new(Encoder) 86 | 87 | obj := make(Object) 88 | obj["foo"] = "bar" 89 | 90 | n, err := enc.EncodeAmf0(buf, obj) 91 | if err != nil { 92 | t.Errorf("%s", err) 93 | } 94 | if n != 15 { 95 | t.Errorf("expected to write 15 bytes, actual %d", n) 96 | } 97 | if bytes.Compare(buf.Bytes(), expect) != 0 { 98 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 99 | } 100 | } 101 | 102 | func TestEncodeAmf0EcmaArray(t *testing.T) { 103 | buf := new(bytes.Buffer) 104 | expect := []byte{0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x00, 0x03, 0x62, 0x61, 0x72, 0x00, 0x00, 0x09} 105 | 106 | enc := new(Encoder) 107 | 108 | obj := make(Object) 109 | obj["foo"] = "bar" 110 | 111 | _, err := enc.EncodeAmf0EcmaArray(buf, obj, true) 112 | if err != nil { 113 | t.Errorf("%s", err) 114 | } 115 | 116 | if bytes.Compare(buf.Bytes(), expect) != 0 { 117 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 118 | } 119 | } 120 | 121 | func TestEncodeAmf0StrictArray(t *testing.T) { 122 | buf := new(bytes.Buffer) 123 | expect := []byte{0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x40, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x05} 124 | 125 | enc := new(Encoder) 126 | 127 | arr := make(Array, 3) 128 | arr[0] = float64(5) 129 | arr[1] = "foo" 130 | arr[2] = nil 131 | 132 | _, err := enc.EncodeAmf0StrictArray(buf, arr, true) 133 | if err != nil { 134 | t.Errorf("%s", err) 135 | } 136 | 137 | if bytes.Compare(buf.Bytes(), expect) != 0 { 138 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 139 | } 140 | } 141 | 142 | func TestEncodeAmf0Null(t *testing.T) { 143 | buf := new(bytes.Buffer) 144 | expect := []byte{0x05} 145 | 146 | enc := new(Encoder) 147 | 148 | n, err := enc.EncodeAmf0(buf, nil) 149 | if err != nil { 150 | t.Errorf("%s", err) 151 | } 152 | if n != 1 { 153 | t.Errorf("expected to write 1 byte, actual %d", n) 154 | } 155 | if bytes.Compare(buf.Bytes(), expect) != 0 { 156 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 157 | } 158 | } 159 | 160 | func TestEncodeAmf0LongString(t *testing.T) { 161 | buf := new(bytes.Buffer) 162 | 163 | testBytes := []byte("12345678") 164 | 165 | tbuf := new(bytes.Buffer) 166 | for i := 0; i < 65536; i++ { 167 | tbuf.Write(testBytes) 168 | } 169 | 170 | enc := new(Encoder) 171 | 172 | _, err := enc.EncodeAmf0(buf, string(tbuf.Bytes())) 173 | if err != nil { 174 | t.Errorf("%s", err) 175 | } 176 | 177 | mbuf := make([]byte, 1) 178 | _, err = buf.Read(mbuf) 179 | if err != nil { 180 | t.Errorf("error reading header") 181 | } 182 | 183 | if mbuf[0] != 0x0c { 184 | t.Errorf("marker mismatch") 185 | } 186 | 187 | var length uint32 188 | err = binary.Read(buf, binary.BigEndian, &length) 189 | if err != nil { 190 | t.Errorf("error reading buffer") 191 | } 192 | if length != (65536 * 8) { 193 | t.Errorf("expected length to be %d, got %d", (65536 * 8), length) 194 | } 195 | 196 | tmpBuf := make([]byte, 8) 197 | counter := 0 198 | for buf.Len() > 0 { 199 | n, err := buf.Read(tmpBuf) 200 | if err != nil { 201 | t.Fatalf("test long string result check, read data(%d) error: %s, n: %d", counter, err, n) 202 | } 203 | if n != 8 { 204 | t.Fatalf("test long string result check, read data(%d) n: %d", counter, n) 205 | } 206 | if !bytes.Equal(testBytes, tmpBuf) { 207 | t.Fatalf("test long string result check, read data % x", tmpBuf) 208 | } 209 | 210 | counter++ 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/encoder_amf3_test.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestEncodeAmf3EmptyString(t *testing.T) { 9 | enc := new(Encoder) 10 | 11 | buf := new(bytes.Buffer) 12 | expect := []byte{0x01} 13 | 14 | _, err := enc.EncodeAmf3String(buf, "", false) 15 | if err != nil { 16 | t.Errorf("%s", err) 17 | } 18 | 19 | if bytes.Compare(buf.Bytes(), expect) != 0 { 20 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 21 | } 22 | } 23 | 24 | func TestEncodeAmf3Undefined(t *testing.T) { 25 | enc := new(Encoder) 26 | 27 | buf := new(bytes.Buffer) 28 | expect := []byte{0x00} 29 | 30 | _, err := enc.EncodeAmf3Undefined(buf, true) 31 | if err != nil { 32 | t.Errorf("%s", err) 33 | } 34 | 35 | if bytes.Compare(buf.Bytes(), expect) != 0 { 36 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 37 | } 38 | } 39 | 40 | func TestEncodeAmf3Null(t *testing.T) { 41 | enc := new(Encoder) 42 | 43 | buf := new(bytes.Buffer) 44 | expect := []byte{0x01} 45 | 46 | _, err := enc.EncodeAmf3(buf, nil) 47 | if err != nil { 48 | t.Errorf("%s", err) 49 | } 50 | 51 | if bytes.Compare(buf.Bytes(), expect) != 0 { 52 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 53 | } 54 | } 55 | 56 | func TestEncodeAmf3False(t *testing.T) { 57 | enc := new(Encoder) 58 | 59 | buf := new(bytes.Buffer) 60 | expect := []byte{0x02} 61 | 62 | _, err := enc.EncodeAmf3(buf, false) 63 | if err != nil { 64 | t.Errorf("%s", err) 65 | } 66 | 67 | if bytes.Compare(buf.Bytes(), expect) != 0 { 68 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 69 | } 70 | } 71 | 72 | func TestEncodeAmf3True(t *testing.T) { 73 | enc := new(Encoder) 74 | 75 | buf := new(bytes.Buffer) 76 | expect := []byte{0x03} 77 | 78 | _, err := enc.EncodeAmf3(buf, true) 79 | if err != nil { 80 | t.Errorf("%s", err) 81 | } 82 | 83 | if bytes.Compare(buf.Bytes(), expect) != 0 { 84 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 85 | } 86 | } 87 | 88 | func TestEncodeAmf3Integer(t *testing.T) { 89 | enc := new(Encoder) 90 | 91 | for _, tc := range u29TestCases { 92 | buf := new(bytes.Buffer) 93 | _, err := enc.EncodeAmf3Integer(buf, tc.value, false) 94 | if err != nil { 95 | t.Errorf("EncodeAmf3Integer error: %s", err) 96 | } 97 | got := buf.Bytes() 98 | if !bytes.Equal(tc.expect, got) { 99 | t.Errorf("EncodeAmf3Integer expect n %x got %x", tc.value, got) 100 | } 101 | } 102 | 103 | buf := new(bytes.Buffer) 104 | expect := []byte{0x04, 0x80, 0xFF, 0xFF, 0xFF} 105 | 106 | n, err := enc.EncodeAmf3(buf, uint32(4194303)) 107 | if err != nil { 108 | t.Errorf("%s", err) 109 | } 110 | if n != 5 { 111 | t.Errorf("expected to write 5 bytes, actual %d", n) 112 | } 113 | if bytes.Compare(buf.Bytes(), expect) != 0 { 114 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 115 | } 116 | } 117 | 118 | func TestEncodeAmf3Double(t *testing.T) { 119 | enc := new(Encoder) 120 | 121 | buf := new(bytes.Buffer) 122 | expect := []byte{0x05, 0x3f, 0xf3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33} 123 | 124 | _, err := enc.EncodeAmf3(buf, float64(1.2)) 125 | if err != nil { 126 | t.Errorf("%s", err) 127 | } 128 | 129 | if bytes.Compare(buf.Bytes(), expect) != 0 { 130 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 131 | } 132 | } 133 | 134 | func TestEncodeAmf3String(t *testing.T) { 135 | enc := new(Encoder) 136 | 137 | buf := new(bytes.Buffer) 138 | expect := []byte{0x06, 0x07, 'f', 'o', 'o'} 139 | 140 | _, err := enc.EncodeAmf3(buf, "foo") 141 | if err != nil { 142 | t.Errorf("%s", err) 143 | } 144 | 145 | if bytes.Compare(buf.Bytes(), expect) != 0 { 146 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 147 | } 148 | } 149 | 150 | func TestEncodeAmf3Array(t *testing.T) { 151 | enc := new(Encoder) 152 | buf := new(bytes.Buffer) 153 | expect := []byte{0x09, 0x13, 0x01, 154 | 0x06, 0x03, '1', 155 | 0x06, 0x03, '2', 156 | 0x06, 0x03, '3', 157 | 0x06, 0x03, '4', 158 | 0x06, 0x03, '5', 159 | 0x06, 0x03, '6', 160 | 0x06, 0x03, '7', 161 | 0x06, 0x03, '8', 162 | 0x06, 0x03, '9', 163 | } 164 | 165 | arr := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9"} 166 | _, err := enc.EncodeAmf3(buf, arr) 167 | if err != nil { 168 | t.Errorf("err: %s", err) 169 | } 170 | 171 | if bytes.Compare(buf.Bytes(), expect) != 0 { 172 | t.Errorf("expected buffer: %+v, got: %+v", expect, buf.Bytes()) 173 | } 174 | } 175 | 176 | func TestEncodeAmf3Object(t *testing.T) { 177 | enc := new(Encoder) 178 | buf := new(bytes.Buffer) 179 | expect := []byte{ 180 | 0x0a, 0x23, 0x1f, 'o', 'r', 'g', '.', 'a', 181 | 'm', 'f', '.', 'A', 'S', 'C', 'l', 'a', 182 | 's', 's', 0x07, 'b', 'a', 'z', 0x07, 'f', 183 | 'o', 'o', 0x01, 0x06, 0x07, 'b', 'a', 'r', 184 | } 185 | 186 | to := *NewTypedObject() 187 | to.Type = "org.amf.ASClass" 188 | to.Object["foo"] = "bar" 189 | to.Object["baz"] = nil 190 | 191 | _, err := enc.EncodeAmf3(buf, to) 192 | if err != nil { 193 | t.Errorf("err: %s", err) 194 | } 195 | 196 | if bytes.Compare(buf.Bytes(), expect) != 0 { 197 | t.Errorf("expected buffer:\n%#v\ngot:\n%#v", expect, buf.Bytes()) 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/metadata.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | const ( 10 | ADD = 0x0 11 | DEL = 0x3 12 | ) 13 | 14 | const ( 15 | SetDataFrame string = "@setDataFrame" 16 | OnMetaData string = "onMetaData" 17 | ) 18 | 19 | var setFrameFrame []byte 20 | 21 | func init() { 22 | b := bytes.NewBuffer(nil) 23 | encoder := &Encoder{} 24 | if _, err := encoder.Encode(b, SetDataFrame, AMF0); err != nil { 25 | log.Fatal(err) 26 | } 27 | setFrameFrame = b.Bytes() 28 | } 29 | 30 | func MetaDataReform(p []byte, flag uint8) ([]byte, error) { 31 | r := bytes.NewReader(p) 32 | decoder := &Decoder{} 33 | switch flag { 34 | case ADD: 35 | v, err := decoder.Decode(r, AMF0) 36 | if err != nil { 37 | return nil, err 38 | } 39 | switch v.(type) { 40 | case string: 41 | vv := v.(string) 42 | if vv != SetDataFrame { 43 | tmplen := len(setFrameFrame) 44 | b := make([]byte, tmplen+len(p)) 45 | copy(b, setFrameFrame) 46 | copy(b[tmplen:], p) 47 | p = b 48 | } 49 | default: 50 | return nil, fmt.Errorf("setFrameFrame error") 51 | } 52 | case DEL: 53 | v, err := decoder.Decode(r, AMF0) 54 | if err != nil { 55 | return nil, err 56 | } 57 | switch v.(type) { 58 | case string: 59 | vv := v.(string) 60 | if vv == SetDataFrame { 61 | p = p[len(setFrameFrame):] 62 | } 63 | default: 64 | return nil, fmt.Errorf("metadata error") 65 | } 66 | default: 67 | return nil, fmt.Errorf("invalid flag:%d", flag) 68 | } 69 | return p, nil 70 | } 71 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/amf/util.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "io" 8 | ) 9 | 10 | func DumpBytes(label string, buf []byte, size int) { 11 | fmt.Printf("Dumping %s (%d bytes):\n", label, size) 12 | for i := 0; i < size; i++ { 13 | fmt.Printf("0x%02x ", buf[i]) 14 | } 15 | fmt.Printf("\n") 16 | } 17 | 18 | func Dump(label string, val interface{}) error { 19 | json, err := json.MarshalIndent(val, "", " ") 20 | if err != nil { 21 | return Error("Error dumping %s: %s", label, err) 22 | } 23 | 24 | fmt.Printf("Dumping %s:\n%s\n", label, json) 25 | return nil 26 | } 27 | 28 | func Error(f string, v ...interface{}) error { 29 | return errors.New(fmt.Sprintf(f, v...)) 30 | } 31 | 32 | func WriteByte(w io.Writer, b byte) (err error) { 33 | bytes := make([]byte, 1) 34 | bytes[0] = b 35 | 36 | _, err = WriteBytes(w, bytes) 37 | 38 | return 39 | } 40 | 41 | func WriteBytes(w io.Writer, bytes []byte) (int, error) { 42 | return w.Write(bytes) 43 | } 44 | 45 | func ReadByte(r io.Reader) (byte, error) { 46 | bytes, err := ReadBytes(r, 1) 47 | if err != nil { 48 | return 0x00, err 49 | } 50 | 51 | return bytes[0], nil 52 | } 53 | 54 | func ReadBytes(r io.Reader, n int) ([]byte, error) { 55 | bytes := make([]byte, n) 56 | 57 | m, err := r.Read(bytes) 58 | if err != nil { 59 | return bytes, err 60 | } 61 | 62 | if m != n { 63 | return bytes, fmt.Errorf("decode read bytes failed: expected %d got %d", m, n) 64 | } 65 | 66 | return bytes, nil 67 | } 68 | 69 | func WriteMarker(w io.Writer, m byte) error { 70 | return WriteByte(w, m) 71 | } 72 | 73 | func ReadMarker(r io.Reader) (byte, error) { 74 | return ReadByte(r) 75 | } 76 | 77 | func AssertMarker(r io.Reader, checkMarker bool, m byte) error { 78 | if checkMarker == false { 79 | return nil 80 | } 81 | 82 | marker, err := ReadMarker(r) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | if marker != m { 88 | return Error("decode assert marker failed: expected %v got %v", m, marker) 89 | } 90 | 91 | return nil 92 | } 93 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/dash/dash.go: -------------------------------------------------------------------------------- 1 | package dash 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/hls/align.go: -------------------------------------------------------------------------------- 1 | package hls 2 | 3 | const ( 4 | syncms = 2 // ms 5 | ) 6 | 7 | type align struct { 8 | frameNum uint64 9 | frameBase uint64 10 | } 11 | 12 | func (self *align) align(dts *uint64, inc uint32) { 13 | aFrameDts := *dts 14 | estPts := self.frameBase + self.frameNum*uint64(inc) 15 | var dPts uint64 16 | if estPts >= aFrameDts { 17 | dPts = estPts - aFrameDts 18 | } else { 19 | dPts = aFrameDts - estPts 20 | } 21 | 22 | if dPts <= uint64(syncms)*h264_default_hz { 23 | self.frameNum++ 24 | *dts = estPts 25 | return 26 | } 27 | self.frameNum = 1 28 | self.frameBase = aFrameDts 29 | } 30 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/hls/audio_cache.go: -------------------------------------------------------------------------------- 1 | package hls 2 | 3 | import "bytes" 4 | 5 | const ( 6 | cache_max_frames byte = 6 7 | audio_cache_len int = 10 * 1024 8 | ) 9 | 10 | type audioCache struct { 11 | soundFormat byte 12 | num byte 13 | offset int 14 | pts uint64 15 | buf *bytes.Buffer 16 | } 17 | 18 | func newAudioCache() *audioCache { 19 | return &audioCache{ 20 | buf: bytes.NewBuffer(make([]byte, audio_cache_len)), 21 | } 22 | } 23 | 24 | func (self *audioCache) Cache(src []byte, pts uint64) bool { 25 | if self.num == 0 { 26 | self.offset = 0 27 | self.pts = pts 28 | self.buf.Reset() 29 | } 30 | self.buf.Write(src) 31 | self.offset += len(src) 32 | self.num++ 33 | 34 | return false 35 | } 36 | 37 | func (self *audioCache) GetFrame() (int, uint64, []byte) { 38 | self.num = 0 39 | return self.offset, self.pts, self.buf.Bytes() 40 | } 41 | 42 | func (self *audioCache) CacheNum() byte { 43 | return self.num 44 | } 45 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/hls/status.go: -------------------------------------------------------------------------------- 1 | package hls 2 | 3 | import "time" 4 | 5 | type status struct { 6 | hasVideo bool 7 | seqId int64 8 | createdAt time.Time 9 | segBeginAt time.Time 10 | hasSetFirstTs bool 11 | firstTimestamp int64 12 | lastTimestamp int64 13 | } 14 | 15 | func newStatus() *status { 16 | return &status{ 17 | seqId: 0, 18 | hasSetFirstTs: false, 19 | segBeginAt: time.Now(), 20 | } 21 | } 22 | 23 | func (t *status) update(isVideo bool, timestamp uint32) { 24 | if isVideo { 25 | t.hasVideo = true 26 | } 27 | if !t.hasSetFirstTs { 28 | t.hasSetFirstTs = true 29 | t.firstTimestamp = int64(timestamp) 30 | } 31 | t.lastTimestamp = int64(timestamp) 32 | } 33 | 34 | func (t *status) resetAndNew() { 35 | t.seqId++ 36 | t.hasVideo = false 37 | t.createdAt = time.Now() 38 | t.hasSetFirstTs = false 39 | } 40 | 41 | func (t *status) durationMs() int64 { 42 | return t.lastTimestamp - t.firstTimestamp 43 | } 44 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/hls/ts_cache.go: -------------------------------------------------------------------------------- 1 | package hls 2 | 3 | import ( 4 | "bytes" 5 | "container/list" 6 | "errors" 7 | "fmt" 8 | ) 9 | 10 | type TSCache struct { 11 | // lock sync.RWMutex 12 | entrys map[string]*TSCacheItem 13 | } 14 | 15 | func NewTSCache() *TSCache { 16 | return &TSCache{ 17 | entrys: make(map[string]*TSCacheItem), 18 | } 19 | } 20 | 21 | func (self *TSCache) Set(key string, e *TSCacheItem) { 22 | // self.lock.Lock() 23 | v, ok := self.entrys[key] 24 | if !ok { 25 | self.entrys[key] = e 26 | } 27 | if v.ID() != e.ID() { 28 | self.entrys[key] = e 29 | } 30 | // self.lock.Unlock() 31 | } 32 | 33 | func (self *TSCache) Get(key string) *TSCacheItem { 34 | // self.lock.Lock() 35 | v := self.entrys[key] 36 | // self.lock.Unlock() 37 | return v 38 | } 39 | 40 | const ( 41 | maxTSCacheNum = 3 42 | ) 43 | 44 | var ( 45 | ErrNoKey = errors.New("No key for cache") 46 | ) 47 | 48 | type TSCacheItem struct { 49 | id string 50 | num int 51 | ll *list.List 52 | // lock sync.RWMutex 53 | lm map[string]TSItem 54 | } 55 | 56 | func NewTSCacheItem(id string) *TSCacheItem { 57 | return &TSCacheItem{ 58 | id: id, 59 | ll: list.New(), 60 | num: maxTSCacheNum, 61 | lm: make(map[string]TSItem), 62 | } 63 | } 64 | 65 | func (self *TSCacheItem) ID() string { 66 | return self.id 67 | } 68 | 69 | func (self *TSCacheItem) GenM3U8PlayList() ([]byte, error) { 70 | var seq int 71 | var getSeq bool 72 | var maxDuration int 73 | m3u8body := bytes.NewBuffer(nil) 74 | // self.lock.Lock() 75 | for e := self.ll.Front(); e != nil; e = e.Next() { 76 | key := e.Value.(string) 77 | v, ok := self.lm[key] 78 | if ok { 79 | if v.Duration > maxDuration { 80 | maxDuration = v.Duration 81 | } 82 | if !getSeq { 83 | getSeq = true 84 | seq = v.SeqNum 85 | } 86 | fmt.Fprintf(m3u8body, "#EXTINF:%.3f,\n%s\n", float64(v.Duration)/float64(1000), v.Name) 87 | } 88 | } 89 | // self.lock.Unlock() 90 | w := bytes.NewBuffer(nil) 91 | fmt.Fprintf(w, 92 | "#EXTM3U\n#EXT-X-VERSION:3\n#EXT-X-ALLOW-CACHE:NO\n#EXT-X-TARGETDURATION:%d\n#EXT-X-MEDIA-SEQUENCE:%d\n\n", 93 | maxDuration/1000+1, seq) 94 | w.Write(m3u8body.Bytes()) 95 | return w.Bytes(), nil 96 | } 97 | 98 | func (self *TSCacheItem) SetItem(key string, item TSItem) { 99 | // self.lock.Lock() 100 | if self.ll.Len() == self.num { 101 | e := self.ll.Front() 102 | self.ll.Remove(e) 103 | k := e.Value.(string) 104 | delete(self.lm, k) 105 | } 106 | self.lm[key] = item 107 | self.ll.PushBack(key) 108 | // self.lock.Unlock() 109 | } 110 | 111 | func (self *TSCacheItem) GetItem(key string) (TSItem, error) { 112 | // self.lock.RLock() 113 | item, ok := self.lm[key] 114 | if !ok { 115 | // self.lock.RUnlock() 116 | return item, ErrNoKey 117 | } 118 | // self.lock.RUnlock() 119 | return item, nil 120 | } 121 | 122 | type TSItem struct { 123 | Name string 124 | SeqNum int 125 | Duration int 126 | Data []byte 127 | } 128 | 129 | func NewTSItem(name string, duration, seqNum int, b []byte) TSItem { 130 | var item TSItem 131 | item.Name = name 132 | item.SeqNum = seqNum 133 | item.Duration = duration 134 | item.Data = make([]byte, len(b)) 135 | copy(item.Data, b) 136 | return item 137 | } 138 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/httpflv/httpflv.go: -------------------------------------------------------------------------------- 1 | package httpflv 2 | 3 | import ( 4 | "encoding/json" 5 | "net" 6 | "net/http" 7 | "strings" 8 | "time" 9 | 10 | "errors" 11 | 12 | "sheepbao.com/glog" 13 | "sheepbao.com/media/av" 14 | "sheepbao.com/media/protocol/amf" 15 | "sheepbao.com/media/protocol/rtmp" 16 | "sheepbao.com/media/utils/pio" 17 | "sheepbao.com/media/utils/uid" 18 | ) 19 | 20 | type Server struct { 21 | handler av.Handler 22 | } 23 | 24 | func NewServer(h av.Handler) *Server { 25 | return &Server{ 26 | handler: h, 27 | } 28 | } 29 | 30 | func (self *Server) Serve(l net.Listener) error { 31 | mux := http.NewServeMux() 32 | mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 33 | self.handleConn(w, r) 34 | }) 35 | mux.HandleFunc("/streams", func(w http.ResponseWriter, r *http.Request) { 36 | self.getStream(w, r) 37 | }) 38 | http.Serve(l, mux) 39 | return nil 40 | } 41 | 42 | func (s *Server) getStream(w http.ResponseWriter, r *http.Request) { 43 | rtmpStream := s.handler.(*rtmp.RtmpStream) 44 | if rtmpStream == nil { 45 | return 46 | } 47 | msg := make(map[string]string) 48 | for item := range rtmpStream.GetStreams().IterBuffered() { 49 | if s, ok := item.Val.(*rtmp.Stream); ok { 50 | if s.GetReader() != nil { 51 | msg[item.Key] = s.GetReader().Info().Key 52 | } 53 | } 54 | } 55 | resp, _ := json.Marshal(msg) 56 | w.Header().Set("Content-Type", "application/json") 57 | w.Write(resp) 58 | msg = make(map[string]string) 59 | for item := range rtmpStream.GetStreams().IterBuffered() { 60 | ws := item.Val.(*rtmp.Stream).GetWs() 61 | for s := range ws.IterBuffered() { 62 | if pw, ok := s.Val.(*rtmp.PackWriterCloser); ok { 63 | if pw.GetWriter() != nil { 64 | msg[pw.GetWriter().Info().UID] = item.Key 65 | } 66 | } 67 | } 68 | } 69 | resp, _ = json.Marshal(msg) 70 | w.Header().Set("Content-Type", "application/json") 71 | w.Write(resp) 72 | 73 | } 74 | 75 | func (self *Server) handleConn(w http.ResponseWriter, r *http.Request) { 76 | defer func() { 77 | if r := recover(); r != nil { 78 | glog.Errorln("http flv handleConn panic: ", r) 79 | } 80 | }() 81 | 82 | url := r.URL.String() 83 | u := r.URL.Path 84 | if pos := strings.LastIndex(u, "."); pos < 0 || u[pos:] != ".flv" { 85 | http.Error(w, "invalid path", http.StatusBadRequest) 86 | return 87 | } 88 | path := strings.TrimSuffix(strings.TrimLeft(u, "/"), ".flv") 89 | paths := strings.SplitN(path, "/", 2) 90 | glog.Infoln("url:", u, "path:", path, "paths:", paths) 91 | 92 | if len(paths) != 2 { 93 | http.Error(w, "invalid path", http.StatusBadRequest) 94 | return 95 | } 96 | 97 | w.Header().Set("Access-Control-Allow-Origin", "*") 98 | writer := NewFLVWriter(paths[0], paths[1], url, w) 99 | 100 | self.handler.HandleWriter(writer) 101 | writer.Wait() 102 | } 103 | 104 | const ( 105 | headerLen = 11 106 | maxQueueNum = 1024 107 | ) 108 | 109 | type FLVWriter struct { 110 | Uid string 111 | av.RWBaser 112 | app, title, url string 113 | buf []byte 114 | closed bool 115 | closedChan chan struct{} 116 | ctx http.ResponseWriter 117 | packetQueue chan av.Packet 118 | } 119 | 120 | func NewFLVWriter(app, title, url string, ctx http.ResponseWriter) *FLVWriter { 121 | ret := &FLVWriter{ 122 | Uid: uid.NEWID(), 123 | app: app, 124 | title: title, 125 | url: url, 126 | ctx: ctx, 127 | RWBaser: av.NewRWBaser(time.Second * 10), 128 | closedChan: make(chan struct{}), 129 | buf: make([]byte, headerLen), 130 | packetQueue: make(chan av.Packet, maxQueueNum), 131 | } 132 | 133 | ret.ctx.Write([]byte{0x46, 0x4c, 0x56, 0x01, 0x05, 0x00, 0x00, 0x00, 0x09}) 134 | pio.PutI32BE(ret.buf[:4], 0) 135 | ret.ctx.Write(ret.buf[:4]) 136 | go func() { 137 | err := ret.SendPacket() 138 | if err != nil { 139 | glog.Errorln("SendPacket error:", err) 140 | ret.closed = true 141 | } 142 | }() 143 | return ret 144 | } 145 | 146 | func (self *FLVWriter) DropPacket(pktQue chan av.Packet, info av.Info) { 147 | glog.Errorf("[%v] packet queue max!!!", info) 148 | for i := 0; i < maxQueueNum-84; i++ { 149 | tmpPkt, ok := <-pktQue 150 | if ok && tmpPkt.IsVideo { 151 | videoPkt, ok := tmpPkt.Header.(av.VideoPacketHeader) 152 | // dont't drop sps config and dont't drop key frame 153 | if ok && (videoPkt.IsSeq() || videoPkt.IsKeyFrame()) { 154 | glog.Infoln("insert keyframe to queue") 155 | pktQue <- tmpPkt 156 | } 157 | 158 | if len(pktQue) > maxQueueNum-10 { 159 | <-pktQue 160 | } 161 | // drop other packet 162 | <-pktQue 163 | } 164 | // try to don't drop audio 165 | if ok && tmpPkt.IsAudio { 166 | glog.Infoln("insert audio to queue") 167 | pktQue <- tmpPkt 168 | } 169 | } 170 | glog.Infoln("packet queue len: ", len(pktQue)) 171 | } 172 | 173 | func (self *FLVWriter) Write(p av.Packet) error { 174 | if !self.closed { 175 | if len(self.packetQueue) >= maxQueueNum-24 { 176 | self.DropPacket(self.packetQueue, self.Info()) 177 | } else { 178 | self.packetQueue <- p 179 | } 180 | return nil 181 | } else { 182 | return errors.New("closed") 183 | } 184 | 185 | } 186 | 187 | // func (self *FLVWriter) Write(p av.Packet) error { 188 | func (self *FLVWriter) SendPacket() error { 189 | for { 190 | p, ok := <-self.packetQueue 191 | if ok { 192 | self.RWBaser.SetPreTime() 193 | h := self.buf[:headerLen] 194 | typeID := av.TAG_VIDEO 195 | if !p.IsVideo { 196 | if p.IsMetadata { 197 | var err error 198 | typeID = av.TAG_SCRIPTDATAAMF0 199 | p.Data, err = amf.MetaDataReform(p.Data, amf.DEL) 200 | if err != nil { 201 | return err 202 | } 203 | } else { 204 | typeID = av.TAG_AUDIO 205 | } 206 | } 207 | dataLen := len(p.Data) 208 | timestamp := p.TimeStamp 209 | timestamp += self.BaseTimeStamp() 210 | self.RWBaser.RecTimeStamp(timestamp, uint32(typeID)) 211 | 212 | preDataLen := dataLen + headerLen 213 | timestampbase := timestamp & 0xffffff 214 | timestampExt := timestamp >> 24 & 0xff 215 | 216 | pio.PutU8(h[0:1], uint8(typeID)) 217 | pio.PutI24BE(h[1:4], int32(dataLen)) 218 | pio.PutI24BE(h[4:7], int32(timestampbase)) 219 | pio.PutU8(h[7:8], uint8(timestampExt)) 220 | 221 | if _, err := self.ctx.Write(h); err != nil { 222 | return err 223 | } 224 | 225 | if _, err := self.ctx.Write(p.Data); err != nil { 226 | return err 227 | } 228 | 229 | pio.PutI32BE(h[:4], int32(preDataLen)) 230 | if _, err := self.ctx.Write(h[:4]); err != nil { 231 | return err 232 | } 233 | } else { 234 | return errors.New("closed") 235 | } 236 | 237 | } 238 | 239 | return nil 240 | } 241 | 242 | func (self *FLVWriter) Wait() { 243 | select { 244 | case <-self.closedChan: 245 | return 246 | } 247 | } 248 | 249 | func (self *FLVWriter) Close(error) { 250 | glog.Infoln("http flv closed") 251 | if !self.closed { 252 | close(self.packetQueue) 253 | close(self.closedChan) 254 | } 255 | self.closed = true 256 | } 257 | 258 | func (self *FLVWriter) Info() (ret av.Info) { 259 | ret.UID = self.Uid 260 | ret.URL = self.url 261 | ret.Key = self.app + "/" + self.title 262 | ret.Inter = true 263 | return 264 | } 265 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/httpopera/httpopera.go: -------------------------------------------------------------------------------- 1 | package httpopera 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "net" 7 | "net/http" 8 | "net/url" 9 | "strings" 10 | 11 | "sheepbao.com/glog" 12 | "sheepbao.com/media/av" 13 | "sheepbao.com/media/protocol/rtmp" 14 | "sheepbao.com/media/utils/uid" 15 | ) 16 | 17 | type Response struct { 18 | w http.ResponseWriter 19 | Status int `json:"status"` 20 | Message string `json:"message"` 21 | } 22 | 23 | func (r *Response) SendJson() (int, error) { 24 | resp, _ := json.Marshal(r) 25 | r.w.Header().Set("Content-Type", "application/json") 26 | return r.w.Write(resp) 27 | } 28 | 29 | type Operation struct { 30 | Method string `json:"method"` 31 | URL string `json:"url"` 32 | Stop bool `json:"stop"` 33 | } 34 | 35 | type OperationChange struct { 36 | Method string `json:"method"` 37 | SourceURL string `json:"source_url"` 38 | TargetURL string `json:"target_url"` 39 | Stop bool `json:"stop"` 40 | } 41 | 42 | type Server struct { 43 | handler av.Handler 44 | } 45 | 46 | func NewServer(h av.Handler) *Server { 47 | return &Server{ 48 | handler: h, 49 | } 50 | } 51 | 52 | func (s *Server) Serve(l net.Listener) error { 53 | mux := http.NewServeMux() 54 | mux.HandleFunc("/rtmp/operation", func(w http.ResponseWriter, r *http.Request) { 55 | s.handleOpera(w, r) 56 | }) 57 | // mux.HandleFunc("/rtmp/operation/change", func(w http.ResponseWriter, r *http.Request) { 58 | // s.handleOperaChange(w, r) 59 | // }) 60 | http.Serve(l, mux) 61 | return nil 62 | } 63 | 64 | // handleOpera, 拉流和推流的http api 65 | // @Path: /rtmp/operation 66 | // @Method: POST 67 | // @Param: json 68 | // method string, "push" or "pull" 69 | // url string 70 | // stop bool 71 | 72 | // @Example, 73 | // curl -v -H "Content-Type: application/json" -X POST --data \ 74 | // '{"method":"pull","url":"rtmp://127.0.0.1:1935/live/test"}' \ 75 | // http://localhost:8087/rtmp/operation 76 | func (s *Server) handleOpera(w http.ResponseWriter, r *http.Request) { 77 | rep := &Response{ 78 | w: w, 79 | } 80 | 81 | if r.Method != "POST" { 82 | rep.Status = 14000 83 | rep.Message = "bad request method" 84 | rep.SendJson() 85 | return 86 | } else { 87 | result, err := ioutil.ReadAll(r.Body) 88 | if err != nil { 89 | rep.Status = 15000 90 | rep.Message = "read request body error" 91 | rep.SendJson() 92 | return 93 | } 94 | r.Body.Close() 95 | glog.Infof("post body: %s\n", result) 96 | 97 | var op Operation 98 | err = json.Unmarshal(result, &op) 99 | if err != nil { 100 | rep.Status = 12000 101 | rep.Message = "parse json body failed" 102 | rep.SendJson() 103 | return 104 | } 105 | 106 | switch op.Method { 107 | case "push": 108 | s.Push(op.URL, op.Stop) 109 | case "pull": 110 | s.Pull(op.URL, op.Stop) 111 | } 112 | 113 | rep.Status = 10000 114 | rep.Message = op.Method + " " + op.URL + " success" 115 | rep.SendJson() 116 | } 117 | } 118 | 119 | func (s *Server) Push(uri string, stop bool) error { 120 | rtmpClient := rtmp.NewRtmpClient(s.handler, nil) 121 | return rtmpClient.Dial(uri, av.PUBLISH) 122 | // return nil 123 | } 124 | 125 | func (s *Server) Pull(uri string, stop bool) error { 126 | rtmpClient := rtmp.NewRtmpClient(s.handler, nil) 127 | return rtmpClient.Dial(uri, av.PLAY) 128 | // return nil 129 | } 130 | 131 | // TODO: 132 | // handleOperaChange, 拉流和推流的http api,支持自定义路径 133 | // @Path: /rtmp/operation/change 134 | // @Method: POST 135 | // @Param: json 136 | // method string, "push" or "pull" 137 | // url string 138 | // stop bool 139 | 140 | // @Example, 141 | // curl -v -H "Content-Type: application/json" -X POST --data \ 142 | // '{"method":"pull","url":"rtmp://127.0.0.1:1935/live/test"}' \ 143 | // http://localhost:8087/rtmp/operation 144 | // func (s *Server) handleOperaChange(w http.ResponseWriter, r *http.Request) { 145 | // rep := &Response{ 146 | // w: w, 147 | // } 148 | 149 | // if r.Method != "POST" { 150 | // rep.Status = 14000 151 | // rep.Message = "bad request method" 152 | // rep.SendJson() 153 | // return 154 | // } else { 155 | // result, err := ioutil.ReadAll(r.Body) 156 | // if err != nil { 157 | // rep.Status = 15000 158 | // rep.Message = "read request body error" 159 | // rep.SendJson() 160 | // return 161 | // } 162 | // r.Body.Close() 163 | // glog.Infof("post body: %s\n", result) 164 | 165 | // var op OperationChange 166 | // err = json.Unmarshal(result, &op) 167 | // if err != nil { 168 | // rep.Status = 12000 169 | // rep.Message = "parse json body failed" 170 | // rep.SendJson() 171 | // return 172 | // } 173 | 174 | // switch op.Method { 175 | // case "push": 176 | // s.PushChange(op.SourceURL, op.TargetURL, op.Stop) 177 | 178 | // case "pull": 179 | // s.PullChange(op.SourceURL, op.TargetURL, op.Stop) 180 | // } 181 | 182 | // rep.Status = 10000 183 | // rep.Message = op.Method + " from" + op.SourceURL + "to " + op.TargetURL + " success" 184 | // rep.SendJson() 185 | // } 186 | // } 187 | 188 | // pushChange suri to turi 189 | // func (s *Server) PushChange(suri, turi string, stop bool) error { 190 | // if !stop { 191 | // sinfo := parseURL(suri) 192 | // tinfo := parseURL(turi) 193 | // rtmpClient := rtmp.NewRtmpClient(s.handler, nil) 194 | // return rtmpClient.Dial(turi, av.PUBLISH) 195 | // } else { 196 | // sinfo := parseURL(suri) 197 | // tinfo := parseURL(turi) 198 | // s.delStream(sinfo.Key, true) 199 | // return nil 200 | // } 201 | // return nil 202 | // } 203 | 204 | // pullChange 205 | // func (s *Server) PullChange(suri, turi string, stop bool) error { 206 | // if !stop { 207 | // rtmpStreams, ok := s.handler.(*rtmp.RtmpStream) 208 | // if ok { 209 | // streams := rtmpStreams.GetStreams() 210 | // rtmpClient := rtmp.NewRtmpClient(s.handler, nil) 211 | // return rtmpClient.Dial(turi, av.PLAY) 212 | // } 213 | // } else { 214 | // info := parseURL(suri) 215 | // s.delStream(info.Key, false) 216 | // return nil 217 | // } 218 | // return nil 219 | // } 220 | 221 | func parseURL(URL string) (ret av.Info) { 222 | ret.UID = uid.NEWID() 223 | ret.URL = URL 224 | _url, err := url.Parse(URL) 225 | if err != nil { 226 | glog.Errorln(err) 227 | } 228 | ret.Key = strings.TrimLeft(_url.Path, "/") 229 | ret.Inter = true 230 | return 231 | } 232 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/kcpts/kcp-ts.go: -------------------------------------------------------------------------------- 1 | package kcpts 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/private/protocol.go: -------------------------------------------------------------------------------- 1 | package private 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import "sheepbao.com/media/av" 4 | import "flag" 5 | 6 | var ( 7 | gopNum = flag.Int("gopNum", 1, "gop num") 8 | ) 9 | 10 | type Cache struct { 11 | gop *GopCache 12 | videoSeq *SpecialCache 13 | audioSeq *SpecialCache 14 | metadata *SpecialCache 15 | } 16 | 17 | func NewCache() *Cache { 18 | return &Cache{ 19 | gop: NewGopCache(*gopNum), 20 | videoSeq: NewSpecialCache(), 21 | audioSeq: NewSpecialCache(), 22 | metadata: NewSpecialCache(), 23 | } 24 | } 25 | 26 | func (self *Cache) Write(p av.Packet) { 27 | if p.IsMetadata { 28 | self.metadata.Write(p) 29 | return 30 | } else { 31 | if !p.IsVideo { 32 | ah, ok := p.Header.(av.AudioPacketHeader) 33 | if ok { 34 | if ah.SoundFormat() == av.SOUND_AAC && 35 | ah.AACPacketType() == av.AAC_SEQHDR { 36 | self.audioSeq.Write(p) 37 | return 38 | } else { 39 | return 40 | } 41 | } 42 | 43 | } else { 44 | vh, ok := p.Header.(av.VideoPacketHeader) 45 | if ok { 46 | if vh.IsSeq() { 47 | self.videoSeq.Write(p) 48 | return 49 | } 50 | } else { 51 | return 52 | } 53 | 54 | } 55 | } 56 | self.gop.Write(p) 57 | } 58 | 59 | func (self *Cache) Send(w av.WriteCloser) error { 60 | if err := self.metadata.Send(w); err != nil { 61 | return err 62 | } 63 | 64 | if err := self.videoSeq.Send(w); err != nil { 65 | return err 66 | } 67 | 68 | if err := self.audioSeq.Send(w); err != nil { 69 | return err 70 | } 71 | 72 | if err := self.gop.Send(w); err != nil { 73 | return err 74 | } 75 | 76 | return nil 77 | } 78 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/cache/gop.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "errors" 5 | 6 | "sheepbao.com/media/av" 7 | ) 8 | 9 | var ( 10 | maxGOPCap int = 1024 11 | ErrGopTooBig = errors.New("gop to big") 12 | ) 13 | 14 | type array struct { 15 | index int 16 | packets []av.Packet 17 | } 18 | 19 | func newArray() *array { 20 | ret := &array{ 21 | index: 0, 22 | packets: make([]av.Packet, 0, maxGOPCap), 23 | } 24 | return ret 25 | } 26 | 27 | func (self *array) reset() { 28 | self.index = 0 29 | self.packets = self.packets[:0] 30 | } 31 | 32 | func (self *array) write(packet av.Packet) error { 33 | if self.index >= maxGOPCap { 34 | return ErrGopTooBig 35 | } 36 | self.packets = append(self.packets, packet) 37 | self.index++ 38 | return nil 39 | } 40 | 41 | func (self *array) send(w av.WriteCloser) error { 42 | var err error 43 | for i := 0; i < self.index; i++ { 44 | packet := self.packets[i] 45 | if err = w.Write(packet); err != nil { 46 | return err 47 | } 48 | } 49 | return err 50 | } 51 | 52 | type GopCache struct { 53 | start bool 54 | num int 55 | count int 56 | nextindex int 57 | gops []*array 58 | } 59 | 60 | func NewGopCache(num int) *GopCache { 61 | return &GopCache{ 62 | count: num, 63 | gops: make([]*array, num), 64 | } 65 | } 66 | 67 | func (self *GopCache) writeToArray(chunk av.Packet, startNew bool) error { 68 | var ginc *array 69 | if startNew { 70 | ginc = self.gops[self.nextindex] 71 | if ginc == nil { 72 | ginc = newArray() 73 | self.num++ 74 | self.gops[self.nextindex] = ginc 75 | } else { 76 | ginc.reset() 77 | } 78 | self.nextindex = (self.nextindex + 1) % self.count 79 | } else { 80 | ginc = self.gops[(self.nextindex+1)%self.count] 81 | } 82 | ginc.write(chunk) 83 | 84 | return nil 85 | } 86 | 87 | func (self *GopCache) Write(p av.Packet) { 88 | var ok bool 89 | if p.IsVideo { 90 | vh := p.Header.(av.VideoPacketHeader) 91 | if vh.IsKeyFrame() && !vh.IsSeq() { 92 | ok = true 93 | } 94 | } 95 | if ok || self.start { 96 | self.start = true 97 | self.writeToArray(p, ok) 98 | } 99 | } 100 | 101 | func (self *GopCache) sendTo(w av.WriteCloser) error { 102 | var err error 103 | pos := (self.nextindex + 1) % self.count 104 | for i := 0; i < self.num; i++ { 105 | index := (pos - self.num + 1) + i 106 | if index < 0 { 107 | index += self.count 108 | } 109 | g := self.gops[index] 110 | err = g.send(w) 111 | if err != nil { 112 | return err 113 | } 114 | } 115 | return nil 116 | } 117 | 118 | func (self *GopCache) Send(w av.WriteCloser) error { 119 | return self.sendTo(w) 120 | } 121 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/cache/special.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | 7 | "sheepbao.com/media/av" 8 | 9 | "sheepbao.com/media/protocol/amf" 10 | ) 11 | 12 | const ( 13 | SetDataFrame string = "@setDataFrame" 14 | OnMetaData string = "onMetaData" 15 | ) 16 | 17 | var setFrameFrame []byte 18 | 19 | func init() { 20 | b := bytes.NewBuffer(nil) 21 | encoder := &amf.Encoder{} 22 | if _, err := encoder.Encode(b, SetDataFrame, amf.AMF0); err != nil { 23 | log.Fatal(err) 24 | } 25 | setFrameFrame = b.Bytes() 26 | } 27 | 28 | type SpecialCache struct { 29 | full bool 30 | p av.Packet 31 | } 32 | 33 | func NewSpecialCache() *SpecialCache { 34 | return &SpecialCache{} 35 | } 36 | 37 | func (self *SpecialCache) Write(p av.Packet) { 38 | self.p = p 39 | self.full = true 40 | } 41 | 42 | func (self *SpecialCache) Send(w av.WriteCloser) error { 43 | if !self.full { 44 | return nil 45 | } 46 | return w.Write(self.p) 47 | } 48 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/chunk_stream.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | 7 | "sheepbao.com/media/av" 8 | "sheepbao.com/media/utils/pool" 9 | ) 10 | 11 | type ChunkStream struct { 12 | Format uint32 13 | CSID uint32 14 | Timestamp uint32 15 | Length uint32 16 | TypeID uint32 17 | StreamID uint32 18 | timeDelta uint32 19 | exted bool 20 | index uint32 21 | remain uint32 22 | got bool 23 | tmpFromat uint32 24 | Data []byte 25 | } 26 | 27 | func (self *ChunkStream) full() bool { 28 | return self.got 29 | } 30 | 31 | func (self *ChunkStream) new(pool *pool.Pool) { 32 | self.got = false 33 | self.index = 0 34 | self.remain = self.Length 35 | self.Data = pool.Get(int(self.Length)) 36 | } 37 | 38 | func (self *ChunkStream) writeHeader(w *ReadWriter) error { 39 | //Chunk Basic Header 40 | h := self.Format << 6 41 | switch { 42 | case self.CSID < 64: 43 | h |= self.CSID 44 | w.WriteUintBE(h, 1) 45 | case self.CSID-64 < 256: 46 | h |= 0 47 | w.WriteUintBE(h, 1) 48 | w.WriteUintLE(self.CSID-64, 1) 49 | case self.CSID-64 < 65536: 50 | h |= 1 51 | w.WriteUintBE(h, 1) 52 | w.WriteUintLE(self.CSID-64, 2) 53 | } 54 | //Chunk Message Header 55 | ts := self.Timestamp 56 | if self.Format == 3 { 57 | goto END 58 | } 59 | if self.Timestamp > 0xffffff { 60 | ts = 0xffffff 61 | } 62 | w.WriteUintBE(ts, 3) 63 | if self.Format == 2 { 64 | goto END 65 | } 66 | if self.Length > 0xffffff { 67 | return fmt.Errorf("length=%d", self.Length) 68 | } 69 | w.WriteUintBE(self.Length, 3) 70 | w.WriteUintBE(self.TypeID, 1) 71 | if self.Format == 1 { 72 | goto END 73 | } 74 | w.WriteUintLE(self.StreamID, 4) 75 | END: 76 | //Extended Timestamp 77 | if ts >= 0xffffff { 78 | w.WriteUintBE(self.Timestamp, 4) 79 | } 80 | return w.WriteError() 81 | } 82 | 83 | func (self *ChunkStream) writeChunk(w *ReadWriter, chunkSize int) error { 84 | if self.TypeID == av.TAG_AUDIO { 85 | self.CSID = 4 86 | } else if self.TypeID == av.TAG_VIDEO || 87 | self.TypeID == av.TAG_SCRIPTDATAAMF0 || 88 | self.TypeID == av.TAG_SCRIPTDATAAMF3 { 89 | self.CSID = 6 90 | } 91 | 92 | totalLen := uint32(0) 93 | numChunks := (self.Length / uint32(chunkSize)) 94 | for i := uint32(0); i <= numChunks; i++ { 95 | if totalLen == self.Length { 96 | break 97 | } 98 | if i == 0 { 99 | self.Format = uint32(0) 100 | } else { 101 | self.Format = uint32(3) 102 | } 103 | if err := self.writeHeader(w); err != nil { 104 | return err 105 | } 106 | inc := uint32(chunkSize) 107 | start := uint32(i) * uint32(chunkSize) 108 | if uint32(len(self.Data))-start <= inc { 109 | inc = uint32(len(self.Data)) - start 110 | } 111 | totalLen += inc 112 | end := start + inc 113 | buf := self.Data[start:end] 114 | if _, err := w.Write(buf); err != nil { 115 | return err 116 | } 117 | } 118 | 119 | return nil 120 | 121 | } 122 | 123 | func (self *ChunkStream) readChunk(r *ReadWriter, chunkSize uint32, pool *pool.Pool) error { 124 | if self.remain != 0 && self.tmpFromat != 3 { 125 | return fmt.Errorf("inlaid remin = %d", self.remain) 126 | } 127 | switch self.CSID { 128 | case 0: 129 | id, _ := r.ReadUintLE(1) 130 | self.CSID = id + 64 131 | case 1: 132 | id, _ := r.ReadUintLE(2) 133 | self.CSID = id + 64 134 | } 135 | 136 | switch self.tmpFromat { 137 | case 0: 138 | self.Format = self.tmpFromat 139 | self.Timestamp, _ = r.ReadUintBE(3) 140 | self.Length, _ = r.ReadUintBE(3) 141 | self.TypeID, _ = r.ReadUintBE(1) 142 | self.StreamID, _ = r.ReadUintLE(4) 143 | if self.Timestamp == 0xffffff { 144 | self.Timestamp, _ = r.ReadUintBE(4) 145 | self.exted = true 146 | } else { 147 | self.exted = false 148 | } 149 | self.new(pool) 150 | case 1: 151 | self.Format = self.tmpFromat 152 | timeStamp, _ := r.ReadUintBE(3) 153 | self.Length, _ = r.ReadUintBE(3) 154 | self.TypeID, _ = r.ReadUintBE(1) 155 | if timeStamp == 0xffffff { 156 | timeStamp, _ = r.ReadUintBE(4) 157 | self.exted = true 158 | } else { 159 | self.exted = false 160 | } 161 | self.timeDelta = timeStamp 162 | self.Timestamp += timeStamp 163 | self.new(pool) 164 | case 2: 165 | self.Format = self.tmpFromat 166 | timeStamp, _ := r.ReadUintBE(3) 167 | if timeStamp == 0xffffff { 168 | timeStamp, _ = r.ReadUintBE(4) 169 | self.exted = true 170 | } else { 171 | self.exted = false 172 | } 173 | self.timeDelta = timeStamp 174 | self.Timestamp += timeStamp 175 | self.new(pool) 176 | case 3: 177 | if self.remain == 0 { 178 | switch self.Format { 179 | case 0: 180 | if self.exted { 181 | timestamp, _ := r.ReadUintBE(4) 182 | self.Timestamp = timestamp 183 | } 184 | case 1, 2: 185 | var timedet uint32 186 | if self.exted { 187 | timedet, _ = r.ReadUintBE(4) 188 | } else { 189 | timedet = self.timeDelta 190 | } 191 | self.Timestamp += timedet 192 | } 193 | self.new(pool) 194 | } else { 195 | if self.exted { 196 | b, err := r.Peek(4) 197 | if err != nil { 198 | return err 199 | } 200 | tmpts := binary.BigEndian.Uint32(b) 201 | if tmpts == self.Timestamp { 202 | r.Discard(4) 203 | } 204 | } 205 | } 206 | default: 207 | return fmt.Errorf("invalid format=%d", self.Format) 208 | } 209 | size := int(self.remain) 210 | if size > int(chunkSize) { 211 | size = int(chunkSize) 212 | } 213 | 214 | buf := self.Data[self.index : self.index+uint32(size)] 215 | if _, err := r.Read(buf); err != nil { 216 | return err 217 | } 218 | self.index += uint32(size) 219 | self.remain -= uint32(size) 220 | if self.remain == 0 { 221 | self.got = true 222 | } 223 | 224 | return r.readError 225 | } 226 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/chunk_stream_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "sheepbao.com/media/utils/pool" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestChunkRead1(t *testing.T) { 13 | at := assert.New(t) 14 | data := []byte{ 15 | 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x01, 0x00, 0x00, 0x00, 16 | } 17 | data1 := make([]byte, 128) 18 | data2 := make([]byte, 51) 19 | data = append(data, data1...) 20 | data = append(data, 0xc6) 21 | data = append(data, data1...) 22 | data = append(data, 0xc6) 23 | data = append(data, data2...) 24 | 25 | rw := NewReadWriter(bytes.NewBuffer(data), 1024) 26 | chunkinc := &ChunkStream{} 27 | 28 | for { 29 | h, _ := rw.ReadUintBE(1) 30 | chunkinc.tmpFromat = h >> 6 31 | chunkinc.CSID = h & 0x3f 32 | chunkinc.readChunk(rw, 128, pool.NewPool()) 33 | if chunkinc.remain == 0 { 34 | break 35 | } 36 | } 37 | 38 | at.Equal(int(chunkinc.Length), 307) 39 | at.Equal(int(chunkinc.TypeID), 9) 40 | at.Equal(int(chunkinc.StreamID), 1) 41 | at.Equal(len(chunkinc.Data), 307) 42 | at.Equal(int(chunkinc.remain), 0) 43 | 44 | data = []byte{ 45 | 0x06, 0xff, 0xff, 0xff, 0x00, 0x01, 0x33, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 46 | } 47 | data = append(data, data1...) 48 | data = append(data, 0xc6) 49 | data = append(data, []byte{0x00, 0x00, 0x00, 0x05}...) 50 | data = append(data, data1...) 51 | data = append(data, 0xc6) 52 | data = append(data, data2...) 53 | 54 | rw = NewReadWriter(bytes.NewBuffer(data), 1024) 55 | chunkinc = &ChunkStream{} 56 | 57 | h, _ := rw.ReadUintBE(1) 58 | chunkinc.tmpFromat = h >> 6 59 | chunkinc.CSID = h & 0x3f 60 | chunkinc.readChunk(rw, 128, pool.NewPool()) 61 | 62 | h, _ = rw.ReadUintBE(1) 63 | chunkinc.tmpFromat = h >> 6 64 | chunkinc.CSID = h & 0x3f 65 | chunkinc.readChunk(rw, 128, pool.NewPool()) 66 | 67 | h, _ = rw.ReadUintBE(1) 68 | chunkinc.tmpFromat = h >> 6 69 | chunkinc.CSID = h & 0x3f 70 | chunkinc.readChunk(rw, 128, pool.NewPool()) 71 | 72 | at.Equal(int(chunkinc.Length), 307) 73 | at.Equal(int(chunkinc.TypeID), 9) 74 | at.Equal(int(chunkinc.StreamID), 1) 75 | at.Equal(len(chunkinc.Data), 307) 76 | at.Equal(chunkinc.exted, true) 77 | at.Equal(int(chunkinc.Timestamp), 5) 78 | at.Equal(int(chunkinc.remain), 0) 79 | 80 | } 81 | 82 | func TestWriteChunk(t *testing.T) { 83 | at := assert.New(t) 84 | chunkinc := &ChunkStream{} 85 | 86 | chunkinc.Length = 307 87 | chunkinc.TypeID = 9 88 | chunkinc.CSID = 4 89 | chunkinc.Timestamp = 40 90 | chunkinc.Data = make([]byte, 307) 91 | 92 | bf := bytes.NewBuffer(nil) 93 | w := NewReadWriter(bf, 1024) 94 | err := chunkinc.writeChunk(w, 128) 95 | w.Flush() 96 | at.Equal(err, nil) 97 | at.Equal(len(bf.Bytes()), 321) 98 | } 99 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/conn.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "encoding/binary" 5 | "net" 6 | "time" 7 | 8 | "sheepbao.com/media/utils/pio" 9 | "sheepbao.com/media/utils/pool" 10 | ) 11 | 12 | const ( 13 | _ = iota 14 | idSetChunkSize 15 | idAbortMessage 16 | idAck 17 | idUserControlMessages 18 | idWindowAckSize 19 | idSetPeerBandwidth 20 | ) 21 | 22 | type Conn struct { 23 | net.Conn 24 | chunkSize uint32 25 | remoteChunkSize uint32 26 | windowAckSize uint32 27 | remoteWindowAckSize uint32 28 | received uint32 29 | ackReceived uint32 30 | rw *ReadWriter 31 | pool *pool.Pool 32 | chunks map[uint32]ChunkStream 33 | } 34 | 35 | func NewConn(c net.Conn, bufferSize int) *Conn { 36 | return &Conn{ 37 | Conn: c, 38 | chunkSize: 128, 39 | remoteChunkSize: 128, 40 | windowAckSize: 2500000, 41 | remoteWindowAckSize: 2500000, 42 | pool: pool.NewPool(), 43 | rw: NewReadWriter(c, bufferSize), 44 | chunks: make(map[uint32]ChunkStream), 45 | } 46 | } 47 | 48 | func (self *Conn) Read(c *ChunkStream) error { 49 | for { 50 | h, _ := self.rw.ReadUintBE(1) 51 | // if err != nil { 52 | // glog.Errorln("read from conn error: ", err) 53 | // return err 54 | // } 55 | format := h >> 6 56 | csid := h & 0x3f 57 | cs, ok := self.chunks[csid] 58 | if !ok { 59 | cs = ChunkStream{} 60 | self.chunks[csid] = cs 61 | } 62 | cs.tmpFromat = format 63 | cs.CSID = csid 64 | err := cs.readChunk(self.rw, self.remoteChunkSize, self.pool) 65 | if err != nil { 66 | return err 67 | } 68 | self.chunks[csid] = cs 69 | if cs.full() { 70 | *c = cs 71 | break 72 | } 73 | } 74 | 75 | self.handleControlMsg(c) 76 | 77 | self.ack(c.Length) 78 | 79 | return nil 80 | } 81 | 82 | func (self *Conn) Write(c *ChunkStream) error { 83 | if c.TypeID == idSetChunkSize { 84 | self.chunkSize = binary.BigEndian.Uint32(c.Data) 85 | } 86 | return c.writeChunk(self.rw, int(self.chunkSize)) 87 | } 88 | 89 | func (self *Conn) Flush() error { 90 | return self.rw.Flush() 91 | } 92 | 93 | func (self *Conn) Close() error { 94 | return self.Conn.Close() 95 | } 96 | 97 | func (self *Conn) RemoteAddr() net.Addr { 98 | return self.Conn.RemoteAddr() 99 | } 100 | 101 | func (self *Conn) LocalAddr() net.Addr { 102 | return self.Conn.LocalAddr() 103 | } 104 | 105 | func (self *Conn) SetDeadline(t time.Time) error { 106 | return self.Conn.SetDeadline(t) 107 | } 108 | 109 | func (self *Conn) NewAck(size uint32) ChunkStream { 110 | return initControlMsg(idAck, 4, size) 111 | } 112 | 113 | func (self *Conn) NewSetChunkSize(size uint32) ChunkStream { 114 | return initControlMsg(idSetChunkSize, 4, size) 115 | } 116 | 117 | func (self *Conn) NewWindowAckSize(size uint32) ChunkStream { 118 | return initControlMsg(idWindowAckSize, 4, size) 119 | } 120 | 121 | func (self *Conn) NewSetPeerBandwidth(size uint32) ChunkStream { 122 | ret := initControlMsg(idSetPeerBandwidth, 5, size) 123 | ret.Data[4] = 2 124 | return ret 125 | } 126 | 127 | func (self *Conn) handleControlMsg(c *ChunkStream) { 128 | if c.TypeID == idSetChunkSize { 129 | self.remoteChunkSize = binary.BigEndian.Uint32(c.Data) 130 | } else if c.TypeID == idWindowAckSize { 131 | self.remoteWindowAckSize = binary.BigEndian.Uint32(c.Data) 132 | } 133 | } 134 | 135 | func (self *Conn) ack(size uint32) { 136 | self.received += uint32(size) 137 | self.ackReceived += uint32(size) 138 | if self.received >= 0xf0000000 { 139 | self.received = 0 140 | } 141 | if self.ackReceived >= self.remoteWindowAckSize { 142 | cs := self.NewAck(self.ackReceived) 143 | cs.writeChunk(self.rw, int(self.chunkSize)) 144 | self.ackReceived = 0 145 | } 146 | } 147 | 148 | func initControlMsg(id, size, value uint32) ChunkStream { 149 | ret := ChunkStream{ 150 | Format: 0, 151 | CSID: 2, 152 | TypeID: id, 153 | StreamID: 0, 154 | Length: size, 155 | Data: make([]byte, size), 156 | } 157 | pio.PutU32BE(ret.Data[:size], value) 158 | return ret 159 | } 160 | 161 | const ( 162 | streamBegin uint32 = 0 163 | streamEOF uint32 = 1 164 | streamDry uint32 = 2 165 | setBufferLen uint32 = 3 166 | streamIsRecorded uint32 = 4 167 | pingRequest uint32 = 6 168 | pingResponse uint32 = 7 169 | ) 170 | 171 | /* 172 | +------------------------------+------------------------- 173 | | Event Type ( 2- bytes ) | Event Data 174 | +------------------------------+------------------------- 175 | Pay load for the ‘User Control Message’. 176 | */ 177 | func (self *Conn) userControlMsg(eventType, buflen uint32) ChunkStream { 178 | var ret ChunkStream 179 | buflen += 2 180 | ret = ChunkStream{ 181 | Format: 0, 182 | CSID: 2, 183 | TypeID: 4, 184 | StreamID: 1, 185 | Length: buflen, 186 | Data: make([]byte, buflen), 187 | } 188 | ret.Data[0] = byte(eventType >> 8 & 0xff) 189 | ret.Data[1] = byte(eventType & 0xff) 190 | return ret 191 | } 192 | 193 | func (self *Conn) SetBegin() { 194 | ret := self.userControlMsg(streamBegin, 4) 195 | for i := 0; i < 4; i++ { 196 | ret.Data[2+i] = byte(1 >> uint32((3-i)*8) & 0xff) 197 | } 198 | self.Write(&ret) 199 | } 200 | 201 | func (self *Conn) SetRecorded() { 202 | ret := self.userControlMsg(streamIsRecorded, 4) 203 | for i := 0; i < 4; i++ { 204 | ret.Data[2+i] = byte(1 >> uint32((3-i)*8) & 0xff) 205 | } 206 | self.Write(&ret) 207 | } 208 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/conn_client.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "math/rand" 9 | "net" 10 | neturl "net/url" 11 | "strings" 12 | 13 | "sheepbao.com/glog" 14 | "sheepbao.com/media/av" 15 | "sheepbao.com/media/protocol/amf" 16 | ) 17 | 18 | var ( 19 | respResult = "_result" 20 | respError = "_error" 21 | onStatus = "onStatus" 22 | publishStart = "NetStream.Publish.Start" 23 | playStart = "NetStream.Play.Start" 24 | connectSuccess = "NetConnection.Connect.Success" 25 | ) 26 | 27 | var ( 28 | ErrFail = errors.New("respone err") 29 | ) 30 | 31 | type ConnClient struct { 32 | done bool 33 | transID int 34 | url string 35 | tcurl string 36 | app string 37 | title string 38 | query string 39 | curcmdName string 40 | streamid uint32 41 | conn *Conn 42 | encoder *amf.Encoder 43 | decoder *amf.Decoder 44 | bytesw *bytes.Buffer 45 | } 46 | 47 | func NewConnClient() *ConnClient { 48 | return &ConnClient{ 49 | transID: 1, 50 | bytesw: bytes.NewBuffer(nil), 51 | encoder: &amf.Encoder{}, 52 | decoder: &amf.Decoder{}, 53 | } 54 | } 55 | 56 | func (self *ConnClient) readRespMsg() error { 57 | var err error 58 | var rc ChunkStream 59 | for { 60 | if err = self.conn.Read(&rc); err != nil { 61 | return err 62 | } 63 | switch rc.TypeID { 64 | case 20, 17: 65 | r := bytes.NewReader(rc.Data) 66 | vs, err := self.decoder.DecodeBatch(r, amf.AMF0) 67 | if err != nil && err != io.EOF { 68 | return err 69 | } 70 | for k, v := range vs { 71 | switch v.(type) { 72 | case string: 73 | switch self.curcmdName { 74 | case cmdConnect, cmdCreateStream: 75 | if v.(string) != respResult { 76 | return ErrFail 77 | } 78 | case cmdPublish: 79 | if v.(string) != onStatus { 80 | return ErrFail 81 | } 82 | } 83 | case float64: 84 | switch self.curcmdName { 85 | case cmdConnect, cmdCreateStream: 86 | id := int(v.(float64)) 87 | if k == 1 { 88 | if id != self.transID { 89 | return ErrFail 90 | } 91 | } else if k == 3 { 92 | self.streamid = uint32(id) 93 | } 94 | case cmdPublish: 95 | if int(v.(float64)) != 0 { 96 | return ErrFail 97 | } 98 | } 99 | case amf.Object: 100 | objmap := v.(amf.Object) 101 | switch self.curcmdName { 102 | case cmdConnect: 103 | code, ok := objmap["code"] 104 | if ok && code.(string) != connectSuccess { 105 | return ErrFail 106 | } 107 | case cmdPublish: 108 | code, ok := objmap["code"] 109 | if ok && code.(string) != publishStart { 110 | return ErrFail 111 | } 112 | } 113 | } 114 | } 115 | return nil 116 | } 117 | } 118 | } 119 | 120 | func (self *ConnClient) writeMsg(args ...interface{}) error { 121 | self.bytesw.Reset() 122 | for _, v := range args { 123 | if _, err := self.encoder.Encode(self.bytesw, v, amf.AMF0); err != nil { 124 | return err 125 | } 126 | } 127 | msg := self.bytesw.Bytes() 128 | c := ChunkStream{ 129 | Format: 0, 130 | CSID: 3, 131 | Timestamp: 0, 132 | TypeID: 20, 133 | StreamID: self.streamid, 134 | Length: uint32(len(msg)), 135 | Data: msg, 136 | } 137 | self.conn.Write(&c) 138 | return self.conn.Flush() 139 | } 140 | 141 | func (self *ConnClient) writeConnectMsg() error { 142 | event := make(amf.Object) 143 | event["app"] = self.app 144 | event["type"] = "nonprivate" 145 | event["flashVer"] = "FMS.3.1" 146 | event["tcUrl"] = self.tcurl 147 | self.curcmdName = cmdConnect 148 | 149 | if err := self.writeMsg(cmdConnect, self.transID, event); err != nil { 150 | return err 151 | } 152 | return self.readRespMsg() 153 | } 154 | 155 | func (self *ConnClient) writeCreateStreamMsg() error { 156 | self.transID++ 157 | self.curcmdName = cmdCreateStream 158 | if err := self.writeMsg(cmdCreateStream, self.transID, nil); err != nil { 159 | return err 160 | } 161 | return self.readRespMsg() 162 | } 163 | 164 | func (self *ConnClient) writePublishMsg() error { 165 | self.transID++ 166 | self.curcmdName = cmdPublish 167 | if err := self.writeMsg(cmdPublish, self.transID, nil, self.title, publishLive); err != nil { 168 | return err 169 | } 170 | return self.readRespMsg() 171 | } 172 | 173 | func (self *ConnClient) writePlayMsg() error { 174 | self.transID++ 175 | self.curcmdName = cmdPlay 176 | if err := self.writeMsg(cmdPlay, 0, nil, self.title); err != nil { 177 | return err 178 | } 179 | return self.readRespMsg() 180 | } 181 | 182 | func (self *ConnClient) Start(url string, method string) error { 183 | u, err := neturl.Parse(url) 184 | if err != nil { 185 | return err 186 | } 187 | self.url = url 188 | path := strings.TrimLeft(u.Path, "/") 189 | ps := strings.SplitN(path, "/", 2) 190 | if len(ps) != 2 { 191 | return fmt.Errorf("u path err: %s", path) 192 | } 193 | self.app = ps[0] 194 | self.title = ps[1] 195 | self.query = u.RawQuery 196 | self.tcurl = "rtmp://" + u.Host + "/" + self.app 197 | port := ":1935" 198 | host := u.Host 199 | localIP := ":0" 200 | var remoteIP string 201 | if strings.Index(host, ":") != -1 { 202 | host, port, err = net.SplitHostPort(host) 203 | if err != nil { 204 | return err 205 | } 206 | port = ":" + port 207 | } 208 | ips, err := net.LookupIP(host) 209 | glog.Infof("ips: %v, host: %v", ips, host) 210 | if err != nil { 211 | glog.Errorln(err) 212 | return err 213 | } 214 | remoteIP = ips[rand.Intn(len(ips))].String() 215 | if strings.Index(remoteIP, ":") == -1 { 216 | remoteIP += port 217 | } 218 | 219 | local, err := net.ResolveTCPAddr("tcp", localIP) 220 | if err != nil { 221 | glog.Errorln(err) 222 | return err 223 | } 224 | glog.Infoln("remoteIP: ", remoteIP) 225 | remote, err := net.ResolveTCPAddr("tcp", remoteIP) 226 | if err != nil { 227 | glog.Errorln(err) 228 | return err 229 | } 230 | conn, err := net.DialTCP("tcp", local, remote) 231 | if err != nil { 232 | glog.Errorln(err) 233 | return err 234 | } 235 | 236 | glog.Infoln("connection:", "local:", conn.LocalAddr(), "remote:", conn.RemoteAddr()) 237 | 238 | self.conn = NewConn(conn, 4*1024) 239 | if err := self.conn.HandshakeClient(); err != nil { 240 | return err 241 | } 242 | if err := self.writeConnectMsg(); err != nil { 243 | return err 244 | } 245 | if err := self.writeCreateStreamMsg(); err != nil { 246 | return err 247 | } 248 | if method == av.PUBLISH { 249 | if err := self.writePublishMsg(); err != nil { 250 | return err 251 | } 252 | } else if method == av.PLAY { 253 | if err := self.writePlayMsg(); err != nil { 254 | return err 255 | } 256 | } 257 | 258 | return nil 259 | } 260 | 261 | func (self *ConnClient) Write(c ChunkStream) error { 262 | if c.TypeID == av.TAG_SCRIPTDATAAMF0 || 263 | c.TypeID == av.TAG_SCRIPTDATAAMF3 { 264 | var err error 265 | if c.Data, err = amf.MetaDataReform(c.Data, amf.ADD); err != nil { 266 | return err 267 | } 268 | c.Length = uint32(len(c.Data)) 269 | } 270 | return self.conn.Write(&c) 271 | } 272 | 273 | func (self *ConnClient) Read(c *ChunkStream) (err error) { 274 | return self.conn.Read(c) 275 | } 276 | 277 | func (self *ConnClient) GetInfo() (app string, name string, url string) { 278 | app = self.app 279 | name = self.title 280 | url = self.url 281 | return 282 | } 283 | 284 | func (self *ConnClient) Close(err error) { 285 | self.conn.Close() 286 | } 287 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/conn_server.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "io" 7 | 8 | "sheepbao.com/media/av" 9 | "sheepbao.com/media/protocol/amf" 10 | 11 | "sheepbao.com/glog" 12 | ) 13 | 14 | var ( 15 | publishLive = "live" 16 | publishRecord = "record" 17 | publishAppend = "append" 18 | ) 19 | 20 | var ( 21 | ErrReq = errors.New("req error") 22 | ) 23 | 24 | var ( 25 | cmdConnect = "connect" 26 | cmdFcpublish = "FCPublish" 27 | cmdReleaseStream = "releaseStream" 28 | cmdCreateStream = "createStream" 29 | cmdPublish = "publish" 30 | cmdFCUnpublish = "FCUnpublish" 31 | cmdDeleteStream = "deleteStream" 32 | cmdPlay = "play" 33 | ) 34 | 35 | type ConnectInfo struct { 36 | App string `amf:"app" json:"app"` 37 | Flashver string `amf:"flashVer" json:"flashVer"` 38 | SwfUrl string `amf:"swfUrl" json:"swfUrl"` 39 | TcUrl string `amf:"tcUrl" json:"tcUrl"` 40 | Fpad bool `amf:"fpad" json:"fpad"` 41 | AudioCodecs int `amf:"audioCodecs" json:"audioCodecs"` 42 | VideoCodecs int `amf:"videoCodecs" json:"videoCodecs"` 43 | VideoFunction int `amf:"videoFunction" json:"videoFunction"` 44 | PageUrl string `amf:"pageUrl" json:"pageUrl"` 45 | ObjectEncoding int `amf:"objectEncoding" json:"objectEncoding"` 46 | } 47 | 48 | type ConnectResp struct { 49 | FMSVer string `amf:"fmsVer"` 50 | Capabilities int `amf:"capabilities"` 51 | } 52 | 53 | type ConnectEvent struct { 54 | Level string `amf:"level"` 55 | Code string `amf:"code"` 56 | Description string `amf:"description"` 57 | ObjectEncoding int `amf:"objectEncoding"` 58 | } 59 | 60 | type PublishInfo struct { 61 | Name string 62 | Type string 63 | } 64 | 65 | type ConnServer struct { 66 | done bool 67 | streamID int 68 | isPublisher bool 69 | conn *Conn 70 | transactionID int 71 | ConnInfo ConnectInfo 72 | PublishInfo PublishInfo 73 | decoder *amf.Decoder 74 | encoder *amf.Encoder 75 | bytesw *bytes.Buffer 76 | } 77 | 78 | func NewConnServer(conn *Conn) *ConnServer { 79 | return &ConnServer{ 80 | conn: conn, 81 | streamID: 1, 82 | bytesw: bytes.NewBuffer(nil), 83 | decoder: &amf.Decoder{}, 84 | encoder: &amf.Encoder{}, 85 | } 86 | } 87 | 88 | func (self *ConnServer) writeMsg(csid, streamID uint32, args ...interface{}) error { 89 | self.bytesw.Reset() 90 | for _, v := range args { 91 | if _, err := self.encoder.Encode(self.bytesw, v, amf.AMF0); err != nil { 92 | return err 93 | } 94 | } 95 | msg := self.bytesw.Bytes() 96 | c := ChunkStream{ 97 | Format: 0, 98 | CSID: csid, 99 | Timestamp: 0, 100 | TypeID: 20, 101 | StreamID: streamID, 102 | Length: uint32(len(msg)), 103 | Data: msg, 104 | } 105 | self.conn.Write(&c) 106 | return self.conn.Flush() 107 | } 108 | 109 | func (self *ConnServer) connect(vs []interface{}) error { 110 | for _, v := range vs { 111 | switch v.(type) { 112 | case string: 113 | case float64: 114 | id := int(v.(float64)) 115 | if id != 1 { 116 | return ErrReq 117 | } 118 | self.transactionID = id 119 | case amf.Object: 120 | obimap := v.(amf.Object) 121 | if app, ok := obimap["app"]; ok { 122 | self.ConnInfo.App = app.(string) 123 | } 124 | if flashVer, ok := obimap["flashVer"]; ok { 125 | self.ConnInfo.Flashver = flashVer.(string) 126 | } 127 | if tcurl, ok := obimap["tcUrl"]; ok { 128 | self.ConnInfo.TcUrl = tcurl.(string) 129 | } 130 | if encoding, ok := obimap["objectEncoding"]; ok { 131 | self.ConnInfo.ObjectEncoding = int(encoding.(float64)) 132 | } 133 | } 134 | } 135 | return nil 136 | } 137 | 138 | func (self *ConnServer) releaseStream(vs []interface{}) error { 139 | return nil 140 | } 141 | 142 | func (self *ConnServer) fcPublish(vs []interface{}) error { 143 | return nil 144 | } 145 | 146 | func (self *ConnServer) connectResp(cur *ChunkStream) error { 147 | c := self.conn.NewWindowAckSize(2500000) 148 | self.conn.Write(&c) 149 | c = self.conn.NewSetPeerBandwidth(2500000) 150 | self.conn.Write(&c) 151 | c = self.conn.NewSetChunkSize(uint32(1024)) 152 | self.conn.Write(&c) 153 | 154 | resp := make(amf.Object) 155 | resp["fmsVer"] = "FMS/3,0,1,123" 156 | resp["capabilities"] = 31 157 | 158 | event := make(amf.Object) 159 | event["level"] = "status" 160 | event["code"] = "NetConnection.Connect.Success" 161 | event["description"] = "Connection succeeded." 162 | event["objectEncoding"] = self.ConnInfo.ObjectEncoding 163 | return self.writeMsg(cur.CSID, cur.StreamID, "_result", self.transactionID, resp, event) 164 | } 165 | 166 | func (self *ConnServer) createStream(vs []interface{}) error { 167 | for _, v := range vs { 168 | switch v.(type) { 169 | case string: 170 | case float64: 171 | self.transactionID = int(v.(float64)) 172 | case amf.Object: 173 | } 174 | } 175 | return nil 176 | } 177 | 178 | func (self *ConnServer) createStreamResp(cur *ChunkStream) error { 179 | return self.writeMsg(cur.CSID, cur.StreamID, "_result", self.transactionID, nil, self.streamID) 180 | } 181 | 182 | func (self *ConnServer) publishOrPlay(vs []interface{}) error { 183 | for k, v := range vs { 184 | switch v.(type) { 185 | case string: 186 | if k == 2 { 187 | self.PublishInfo.Name = v.(string) 188 | } else if k == 3 { 189 | self.PublishInfo.Type = v.(string) 190 | } 191 | case float64: 192 | id := int(v.(float64)) 193 | self.transactionID = id 194 | case amf.Object: 195 | } 196 | } 197 | 198 | return nil 199 | } 200 | 201 | func (self *ConnServer) publishResp(cur *ChunkStream) error { 202 | event := make(amf.Object) 203 | event["level"] = "status" 204 | event["code"] = "NetStream.Publish.Start" 205 | event["description"] = "Start publising." 206 | return self.writeMsg(cur.CSID, cur.StreamID, "onStatus", 0, nil, event) 207 | } 208 | 209 | func (self *ConnServer) playResp(cur *ChunkStream) error { 210 | self.conn.SetRecorded() 211 | self.conn.SetBegin() 212 | 213 | event := make(amf.Object) 214 | event["level"] = "status" 215 | event["code"] = "NetStream.Play.Reset" 216 | event["description"] = "Playing and resetting stream." 217 | if err := self.writeMsg(cur.CSID, cur.StreamID, "onStatus", 0, nil, event); err != nil { 218 | return err 219 | } 220 | 221 | event["level"] = "status" 222 | event["code"] = "NetStream.Play.Start" 223 | event["description"] = "Started playing stream." 224 | if err := self.writeMsg(cur.CSID, cur.StreamID, "onStatus", 0, nil, event); err != nil { 225 | return err 226 | } 227 | 228 | event["level"] = "status" 229 | event["code"] = "NetStream.Data.Start" 230 | event["description"] = "Started playing stream." 231 | if err := self.writeMsg(cur.CSID, cur.StreamID, "onStatus", 0, nil, event); err != nil { 232 | return err 233 | } 234 | 235 | event["level"] = "status" 236 | event["code"] = "NetStream.Play.PublishNotify" 237 | event["description"] = "Started playing notify." 238 | if err := self.writeMsg(cur.CSID, cur.StreamID, "onStatus", 0, nil, event); err != nil { 239 | return err 240 | } 241 | return self.conn.Flush() 242 | } 243 | 244 | func (self *ConnServer) handleCmdMsg(c *ChunkStream) error { 245 | amfType := amf.AMF0 246 | if c.TypeID == 17 { 247 | c.Data = c.Data[1:] 248 | } 249 | r := bytes.NewReader(c.Data) 250 | vs, err := self.decoder.DecodeBatch(r, amf.Version(amfType)) 251 | if err != nil && err != io.EOF { 252 | return err 253 | } 254 | // glog.Infof("rtmp req: %#v", vs) 255 | switch vs[0].(type) { 256 | case string: 257 | switch vs[0].(string) { 258 | case cmdConnect: 259 | if err = self.connect(vs[1:]); err != nil { 260 | return err 261 | } 262 | if err = self.connectResp(c); err != nil { 263 | return err 264 | } 265 | case cmdCreateStream: 266 | if err = self.createStream(vs[1:]); err != nil { 267 | return err 268 | } 269 | if err = self.createStreamResp(c); err != nil { 270 | return err 271 | } 272 | case cmdPublish: 273 | if err = self.publishOrPlay(vs[1:]); err != nil { 274 | return err 275 | } 276 | if err = self.publishResp(c); err != nil { 277 | return err 278 | } 279 | self.done = true 280 | self.isPublisher = true 281 | glog.Infoln("handle publish req done") 282 | case cmdPlay: 283 | if err = self.publishOrPlay(vs[1:]); err != nil { 284 | return err 285 | } 286 | if err = self.playResp(c); err != nil { 287 | return err 288 | } 289 | self.done = true 290 | self.isPublisher = false 291 | glog.Infoln("handle play req done") 292 | case cmdFcpublish: 293 | self.fcPublish(vs) 294 | case cmdReleaseStream: 295 | self.releaseStream(vs) 296 | case cmdFCUnpublish: 297 | case cmdDeleteStream: 298 | default: 299 | glog.Infoln("no support command=", vs[0].(string)) 300 | } 301 | } 302 | 303 | return nil 304 | } 305 | 306 | func (self *ConnServer) ReadMsg() error { 307 | var c ChunkStream 308 | for { 309 | if err := self.conn.Read(&c); err != nil { 310 | return err 311 | } 312 | switch c.TypeID { 313 | case 20, 17: 314 | if err := self.handleCmdMsg(&c); err != nil { 315 | return err 316 | } 317 | } 318 | if self.done { 319 | break 320 | } 321 | } 322 | return nil 323 | } 324 | 325 | func (self *ConnServer) IsPublisher() bool { 326 | return self.isPublisher 327 | } 328 | 329 | func (self *ConnServer) Write(c ChunkStream) error { 330 | if c.TypeID == av.TAG_SCRIPTDATAAMF0 || 331 | c.TypeID == av.TAG_SCRIPTDATAAMF3 { 332 | var err error 333 | if c.Data, err = amf.MetaDataReform(c.Data, amf.DEL); err != nil { 334 | return err 335 | } 336 | c.Length = uint32(len(c.Data)) 337 | } 338 | return self.conn.Write(&c) 339 | } 340 | 341 | func (self *ConnServer) Read(c *ChunkStream) (err error) { 342 | return self.conn.Read(c) 343 | } 344 | 345 | func (self *ConnServer) GetInfo() (app string, name string, url string) { 346 | app = self.ConnInfo.App 347 | name = self.PublishInfo.Name 348 | url = self.ConnInfo.TcUrl + "/" + self.PublishInfo.Name 349 | return 350 | } 351 | 352 | func (self *ConnServer) Close(err error) { 353 | self.conn.Close() 354 | } 355 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/conn_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | 8 | "sheepbao.com/media/utils/pool" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestConnReadNormal(t *testing.T) { 14 | at := assert.New(t) 15 | data := []byte{ 16 | 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x01, 0x00, 0x00, 0x00, 17 | } 18 | data1 := make([]byte, 128) 19 | data2 := make([]byte, 51) 20 | data = append(data, data1...) 21 | data = append(data, 0xc6) 22 | data = append(data, data1...) 23 | data = append(data, 0xc6) 24 | data = append(data, data2...) 25 | conn := &Conn{ 26 | pool: pool.NewPool(), 27 | rw: NewReadWriter(bytes.NewBuffer(data), 1024), 28 | remoteChunkSize: 128, 29 | windowAckSize: 2500000, 30 | remoteWindowAckSize: 2500000, 31 | chunks: make(map[uint32]ChunkStream), 32 | } 33 | var c ChunkStream 34 | err := conn.Read(&c) 35 | at.Equal(err, nil) 36 | at.Equal(int(c.CSID), 6) 37 | at.Equal(int(c.Length), 307) 38 | at.Equal(int(c.TypeID), 9) 39 | } 40 | 41 | //交叉读音视频数据 42 | func TestConnCrossReading(t *testing.T) { 43 | at := assert.New(t) 44 | data1 := make([]byte, 128) 45 | data2 := make([]byte, 51) 46 | 47 | videoData := []byte{ 48 | 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x01, 0x00, 0x00, 0x00, 49 | } 50 | audioData := []byte{ 51 | 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x08, 0x01, 0x00, 0x00, 0x00, 52 | } 53 | //video 1 54 | videoData = append(videoData, data1...) 55 | //video 2 56 | videoData = append(videoData, 0xc6) 57 | videoData = append(videoData, data1...) 58 | //audio 1 59 | videoData = append(videoData, audioData...) 60 | videoData = append(videoData, data1...) 61 | //audio 2 62 | videoData = append(videoData, 0xc4) 63 | videoData = append(videoData, data1...) 64 | //video 3 65 | videoData = append(videoData, 0xc6) 66 | videoData = append(videoData, data2...) 67 | //audio 3 68 | videoData = append(videoData, 0xc4) 69 | videoData = append(videoData, data2...) 70 | 71 | conn := &Conn{ 72 | pool: pool.NewPool(), 73 | rw: NewReadWriter(bytes.NewBuffer(videoData), 1024), 74 | remoteChunkSize: 128, 75 | windowAckSize: 2500000, 76 | remoteWindowAckSize: 2500000, 77 | chunks: make(map[uint32]ChunkStream), 78 | } 79 | var c ChunkStream 80 | //video 1 81 | err := conn.Read(&c) 82 | at.Equal(err, nil) 83 | at.Equal(int(c.TypeID), 9) 84 | at.Equal(len(c.Data), 307) 85 | 86 | //audio2 87 | err = conn.Read(&c) 88 | at.Equal(err, nil) 89 | at.Equal(int(c.TypeID), 8) 90 | at.Equal(len(c.Data), 307) 91 | 92 | err = conn.Read(&c) 93 | at.Equal(err, io.EOF) 94 | } 95 | 96 | func TestSetChunksizeForWrite(t *testing.T) { 97 | at := assert.New(t) 98 | chunk := ChunkStream{ 99 | Format: 0, 100 | CSID: 2, 101 | Timestamp: 0, 102 | Length: 4, 103 | StreamID: 1, 104 | TypeID: idSetChunkSize, 105 | Data: []byte{0x00, 0x00, 0x00, 0x96}, 106 | } 107 | buf := bytes.NewBuffer(nil) 108 | rw := NewReadWriter(buf, 1024) 109 | conn := &Conn{ 110 | pool: pool.NewPool(), 111 | rw: rw, 112 | chunkSize: 128, 113 | remoteChunkSize: 128, 114 | windowAckSize: 2500000, 115 | remoteWindowAckSize: 2500000, 116 | chunks: make(map[uint32]ChunkStream), 117 | } 118 | 119 | audio := ChunkStream{ 120 | Format: 0, 121 | CSID: 4, 122 | Timestamp: 40, 123 | Length: 133, 124 | StreamID: 1, 125 | TypeID: 0x8, 126 | } 127 | audio.Data = make([]byte, 133) 128 | audio.Data = audio.Data[:133] 129 | audio.Data[0] = 0xff 130 | audio.Data[128] = 0xff 131 | err := conn.Write(&audio) 132 | at.Equal(err, nil) 133 | conn.Flush() 134 | at.Equal(len(buf.Bytes()), 146) 135 | 136 | buf.Reset() 137 | err = conn.Write(&chunk) 138 | at.Equal(err, nil) 139 | conn.Flush() 140 | 141 | buf.Reset() 142 | err = conn.Write(&audio) 143 | at.Equal(err, nil) 144 | conn.Flush() 145 | at.Equal(len(buf.Bytes()), 145) 146 | } 147 | 148 | func TestSetChunksize(t *testing.T) { 149 | at := assert.New(t) 150 | data := []byte{ 151 | 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x09, 0x01, 0x00, 0x00, 0x00, 152 | } 153 | data1 := make([]byte, 128) 154 | data2 := make([]byte, 51) 155 | data = append(data, data1...) 156 | data = append(data, 0xc6) 157 | data = append(data, data1...) 158 | data = append(data, 0xc6) 159 | data = append(data, data2...) 160 | rw := NewReadWriter(bytes.NewBuffer(data), 1024) 161 | conn := &Conn{ 162 | pool: pool.NewPool(), 163 | rw: rw, 164 | chunkSize: 128, 165 | remoteChunkSize: 128, 166 | windowAckSize: 2500000, 167 | remoteWindowAckSize: 2500000, 168 | chunks: make(map[uint32]ChunkStream), 169 | } 170 | 171 | var c ChunkStream 172 | err := conn.Read(&c) 173 | at.Equal(err, nil) 174 | at.Equal(int(c.TypeID), 9) 175 | at.Equal(int(c.CSID), 6) 176 | at.Equal(int(c.StreamID), 1) 177 | at.Equal(len(c.Data), 307) 178 | 179 | //设置chunksize 180 | chunkBuf := []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 181 | 0x00, 0x00, 0x00, 0x96} 182 | conn.rw = NewReadWriter(bytes.NewBuffer(chunkBuf), 1024) 183 | err = conn.Read(&c) 184 | at.Equal(err, nil) 185 | 186 | data = data[:12] 187 | data[7] = 0x8 188 | data1 = make([]byte, 150) 189 | data2 = make([]byte, 7) 190 | data = append(data, data1...) 191 | data = append(data, 0xc6) 192 | data = append(data, data1...) 193 | data = append(data, 0xc6) 194 | data = append(data, data2...) 195 | 196 | conn.rw = NewReadWriter(bytes.NewBuffer(data), 1024) 197 | err = conn.Read(&c) 198 | at.Equal(err, nil) 199 | at.Equal(len(c.Data), 307) 200 | 201 | err = conn.Read(&c) 202 | at.Equal(err, io.EOF) 203 | } 204 | 205 | func TestConnWrite(t *testing.T) { 206 | at := assert.New(t) 207 | wr := bytes.NewBuffer(nil) 208 | readWriter := NewReadWriter(wr, 128) 209 | conn := &Conn{ 210 | pool: pool.NewPool(), 211 | rw: readWriter, 212 | chunkSize: 128, 213 | remoteChunkSize: 128, 214 | windowAckSize: 2500000, 215 | remoteWindowAckSize: 2500000, 216 | chunks: make(map[uint32]ChunkStream), 217 | } 218 | 219 | c1 := ChunkStream{ 220 | Length: 3, 221 | TypeID: 8, 222 | CSID: 3, 223 | Timestamp: 40, 224 | Data: []byte{0x01, 0x02, 0x03}, 225 | } 226 | err := conn.Write(&c1) 227 | at.Equal(err, nil) 228 | conn.Flush() 229 | at.Equal(wr.Bytes(), []byte{0x4, 0x0, 0x0, 0x28, 0x0, 0x0, 0x3, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x3}) 230 | 231 | //for type 1 232 | wr.Reset() 233 | c1 = ChunkStream{ 234 | Length: 4, 235 | TypeID: 8, 236 | CSID: 3, 237 | Timestamp: 80, 238 | Data: []byte{0x01, 0x02, 0x03, 0x4}, 239 | } 240 | err = conn.Write(&c1) 241 | at.Equal(err, nil) 242 | conn.Flush() 243 | at.Equal(wr.Bytes(), []byte{0x4, 0x0, 0x0, 0x50, 0x0, 0x0, 0x4, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4}) 244 | 245 | //for type 2 246 | wr.Reset() 247 | c1.Timestamp = 160 248 | err = conn.Write(&c1) 249 | at.Equal(err, nil) 250 | conn.Flush() 251 | at.Equal(wr.Bytes(), []byte{0x4, 0x0, 0x0, 0xa0, 0x0, 0x0, 0x4, 0x8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4}) 252 | } 253 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/handshake.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "crypto/hmac" 6 | "crypto/rand" 7 | "crypto/sha256" 8 | "fmt" 9 | "io" 10 | 11 | "time" 12 | 13 | "sheepbao.com/media/utils/pio" 14 | ) 15 | 16 | var ( 17 | timeout = 3 * time.Second 18 | ) 19 | 20 | var ( 21 | hsClientFullKey = []byte{ 22 | 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', 23 | 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', 24 | '0', '0', '1', 25 | 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 26 | 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 27 | 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE, 28 | } 29 | hsServerFullKey = []byte{ 30 | 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', 31 | 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ', 32 | 'S', 'e', 'r', 'v', 'e', 'r', ' ', 33 | '0', '0', '1', 34 | 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 35 | 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 36 | 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE, 37 | } 38 | hsClientPartialKey = hsClientFullKey[:30] 39 | hsServerPartialKey = hsServerFullKey[:36] 40 | ) 41 | 42 | func hsMakeDigest(key []byte, src []byte, gap int) (dst []byte) { 43 | h := hmac.New(sha256.New, key) 44 | if gap <= 0 { 45 | h.Write(src) 46 | } else { 47 | h.Write(src[:gap]) 48 | h.Write(src[gap+32:]) 49 | } 50 | return h.Sum(nil) 51 | } 52 | 53 | func hsCalcDigestPos(p []byte, base int) (pos int) { 54 | for i := 0; i < 4; i++ { 55 | pos += int(p[base+i]) 56 | } 57 | pos = (pos % 728) + base + 4 58 | return 59 | } 60 | 61 | func hsFindDigest(p []byte, key []byte, base int) int { 62 | gap := hsCalcDigestPos(p, base) 63 | digest := hsMakeDigest(key, p, gap) 64 | if bytes.Compare(p[gap:gap+32], digest) != 0 { 65 | return -1 66 | } 67 | return gap 68 | } 69 | 70 | func hsParse1(p []byte, peerkey []byte, key []byte) (ok bool, digest []byte) { 71 | var pos int 72 | if pos = hsFindDigest(p, peerkey, 772); pos == -1 { 73 | if pos = hsFindDigest(p, peerkey, 8); pos == -1 { 74 | return 75 | } 76 | } 77 | ok = true 78 | digest = hsMakeDigest(key, p[pos:pos+32], -1) 79 | return 80 | } 81 | 82 | func hsCreate01(p []byte, time uint32, ver uint32, key []byte) { 83 | p[0] = 3 84 | p1 := p[1:] 85 | rand.Read(p1[8:]) 86 | pio.PutU32BE(p1[0:4], time) 87 | pio.PutU32BE(p1[4:8], ver) 88 | gap := hsCalcDigestPos(p1, 8) 89 | digest := hsMakeDigest(key, p1, gap) 90 | copy(p1[gap:], digest) 91 | } 92 | 93 | func hsCreate2(p []byte, key []byte) { 94 | rand.Read(p) 95 | gap := len(p) - 32 96 | digest := hsMakeDigest(key, p, gap) 97 | copy(p[gap:], digest) 98 | } 99 | 100 | func (self *Conn) HandshakeClient() (err error) { 101 | var random [(1 + 1536*2) * 2]byte 102 | 103 | C0C1C2 := random[:1536*2+1] 104 | C0 := C0C1C2[:1] 105 | C0C1 := C0C1C2[:1536+1] 106 | C2 := C0C1C2[1536+1:] 107 | 108 | S0S1S2 := random[1536*2+1:] 109 | 110 | C0[0] = 3 111 | // > C0C1 112 | self.Conn.SetDeadline(time.Now().Add(timeout)) 113 | if _, err = self.rw.Write(C0C1); err != nil { 114 | return 115 | } 116 | self.Conn.SetDeadline(time.Now().Add(timeout)) 117 | if err = self.rw.Flush(); err != nil { 118 | return 119 | } 120 | 121 | // < S0S1S2 122 | self.Conn.SetDeadline(time.Now().Add(timeout)) 123 | if _, err = io.ReadFull(self.rw, S0S1S2); err != nil { 124 | return 125 | } 126 | 127 | S1 := S0S1S2[1 : 1536+1] 128 | if ver := pio.U32BE(S1[4:8]); ver != 0 { 129 | C2 = S1 130 | } else { 131 | C2 = S1 132 | } 133 | 134 | // > C2 135 | self.Conn.SetDeadline(time.Now().Add(timeout)) 136 | if _, err = self.rw.Write(C2); err != nil { 137 | return 138 | } 139 | self.Conn.SetDeadline(time.Time{}) 140 | return 141 | } 142 | 143 | func (self *Conn) HandshakeServer() (err error) { 144 | var random [(1 + 1536*2) * 2]byte 145 | 146 | C0C1C2 := random[:1536*2+1] 147 | C0 := C0C1C2[:1] 148 | C1 := C0C1C2[1 : 1536+1] 149 | C0C1 := C0C1C2[:1536+1] 150 | C2 := C0C1C2[1536+1:] 151 | 152 | S0S1S2 := random[1536*2+1:] 153 | S0 := S0S1S2[:1] 154 | S1 := S0S1S2[1 : 1536+1] 155 | S0S1 := S0S1S2[:1536+1] 156 | S2 := S0S1S2[1536+1:] 157 | 158 | // < C0C1 159 | self.Conn.SetDeadline(time.Now().Add(timeout)) 160 | if _, err = io.ReadFull(self.rw, C0C1); err != nil { 161 | return 162 | } 163 | self.Conn.SetDeadline(time.Now().Add(timeout)) 164 | if C0[0] != 3 { 165 | err = fmt.Errorf("rtmp: handshake version=%d invalid", C0[0]) 166 | return 167 | } 168 | 169 | S0[0] = 3 170 | 171 | clitime := pio.U32BE(C1[0:4]) 172 | srvtime := clitime 173 | srvver := uint32(0x0d0e0a0d) 174 | cliver := pio.U32BE(C1[4:8]) 175 | 176 | if cliver != 0 { 177 | var ok bool 178 | var digest []byte 179 | if ok, digest = hsParse1(C1, hsClientPartialKey, hsServerFullKey); !ok { 180 | err = fmt.Errorf("rtmp: handshake server: C1 invalid") 181 | return 182 | } 183 | hsCreate01(S0S1, srvtime, srvver, hsServerPartialKey) 184 | hsCreate2(S2, digest) 185 | } else { 186 | copy(S1, C2) 187 | copy(S2, C1) 188 | } 189 | 190 | // > S0S1S2 191 | self.Conn.SetDeadline(time.Now().Add(timeout)) 192 | if _, err = self.rw.Write(S0S1S2); err != nil { 193 | return 194 | } 195 | self.Conn.SetDeadline(time.Now().Add(timeout)) 196 | if err = self.rw.Flush(); err != nil { 197 | return 198 | } 199 | 200 | // < C2 201 | self.Conn.SetDeadline(time.Now().Add(timeout)) 202 | if _, err = io.ReadFull(self.rw, C2); err != nil { 203 | return 204 | } 205 | self.Conn.SetDeadline(time.Time{}) 206 | return 207 | } 208 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/read_writer.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | ) 7 | 8 | type ReadWriter struct { 9 | *bufio.ReadWriter 10 | readError error 11 | writeError error 12 | } 13 | 14 | func NewReadWriter(rw io.ReadWriter, bufSize int) *ReadWriter { 15 | return &ReadWriter{ 16 | ReadWriter: bufio.NewReadWriter(bufio.NewReaderSize(rw, bufSize), bufio.NewWriterSize(rw, bufSize)), 17 | } 18 | } 19 | 20 | func (rw *ReadWriter) Read(p []byte) (int, error) { 21 | if rw.readError != nil { 22 | return 0, rw.readError 23 | } 24 | n, err := io.ReadAtLeast(rw.ReadWriter, p, len(p)) 25 | rw.readError = err 26 | return n, err 27 | } 28 | 29 | func (rw *ReadWriter) ReadError() error { 30 | return rw.readError 31 | } 32 | 33 | func (rw *ReadWriter) ReadUintBE(n int) (uint32, error) { 34 | if rw.readError != nil { 35 | return 0, rw.readError 36 | } 37 | ret := uint32(0) 38 | for i := 0; i < n; i++ { 39 | b, err := rw.ReadByte() 40 | if err != nil { 41 | rw.readError = err 42 | return 0, err 43 | } 44 | ret = ret<<8 + uint32(b) 45 | } 46 | return ret, nil 47 | } 48 | 49 | func (rw *ReadWriter) ReadUintLE(n int) (uint32, error) { 50 | if rw.readError != nil { 51 | return 0, rw.readError 52 | } 53 | ret := uint32(0) 54 | for i := 0; i < n; i++ { 55 | b, err := rw.ReadByte() 56 | if err != nil { 57 | rw.readError = err 58 | return 0, err 59 | } 60 | ret += uint32(b) << uint32(i*8) 61 | } 62 | return ret, nil 63 | } 64 | 65 | func (rw *ReadWriter) Flush() error { 66 | if rw.writeError != nil { 67 | return rw.writeError 68 | } 69 | 70 | if rw.ReadWriter.Writer.Buffered() == 0 { 71 | return nil 72 | } 73 | return rw.ReadWriter.Flush() 74 | } 75 | 76 | func (rw *ReadWriter) Write(p []byte) (int, error) { 77 | if rw.writeError != nil { 78 | return 0, rw.writeError 79 | } 80 | return rw.ReadWriter.Write(p) 81 | } 82 | 83 | func (rw *ReadWriter) WriteError() error { 84 | return rw.writeError 85 | } 86 | 87 | func (rw *ReadWriter) WriteUintBE(v uint32, n int) error { 88 | if rw.writeError != nil { 89 | return rw.writeError 90 | } 91 | for i := 0; i < n; i++ { 92 | b := byte(v>>uint32((n-i-1)<<3)) & 0xff 93 | if err := rw.WriteByte(b); err != nil { 94 | rw.writeError = err 95 | return err 96 | } 97 | } 98 | return nil 99 | } 100 | 101 | func (rw *ReadWriter) WriteUintLE(v uint32, n int) error { 102 | if rw.writeError != nil { 103 | return rw.writeError 104 | } 105 | for i := 0; i < n; i++ { 106 | b := byte(v) & 0xff 107 | if err := rw.WriteByte(b); err != nil { 108 | rw.writeError = err 109 | return err 110 | } 111 | v = v >> 8 112 | } 113 | return nil 114 | } 115 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/core/read_writer_test.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestReader(t *testing.T) { 12 | at := assert.New(t) 13 | buf := bytes.NewBufferString("abc") 14 | r := NewReadWriter(buf, 1024) 15 | b := make([]byte, 3) 16 | n, err := r.Read(b) 17 | at.Equal(err, nil) 18 | at.Equal(r.ReadError(), nil) 19 | at.Equal(n, 3) 20 | n, err = r.Read(b) 21 | at.Equal(err, io.EOF) 22 | at.Equal(r.ReadError(), io.EOF) 23 | buf.WriteString("123") 24 | n, err = r.Read(b) 25 | at.Equal(err, io.EOF) 26 | at.Equal(r.ReadError(), io.EOF) 27 | at.Equal(n, 0) 28 | } 29 | 30 | func TestReaderUintBE(t *testing.T) { 31 | at := assert.New(t) 32 | type Test struct { 33 | i int 34 | value uint32 35 | bytes []byte 36 | } 37 | tests := []Test{ 38 | {1, 0x01, []byte{0x01}}, 39 | {2, 0x0102, []byte{0x01, 0x02}}, 40 | {3, 0x010203, []byte{0x01, 0x02, 0x03}}, 41 | {4, 0x01020304, []byte{0x01, 0x02, 0x03, 0x04}}, 42 | } 43 | for _, test := range tests { 44 | buf := bytes.NewBuffer(test.bytes) 45 | r := NewReadWriter(buf, 1024) 46 | n, err := r.ReadUintBE(test.i) 47 | at.Equal(err, nil, "test %d", test.i) 48 | at.Equal(n, test.value, "test %d", test.i) 49 | } 50 | } 51 | 52 | func TestReaderUintLE(t *testing.T) { 53 | at := assert.New(t) 54 | type Test struct { 55 | i int 56 | value uint32 57 | bytes []byte 58 | } 59 | tests := []Test{ 60 | {1, 0x01, []byte{0x01}}, 61 | {2, 0x0102, []byte{0x02, 0x01}}, 62 | {3, 0x010203, []byte{0x03, 0x02, 0x01}}, 63 | {4, 0x01020304, []byte{0x04, 0x03, 0x02, 0x01}}, 64 | } 65 | for _, test := range tests { 66 | buf := bytes.NewBuffer(test.bytes) 67 | r := NewReadWriter(buf, 1024) 68 | n, err := r.ReadUintLE(test.i) 69 | at.Equal(err, nil, "test %d", test.i) 70 | at.Equal(n, test.value, "test %d", test.i) 71 | } 72 | } 73 | 74 | func TestWriter(t *testing.T) { 75 | at := assert.New(t) 76 | buf := bytes.NewBuffer(nil) 77 | w := NewReadWriter(buf, 1024) 78 | b := []byte{1, 2, 3} 79 | n, err := w.Write(b) 80 | at.Equal(err, nil) 81 | at.Equal(w.WriteError(), nil) 82 | at.Equal(n, 3) 83 | w.writeError = io.EOF 84 | n, err = w.Write(b) 85 | at.Equal(err, io.EOF) 86 | at.Equal(w.WriteError(), io.EOF) 87 | at.Equal(n, 0) 88 | } 89 | 90 | func TestWriteUintBE(t *testing.T) { 91 | at := assert.New(t) 92 | type Test struct { 93 | i int 94 | value uint32 95 | bytes []byte 96 | } 97 | tests := []Test{ 98 | {1, 0x01, []byte{0x01}}, 99 | {2, 0x0102, []byte{0x01, 0x02}}, 100 | {3, 0x010203, []byte{0x01, 0x02, 0x03}}, 101 | {4, 0x01020304, []byte{0x01, 0x02, 0x03, 0x04}}, 102 | } 103 | for _, test := range tests { 104 | buf := bytes.NewBuffer(nil) 105 | r := NewReadWriter(buf, 1024) 106 | err := r.WriteUintBE(test.value, test.i) 107 | at.Equal(err, nil, "test %d", test.i) 108 | err = r.Flush() 109 | at.Equal(err, nil, "test %d", test.i) 110 | at.Equal(buf.Bytes(), test.bytes, "test %d", test.i) 111 | } 112 | } 113 | 114 | func TestWriteUintLE(t *testing.T) { 115 | at := assert.New(t) 116 | type Test struct { 117 | i int 118 | value uint32 119 | bytes []byte 120 | } 121 | tests := []Test{ 122 | {1, 0x01, []byte{0x01}}, 123 | {2, 0x0102, []byte{0x02, 0x01}}, 124 | {3, 0x010203, []byte{0x03, 0x02, 0x01}}, 125 | {4, 0x01020304, []byte{0x04, 0x03, 0x02, 0x01}}, 126 | } 127 | for _, test := range tests { 128 | buf := bytes.NewBuffer(nil) 129 | r := NewReadWriter(buf, 1024) 130 | err := r.WriteUintLE(test.value, test.i) 131 | at.Equal(err, nil, "test %d", test.i) 132 | err = r.Flush() 133 | at.Equal(err, nil, "test %d", test.i) 134 | at.Equal(buf.Bytes(), test.bytes, "test %d", test.i) 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/rtmp.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "net" 5 | "time" 6 | 7 | "sheepbao.com/media/av" 8 | "sheepbao.com/media/container/flv" 9 | "sheepbao.com/media/protocol/rtmp/core" 10 | "sheepbao.com/media/utils/uid" 11 | 12 | "net/url" 13 | 14 | "strings" 15 | 16 | "errors" 17 | 18 | "sheepbao.com/glog" 19 | ) 20 | 21 | const ( 22 | maxQueueNum = 1024 23 | ) 24 | 25 | type Client struct { 26 | handler av.Handler 27 | getter av.GetWriter 28 | } 29 | 30 | func NewRtmpClient(h av.Handler, getter av.GetWriter) *Client { 31 | return &Client{ 32 | handler: h, 33 | getter: getter, 34 | } 35 | } 36 | 37 | func (self *Client) Dial(url string, method string) error { 38 | connClient := core.NewConnClient() 39 | if err := connClient.Start(url, method); err != nil { 40 | return err 41 | } 42 | if method == av.PUBLISH { 43 | writer := NewVirWriter(connClient) 44 | self.handler.HandleWriter(writer) 45 | } else if method == av.PLAY { 46 | reader := NewVirReader(connClient) 47 | self.handler.HandleReader(reader) 48 | if self.getter != nil { 49 | writer := self.getter.GetWriter(reader.Info()) 50 | self.handler.HandleWriter(writer) 51 | } 52 | } 53 | return nil 54 | } 55 | 56 | func (self *Client) GetHandle() av.Handler { 57 | return self.handler 58 | } 59 | 60 | type Server struct { 61 | handler av.Handler 62 | getter av.GetWriter 63 | } 64 | 65 | func NewRtmpServer(h av.Handler, getter av.GetWriter) *Server { 66 | return &Server{ 67 | handler: h, 68 | getter: getter, 69 | } 70 | } 71 | 72 | func (self *Server) Serve(listener net.Listener) (err error) { 73 | defer func() { 74 | if r := recover(); r != nil { 75 | glog.Errorln("rtmp serve panic: ", r) 76 | } 77 | }() 78 | 79 | for { 80 | var netconn net.Conn 81 | netconn, err = listener.Accept() 82 | if err != nil { 83 | return 84 | } 85 | conn := core.NewConn(netconn, 4*1024) 86 | glog.Infoln("new client, connect remote:", conn.RemoteAddr().String(), 87 | "local:", conn.LocalAddr().String()) 88 | go self.handleConn(conn) 89 | } 90 | } 91 | 92 | func (self *Server) handleConn(conn *core.Conn) error { 93 | conn.SetDeadline(time.Now().Add(time.Second * 30)) 94 | if err := conn.HandshakeServer(); err != nil { 95 | conn.Close() 96 | glog.Errorln("handleConn HandshakeServer err:", err) 97 | return err 98 | } 99 | conn.SetDeadline(time.Time{}) 100 | connServer := core.NewConnServer(conn) 101 | 102 | if err := connServer.ReadMsg(); err != nil { 103 | conn.Close() 104 | glog.Errorln("handleConn read msg err:", err) 105 | return err 106 | } 107 | if connServer.IsPublisher() { 108 | reader := NewVirReader(connServer) 109 | self.handler.HandleReader(reader) 110 | glog.Infof("new publisher: %+v", reader.Info()) 111 | 112 | if self.getter != nil { 113 | writer := self.getter.GetWriter(reader.Info()) 114 | self.handler.HandleWriter(writer) 115 | } 116 | } else { 117 | writer := NewVirWriter(connServer) 118 | glog.Infof("new player: %+v", writer.Info()) 119 | self.handler.HandleWriter(writer) 120 | } 121 | 122 | return nil 123 | } 124 | 125 | type GetInFo interface { 126 | GetInfo() (string, string, string) 127 | } 128 | 129 | type StreamReadWriteCloser interface { 130 | GetInFo 131 | Close(error) 132 | Write(core.ChunkStream) error 133 | Read(c *core.ChunkStream) error 134 | } 135 | 136 | type VirWriter struct { 137 | Uid string 138 | closed bool 139 | av.RWBaser 140 | conn StreamReadWriteCloser 141 | packetQueue chan av.Packet 142 | } 143 | 144 | func NewVirWriter(conn StreamReadWriteCloser) *VirWriter { 145 | ret := &VirWriter{ 146 | Uid: uid.NEWID(), 147 | conn: conn, 148 | RWBaser: av.NewRWBaser(time.Second * 10), 149 | packetQueue: make(chan av.Packet, maxQueueNum), 150 | } 151 | go ret.Check() 152 | go func() { 153 | err := ret.SendPacket() 154 | if err != nil { 155 | glog.Errorln(err) 156 | } 157 | }() 158 | return ret 159 | } 160 | 161 | func (self *VirWriter) Check() { 162 | var c core.ChunkStream 163 | for { 164 | if err := self.conn.Read(&c); err != nil { 165 | self.Close(err) 166 | return 167 | } 168 | } 169 | } 170 | 171 | func (self *VirWriter) DropPacket(pktQue chan av.Packet, info av.Info) { 172 | glog.Errorf("[%v] packet queue max!!!", info) 173 | for i := 0; i < maxQueueNum-84; i++ { 174 | tmpPkt, ok := <-pktQue 175 | // try to don't drop audio 176 | if ok && tmpPkt.IsAudio { 177 | if len(pktQue) > maxQueueNum-2 { 178 | glog.Infoln("drop audio pkt") 179 | <-pktQue 180 | } else { 181 | pktQue <- tmpPkt 182 | } 183 | 184 | } 185 | 186 | if ok && tmpPkt.IsVideo { 187 | videoPkt, ok := tmpPkt.Header.(av.VideoPacketHeader) 188 | // dont't drop sps config and dont't drop key frame 189 | if ok && (videoPkt.IsSeq() || videoPkt.IsKeyFrame()) { 190 | pktQue <- tmpPkt 191 | } 192 | if len(pktQue) > maxQueueNum-10 { 193 | glog.Infoln("drop video pkt") 194 | <-pktQue 195 | } 196 | } 197 | 198 | } 199 | glog.Infoln("packet queue len: ", len(pktQue)) 200 | } 201 | 202 | // 203 | func (self *VirWriter) Write(p av.Packet) error { 204 | if !self.closed { 205 | if len(self.packetQueue) >= maxQueueNum-24 { 206 | self.DropPacket(self.packetQueue, self.Info()) 207 | } else { 208 | self.packetQueue <- p 209 | } 210 | return nil 211 | } else { 212 | return errors.New("closed") 213 | } 214 | } 215 | 216 | func (self *VirWriter) SendPacket() error { 217 | var cs core.ChunkStream 218 | for { 219 | p, ok := <-self.packetQueue 220 | if ok { 221 | cs.Data = p.Data 222 | cs.Length = uint32(len(p.Data)) 223 | cs.StreamID = 1 224 | cs.Timestamp = p.TimeStamp 225 | cs.Timestamp += self.BaseTimeStamp() 226 | 227 | if p.IsVideo { 228 | cs.TypeID = av.TAG_VIDEO 229 | } else { 230 | if p.IsMetadata { 231 | cs.TypeID = av.TAG_SCRIPTDATAAMF0 232 | } else { 233 | cs.TypeID = av.TAG_AUDIO 234 | } 235 | } 236 | 237 | self.SetPreTime() 238 | self.RecTimeStamp(cs.Timestamp, cs.TypeID) 239 | err := self.conn.Write(cs) 240 | if err != nil { 241 | self.closed = true 242 | return err 243 | } 244 | } else { 245 | return errors.New("closed") 246 | } 247 | 248 | } 249 | return nil 250 | } 251 | 252 | func (self *VirWriter) Info() (ret av.Info) { 253 | ret.UID = self.Uid 254 | _, _, URL := self.conn.GetInfo() 255 | ret.URL = URL 256 | _url, err := url.Parse(URL) 257 | if err != nil { 258 | glog.Errorln(err) 259 | } 260 | ret.Key = strings.TrimLeft(_url.Path, "/") 261 | ret.Inter = true 262 | return 263 | } 264 | 265 | func (self *VirWriter) Close(err error) { 266 | glog.Infoln("player ", self.Info(), "closed: "+err.Error()) 267 | if !self.closed { 268 | close(self.packetQueue) 269 | } 270 | self.closed = true 271 | self.conn.Close(err) 272 | } 273 | 274 | type VirReader struct { 275 | Uid string 276 | av.RWBaser 277 | demuxer *flv.Demuxer 278 | conn StreamReadWriteCloser 279 | } 280 | 281 | func NewVirReader(conn StreamReadWriteCloser) *VirReader { 282 | return &VirReader{ 283 | Uid: uid.NEWID(), 284 | conn: conn, 285 | RWBaser: av.NewRWBaser(time.Second * 10), 286 | demuxer: flv.NewDemuxer(), 287 | } 288 | } 289 | 290 | func (self *VirReader) Read(p *av.Packet) (err error) { 291 | defer func() { 292 | if r := recover(); r != nil { 293 | glog.Errorln("rtmp read packet panic: ", r) 294 | } 295 | }() 296 | 297 | self.SetPreTime() 298 | var cs core.ChunkStream 299 | for { 300 | err = self.conn.Read(&cs) 301 | if err != nil { 302 | return err 303 | } 304 | if cs.TypeID == av.TAG_AUDIO || 305 | cs.TypeID == av.TAG_VIDEO || 306 | cs.TypeID == av.TAG_SCRIPTDATAAMF0 || 307 | cs.TypeID == av.TAG_SCRIPTDATAAMF3 { 308 | break 309 | } 310 | } 311 | 312 | p.IsAudio = cs.TypeID == av.TAG_AUDIO 313 | p.IsVideo = cs.TypeID == av.TAG_VIDEO 314 | p.IsMetadata = (cs.TypeID == av.TAG_SCRIPTDATAAMF0 || cs.TypeID == av.TAG_SCRIPTDATAAMF3) 315 | p.Data = cs.Data 316 | p.TimeStamp = cs.Timestamp 317 | self.demuxer.DemuxH(p) 318 | return err 319 | } 320 | 321 | func (self *VirReader) Info() (ret av.Info) { 322 | ret.UID = self.Uid 323 | _, _, URL := self.conn.GetInfo() 324 | ret.URL = URL 325 | _url, err := url.Parse(URL) 326 | if err != nil { 327 | glog.Errorln(err) 328 | } 329 | ret.Key = strings.TrimLeft(_url.Path, "/") 330 | return 331 | } 332 | 333 | func (self *VirReader) Close(err error) { 334 | glog.Infoln("publisher ", self.Info(), "closed: "+err.Error()) 335 | self.conn.Close(err) 336 | } 337 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtmp/stream.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | 7 | "sheepbao.com/glog" 8 | "sheepbao.com/media/av" 9 | "sheepbao.com/media/protocol/rtmp/cache" 10 | "sheepbao.com/media/utils/cmap" 11 | ) 12 | 13 | var ( 14 | EmptyID = "" 15 | ) 16 | 17 | type RtmpStream struct { 18 | streams cmap.ConcurrentMap 19 | } 20 | 21 | func NewRtmpStream() *RtmpStream { 22 | ret := &RtmpStream{ 23 | streams: cmap.New(), 24 | } 25 | go ret.CheckAlive() 26 | return ret 27 | } 28 | 29 | func (rs *RtmpStream) HandleReader(r av.ReadCloser) { 30 | info := r.Info() 31 | var s *Stream 32 | ok := rs.streams.Has(info.Key) 33 | if !ok { 34 | s = NewStream() 35 | rs.streams.Set(info.Key, s) 36 | } else { 37 | s.TransStop() 38 | id := s.ID() 39 | if id != EmptyID && id != info.UID { 40 | ns := NewStream() 41 | s.Copy(ns) 42 | s = ns 43 | rs.streams.Set(info.Key, ns) 44 | } 45 | } 46 | s.AddReader(r) 47 | } 48 | 49 | func (rs *RtmpStream) HandleWriter(w av.WriteCloser) { 50 | info := w.Info() 51 | var s *Stream 52 | ok := rs.streams.Has(info.Key) 53 | if !ok { 54 | s = NewStream() 55 | rs.streams.Set(info.Key, s) 56 | } else { 57 | item, ok := rs.streams.Get(info.Key) 58 | if ok { 59 | s = item.(*Stream) 60 | s.AddWriter(w) 61 | } 62 | 63 | } 64 | 65 | } 66 | 67 | func (rs *RtmpStream) GetStreams() cmap.ConcurrentMap { 68 | return rs.streams 69 | } 70 | 71 | func (rs *RtmpStream) CheckAlive() { 72 | for { 73 | <-time.After(5 * time.Second) 74 | for item := range rs.streams.IterBuffered() { 75 | v := item.Val.(*Stream) 76 | if v.CheckAlive() == 0 { 77 | rs.streams.Remove(item.Key) 78 | } 79 | } 80 | } 81 | } 82 | 83 | type Stream struct { 84 | isStart bool 85 | cache *cache.Cache 86 | r av.ReadCloser 87 | ws cmap.ConcurrentMap 88 | } 89 | 90 | type PackWriterCloser struct { 91 | init bool 92 | w av.WriteCloser 93 | } 94 | 95 | func (p *PackWriterCloser) GetWriter() av.WriteCloser { 96 | return p.w 97 | } 98 | 99 | func NewStream() *Stream { 100 | return &Stream{ 101 | cache: cache.NewCache(), 102 | ws: cmap.New(), 103 | } 104 | } 105 | 106 | func (s *Stream) ID() string { 107 | if s.r != nil { 108 | return s.r.Info().UID 109 | } 110 | return EmptyID 111 | } 112 | 113 | func (s *Stream) GetReader() av.ReadCloser { 114 | return s.r 115 | } 116 | 117 | func (s *Stream) GetWs() cmap.ConcurrentMap { 118 | return s.ws 119 | } 120 | 121 | func (s *Stream) Copy(dst *Stream) { 122 | for item := range s.ws.IterBuffered() { 123 | v := item.Val.(*PackWriterCloser) 124 | s.ws.Remove(item.Key) 125 | v.w.CalcBaseTimestamp() 126 | dst.AddWriter(v.w) 127 | } 128 | } 129 | 130 | func (s *Stream) AddReader(r av.ReadCloser) { 131 | s.r = r 132 | go s.TransStart() 133 | } 134 | 135 | func (s *Stream) AddWriter(w av.WriteCloser) { 136 | info := w.Info() 137 | pw := &PackWriterCloser{w: w} 138 | s.ws.Set(info.UID, pw) 139 | } 140 | 141 | func (s *Stream) TransStart() { 142 | // debug mode don't use it 143 | // defer func() { 144 | // if r := recover(); r != nil { 145 | // glog.Errorln("rtmp TransStart panic: ", r) 146 | // } 147 | // }() 148 | 149 | s.isStart = true 150 | var p av.Packet 151 | for { 152 | if !s.isStart { 153 | s.closeInter() 154 | return 155 | } 156 | err := s.r.Read(&p) 157 | if err != nil { 158 | s.closeInter() 159 | s.isStart = false 160 | return 161 | } 162 | s.cache.Write(p) 163 | 164 | for item := range s.ws.IterBuffered() { 165 | v := item.Val.(*PackWriterCloser) 166 | if !v.init { 167 | if err = s.cache.Send(v.w); err != nil { 168 | glog.Errorf("[%s] send cache packet error: %v, remove", v.w.Info(), err) 169 | s.ws.Remove(item.Key) 170 | continue 171 | } 172 | v.init = true 173 | } else { 174 | if err = v.w.Write(p); err != nil { 175 | glog.Errorf("[%s] write packet error: %v, remove", v.w.Info(), err) 176 | s.ws.Remove(item.Key) 177 | } 178 | } 179 | } 180 | } 181 | } 182 | 183 | func (s *Stream) TransStop() { 184 | if s.isStart && s.r != nil { 185 | s.r.Close(errors.New("stop old")) 186 | } 187 | s.isStart = false 188 | } 189 | 190 | func (s *Stream) CheckAlive() (n int) { 191 | if s.r != nil && s.isStart { 192 | if s.r.Alive() { 193 | n++ 194 | } else { 195 | s.r.Close(errors.New("read timeout")) 196 | } 197 | } 198 | for item := range s.ws.IterBuffered() { 199 | v := item.Val.(*PackWriterCloser) 200 | if v.w != nil { 201 | if !v.w.Alive() && s.isStart { 202 | s.ws.Remove(item.Key) 203 | v.w.Close(errors.New("write timeout")) 204 | continue 205 | } 206 | n++ 207 | } 208 | 209 | } 210 | return 211 | } 212 | 213 | func (s *Stream) closeInter() { 214 | if s.r != nil { 215 | glog.Infof("[%v] publisher closed", s.r.Info()) 216 | } 217 | 218 | for item := range s.ws.IterBuffered() { 219 | v := item.Val.(*PackWriterCloser) 220 | if v.w != nil { 221 | if v.w.Info().IsInterval() { 222 | v.w.Close(errors.New("closed")) 223 | s.ws.Remove(item.Key) 224 | glog.Infof("[%v] player closed and remove\n", v.w.Info()) 225 | } 226 | } 227 | 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtp/rtp.go: -------------------------------------------------------------------------------- 1 | package rtp 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtsp/protocol.go: -------------------------------------------------------------------------------- 1 | package rtsp 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/rtsp/rtsp.go: -------------------------------------------------------------------------------- 1 | package rtsp 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/protocol/webrtc/webrtc.go: -------------------------------------------------------------------------------- 1 | package webrtc 2 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/utils/cmap/cmap.go: -------------------------------------------------------------------------------- 1 | package cmap 2 | 3 | import ( 4 | "encoding/json" 5 | "sync" 6 | ) 7 | 8 | var SHARD_COUNT = 32 9 | 10 | // A "thread" safe map of type string:Anything. 11 | // To avoid lock bottlenecks this map is dived to several (SHARD_COUNT) map shards. 12 | type ConcurrentMap []*ConcurrentMapShared 13 | 14 | // A "thread" safe string to anything map. 15 | type ConcurrentMapShared struct { 16 | items map[string]interface{} 17 | sync.RWMutex // Read Write mutex, guards access to internal map. 18 | } 19 | 20 | // Creates a new concurrent map. 21 | func New() ConcurrentMap { 22 | m := make(ConcurrentMap, SHARD_COUNT) 23 | for i := 0; i < SHARD_COUNT; i++ { 24 | m[i] = &ConcurrentMapShared{items: make(map[string]interface{})} 25 | } 26 | return m 27 | } 28 | 29 | // Returns shard under given key 30 | func (m ConcurrentMap) GetShard(key string) *ConcurrentMapShared { 31 | return m[uint(fnv32(key))%uint(SHARD_COUNT)] 32 | } 33 | 34 | func (m ConcurrentMap) MSet(data map[string]interface{}) { 35 | for key, value := range data { 36 | shard := m.GetShard(key) 37 | shard.Lock() 38 | shard.items[key] = value 39 | shard.Unlock() 40 | } 41 | } 42 | 43 | // Sets the given value under the specified key. 44 | func (m *ConcurrentMap) Set(key string, value interface{}) { 45 | // Get map shard. 46 | shard := m.GetShard(key) 47 | shard.Lock() 48 | shard.items[key] = value 49 | shard.Unlock() 50 | } 51 | 52 | // Callback to return new element to be inserted into the map 53 | // It is called while lock is held, therefore it MUST NOT 54 | // try to access other keys in same map, as it can lead to deadlock since 55 | // Go sync.RWLock is not reentrant 56 | type UpsertCb func(exist bool, valueInMap interface{}, newValue interface{}) interface{} 57 | 58 | // Insert or Update - updates existing element or inserts a new one using UpsertCb 59 | func (m *ConcurrentMap) Upsert(key string, value interface{}, cb UpsertCb) (res interface{}) { 60 | shard := m.GetShard(key) 61 | shard.Lock() 62 | v, ok := shard.items[key] 63 | res = cb(ok, v, value) 64 | shard.items[key] = res 65 | shard.Unlock() 66 | return res 67 | } 68 | 69 | // Sets the given value under the specified key if no value was associated with it. 70 | func (m *ConcurrentMap) SetIfAbsent(key string, value interface{}) bool { 71 | // Get map shard. 72 | shard := m.GetShard(key) 73 | shard.Lock() 74 | _, ok := shard.items[key] 75 | if !ok { 76 | shard.items[key] = value 77 | } 78 | shard.Unlock() 79 | return !ok 80 | } 81 | 82 | // Retrieves an element from map under given key. 83 | func (m ConcurrentMap) Get(key string) (interface{}, bool) { 84 | // Get shard 85 | shard := m.GetShard(key) 86 | shard.RLock() 87 | // Get item from shard. 88 | val, ok := shard.items[key] 89 | shard.RUnlock() 90 | return val, ok 91 | } 92 | 93 | // Returns the number of elements within the map. 94 | func (m ConcurrentMap) Count() int { 95 | count := 0 96 | for i := 0; i < SHARD_COUNT; i++ { 97 | shard := m[i] 98 | shard.RLock() 99 | count += len(shard.items) 100 | shard.RUnlock() 101 | } 102 | return count 103 | } 104 | 105 | // Looks up an item under specified key 106 | func (m *ConcurrentMap) Has(key string) bool { 107 | // Get shard 108 | shard := m.GetShard(key) 109 | shard.RLock() 110 | // See if element is within shard. 111 | _, ok := shard.items[key] 112 | shard.RUnlock() 113 | return ok 114 | } 115 | 116 | // Removes an element from the map. 117 | func (m *ConcurrentMap) Remove(key string) { 118 | // Try to get shard. 119 | shard := m.GetShard(key) 120 | shard.Lock() 121 | delete(shard.items, key) 122 | shard.Unlock() 123 | } 124 | 125 | // Removes an element from the map and returns it 126 | func (m *ConcurrentMap) Pop(key string) (v interface{}, exists bool) { 127 | // Try to get shard. 128 | shard := m.GetShard(key) 129 | shard.Lock() 130 | v, exists = shard.items[key] 131 | delete(shard.items, key) 132 | shard.Unlock() 133 | return v, exists 134 | } 135 | 136 | // Checks if map is empty. 137 | func (m *ConcurrentMap) IsEmpty() bool { 138 | return m.Count() == 0 139 | } 140 | 141 | // Used by the Iter & IterBuffered functions to wrap two variables together over a channel, 142 | type Tuple struct { 143 | Key string 144 | Val interface{} 145 | } 146 | 147 | // Returns an iterator which could be used in a for range loop. 148 | // 149 | // Deprecated: using IterBuffered() will get a better performence 150 | func (m ConcurrentMap) Iter() <-chan Tuple { 151 | ch := make(chan Tuple) 152 | go func() { 153 | wg := sync.WaitGroup{} 154 | wg.Add(SHARD_COUNT) 155 | // Foreach shard. 156 | for _, shard := range m { 157 | go func(shard *ConcurrentMapShared) { 158 | // Foreach key, value pair. 159 | shard.RLock() 160 | for key, val := range shard.items { 161 | ch <- Tuple{key, val} 162 | } 163 | shard.RUnlock() 164 | wg.Done() 165 | }(shard) 166 | } 167 | wg.Wait() 168 | close(ch) 169 | }() 170 | return ch 171 | } 172 | 173 | // Returns a buffered iterator which could be used in a for range loop. 174 | func (m ConcurrentMap) IterBuffered() <-chan Tuple { 175 | ch := make(chan Tuple, m.Count()) 176 | go func() { 177 | wg := sync.WaitGroup{} 178 | wg.Add(SHARD_COUNT) 179 | // Foreach shard. 180 | for _, shard := range m { 181 | go func(shard *ConcurrentMapShared) { 182 | // Foreach key, value pair. 183 | shard.RLock() 184 | for key, val := range shard.items { 185 | ch <- Tuple{key, val} 186 | } 187 | shard.RUnlock() 188 | wg.Done() 189 | }(shard) 190 | } 191 | wg.Wait() 192 | close(ch) 193 | }() 194 | return ch 195 | } 196 | 197 | // Returns all items as map[string]interface{} 198 | func (m ConcurrentMap) Items() map[string]interface{} { 199 | tmp := make(map[string]interface{}) 200 | 201 | // Insert items to temporary map. 202 | for item := range m.IterBuffered() { 203 | tmp[item.Key] = item.Val 204 | } 205 | 206 | return tmp 207 | } 208 | 209 | // Iterator callback,called for every key,value found in 210 | // maps. RLock is held for all calls for a given shard 211 | // therefore callback sess consistent view of a shard, 212 | // but not across the shards 213 | type IterCb func(key string, v interface{}) 214 | 215 | // Callback based iterator, cheapest way to read 216 | // all elements in a map. 217 | func (m *ConcurrentMap) IterCb(fn IterCb) { 218 | for idx := range *m { 219 | shard := (*m)[idx] 220 | shard.RLock() 221 | for key, value := range shard.items { 222 | fn(key, value) 223 | } 224 | shard.RUnlock() 225 | } 226 | } 227 | 228 | // Return all keys as []string 229 | func (m ConcurrentMap) Keys() []string { 230 | count := m.Count() 231 | ch := make(chan string, count) 232 | go func() { 233 | // Foreach shard. 234 | wg := sync.WaitGroup{} 235 | wg.Add(SHARD_COUNT) 236 | for _, shard := range m { 237 | go func(shard *ConcurrentMapShared) { 238 | // Foreach key, value pair. 239 | shard.RLock() 240 | for key := range shard.items { 241 | ch <- key 242 | } 243 | shard.RUnlock() 244 | wg.Done() 245 | }(shard) 246 | } 247 | wg.Wait() 248 | close(ch) 249 | }() 250 | 251 | // Generate keys 252 | keys := make([]string, 0, count) 253 | for k := range ch { 254 | keys = append(keys, k) 255 | } 256 | return keys 257 | } 258 | 259 | //Reviles ConcurrentMap "private" variables to json marshal. 260 | func (m ConcurrentMap) MarshalJSON() ([]byte, error) { 261 | // Create a temporary map, which will hold all item spread across shards. 262 | tmp := make(map[string]interface{}) 263 | 264 | // Insert items to temporary map. 265 | for item := range m.IterBuffered() { 266 | tmp[item.Key] = item.Val 267 | } 268 | return json.Marshal(tmp) 269 | } 270 | 271 | func fnv32(key string) uint32 { 272 | hash := uint32(2166136261) 273 | const prime32 = uint32(16777619) 274 | for i := 0; i < len(key); i++ { 275 | hash *= prime32 276 | hash ^= uint32(key[i]) 277 | } 278 | return hash 279 | } 280 | 281 | // Concurrent map uses Interface{} as its value, therefor JSON Unmarshal 282 | // will probably won't know which to type to unmarshal into, in such case 283 | // we'll end up with a value of type map[string]interface{}, In most cases this isn't 284 | // out value type, this is why we've decided to remove this functionality. 285 | 286 | // func (m *ConcurrentMap) UnmarshalJSON(b []byte) (err error) { 287 | // // Reverse process of Marshal. 288 | 289 | // tmp := make(map[string]interface{}) 290 | 291 | // // Unmarshal into a single map. 292 | // if err := json.Unmarshal(b, &tmp); err != nil { 293 | // return nil 294 | // } 295 | 296 | // // foreach key,value pair in temporary map insert into our concurrent map. 297 | // for key, val := range tmp { 298 | // m.Set(key, val) 299 | // } 300 | // return nil 301 | // } 302 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/utils/pio/pio.go: -------------------------------------------------------------------------------- 1 | package pio 2 | 3 | var RecommendBufioSize = 1024 * 64 4 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/utils/pio/reader.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 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/utils/pio/writer.go: -------------------------------------------------------------------------------- 1 | 2 | package pio 3 | 4 | func PutU8(b []byte, v uint8) { 5 | b[0] = v 6 | } 7 | 8 | func PutI16BE(b []byte, v int16) { 9 | b[0] = byte(v>>8) 10 | b[1] = byte(v) 11 | } 12 | 13 | func PutU16BE(b []byte, v uint16) { 14 | b[0] = byte(v>>8) 15 | b[1] = byte(v) 16 | } 17 | 18 | func PutI24BE(b []byte, v int32) { 19 | b[0] = byte(v>>16) 20 | b[1] = byte(v>>8) 21 | b[2] = byte(v) 22 | } 23 | 24 | func PutU24BE(b []byte, v uint32) { 25 | b[0] = byte(v>>16) 26 | b[1] = byte(v>>8) 27 | b[2] = byte(v) 28 | } 29 | 30 | func PutI32BE(b []byte, v int32) { 31 | b[0] = byte(v>>24) 32 | b[1] = byte(v>>16) 33 | b[2] = byte(v>>8) 34 | b[3] = byte(v) 35 | } 36 | 37 | func PutU32BE(b []byte, v uint32) { 38 | b[0] = byte(v>>24) 39 | b[1] = byte(v>>16) 40 | b[2] = byte(v>>8) 41 | b[3] = byte(v) 42 | } 43 | 44 | func PutU32LE(b []byte, v uint32) { 45 | b[3] = byte(v>>24) 46 | b[2] = byte(v>>16) 47 | b[1] = byte(v>>8) 48 | b[0] = byte(v) 49 | } 50 | 51 | func PutU40BE(b []byte, v uint64) { 52 | b[0] = byte(v>>32) 53 | b[1] = byte(v>>24) 54 | b[2] = byte(v>>16) 55 | b[3] = byte(v>>8) 56 | b[4] = byte(v) 57 | } 58 | 59 | func PutU48BE(b []byte, v uint64) { 60 | b[0] = byte(v>>40) 61 | b[1] = byte(v>>32) 62 | b[2] = byte(v>>24) 63 | b[3] = byte(v>>16) 64 | b[4] = byte(v>>8) 65 | b[5] = byte(v) 66 | } 67 | 68 | func PutU64BE(b []byte, v uint64) { 69 | b[0] = byte(v>>56) 70 | b[1] = byte(v>>48) 71 | b[2] = byte(v>>40) 72 | b[3] = byte(v>>32) 73 | b[4] = byte(v>>24) 74 | b[5] = byte(v>>16) 75 | b[6] = byte(v>>8) 76 | b[7] = byte(v) 77 | } 78 | 79 | func PutI64BE(b []byte, v int64) { 80 | b[0] = byte(v>>56) 81 | b[1] = byte(v>>48) 82 | b[2] = byte(v>>40) 83 | b[3] = byte(v>>32) 84 | b[4] = byte(v>>24) 85 | b[5] = byte(v>>16) 86 | b[6] = byte(v>>8) 87 | b[7] = byte(v) 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/utils/pool/pool.go: -------------------------------------------------------------------------------- 1 | package pool 2 | 3 | type Pool struct { 4 | pos int 5 | buf []byte 6 | } 7 | 8 | const maxpoolsize = 500 * 1024 9 | 10 | func (self *Pool) Get(size int) []byte { 11 | if maxpoolsize-self.pos < size { 12 | self.pos = 0 13 | self.buf = make([]byte, maxpoolsize) 14 | } 15 | b := self.buf[self.pos : self.pos+size] 16 | self.pos += size 17 | return b 18 | } 19 | 20 | func NewPool() *Pool { 21 | return &Pool{ 22 | buf: make([]byte, maxpoolsize), 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/vendor/sheepbao.com/media/utils/queue/queue.go: -------------------------------------------------------------------------------- 1 | package queue 2 | 3 | import ( 4 | "sync" 5 | 6 | "sheepbao.com/media/av" 7 | ) 8 | 9 | // Queue is a basic FIFO queue for Messages. 10 | type Queue struct { 11 | maxSize int 12 | 13 | list []*av.Packet 14 | mutex sync.Mutex 15 | } 16 | 17 | // NewQueue returns a new Queue. If maxSize is greater than zero the queue will 18 | // not grow more than the defined size. 19 | func NewQueue(maxSize int) *Queue { 20 | return &Queue{ 21 | maxSize: maxSize, 22 | } 23 | } 24 | 25 | // Push adds a message to the queue. 26 | func (q *Queue) Push(msg *av.Packet) { 27 | q.mutex.Lock() 28 | defer q.mutex.Unlock() 29 | 30 | if len(q.list) == q.maxSize { 31 | q.pop() 32 | } 33 | 34 | q.list = append(q.list, msg) 35 | } 36 | 37 | // Pop removes and returns a message from the queue in first to last order. 38 | func (q *Queue) Pop() *av.Packet { 39 | q.mutex.Lock() 40 | defer q.mutex.Unlock() 41 | 42 | if len(q.list) == 0 { 43 | return nil 44 | } 45 | 46 | return q.pop() 47 | } 48 | 49 | func (q *Queue) pop() *av.Packet { 50 | x := len(q.list) - 1 51 | msg := q.list[x] 52 | q.list = q.list[:x] 53 | return msg 54 | } 55 | 56 | // Len returns the length of the queue. 57 | func (q *Queue) Len() int { 58 | q.mutex.Lock() 59 | defer q.mutex.Unlock() 60 | 61 | return len(q.list) 62 | } 63 | 64 | // All returns and removes all messages from the queue. 65 | func (q *Queue) All() []*av.Packet { 66 | q.mutex.Lock() 67 | defer q.mutex.Unlock() 68 | 69 | cache := q.list 70 | q.list = nil 71 | return cache 72 | } 73 | --------------------------------------------------------------------------------