mirror of
https://github.com/aler9/gortsplib
synced 2025-12-24 13:38:08 +08:00
This commit is contained in:
@@ -97,18 +97,26 @@ func (h *Header) unmarshal(br *bufio.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h Header) marshalSize() int {
|
||||
// sort headers by key
|
||||
// in order to obtain deterministic results
|
||||
// sort headers by key
|
||||
// in order to obtain deterministic results
|
||||
func (h Header) sortedKeys() []string {
|
||||
keys := make([]string, len(h))
|
||||
for key := range h {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// some cameras require CSeq to be put before everything else
|
||||
sort.Slice(keys, func(i, j int) bool {
|
||||
return keys[i] == "CSeq" || (keys[j] != "CSeq" && keys[i] < keys[j])
|
||||
})
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
func (h Header) marshalSize() int {
|
||||
n := 0
|
||||
|
||||
for _, key := range keys {
|
||||
for _, key := range h.sortedKeys() {
|
||||
for _, val := range h[key] {
|
||||
n += len([]byte(key + ": " + val + "\r\n"))
|
||||
}
|
||||
@@ -120,17 +128,9 @@ func (h Header) marshalSize() int {
|
||||
}
|
||||
|
||||
func (h Header) marshalTo(buf []byte) int {
|
||||
// sort headers by key
|
||||
// in order to obtain deterministic results
|
||||
keys := make([]string, len(h))
|
||||
for key := range h {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
pos := 0
|
||||
|
||||
for _, key := range keys {
|
||||
for _, key := range h.sortedKeys() {
|
||||
for _, val := range h[key] {
|
||||
pos += copy(buf[pos:], []byte(key+": "+val+"\r\n"))
|
||||
}
|
||||
|
||||
@@ -45,60 +45,27 @@ var cases = []struct {
|
||||
},
|
||||
},
|
||||
{
|
||||
"empty",
|
||||
[]byte("Testing:\r\n" +
|
||||
"\r\n"),
|
||||
[]byte("Testing: \r\n" +
|
||||
"\r\n"),
|
||||
Header{
|
||||
"Testing": HeaderValue{""},
|
||||
},
|
||||
},
|
||||
{
|
||||
"without space",
|
||||
[]byte("CSeq:2\r\n" +
|
||||
"\r\n"),
|
||||
[]byte("CSeq: 2\r\n" +
|
||||
"\r\n"),
|
||||
Header{
|
||||
"CSeq": HeaderValue{"2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"with multiple spaces",
|
||||
[]byte("CSeq: 2\r\n" +
|
||||
"\r\n"),
|
||||
[]byte("CSeq: 2\r\n" +
|
||||
"\r\n"),
|
||||
Header{
|
||||
"CSeq": HeaderValue{"2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"normalized keys, standard",
|
||||
[]byte("content-type: testing\r\n" +
|
||||
"content-length: value\r\n" +
|
||||
"\r\n"),
|
||||
[]byte("Content-Length: value\r\n" +
|
||||
"Content-Type: testing\r\n" +
|
||||
"\r\n"),
|
||||
Header{
|
||||
"Content-Length": HeaderValue{"value"},
|
||||
"Content-Type": HeaderValue{"testing"},
|
||||
},
|
||||
},
|
||||
{
|
||||
"normalized keys, non-standard",
|
||||
[]byte("www-authenticate: value\r\n" +
|
||||
"cseq: value\r\n" +
|
||||
"rtp-info: value\r\n" +
|
||||
"\r\n"),
|
||||
"various",
|
||||
[]byte(
|
||||
"Testing:\r\n" +
|
||||
"content-type: testing\r\n" +
|
||||
"content-length:value\r\n" +
|
||||
"www-authenticate: value\r\n" +
|
||||
"cseq: value\r\n" +
|
||||
"rtp-info: value\r\n" +
|
||||
"\r\n"),
|
||||
[]byte("CSeq: value\r\n" +
|
||||
"Content-Length: value\r\n" +
|
||||
"Content-Type: testing\r\n" +
|
||||
"Testing: \r\n" +
|
||||
"RTP-Info: value\r\n" +
|
||||
"WWW-Authenticate: value\r\n" +
|
||||
"\r\n"),
|
||||
Header{
|
||||
"Content-Length": HeaderValue{"value"},
|
||||
"Content-Type": HeaderValue{"testing"},
|
||||
"CSeq": HeaderValue{"value"},
|
||||
"Testing": HeaderValue{""},
|
||||
"RTP-Info": HeaderValue{"value"},
|
||||
"WWW-Authenticate": HeaderValue{"value"},
|
||||
},
|
||||
|
||||
@@ -114,15 +114,16 @@ func (s *SessionDescription) unmarshalOrigin(value string) error {
|
||||
var tmp string
|
||||
tmp, value = value[i+1:], value[:i]
|
||||
|
||||
tmp = strings.TrimRight(tmp, " ")
|
||||
|
||||
var err error
|
||||
|
||||
switch {
|
||||
case strings.ContainsAny(tmp, "."):
|
||||
i := strings.Index(tmp, ".")
|
||||
if i := strings.Index(tmp, "."); i >= 0 {
|
||||
s.Origin.SessionVersion, err = strconv.ParseUint(tmp[:i], 16, 64)
|
||||
default:
|
||||
} else {
|
||||
s.Origin.SessionVersion, err = strconv.ParseUint(tmp, 10, 64)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w `%v`", errSDPInvalidNumericValue, tmp)
|
||||
}
|
||||
|
||||
@@ -227,8 +227,7 @@ var cases = []struct {
|
||||
Value: "0 1 UDP 2113667327 203.0.113.1 54400 typ host",
|
||||
},
|
||||
{
|
||||
Key: "recvonly",
|
||||
Value: "",
|
||||
Key: "recvonly",
|
||||
},
|
||||
},
|
||||
MediaDescriptions: []*psdp.MediaDescription{
|
||||
@@ -371,8 +370,7 @@ var cases = []struct {
|
||||
Value: "?ctype=video",
|
||||
},
|
||||
{
|
||||
Key: "recvonly",
|
||||
Value: "",
|
||||
Key: "recvonly",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -393,8 +391,7 @@ var cases = []struct {
|
||||
Value: "?ctype=app106",
|
||||
},
|
||||
{
|
||||
Key: "sendonly",
|
||||
Value: "",
|
||||
Key: "sendonly",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -746,8 +743,7 @@ var cases = []struct {
|
||||
Value: "trackID=1",
|
||||
},
|
||||
{
|
||||
Key: "recvonly",
|
||||
Value: "",
|
||||
Key: "recvonly",
|
||||
},
|
||||
{
|
||||
Key: "framerate",
|
||||
@@ -996,7 +992,6 @@ var cases = []struct {
|
||||
SessionVersion: 16381778200090839277,
|
||||
NetworkType: "IN",
|
||||
AddressType: "IP4",
|
||||
UnicastAddress: "",
|
||||
},
|
||||
SessionName: psdp.SessionName("RTSP Server"),
|
||||
EmailAddress: func() *psdp.EmailAddress {
|
||||
@@ -2419,8 +2414,7 @@ var cases = []struct {
|
||||
"sprop-parameter-sets=Z2QAKKwbGoB4AiflwFuAgICgAAB9AAATiB0MAEr4AAL68F3lxoYAJXwAAX14LvLhQA==,aO48MA==",
|
||||
},
|
||||
{
|
||||
Key: "recvonly",
|
||||
Value: "",
|
||||
Key: "recvonly",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2462,7 +2456,6 @@ var cases = []struct {
|
||||
AddressType: "IP4",
|
||||
UnicastAddress: "192.168.1.10",
|
||||
},
|
||||
SessionName: "",
|
||||
Attributes: []psdp.Attribute{
|
||||
{
|
||||
Key: "range",
|
||||
@@ -2857,8 +2850,7 @@ var cases = []struct {
|
||||
Value: "rtsp://192.168.1.63/defaultPrimary/micCfg0/trackID=9?mtu=1440&streamType=u",
|
||||
},
|
||||
{
|
||||
Key: "recvonly",
|
||||
Value: "",
|
||||
Key: "recvonly",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2916,6 +2908,112 @@ var cases = []struct {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"issue mediamtx/2887",
|
||||
[]byte("v=0\r\n" +
|
||||
"o=- 57160522 782967157 IN IP4 192.168.1.44\r\n" +
|
||||
"s=live\r\n" +
|
||||
"c=IN IP4 0.0.0.0\r\n" +
|
||||
"t=0 0\r\n" +
|
||||
"a=control:*\r\n" +
|
||||
"m=video 0 RTP/AVP 96\r\n" +
|
||||
"b=AS:2058\r\n" +
|
||||
"a=rtpmap:96 H264/90000\r\n" +
|
||||
"a=range:npt=0-\r\n" +
|
||||
"a=control:rtsp://192.168.1.44:554/video/live00_0\r\n" +
|
||||
"m=audio 0 RTP/AVP 8\r\n" +
|
||||
"b=AS:64\r\n" +
|
||||
"a=rtpmap:8 PCMA/8000\r\n" +
|
||||
"a=control:rtsp://192.168.1.44:554/audio/live00_0\r\n"),
|
||||
[]byte("v=0\r\n" +
|
||||
"o=- 57160522 782967157 IN IP4 192.168.1.44\r\n" +
|
||||
"s=live\r\n" +
|
||||
"c=IN IP4 0.0.0.0\r\n" +
|
||||
"t=0 0\r\n" +
|
||||
"a=control:*\r\n" +
|
||||
"m=video 0 RTP/AVP 96\r\n" +
|
||||
"b=AS:2058\r\n" +
|
||||
"a=rtpmap:96 H264/90000\r\n" +
|
||||
"a=range:npt=0-\r\n" +
|
||||
"a=control:rtsp://192.168.1.44:554/video/live00_0\r\n" +
|
||||
"m=audio 0 RTP/AVP 8\r\n" +
|
||||
"b=AS:64\r\n" +
|
||||
"a=rtpmap:8 PCMA/8000\r\n" +
|
||||
"a=control:rtsp://192.168.1.44:554/audio/live00_0\r\n"),
|
||||
SessionDescription{
|
||||
Origin: psdp.Origin{
|
||||
Username: "-",
|
||||
SessionID: 57160522,
|
||||
SessionVersion: 782967157,
|
||||
NetworkType: "IN",
|
||||
AddressType: "IP4",
|
||||
UnicastAddress: "192.168.1.44",
|
||||
},
|
||||
SessionName: "live",
|
||||
ConnectionInformation: &psdp.ConnectionInformation{
|
||||
NetworkType: "IN",
|
||||
AddressType: "IP4",
|
||||
Address: &psdp.Address{
|
||||
Address: "0.0.0.0",
|
||||
},
|
||||
},
|
||||
Attributes: []psdp.Attribute{
|
||||
{
|
||||
Key: "control",
|
||||
Value: "*",
|
||||
},
|
||||
},
|
||||
TimeDescriptions: []psdp.TimeDescription{{}},
|
||||
MediaDescriptions: []*psdp.MediaDescription{
|
||||
{
|
||||
MediaName: psdp.MediaName{
|
||||
Media: "video",
|
||||
Protos: []string{"RTP", "AVP"},
|
||||
Formats: []string{"96"},
|
||||
},
|
||||
Bandwidth: []psdp.Bandwidth{{
|
||||
Type: "AS",
|
||||
Bandwidth: 2058,
|
||||
}},
|
||||
Attributes: []psdp.Attribute{
|
||||
{
|
||||
Key: "rtpmap",
|
||||
Value: "96 H264/90000",
|
||||
},
|
||||
{
|
||||
Key: "range",
|
||||
Value: "npt=0-",
|
||||
},
|
||||
{
|
||||
Key: "control",
|
||||
Value: "rtsp://192.168.1.44:554/video/live00_0",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
MediaName: psdp.MediaName{
|
||||
Media: "audio",
|
||||
Protos: []string{"RTP", "AVP"},
|
||||
Formats: []string{"8"},
|
||||
},
|
||||
Bandwidth: []psdp.Bandwidth{{
|
||||
Type: "AS",
|
||||
Bandwidth: 64,
|
||||
}},
|
||||
Attributes: []psdp.Attribute{
|
||||
{
|
||||
Key: "rtpmap",
|
||||
Value: "8 PCMA/8000",
|
||||
},
|
||||
{
|
||||
Key: "control",
|
||||
Value: "rtsp://192.168.1.44:554/audio/live00_0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user