forked from bluenviron/gortsplib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrack.go
158 lines (123 loc) · 3.75 KB
/
track.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package gortsplib
import (
"fmt"
"strconv"
"strings"
psdp "github.com/pion/sdp/v3"
"github.com/cobalt-robotics/gortsplib/pkg/url"
)
// Track is a RTSP track.
type Track interface {
// ClockRate returns the track clock rate.
ClockRate() int
// GetControl returns the track control attribute.
GetControl() string
// SetControl sets the track control attribute.
SetControl(string)
// MediaDescription returns the track media description in SDP format.
MediaDescription() *psdp.MediaDescription
clone() Track
url(*url.URL) (*url.URL, error)
}
func newTrackFromMediaDescription(md *psdp.MediaDescription) (Track, error) {
control := func() string {
for _, attr := range md.Attributes {
if attr.Key == "control" {
return attr.Value
}
}
return ""
}()
rtpmapPart1, payloadType := func() (string, uint8) {
rtpmap, ok := md.Attribute("rtpmap")
if !ok {
return "", 0
}
rtpmap = strings.TrimSpace(rtpmap)
rtpmapParts := strings.Split(rtpmap, " ")
if len(rtpmapParts) != 2 {
return "", 0
}
tmp, err := strconv.ParseInt(rtpmapParts[0], 10, 64)
if err != nil {
return "", 0
}
payloadType := uint8(tmp)
return rtpmapParts[1], payloadType
}()
if len(md.MediaName.Formats) == 1 {
switch {
case md.MediaName.Media == "video":
switch {
case md.MediaName.Formats[0] == "26":
return newTrackJPEGFromMediaDescription(control)
case md.MediaName.Formats[0] == "32":
return newTrackMPEG2VideoFromMediaDescription(control)
case rtpmapPart1 == "H264/90000":
return newTrackH264FromMediaDescription(control, payloadType, md)
case rtpmapPart1 == "H265/90000":
return newTrackH265FromMediaDescription(control, payloadType, md)
case rtpmapPart1 == "VP8/90000":
return newTrackVP8FromMediaDescription(control, payloadType, md)
case rtpmapPart1 == "VP9/90000":
return newTrackVP9FromMediaDescription(control, payloadType, md)
}
case md.MediaName.Media == "audio":
switch {
case md.MediaName.Formats[0] == "0":
return newTrackPCMUFromMediaDescription(control, rtpmapPart1)
case md.MediaName.Formats[0] == "8":
return newTrackPCMAFromMediaDescription(control, rtpmapPart1)
case md.MediaName.Formats[0] == "14":
return newTrackMPEG2AudioFromMediaDescription(control)
case strings.HasPrefix(strings.ToLower(rtpmapPart1), "mpeg4-generic/"):
return newTrackMPEG4AudioFromMediaDescription(control, payloadType, md)
case strings.HasPrefix(rtpmapPart1, "opus/"):
return newTrackOpusFromMediaDescription(control, payloadType, rtpmapPart1, md)
}
}
}
return newTrackGenericFromMediaDescription(control, md)
}
type trackBase struct {
control string
}
// GetControl gets the track control attribute.
func (t *trackBase) GetControl() string {
return t.control
}
// SetControl sets the track control attribute.
func (t *trackBase) SetControl(c string) {
t.control = c
}
func (t *trackBase) url(contentBase *url.URL) (*url.URL, error) {
if contentBase == nil {
return nil, fmt.Errorf("Content-Base header not provided")
}
control := t.GetControl()
// no control attribute, use base URL
if control == "" {
return contentBase, nil
}
// control attribute contains an absolute path
if strings.HasPrefix(control, "rtsp://") {
ur, err := url.Parse(control)
if err != nil {
return nil, err
}
// copy host and credentials
ur.Host = contentBase.Host
ur.User = contentBase.User
return ur, nil
}
// control attribute contains a relative control attribute
// insert the control attribute at the end of the URL
// if there's a query, insert it after the query
// otherwise insert it after the path
strURL := contentBase.String()
if control[0] != '?' && !strings.HasSuffix(strURL, "/") {
strURL += "/"
}
ur, _ := url.Parse(strURL + control)
return ur, nil
}