mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 15:16:51 +08:00
104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
package gortsplib
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
psdp "github.com/pion/sdp/v3"
|
|
|
|
"github.com/aler9/gortsplib/pkg/base"
|
|
)
|
|
|
|
// Track is a RTSP track.
|
|
type Track interface {
|
|
// ClockRate returns the track clock rate.
|
|
ClockRate() int
|
|
// GetControl returns the track control.
|
|
GetControl() string
|
|
// SetControl sets the track control.
|
|
SetControl(string)
|
|
// MediaDescription returns the media description in SDP format.
|
|
MediaDescription() *psdp.MediaDescription
|
|
clone() Track
|
|
url(*base.URL) (*base.URL, error)
|
|
}
|
|
|
|
func newTrackFromMediaDescription(md *psdp.MediaDescription) (Track, error) {
|
|
if rtpmap, ok := md.Attribute("rtpmap"); ok {
|
|
rtpmap = strings.TrimSpace(rtpmap)
|
|
|
|
if rtpmapParts := strings.Split(rtpmap, " "); len(rtpmapParts) == 2 {
|
|
tmp, err := strconv.ParseInt(rtpmapParts[0], 10, 64)
|
|
if err == nil {
|
|
payloadType := uint8(tmp)
|
|
|
|
switch {
|
|
case md.MediaName.Media == "video":
|
|
if rtpmapParts[1] == "H264/90000" {
|
|
return newTrackH264FromMediaDescription(payloadType, md)
|
|
}
|
|
|
|
case md.MediaName.Media == "audio":
|
|
switch {
|
|
case strings.HasPrefix(strings.ToLower(rtpmapParts[1]), "mpeg4-generic/"):
|
|
return newTrackAACFromMediaDescription(payloadType, md)
|
|
|
|
case strings.HasPrefix(rtpmapParts[1], "opus/"):
|
|
return newTrackOpusFromMediaDescription(payloadType, rtpmapParts[1], md)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return newTrackGenericFromMediaDescription(md)
|
|
}
|
|
|
|
func trackFindControl(md *psdp.MediaDescription) string {
|
|
for _, attr := range md.Attributes {
|
|
if attr.Key == "control" {
|
|
return attr.Value
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func trackURL(t Track, contentBase *base.URL) (*base.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 := base.ParseURL(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, _ := base.ParseURL(strURL + control)
|
|
return ur, nil
|
|
}
|