2019-12-01 04:53:21 +08:00
|
|
|
package sdp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
2021-02-03 11:10:03 +08:00
|
|
|
"log"
|
2019-12-01 04:53:21 +08:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/deepch/vdk/av"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Session struct {
|
|
|
|
Uri string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Media struct {
|
|
|
|
AVType string
|
|
|
|
Type av.CodecType
|
2021-05-09 04:07:59 +08:00
|
|
|
FPS int
|
2019-12-01 04:53:21 +08:00
|
|
|
TimeScale int
|
|
|
|
Control string
|
|
|
|
Rtpmap int
|
2021-01-09 12:37:19 +08:00
|
|
|
ChannelCount int
|
2019-12-01 04:53:21 +08:00
|
|
|
Config []byte
|
|
|
|
SpropParameterSets [][]byte
|
2021-02-03 11:10:03 +08:00
|
|
|
SpropVPS []byte
|
|
|
|
SpropSPS []byte
|
|
|
|
SpropPPS []byte
|
2019-12-01 04:53:21 +08:00
|
|
|
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)
|
2021-05-09 04:07:59 +08:00
|
|
|
////Camera [BUG] a=x-framerate: 25
|
|
|
|
if strings.Contains(line, "x-framerate") {
|
|
|
|
line = strings.Replace(line, " ", "", -1)
|
|
|
|
}
|
2019-12-01 04:53:21 +08:00
|
|
|
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])
|
|
|
|
}
|
2021-01-08 12:23:06 +08:00
|
|
|
switch media.PayloadType {
|
|
|
|
case 0:
|
|
|
|
media.Type = av.PCM_MULAW
|
|
|
|
case 8:
|
|
|
|
media.Type = av.PCM_ALAW
|
|
|
|
}
|
2020-06-29 23:35:37 +08:00
|
|
|
default:
|
|
|
|
media = nil
|
2019-12-01 04:53:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2021-05-09 04:07:59 +08:00
|
|
|
case "x-framerate":
|
|
|
|
media.FPS, _ = strconv.Atoi(val)
|
2019-12-01 04:53:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
keyval = strings.Split(field, "/")
|
|
|
|
if len(keyval) >= 2 {
|
|
|
|
key := keyval[0]
|
|
|
|
switch strings.ToUpper(key) {
|
|
|
|
case "MPEG4-GENERIC":
|
|
|
|
media.Type = av.AAC
|
2021-01-08 12:23:06 +08:00
|
|
|
case "L16":
|
|
|
|
media.Type = av.PCM
|
2021-01-09 12:37:19 +08:00
|
|
|
case "OPUS":
|
|
|
|
media.Type = av.OPUS
|
|
|
|
if len(keyval) > 2 {
|
|
|
|
if i, err := strconv.Atoi(keyval[2]); err == nil {
|
|
|
|
media.ChannelCount = i
|
|
|
|
}
|
|
|
|
}
|
2019-12-01 04:53:21 +08:00
|
|
|
case "H264":
|
|
|
|
media.Type = av.H264
|
2021-09-30 07:10:08 +08:00
|
|
|
case "JPEG":
|
|
|
|
media.Type = av.JPEG
|
2021-02-03 11:10:03 +08:00
|
|
|
case "H265":
|
|
|
|
media.Type = av.H265
|
|
|
|
case "HEVC":
|
|
|
|
media.Type = av.H265
|
2021-04-21 22:03:35 +08:00
|
|
|
case "PCMA":
|
|
|
|
media.Type = av.PCM_ALAW
|
|
|
|
case "PCMU":
|
|
|
|
media.Type = av.PCM_MULAW
|
2019-12-01 04:53:21 +08:00
|
|
|
}
|
|
|
|
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)
|
2021-02-03 11:10:03 +08:00
|
|
|
case "sprop-vps":
|
|
|
|
val, err := base64.StdEncoding.DecodeString(val)
|
|
|
|
if err == nil {
|
|
|
|
media.SpropVPS = val
|
|
|
|
} else {
|
|
|
|
log.Println("SDP: decode vps error", err)
|
|
|
|
}
|
|
|
|
case "sprop-sps":
|
|
|
|
val, err := base64.StdEncoding.DecodeString(val)
|
|
|
|
if err == nil {
|
|
|
|
media.SpropSPS = val
|
|
|
|
} else {
|
|
|
|
log.Println("SDP: decode sps error", err)
|
|
|
|
}
|
|
|
|
case "sprop-pps":
|
|
|
|
val, err := base64.StdEncoding.DecodeString(val)
|
|
|
|
if err == nil {
|
|
|
|
media.SpropPPS = val
|
|
|
|
} else {
|
|
|
|
log.Println("SDP: decode pps error", err)
|
|
|
|
}
|
2019-12-01 04:53:21 +08:00
|
|
|
case "sprop-parameter-sets":
|
|
|
|
fields := strings.Split(val, ",")
|
|
|
|
for _, field := range fields {
|
2022-09-13 09:20:14 +08:00
|
|
|
if field == "" {
|
|
|
|
continue
|
|
|
|
}
|
2019-12-01 04:53:21 +08:00
|
|
|
val, _ := base64.StdEncoding.DecodeString(field)
|
|
|
|
media.SpropParameterSets = append(media.SpropParameterSets, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2020-06-26 13:28:33 +08:00
|
|
|
|
2019-12-01 04:53:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|