mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 07:06:58 +08:00
125 lines
2.6 KiB
Go
125 lines
2.6 KiB
Go
package gortsplib
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
psdp "github.com/pion/sdp/v3"
|
|
)
|
|
|
|
// TrackConfigH264 is the configuration of an H264 track.
|
|
type TrackConfigH264 struct {
|
|
SPS []byte
|
|
PPS []byte
|
|
}
|
|
|
|
// NewTrackH264 initializes an H264 track.
|
|
func NewTrackH264(payloadType uint8, conf *TrackConfigH264) (*Track, error) {
|
|
if len(conf.SPS) < 4 {
|
|
return nil, fmt.Errorf("invalid SPS")
|
|
}
|
|
|
|
spropParameterSets := base64.StdEncoding.EncodeToString(conf.SPS) +
|
|
"," + base64.StdEncoding.EncodeToString(conf.PPS)
|
|
profileLevelID := strings.ToUpper(hex.EncodeToString(conf.SPS[1:4]))
|
|
|
|
typ := strconv.FormatInt(int64(payloadType), 10)
|
|
|
|
return &Track{
|
|
Media: &psdp.MediaDescription{
|
|
MediaName: psdp.MediaName{
|
|
Media: "video",
|
|
Protos: []string{"RTP", "AVP"},
|
|
Formats: []string{typ},
|
|
},
|
|
Attributes: []psdp.Attribute{
|
|
{
|
|
Key: "rtpmap",
|
|
Value: typ + " H264/90000",
|
|
},
|
|
{
|
|
Key: "fmtp",
|
|
Value: typ + " packetization-mode=1; " +
|
|
"sprop-parameter-sets=" + spropParameterSets + "; " +
|
|
"profile-level-id=" + profileLevelID,
|
|
},
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// IsH264 checks whether the track is an H264 track.
|
|
func (t *Track) IsH264() bool {
|
|
if t.Media.MediaName.Media != "video" {
|
|
return false
|
|
}
|
|
|
|
v, ok := t.Media.Attribute("rtpmap")
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
v = strings.TrimSpace(v)
|
|
vals := strings.Split(v, " ")
|
|
if len(vals) != 2 {
|
|
return false
|
|
}
|
|
|
|
return vals[1] == "H264/90000"
|
|
}
|
|
|
|
// ExtractConfigH264 extracts the configuration of an H264 track.
|
|
func (t *Track) ExtractConfigH264() (*TrackConfigH264, error) {
|
|
v, ok := t.Media.Attribute("fmtp")
|
|
if !ok {
|
|
return nil, fmt.Errorf("fmtp attribute is missing")
|
|
}
|
|
|
|
tmp := strings.SplitN(v, " ", 2)
|
|
if len(tmp) != 2 {
|
|
return nil, fmt.Errorf("invalid fmtp attribute (%v)", v)
|
|
}
|
|
|
|
for _, kv := range strings.Split(tmp[1], ";") {
|
|
kv = strings.Trim(kv, " ")
|
|
|
|
if len(kv) == 0 {
|
|
continue
|
|
}
|
|
|
|
tmp := strings.SplitN(kv, "=", 2)
|
|
if len(tmp) != 2 {
|
|
return nil, fmt.Errorf("invalid fmtp attribute (%v)", v)
|
|
}
|
|
|
|
if tmp[0] == "sprop-parameter-sets" {
|
|
tmp := strings.SplitN(tmp[1], ",", 2)
|
|
if len(tmp) != 2 {
|
|
return nil, fmt.Errorf("invalid sprop-parameter-sets (%v)", v)
|
|
}
|
|
|
|
sps, err := base64.StdEncoding.DecodeString(tmp[0])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid sprop-parameter-sets (%v)", v)
|
|
}
|
|
|
|
pps, err := base64.StdEncoding.DecodeString(tmp[1])
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid sprop-parameter-sets (%v)", v)
|
|
}
|
|
|
|
conf := &TrackConfigH264{
|
|
SPS: sps,
|
|
PPS: pps,
|
|
}
|
|
|
|
return conf, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("sprop-parameter-sets is missing (%v)", v)
|
|
}
|