mirror of
https://github.com/aler9/gortsplib
synced 2025-10-04 23:02:45 +08:00
Merge branch 'main' into v4
This commit is contained in:
@@ -18,10 +18,10 @@ type AV1 struct {
|
|||||||
Tier *int
|
Tier *int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *AV1) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error {
|
func (f *AV1) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "level-idx":
|
case "level-idx":
|
||||||
n, err := strconv.ParseUint(val, 10, 31)
|
n, err := strconv.ParseUint(val, 10, 31)
|
||||||
|
@@ -16,10 +16,19 @@ func getCodecAndClock(rtpMap string) (string, string) {
|
|||||||
return strings.ToLower(parts2[0]), parts2[1]
|
return strings.ToLower(parts2[0]), parts2[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type unmarshalContext struct {
|
||||||
|
mediaType string
|
||||||
|
payloadType uint8
|
||||||
|
clock string
|
||||||
|
codec string
|
||||||
|
rtpMap string
|
||||||
|
fmtp map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
// Format is a media format.
|
// Format is a media format.
|
||||||
// It defines the payload type of RTP packets and how to encode/decode them.
|
// It defines the payload type of RTP packets and how to encode/decode them.
|
||||||
type Format interface {
|
type Format interface {
|
||||||
unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error
|
unmarshal(ctx *unmarshalContext) error
|
||||||
|
|
||||||
// Codec returns the codec name.
|
// Codec returns the codec name.
|
||||||
Codec() string
|
Codec() string
|
||||||
@@ -46,8 +55,8 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri
|
|||||||
|
|
||||||
format := func() Format {
|
format := func() Format {
|
||||||
switch {
|
switch {
|
||||||
case mediaType == "video":
|
// video
|
||||||
switch {
|
|
||||||
case payloadType == 26:
|
case payloadType == 26:
|
||||||
return &MJPEG{}
|
return &MJPEG{}
|
||||||
|
|
||||||
@@ -74,10 +83,9 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri
|
|||||||
|
|
||||||
case codec == "av1" && clock == "90000":
|
case codec == "av1" && clock == "90000":
|
||||||
return &AV1{}
|
return &AV1{}
|
||||||
}
|
|
||||||
|
|
||||||
case mediaType == "audio":
|
// audio
|
||||||
switch {
|
|
||||||
case payloadType == 0, payloadType == 8:
|
case payloadType == 0, payloadType == 8:
|
||||||
return &G711{}
|
return &G711{}
|
||||||
|
|
||||||
@@ -115,12 +123,18 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri
|
|||||||
case codec == "opus":
|
case codec == "opus":
|
||||||
return &Opus{}
|
return &Opus{}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return &Generic{}
|
return &Generic{}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err := format.unmarshal(payloadType, clock, codec, rtpMap, fmtp)
|
err := format.unmarshal(&unmarshalContext{
|
||||||
|
mediaType: mediaType,
|
||||||
|
payloadType: payloadType,
|
||||||
|
clock: clock,
|
||||||
|
codec: codec,
|
||||||
|
rtpMap: rtpMap,
|
||||||
|
fmtp: fmtp,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -890,19 +890,6 @@ var casesFormat = []struct {
|
|||||||
"custom",
|
"custom",
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"application invalid rtpmap 2",
|
|
||||||
"application",
|
|
||||||
98,
|
|
||||||
"custom/aaa",
|
|
||||||
nil,
|
|
||||||
&Generic{
|
|
||||||
PayloadTyp: 98,
|
|
||||||
RTPMa: "custom/aaa",
|
|
||||||
},
|
|
||||||
"custom/aaa",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshal(t *testing.T) {
|
func TestUnmarshal(t *testing.T) {
|
||||||
@@ -925,7 +912,13 @@ func TestMarshal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalMPEG4AudioGenericErrors(t *testing.T) {
|
func TestUnmarshalErrors(t *testing.T) {
|
||||||
|
t.Run("invalid video", func(t *testing.T) {
|
||||||
|
_, err := Unmarshal("video", 96, "", map[string]string{})
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("mpeg-4 audio generic", func(t *testing.T) {
|
||||||
_, err := Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{
|
_, err := Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{
|
||||||
"streamtype": "10",
|
"streamtype": "10",
|
||||||
})
|
})
|
||||||
@@ -981,9 +974,9 @@ func TestUnmarshalMPEG4AudioGenericErrors(t *testing.T) {
|
|||||||
"indexdeltalength": "3",
|
"indexdeltalength": "3",
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
})
|
||||||
|
|
||||||
func TestUnmarshalMPEG4AudioLATMErrors(t *testing.T) {
|
t.Run("mpeg-4 audio latm", func(t *testing.T) {
|
||||||
_, err := Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{
|
_, err := Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{
|
||||||
"profile-level-id": "aaa",
|
"profile-level-id": "aaa",
|
||||||
})
|
})
|
||||||
@@ -1011,9 +1004,9 @@ func TestUnmarshalMPEG4AudioLATMErrors(t *testing.T) {
|
|||||||
"sbr-enabled": "1",
|
"sbr-enabled": "1",
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
})
|
||||||
|
|
||||||
func TestUnmarshalAV1Errors(t *testing.T) {
|
t.Run("av1", func(t *testing.T) {
|
||||||
_, err := Unmarshal("video", 96, "AV1/90000", map[string]string{
|
_, err := Unmarshal("video", 96, "AV1/90000", map[string]string{
|
||||||
"level-idx": "aaa",
|
"level-idx": "aaa",
|
||||||
})
|
})
|
||||||
@@ -1028,6 +1021,7 @@ func TestUnmarshalAV1Errors(t *testing.T) {
|
|||||||
"tier": "aaa",
|
"tier": "aaa",
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func FuzzUnmarshalH264(f *testing.F) {
|
func FuzzUnmarshalH264(f *testing.F) {
|
||||||
|
@@ -13,8 +13,8 @@ type G711 struct {
|
|||||||
MULaw bool
|
MULaw bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *G711) unmarshal(payloadType uint8, _ string, _ string, _ string, _ map[string]string) error {
|
func (f *G711) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.MULaw = (payloadType == 0)
|
f.MULaw = (ctx.payloadType == 0)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc3551
|
// Specification: https://datatracker.ietf.org/doc/html/rfc3551
|
||||||
type G722 struct{}
|
type G722 struct{}
|
||||||
|
|
||||||
func (f *G722) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error {
|
func (f *G722) unmarshal(_ *unmarshalContext) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,19 +15,19 @@ type G726 struct {
|
|||||||
BigEndian bool
|
BigEndian bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *G726) unmarshal(payloadType uint8, _ string, codec string, _ string, _ map[string]string) error {
|
func (f *G726) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
if strings.HasPrefix(codec, "aal2-") {
|
if strings.HasPrefix(ctx.codec, "aal2-") {
|
||||||
f.BigEndian = true
|
f.BigEndian = true
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasSuffix(codec, "-16"):
|
case strings.HasSuffix(ctx.codec, "-16"):
|
||||||
f.BitRate = 16
|
f.BitRate = 16
|
||||||
case strings.HasSuffix(codec, "-24"):
|
case strings.HasSuffix(ctx.codec, "-24"):
|
||||||
f.BitRate = 24
|
f.BitRate = 24
|
||||||
case strings.HasSuffix(codec, "-32"):
|
case strings.HasSuffix(ctx.codec, "-32"):
|
||||||
f.BitRate = 32
|
f.BitRate = 32
|
||||||
default:
|
default:
|
||||||
f.BitRate = 40
|
f.BitRate = 40
|
||||||
|
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func findClockRate(payloadType uint8, rtpMap string) (int, error) {
|
func findClockRate(payloadType uint8, rtpMap string, isApplication bool) (int, error) {
|
||||||
// get clock rate from payload type
|
// get clock rate from payload type
|
||||||
// https://en.wikipedia.org/wiki/RTP_payload_formats
|
// https://en.wikipedia.org/wiki/RTP_payload_formats
|
||||||
switch payloadType {
|
switch payloadType {
|
||||||
@@ -34,21 +34,23 @@ func findClockRate(payloadType uint8, rtpMap string) (int, error) {
|
|||||||
// get clock rate from rtpmap
|
// get clock rate from rtpmap
|
||||||
// https://tools.ietf.org/html/rfc4566
|
// https://tools.ietf.org/html/rfc4566
|
||||||
// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
|
// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
|
||||||
if rtpMap == "" {
|
if rtpMap != "" {
|
||||||
return 0, fmt.Errorf("attribute 'rtpmap' not found")
|
if tmp := strings.Split(rtpMap, "/"); len(tmp) >= 2 {
|
||||||
}
|
|
||||||
|
|
||||||
tmp := strings.Split(rtpMap, "/")
|
|
||||||
if len(tmp) != 2 && len(tmp) != 3 {
|
|
||||||
return 0, fmt.Errorf("invalid rtpmap (%v)", rtpMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
v, err := strconv.ParseUint(tmp[1], 10, 31)
|
v, err := strconv.ParseUint(tmp[1], 10, 31)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return int(v), nil
|
return int(v), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// application format without clock rate.
|
||||||
|
// do not throw an error, but return zero, that disables RTCP sender and receiver reports.
|
||||||
|
if isApplication || rtpMap != "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf("clock rate not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic is a generic RTP format.
|
// Generic is a generic RTP format.
|
||||||
@@ -63,16 +65,19 @@ type Generic struct {
|
|||||||
|
|
||||||
// Init computes the clock rate of the format. It is mandatory to call it.
|
// Init computes the clock rate of the format. It is mandatory to call it.
|
||||||
func (f *Generic) Init() error {
|
func (f *Generic) Init() error {
|
||||||
f.ClockRat, _ = findClockRate(f.PayloadTyp, f.RTPMa)
|
var err error
|
||||||
return nil
|
f.ClockRat, err = findClockRate(f.PayloadTyp, f.RTPMa, true)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Generic) unmarshal(payloadType uint8, _ string, _ string, rtpmap string, fmtp map[string]string) error {
|
func (f *Generic) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
f.RTPMa = rtpmap
|
f.RTPMa = ctx.rtpMap
|
||||||
f.FMT = fmtp
|
f.FMT = ctx.fmtp
|
||||||
|
|
||||||
return f.Init()
|
var err error
|
||||||
|
f.ClockRat, err = findClockRate(f.PayloadTyp, f.RTPMa, ctx.mediaType == "application")
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Codec implements Format.
|
// Codec implements Format.
|
||||||
|
@@ -25,10 +25,10 @@ type H264 struct {
|
|||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *H264) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error {
|
func (f *H264) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "sprop-parameter-sets":
|
case "sprop-parameter-sets":
|
||||||
tmp := strings.Split(val, ",")
|
tmp := strings.Split(val, ",")
|
||||||
|
@@ -24,36 +24,36 @@ type H265 struct {
|
|||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *H265) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error {
|
func (f *H265) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "sprop-vps":
|
case "sprop-vps":
|
||||||
var err error
|
var err error
|
||||||
f.VPS, err = base64.StdEncoding.DecodeString(val)
|
f.VPS, err = base64.StdEncoding.DecodeString(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid sprop-vps (%v)", fmtp)
|
return fmt.Errorf("invalid sprop-vps (%v)", ctx.fmtp)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "sprop-sps":
|
case "sprop-sps":
|
||||||
var err error
|
var err error
|
||||||
f.SPS, err = base64.StdEncoding.DecodeString(val)
|
f.SPS, err = base64.StdEncoding.DecodeString(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid sprop-sps (%v)", fmtp)
|
return fmt.Errorf("invalid sprop-sps (%v)", ctx.fmtp)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "sprop-pps":
|
case "sprop-pps":
|
||||||
var err error
|
var err error
|
||||||
f.PPS, err = base64.StdEncoding.DecodeString(val)
|
f.PPS, err = base64.StdEncoding.DecodeString(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid sprop-pps (%v)", fmtp)
|
return fmt.Errorf("invalid sprop-pps (%v)", ctx.fmtp)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "sprop-max-don-diff":
|
case "sprop-max-don-diff":
|
||||||
tmp, err := strconv.ParseUint(val, 10, 31)
|
tmp, err := strconv.ParseUint(val, 10, 31)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid sprop-max-don-diff (%v)", fmtp)
|
return fmt.Errorf("invalid sprop-max-don-diff (%v)", ctx.fmtp)
|
||||||
}
|
}
|
||||||
f.MaxDONDiff = int(tmp)
|
f.MaxDONDiff = int(tmp)
|
||||||
}
|
}
|
||||||
|
@@ -18,10 +18,10 @@ type LPCM struct {
|
|||||||
ChannelCount int
|
ChannelCount int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *LPCM) unmarshal(payloadType uint8, clock string, codec string, _ string, _ map[string]string) error {
|
func (f *LPCM) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
switch codec {
|
switch ctx.codec {
|
||||||
case "l8":
|
case "l8":
|
||||||
f.BitDepth = 8
|
f.BitDepth = 8
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ func (f *LPCM) unmarshal(payloadType uint8, clock string, codec string, _ string
|
|||||||
f.BitDepth = 24
|
f.BitDepth = 24
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp := strings.SplitN(clock, "/", 2)
|
tmp := strings.SplitN(ctx.clock, "/", 2)
|
||||||
|
|
||||||
tmp1, err := strconv.ParseUint(tmp[0], 10, 31)
|
tmp1, err := strconv.ParseUint(tmp[0], 10, 31)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc2435
|
// Specification: https://datatracker.ietf.org/doc/html/rfc2435
|
||||||
type MJPEG struct{}
|
type MJPEG struct{}
|
||||||
|
|
||||||
func (f *MJPEG) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error {
|
func (f *MJPEG) unmarshal(_ *unmarshalContext) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import (
|
|||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
||||||
type MPEG1Audio struct{}
|
type MPEG1Audio struct{}
|
||||||
|
|
||||||
func (f *MPEG1Audio) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error {
|
func (f *MPEG1Audio) unmarshal(_ *unmarshalContext) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ import (
|
|||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
||||||
type MPEG1Video struct{}
|
type MPEG1Video struct{}
|
||||||
|
|
||||||
func (f *MPEG1Video) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error {
|
func (f *MPEG1Video) unmarshal(_ *unmarshalContext) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -26,13 +26,10 @@ type MPEG4AudioGeneric struct {
|
|||||||
IndexDeltaLength int
|
IndexDeltaLength int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *MPEG4AudioGeneric) unmarshal(
|
func (f *MPEG4AudioGeneric) unmarshal(ctx *unmarshalContext) error {
|
||||||
payloadType uint8, _ string, _ string,
|
f.PayloadTyp = ctx.payloadType
|
||||||
_ string, fmtp map[string]string,
|
|
||||||
) error {
|
|
||||||
f.PayloadTyp = payloadType
|
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "streamtype":
|
case "streamtype":
|
||||||
if val != "5" { // AudioStream in ISO 14496-1
|
if val != "5" { // AudioStream in ISO 14496-1
|
||||||
|
@@ -22,17 +22,14 @@ type MPEG4AudioLATM struct {
|
|||||||
SBREnabled *bool
|
SBREnabled *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *MPEG4AudioLATM) unmarshal(
|
func (f *MPEG4AudioLATM) unmarshal(ctx *unmarshalContext) error {
|
||||||
payloadType uint8, _ string, _ string,
|
f.PayloadTyp = ctx.payloadType
|
||||||
_ string, fmtp map[string]string,
|
|
||||||
) error {
|
|
||||||
f.PayloadTyp = payloadType
|
|
||||||
|
|
||||||
// default value set by specification
|
// default value set by specification
|
||||||
f.ProfileLevelID = 30
|
f.ProfileLevelID = 30
|
||||||
f.CPresent = true
|
f.CPresent = true
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "profile-level-id":
|
case "profile-level-id":
|
||||||
tmp, err := strconv.ParseUint(val, 10, 31)
|
tmp, err := strconv.ParseUint(val, 10, 31)
|
||||||
|
@@ -22,14 +22,11 @@ type MPEG4VideoES struct {
|
|||||||
Config []byte
|
Config []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *MPEG4VideoES) unmarshal(
|
func (f *MPEG4VideoES) unmarshal(ctx *unmarshalContext) error {
|
||||||
payloadType uint8, _ string, _ string,
|
f.PayloadTyp = ctx.payloadType
|
||||||
_ string, fmtp map[string]string,
|
f.ProfileLevelID = 1 // default value imposed by specification
|
||||||
) error {
|
|
||||||
f.PayloadTyp = payloadType
|
|
||||||
f.ProfileLevelID = 1 // default value defined by specification
|
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "profile-level-id":
|
case "profile-level-id":
|
||||||
tmp, err := strconv.ParseUint(val, 10, 31)
|
tmp, err := strconv.ParseUint(val, 10, 31)
|
||||||
|
@@ -8,7 +8,7 @@ import (
|
|||||||
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
// Specification: https://datatracker.ietf.org/doc/html/rfc2250
|
||||||
type MPEGTS struct{}
|
type MPEGTS struct{}
|
||||||
|
|
||||||
func (f *MPEGTS) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error {
|
func (f *MPEGTS) unmarshal(_ *unmarshalContext) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -17,12 +17,12 @@ type Opus struct {
|
|||||||
IsStereo bool
|
IsStereo bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Opus) unmarshal(payloadType uint8, clock string, _ string, _ string, fmtp map[string]string) error {
|
func (f *Opus) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
tmp := strings.SplitN(clock, "/", 2)
|
tmp := strings.SplitN(ctx.clock, "/", 2)
|
||||||
if len(tmp) != 2 {
|
if len(tmp) != 2 {
|
||||||
return fmt.Errorf("invalid clock (%v)", clock)
|
return fmt.Errorf("invalid clock (%v)", ctx.clock)
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleRate, err := strconv.ParseUint(tmp[0], 10, 31)
|
sampleRate, err := strconv.ParseUint(tmp[0], 10, 31)
|
||||||
@@ -35,7 +35,7 @@ func (f *Opus) unmarshal(payloadType uint8, clock string, _ string, _ string, fm
|
|||||||
return fmt.Errorf("invalid channel count: %d", channelCount)
|
return fmt.Errorf("invalid channel count: %d", channelCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
if key == "sprop-stereo" {
|
if key == "sprop-stereo" {
|
||||||
f.IsStereo = (val == "1")
|
f.IsStereo = (val == "1")
|
||||||
}
|
}
|
||||||
|
@@ -15,16 +15,16 @@ type Speex struct {
|
|||||||
VBR *bool
|
VBR *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Speex) unmarshal(payloadType uint8, clock string, _ string, _ string, fmtp map[string]string) error {
|
func (f *Speex) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
sampleRate, err := strconv.ParseUint(clock, 10, 31)
|
sampleRate, err := strconv.ParseUint(ctx.clock, 10, 31)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
f.SampleRate = int(sampleRate)
|
f.SampleRate = int(sampleRate)
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
if key == "vbr" {
|
if key == "vbr" {
|
||||||
if val != "on" && val != "off" {
|
if val != "on" && val != "off" {
|
||||||
return fmt.Errorf("invalid vbr value: %v", val)
|
return fmt.Errorf("invalid vbr value: %v", val)
|
||||||
|
@@ -18,12 +18,12 @@ type Vorbis struct {
|
|||||||
Configuration []byte
|
Configuration []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Vorbis) unmarshal(payloadType uint8, clock string, _ string, _ string, fmtp map[string]string) error {
|
func (f *Vorbis) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
tmp := strings.SplitN(clock, "/", 2)
|
tmp := strings.SplitN(ctx.clock, "/", 2)
|
||||||
if len(tmp) != 2 {
|
if len(tmp) != 2 {
|
||||||
return fmt.Errorf("invalid clock (%v)", clock)
|
return fmt.Errorf("invalid clock (%v)", ctx.clock)
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleRate, err := strconv.ParseUint(tmp[0], 10, 31)
|
sampleRate, err := strconv.ParseUint(tmp[0], 10, 31)
|
||||||
@@ -38,7 +38,7 @@ func (f *Vorbis) unmarshal(payloadType uint8, clock string, _ string, _ string,
|
|||||||
}
|
}
|
||||||
f.ChannelCount = int(channelCount)
|
f.ChannelCount = int(channelCount)
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
if key == "configuration" {
|
if key == "configuration" {
|
||||||
conf, err := base64.StdEncoding.DecodeString(val)
|
conf, err := base64.StdEncoding.DecodeString(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -17,10 +17,10 @@ type VP8 struct {
|
|||||||
MaxFS *int
|
MaxFS *int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *VP8) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error {
|
func (f *VP8) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "max-fr":
|
case "max-fr":
|
||||||
n, err := strconv.ParseUint(val, 10, 31)
|
n, err := strconv.ParseUint(val, 10, 31)
|
||||||
|
@@ -18,10 +18,10 @@ type VP9 struct {
|
|||||||
ProfileID *int
|
ProfileID *int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *VP9) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error {
|
func (f *VP9) unmarshal(ctx *unmarshalContext) error {
|
||||||
f.PayloadTyp = payloadType
|
f.PayloadTyp = ctx.payloadType
|
||||||
|
|
||||||
for key, val := range fmtp {
|
for key, val := range ctx.fmtp {
|
||||||
switch key {
|
switch key {
|
||||||
case "max-fr":
|
case "max-fr":
|
||||||
n, err := strconv.ParseUint(val, 10, 31)
|
n, err := strconv.ParseUint(val, 10, 31)
|
||||||
|
Reference in New Issue
Block a user