Files
gortsplib/track.go
2022-01-30 15:51:49 +01:00

110 lines
2.6 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
clone() Track
getControl() string
setControl(string)
url(*base.URL) (*base.URL, error)
mediaDescription() *psdp.MediaDescription
}
func newTrackFromMediaDescription(md *psdp.MediaDescription) (Track, error) {
if md.MediaName.Media == "video" {
if rtpmap, ok := md.Attribute("rtpmap"); ok {
rtpmap = strings.TrimSpace(rtpmap)
if vals := strings.Split(rtpmap, " "); len(vals) == 2 && vals[1] == "H264/90000" {
tmp, err := strconv.ParseInt(vals[0], 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid payload type '%s'", vals[0])
}
payloadType := uint8(tmp)
return newTrackH264FromMediaDescription(payloadType, md)
}
}
}
if md.MediaName.Media == "audio" {
if rtpmap, ok := md.Attribute("rtpmap"); ok {
if vals := strings.Split(rtpmap, " "); len(vals) == 2 {
tmp, err := strconv.ParseInt(vals[0], 10, 64)
if err != nil {
return nil, fmt.Errorf("invalid payload type '%s'", vals[0])
}
payloadType := uint8(tmp)
if strings.HasPrefix(strings.ToLower(vals[1]), "mpeg4-generic/") {
return newTrackAACFromMediaDescription(payloadType, md)
}
if strings.HasPrefix(vals[1], "opus/") {
return newTrackOpusFromMediaDescription(payloadType, 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("no Content-Base header 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
}