improve sdp
This commit is contained in:
parent
0bfb3c6cf0
commit
2f1caf9151
28
client.go
28
client.go
@ -61,7 +61,7 @@ func Connect(uri string) (self *Client, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.IndexByte(URL.Host, ':') == -1 {
|
if _, _, err := net.SplitHostPort(URL.Host); err != nil {
|
||||||
URL.Host = URL.Host + ":554"
|
URL.Host = URL.Host + ":554"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,18 +342,24 @@ func (self *Client) Describe() (streams []av.CodecData, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.streams = []*Stream{}
|
self.streams = []*Stream{}
|
||||||
for _, info := range sdp.Decode(body) {
|
sess, medias := sdp.Parse(body)
|
||||||
stream := &Stream{Sdp: info}
|
|
||||||
|
if sess.Uri != "" {
|
||||||
|
self.requestUri = sess.Uri
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, media := range medias {
|
||||||
|
stream := &Stream{Sdp: media}
|
||||||
|
|
||||||
if false {
|
if false {
|
||||||
fmt.Println("sdp:", info.TimeScale)
|
fmt.Println("sdp:", media.TimeScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.PayloadType >= 96 && info.PayloadType <= 127 {
|
if media.PayloadType >= 96 && media.PayloadType <= 127 {
|
||||||
switch info.Type {
|
switch media.Type {
|
||||||
case av.H264:
|
case av.H264:
|
||||||
var sps, pps []byte
|
var sps, pps []byte
|
||||||
for _, nalu := range info.SpropParameterSets {
|
for _, nalu := range media.SpropParameterSets {
|
||||||
if len(nalu) > 0 {
|
if len(nalu) > 0 {
|
||||||
switch nalu[0]&0x1f {
|
switch nalu[0]&0x1f {
|
||||||
case 7:
|
case 7:
|
||||||
@ -374,22 +380,22 @@ func (self *Client) Describe() (streams []av.CodecData, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case av.AAC:
|
case av.AAC:
|
||||||
if len(info.Config) == 0 {
|
if len(media.Config) == 0 {
|
||||||
err = fmt.Errorf("rtsp: aac sdp config missing")
|
err = fmt.Errorf("rtsp: aac sdp config missing")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if stream.CodecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(info.Config); err != nil {
|
if stream.CodecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(media.Config); err != nil {
|
||||||
err = fmt.Errorf("rtsp: aac sdp config invalid: %s", err)
|
err = fmt.Errorf("rtsp: aac sdp config invalid: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch info.PayloadType {
|
switch media.PayloadType {
|
||||||
case 0:
|
case 0:
|
||||||
stream.CodecData = codec.NewPCMMulawCodecData()
|
stream.CodecData = codec.NewPCMMulawCodecData()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("rtsp: PayloadType=%d unsupported", info.PayloadType)
|
err = fmt.Errorf("rtsp: PayloadType=%d unsupported", media.PayloadType)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,11 @@ import (
|
|||||||
"github.com/nareix/av"
|
"github.com/nareix/av"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Info struct {
|
type Session struct {
|
||||||
|
Uri string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Media struct {
|
||||||
AVType string
|
AVType string
|
||||||
Type int
|
Type int
|
||||||
TimeScale int
|
TimeScale int
|
||||||
@ -22,8 +26,8 @@ type Info struct {
|
|||||||
IndexLength int
|
IndexLength int
|
||||||
}
|
}
|
||||||
|
|
||||||
func Decode(content string) (infos []Info) {
|
func Parse(content string) (sess Session, medias []Media) {
|
||||||
var info *Info
|
var media *Media
|
||||||
|
|
||||||
for _, line := range strings.Split(content, "\n") {
|
for _, line := range strings.Split(content, "\n") {
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
@ -36,17 +40,20 @@ func Decode(content string) (infos []Info) {
|
|||||||
if len(fields) > 0 {
|
if len(fields) > 0 {
|
||||||
switch fields[0] {
|
switch fields[0] {
|
||||||
case "audio", "video":
|
case "audio", "video":
|
||||||
infos = append(infos, Info{AVType: fields[0]})
|
medias = append(medias, Media{AVType: fields[0]})
|
||||||
info = &infos[len(infos)-1]
|
media = &medias[len(medias)-1]
|
||||||
mfields := strings.Split(fields[1], " ")
|
mfields := strings.Split(fields[1], " ")
|
||||||
if len(mfields) >= 3 {
|
if len(mfields) >= 3 {
|
||||||
info.PayloadType, _ = strconv.Atoi(mfields[2])
|
media.PayloadType, _ = strconv.Atoi(mfields[2])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "u":
|
||||||
|
sess.Uri = typeval[1]
|
||||||
|
|
||||||
case "a":
|
case "a":
|
||||||
if info != nil {
|
if media != nil {
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
keyval := strings.SplitN(field, ":", 2)
|
keyval := strings.SplitN(field, ":", 2)
|
||||||
if len(keyval) >= 2 {
|
if len(keyval) >= 2 {
|
||||||
@ -54,9 +61,9 @@ func Decode(content string) (infos []Info) {
|
|||||||
val := keyval[1]
|
val := keyval[1]
|
||||||
switch key {
|
switch key {
|
||||||
case "control":
|
case "control":
|
||||||
info.Control = val
|
media.Control = val
|
||||||
case "rtpmap":
|
case "rtpmap":
|
||||||
info.Rtpmap, _ = strconv.Atoi(val)
|
media.Rtpmap, _ = strconv.Atoi(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyval = strings.Split(field, "/")
|
keyval = strings.Split(field, "/")
|
||||||
@ -64,15 +71,15 @@ func Decode(content string) (infos []Info) {
|
|||||||
key := keyval[0]
|
key := keyval[0]
|
||||||
switch key {
|
switch key {
|
||||||
case "MPEG4-GENERIC":
|
case "MPEG4-GENERIC":
|
||||||
info.Type = av.AAC
|
media.Type = av.AAC
|
||||||
case "H264":
|
case "H264":
|
||||||
info.Type = av.H264
|
media.Type = av.H264
|
||||||
}
|
}
|
||||||
if i, err := strconv.Atoi(keyval[1]); err == nil {
|
if i, err := strconv.Atoi(keyval[1]); err == nil {
|
||||||
info.TimeScale = i
|
media.TimeScale = i
|
||||||
}
|
}
|
||||||
if false {
|
if false {
|
||||||
fmt.Println("sdp:", keyval[1], info.TimeScale)
|
fmt.Println("sdp:", keyval[1], media.TimeScale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyval = strings.Split(field, ";")
|
keyval = strings.Split(field, ";")
|
||||||
@ -84,16 +91,16 @@ func Decode(content string) (infos []Info) {
|
|||||||
val := keyval[1]
|
val := keyval[1]
|
||||||
switch key {
|
switch key {
|
||||||
case "config":
|
case "config":
|
||||||
info.Config, _ = hex.DecodeString(val)
|
media.Config, _ = hex.DecodeString(val)
|
||||||
case "sizelength":
|
case "sizelength":
|
||||||
info.SizeLength, _ = strconv.Atoi(val)
|
media.SizeLength, _ = strconv.Atoi(val)
|
||||||
case "indexlength":
|
case "indexlength":
|
||||||
info.IndexLength, _ = strconv.Atoi(val)
|
media.IndexLength, _ = strconv.Atoi(val)
|
||||||
case "sprop-parameter-sets":
|
case "sprop-parameter-sets":
|
||||||
fields := strings.Split(val, ",")
|
fields := strings.Split(val, ",")
|
||||||
for _, field := range fields {
|
for _, field := range fields {
|
||||||
val, _ := base64.StdEncoding.DecodeString(field)
|
val, _ := base64.StdEncoding.DecodeString(field)
|
||||||
info.SpropParameterSets = append(info.SpropParameterSets, val)
|
media.SpropParameterSets = append(media.SpropParameterSets, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user