Add 'rtsp/' from commit 'df0f52cf38a45d842291bb72e1adc24de397d1dd'

git-subtree-dir: rtsp
git-subtree-mainline: 6b682ae3918d3f153df86e11eb07d386bfcd26b8
git-subtree-split: df0f52cf38a45d842291bb72e1adc24de397d1dd
This commit is contained in:
nareix 2016-07-01 21:35:08 +08:00
commit 452846833c
5 changed files with 1428 additions and 0 deletions

1214
rtsp/client.go Normal file

File diff suppressed because it is too large Load Diff

25
rtsp/conn.go Normal file
View File

@ -0,0 +1,25 @@
package rtsp
import (
"net"
"time"
)
type connWithTimeout struct {
Timeout time.Duration
net.Conn
}
func (self connWithTimeout) Read(p []byte) (n int, err error) {
if self.Timeout > 0 {
self.Conn.SetReadDeadline(time.Now().Add(self.Timeout))
}
return self.Conn.Read(p)
}
func (self connWithTimeout) Write(p []byte) (n int, err error) {
if self.Timeout > 0 {
self.Conn.SetWriteDeadline(time.Now().Add(self.Timeout))
}
return self.Conn.Write(p)
}

116
rtsp/sdp/parser.go Normal file
View File

@ -0,0 +1,116 @@
package sdp
import (
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/nareix/av"
"strconv"
"strings"
)
type Session struct {
Uri string
}
type Media struct {
AVType string
Type av.CodecType
TimeScale int
Control string
Rtpmap int
Config []byte
SpropParameterSets [][]byte
PayloadType int
SizeLength int
IndexLength int
}
func Parse(content string) (sess Session, medias []Media) {
var media *Media
for _, line := range strings.Split(content, "\n") {
line = strings.TrimSpace(line)
typeval := strings.SplitN(line, "=", 2)
if len(typeval) == 2 {
fields := strings.SplitN(typeval[1], " ", 2)
switch typeval[0] {
case "m":
if len(fields) > 0 {
switch fields[0] {
case "audio", "video":
medias = append(medias, Media{AVType: fields[0]})
media = &medias[len(medias)-1]
mfields := strings.Split(fields[1], " ")
if len(mfields) >= 3 {
media.PayloadType, _ = strconv.Atoi(mfields[2])
}
}
}
case "u":
sess.Uri = typeval[1]
case "a":
if media != nil {
for _, field := range fields {
keyval := strings.SplitN(field, ":", 2)
if len(keyval) >= 2 {
key := keyval[0]
val := keyval[1]
switch key {
case "control":
media.Control = val
case "rtpmap":
media.Rtpmap, _ = strconv.Atoi(val)
}
}
keyval = strings.Split(field, "/")
if len(keyval) >= 2 {
key := keyval[0]
switch strings.ToUpper(key) {
case "MPEG4-GENERIC":
media.Type = av.AAC
case "H264":
media.Type = av.H264
}
if i, err := strconv.Atoi(keyval[1]); err == nil {
media.TimeScale = i
}
if false {
fmt.Println("sdp:", keyval[1], media.TimeScale)
}
}
keyval = strings.Split(field, ";")
if len(keyval) > 1 {
for _, field := range keyval {
keyval := strings.SplitN(field, "=", 2)
if len(keyval) == 2 {
key := strings.TrimSpace(keyval[0])
val := keyval[1]
switch key {
case "config":
media.Config, _ = hex.DecodeString(val)
case "sizelength":
media.SizeLength, _ = strconv.Atoi(val)
case "indexlength":
media.IndexLength, _ = strconv.Atoi(val)
case "sprop-parameter-sets":
fields := strings.Split(val, ",")
for _, field := range fields {
val, _ := base64.StdEncoding.DecodeString(field)
media.SpropParameterSets = append(media.SpropParameterSets, val)
}
}
}
}
}
}
}
}
}
}
return
}

44
rtsp/sdp/parser_test.go Normal file
View File

@ -0,0 +1,44 @@
package sdp
import (
"testing"
)
func TestParse(t *testing.T) {
infos := Decode(`
v=0
o=- 1459325504777324 1 IN IP4 192.168.0.123
s=RTSP/RTP stream from Network Video Server
i=mpeg4cif
t=0 0
a=tool:LIVE555 Streaming Media v2009.09.28
a=type:broadcast
a=control:*
a=range:npt=0-
a=x-qt-text-nam:RTSP/RTP stream from Network Video Server
a=x-qt-text-inf:mpeg4cif
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:300
a=rtpmap:96 H264/90000
a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z00AHpWoKA9k,aO48gA==
a=x-dimensions: 720, 480
a=x-framerate: 15
a=control:track1
m=audio 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:256
a=rtpmap:96 MPEG4-GENERIC/16000/2
a=fmtp:96 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1408
a=control:track2
m=audio 0 RTP/AVP 0
c=IN IP4 0.0.0.0
b=AS:50
a=recvonly
a=control:rtsp://109.195.127.207:554/mpeg4cif/trackID=2
a=rtpmap:0 PCMU/8000
a=Media_header:MEDIAINFO=494D4B48010100000400010010710110401F000000FA000000000000000000000000000000000000;
a=appversion:1.0
`)
t.Logf("%v", infos)
}

29
rtsp/stream.go Normal file
View File

@ -0,0 +1,29 @@
package rtsp
import (
"github.com/nareix/av"
"github.com/nareix/rtsp/sdp"
"time"
)
type Stream struct {
av.CodecData
Sdp sdp.Media
client *Client
// h264
fuStarted bool
fuBuffer []byte
sps []byte
pps []byte
spsChanged bool
ppsChanged bool
gotpkt bool
pkt av.Packet
timestamp uint32
firsttimestamp uint32
lasttime time.Duration
}