mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 23:26:54 +08:00
rewrite unmarshaling interface and tests of formats (#238)
This commit is contained in:
@@ -2,59 +2,18 @@
|
|||||||
package formats
|
package formats
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
psdp "github.com/pion/sdp/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getFormatAttribute(attributes []psdp.Attribute, payloadType uint8, key string) string {
|
|
||||||
for _, attr := range attributes {
|
|
||||||
if attr.Key == key {
|
|
||||||
v := strings.TrimSpace(attr.Value)
|
|
||||||
if parts := strings.SplitN(v, " ", 2); len(parts) == 2 {
|
|
||||||
if tmp, err := strconv.ParseInt(parts[0], 10, 8); err == nil && uint8(tmp) == payloadType {
|
|
||||||
return parts[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCodecAndClock(rtpMap string) (string, string) {
|
func getCodecAndClock(rtpMap string) (string, string) {
|
||||||
parts2 := strings.SplitN(rtpMap, "/", 2)
|
parts2 := strings.SplitN(rtpMap, "/", 2)
|
||||||
if len(parts2) != 2 {
|
if len(parts2) != 2 {
|
||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return parts2[0], parts2[1]
|
return strings.ToLower(parts2[0]), parts2[1]
|
||||||
}
|
|
||||||
|
|
||||||
func decodeFMTP(enc string) map[string]string {
|
|
||||||
if enc == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ret := make(map[string]string)
|
|
||||||
|
|
||||||
for _, kv := range strings.Split(enc, ";") {
|
|
||||||
kv = strings.Trim(kv, " ")
|
|
||||||
|
|
||||||
if len(kv) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp := strings.SplitN(kv, "=", 2)
|
|
||||||
if len(tmp) != 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
ret[strings.ToLower(tmp[0])] = tmp[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format is a RTP format of a media.
|
// Format is a RTP format of a media.
|
||||||
@@ -79,31 +38,12 @@ type Format interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal decodes a format from a media description.
|
// Unmarshal decodes a format from a media description.
|
||||||
func Unmarshal(md *psdp.MediaDescription, payloadTypeStr string) (Format, error) {
|
func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[string]string) (Format, error) {
|
||||||
if payloadTypeStr == "smart/1/90000" {
|
|
||||||
attr, ok := md.Attribute("rtpmap")
|
|
||||||
if ok {
|
|
||||||
i := strings.Index(attr, " TP-LINK/90000")
|
|
||||||
if i >= 0 {
|
|
||||||
payloadTypeStr = attr[:i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp, err := strconv.ParseInt(payloadTypeStr, 10, 8)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
payloadType := uint8(tmp)
|
|
||||||
|
|
||||||
rtpMap := getFormatAttribute(md.Attributes, payloadType, "rtpmap")
|
|
||||||
codec, clock := getCodecAndClock(rtpMap)
|
codec, clock := getCodecAndClock(rtpMap)
|
||||||
codec = strings.ToLower(codec)
|
|
||||||
fmtp := decodeFMTP(getFormatAttribute(md.Attributes, payloadType, "fmtp"))
|
|
||||||
|
|
||||||
format := func() Format {
|
format := func() Format {
|
||||||
switch {
|
switch {
|
||||||
case md.MediaName.Media == "video":
|
case mediaType == "video":
|
||||||
switch {
|
switch {
|
||||||
case payloadType == 26:
|
case payloadType == 26:
|
||||||
return &MJPEG{}
|
return &MJPEG{}
|
||||||
@@ -127,7 +67,7 @@ func Unmarshal(md *psdp.MediaDescription, payloadTypeStr string) (Format, error)
|
|||||||
return &VP9{}
|
return &VP9{}
|
||||||
}
|
}
|
||||||
|
|
||||||
case md.MediaName.Media == "audio":
|
case mediaType == "audio":
|
||||||
switch {
|
switch {
|
||||||
case payloadType == 0, payloadType == 8:
|
case payloadType == 0, payloadType == 8:
|
||||||
return &G711{}
|
return &G711{}
|
||||||
@@ -158,7 +98,7 @@ func Unmarshal(md *psdp.MediaDescription, payloadTypeStr string) (Format, error)
|
|||||||
return &Generic{}
|
return &Generic{}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = format.unmarshal(payloadType, clock, codec, rtpMap, fmtp)
|
err := format.unmarshal(payloadType, clock, codec, rtpMap, fmtp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -22,26 +22,6 @@ func TestG711Attributes(t *testing.T) {
|
|||||||
require.Equal(t, uint8(0), format.PayloadType())
|
require.Equal(t, uint8(0), format.PayloadType())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestG711MediaDescription(t *testing.T) {
|
|
||||||
t.Run("pcma", func(t *testing.T) {
|
|
||||||
format := &G711{}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "PCMA/8000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string(nil), fmtp)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("pcmu", func(t *testing.T) {
|
|
||||||
format := &G711{
|
|
||||||
MULaw: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "PCMU/8000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string(nil), fmtp)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestG711DecEncoder(t *testing.T) {
|
func TestG711DecEncoder(t *testing.T) {
|
||||||
format := &G711{}
|
format := &G711{}
|
||||||
|
|
||||||
|
@@ -15,14 +15,6 @@ func TestG722Attributes(t *testing.T) {
|
|||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestG722MediaDescription(t *testing.T) {
|
|
||||||
format := &G722{}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "G722/8000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string(nil), fmtp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestG722DecEncoder(t *testing.T) {
|
func TestG722DecEncoder(t *testing.T) {
|
||||||
format := &G722{}
|
format := &G722{}
|
||||||
|
|
||||||
|
@@ -26,27 +26,3 @@ func TestGenericAttributes(t *testing.T) {
|
|||||||
require.Equal(t, uint8(98), format.PayloadType())
|
require.Equal(t, uint8(98), format.PayloadType())
|
||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenericMediaDescription(t *testing.T) {
|
|
||||||
format := &Generic{
|
|
||||||
PayloadTyp: 98,
|
|
||||||
RTPMap: "H265/90000",
|
|
||||||
FMTP: map[string]string{
|
|
||||||
"profile-id": "1",
|
|
||||||
"sprop-vps": "QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ",
|
|
||||||
"sprop-sps": "QgEBAWAAAAMAAAMAAAMAAAMAlqADwIAQ5Za5JMmuWcBSSgAAB9AAAHUwgkA=",
|
|
||||||
"sprop-pps": "RAHgdrAwxmQ=",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err := format.Init()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "H265/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"profile-id": "1",
|
|
||||||
"sprop-vps": "QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ",
|
|
||||||
"sprop-sps": "QgEBAWAAAAMAAAMAAAMAAAMAlqADwIAQ5Za5JMmuWcBSSgAAB9AAAHUwgkA=",
|
|
||||||
"sprop-pps": "RAHgdrAwxmQ=",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
@@ -45,44 +45,6 @@ func TestH264PTSEqualsDTS(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestH264MediaDescription(t *testing.T) {
|
|
||||||
t.Run("standard", func(t *testing.T) {
|
|
||||||
format := &H264{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
SPS: []byte{
|
|
||||||
0x67, 0x64, 0x00, 0x0c, 0xac, 0x3b, 0x50, 0xb0,
|
|
||||||
0x4b, 0x42, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00,
|
|
||||||
0x00, 0x03, 0x00, 0x3d, 0x08,
|
|
||||||
},
|
|
||||||
PPS: []byte{
|
|
||||||
0x68, 0xee, 0x3c, 0x80,
|
|
||||||
},
|
|
||||||
PacketizationMode: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "H264/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"packetization-mode": "1",
|
|
||||||
"sprop-parameter-sets": "Z2QADKw7ULBLQgAAAwACAAADAD0I,aO48gA==",
|
|
||||||
"profile-level-id": "64000C",
|
|
||||||
}, fmtp)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("no sps/pps", func(t *testing.T) {
|
|
||||||
format := &H264{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
PacketizationMode: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "H264/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"packetization-mode": "1",
|
|
||||||
}, fmtp)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestH264DecEncoder(t *testing.T) {
|
func TestH264DecEncoder(t *testing.T) {
|
||||||
format := &H264{}
|
format := &H264{}
|
||||||
|
|
||||||
|
@@ -32,23 +32,6 @@ func TestH265Attributes(t *testing.T) {
|
|||||||
require.Equal(t, []byte{0x0B, 0x0C}, pps)
|
require.Equal(t, []byte{0x0B, 0x0C}, pps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestH265MediaDescription(t *testing.T) {
|
|
||||||
format := &H265{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
VPS: []byte{0x01, 0x02},
|
|
||||||
SPS: []byte{0x03, 0x04},
|
|
||||||
PPS: []byte{0x05, 0x06},
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "H265/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"sprop-vps": "AQI=",
|
|
||||||
"sprop-sps": "AwQ=",
|
|
||||||
"sprop-pps": "BQY=",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestH265DecEncoder(t *testing.T) {
|
func TestH265DecEncoder(t *testing.T) {
|
||||||
format := &H265{}
|
format := &H265{}
|
||||||
|
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
package formats
|
package formats
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/pion/rtp"
|
"github.com/pion/rtp"
|
||||||
@@ -22,23 +20,6 @@ func TestLPCMAttributes(t *testing.T) {
|
|||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLPCMMediaDescription(t *testing.T) {
|
|
||||||
for _, ca := range []int{8, 16, 24} {
|
|
||||||
t.Run(strconv.FormatInt(int64(ca), 10), func(t *testing.T) {
|
|
||||||
format := &LPCM{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
BitDepth: ca,
|
|
||||||
SampleRate: 96000,
|
|
||||||
ChannelCount: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, fmt.Sprintf("L%d/96000/2", ca), rtpmap)
|
|
||||||
require.Equal(t, map[string]string(nil), fmtp)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLPCMDecEncoder(t *testing.T) {
|
func TestLPCMDecEncoder(t *testing.T) {
|
||||||
format := &LPCM{
|
format := &LPCM{
|
||||||
PayloadTyp: 96,
|
PayloadTyp: 96,
|
||||||
|
@@ -15,14 +15,6 @@ func TestMJPEGAttributes(t *testing.T) {
|
|||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMJPEGMediaDescription(t *testing.T) {
|
|
||||||
format := &MJPEG{}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "JPEG/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string(nil), fmtp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMJPEGDecEncoder(t *testing.T) {
|
func TestMJPEGDecEncoder(t *testing.T) {
|
||||||
format := &MJPEG{}
|
format := &MJPEG{}
|
||||||
|
|
||||||
|
@@ -14,11 +14,3 @@ func TestMPEG2AudioAttributes(t *testing.T) {
|
|||||||
require.Equal(t, uint8(14), format.PayloadType())
|
require.Equal(t, uint8(14), format.PayloadType())
|
||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMPEG2AudioMediaDescription(t *testing.T) {
|
|
||||||
format := &MPEG2Audio{}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "", rtpmap)
|
|
||||||
require.Equal(t, map[string]string(nil), fmtp)
|
|
||||||
}
|
|
||||||
|
@@ -14,11 +14,3 @@ func TestMPEG2VideoAttributes(t *testing.T) {
|
|||||||
require.Equal(t, uint8(32), format.PayloadType())
|
require.Equal(t, uint8(32), format.PayloadType())
|
||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMPEG2VideoMediaDescription(t *testing.T) {
|
|
||||||
format := &MPEG2Video{}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "", rtpmap)
|
|
||||||
require.Equal(t, map[string]string(nil), fmtp)
|
|
||||||
}
|
|
||||||
|
@@ -27,31 +27,6 @@ func TestMPEG4AudioGenericAttributes(t *testing.T) {
|
|||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMPEG4AudioGenericMediaDescription(t *testing.T) {
|
|
||||||
format := &MPEG4AudioGeneric{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
Config: &mpeg4audio.Config{
|
|
||||||
Type: mpeg4audio.ObjectTypeAACLC,
|
|
||||||
SampleRate: 48000,
|
|
||||||
ChannelCount: 2,
|
|
||||||
},
|
|
||||||
SizeLength: 13,
|
|
||||||
IndexLength: 3,
|
|
||||||
IndexDeltaLength: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "mpeg4-generic/48000/2", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"profile-level-id": "1",
|
|
||||||
"mode": "AAC-hbr",
|
|
||||||
"sizelength": "13",
|
|
||||||
"indexlength": "3",
|
|
||||||
"indexdeltalength": "3",
|
|
||||||
"config": "1190",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMPEG4AudioGenericDecEncoder(t *testing.T) {
|
func TestMPEG4AudioGenericDecEncoder(t *testing.T) {
|
||||||
format := &MPEG4AudioGeneric{
|
format := &MPEG4AudioGeneric{
|
||||||
PayloadTyp: 96,
|
PayloadTyp: 96,
|
||||||
|
@@ -147,7 +147,7 @@ func (f *MPEG4AudioLATM) Marshal() (string, map[string]string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f.SBREnabled != nil {
|
if f.SBREnabled != nil {
|
||||||
if *f.CPresent {
|
if *f.SBREnabled {
|
||||||
fmtp["SBR-enabled"] = "1"
|
fmtp["SBR-enabled"] = "1"
|
||||||
} else {
|
} else {
|
||||||
fmtp["SBR-enabled"] = "0"
|
fmtp["SBR-enabled"] = "0"
|
||||||
|
@@ -21,22 +21,3 @@ func TestMPEG4AudioLATMAttributes(t *testing.T) {
|
|||||||
require.Equal(t, uint8(96), format.PayloadType())
|
require.Equal(t, uint8(96), format.PayloadType())
|
||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMPEG4AudioLATMMediaDescription(t *testing.T) {
|
|
||||||
format := &MPEG4AudioLATM{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
SampleRate: 48000,
|
|
||||||
Channels: 2,
|
|
||||||
Object: 2,
|
|
||||||
ProfileLevelID: 1,
|
|
||||||
Config: []byte{0x01, 0x02, 0x03},
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "MP4A-LATM/48000/2", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"profile-level-id": "1",
|
|
||||||
"object": "2",
|
|
||||||
"config": "010203",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
@@ -18,18 +18,3 @@ func TestMPEG4VideoESAttributes(t *testing.T) {
|
|||||||
require.Equal(t, uint8(96), format.PayloadType())
|
require.Equal(t, uint8(96), format.PayloadType())
|
||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMPEG4VideoESMediaDescription(t *testing.T) {
|
|
||||||
format := &MPEG4VideoES{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
ProfileLevelID: 1,
|
|
||||||
Config: []byte{0x0a, 0x0b, 0x03},
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "MP4V-ES/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"profile-level-id": "1",
|
|
||||||
"config": "0A0B03",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
@@ -43,18 +43,12 @@ func (f *Opus) unmarshal(payloadType uint8, clock string, codec string, rtpmap s
|
|||||||
}
|
}
|
||||||
|
|
||||||
sampleRate, err := strconv.ParseInt(tmp[0], 10, 64)
|
sampleRate, err := strconv.ParseInt(tmp[0], 10, 64)
|
||||||
if err != nil {
|
if err != nil || sampleRate != 48000 {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if sampleRate != 48000 {
|
|
||||||
return fmt.Errorf("invalid sample rate: %d", sampleRate)
|
return fmt.Errorf("invalid sample rate: %d", sampleRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
channelCount, err := strconv.ParseInt(tmp[1], 10, 64)
|
channelCount, err := strconv.ParseInt(tmp[1], 10, 64)
|
||||||
if err != nil {
|
if err != nil || channelCount != 2 {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if channelCount != 2 {
|
|
||||||
return fmt.Errorf("invalid channel count: %d", channelCount)
|
return fmt.Errorf("invalid channel count: %d", channelCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,19 +18,6 @@ func TestOpusAttributes(t *testing.T) {
|
|||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpusMediaDescription(t *testing.T) {
|
|
||||||
format := &Opus{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
IsStereo: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "opus/48000/2", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"sprop-stereo": "1",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOpusDecEncoder(t *testing.T) {
|
func TestOpusDecEncoder(t *testing.T) {
|
||||||
format := &Opus{}
|
format := &Opus{}
|
||||||
|
|
||||||
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalH264/708789f132a57d65
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalH264/708789f132a57d65
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0,")
|
||||||
|
string("0")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalH264/85649d45641911d0
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalH264/85649d45641911d0
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0")
|
||||||
|
string("")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalH264/d0410f4fd49cc1b8
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalH264/d0410f4fd49cc1b8
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string(",0")
|
||||||
|
string("0")
|
5
pkg/formats/testdata/fuzz/FuzzUnmarshalH265/09376da4826c9233
vendored
Normal file
5
pkg/formats/testdata/fuzz/FuzzUnmarshalH265/09376da4826c9233
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("A")
|
5
pkg/formats/testdata/fuzz/FuzzUnmarshalH265/63e3b0a8cb682bdf
vendored
Normal file
5
pkg/formats/testdata/fuzz/FuzzUnmarshalH265/63e3b0a8cb682bdf
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0")
|
||||||
|
string("0")
|
||||||
|
string("")
|
||||||
|
string("0")
|
5
pkg/formats/testdata/fuzz/FuzzUnmarshalH265/fae5e048802aad6c
vendored
Normal file
5
pkg/formats/testdata/fuzz/FuzzUnmarshalH265/fae5e048802aad6c
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("0")
|
||||||
|
string("")
|
2
pkg/formats/testdata/fuzz/FuzzUnmarshalLPCM/4e36b64da83067c2
vendored
Normal file
2
pkg/formats/testdata/fuzz/FuzzUnmarshalLPCM/4e36b64da83067c2
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0/")
|
2
pkg/formats/testdata/fuzz/FuzzUnmarshalLPCM/e9e3ffbe3b3a072c
vendored
Normal file
2
pkg/formats/testdata/fuzz/FuzzUnmarshalLPCM/e9e3ffbe3b3a072c
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("A")
|
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/2898e764696b0420
vendored
Normal file
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/2898e764696b0420
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0")
|
||||||
|
string("\xc9u\xb9")
|
||||||
|
string("\x94\xe3ȿJ\xcai\xd5\xee\xc0\xff\xff\x00\x00O\x96a\xdb\x04\x01y\xc8@")
|
||||||
|
string("d\x00\x00\x00")
|
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/47164857eaf9f343
vendored
Normal file
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/47164857eaf9f343
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0")
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("0")
|
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/6775f71697eec2db
vendored
Normal file
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/6775f71697eec2db
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("0")
|
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/76b36b8b3c310afb
vendored
Normal file
5
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioGeneric/76b36b8b3c310afb
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("\f3r\x05\x00\xe7\xe8")
|
||||||
|
string("2\xf5\xe13")
|
||||||
|
string("7")
|
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/3570da660901e702
vendored
Normal file
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/3570da660901e702
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("%20")
|
||||||
|
string("")
|
||||||
|
string("oc\x97\xf3V\x8e\xe0")
|
||||||
|
string("")
|
||||||
|
string("\x0f\x11")
|
||||||
|
string("Z")
|
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/400020fb8be5431f
vendored
Normal file
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/400020fb8be5431f
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("0")
|
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/b95227f0e71f8fa1
vendored
Normal file
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/b95227f0e71f8fa1
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("oc\x97\xf3V\x8e\xe0")
|
||||||
|
string("")
|
||||||
|
string("9A")
|
||||||
|
string("X")
|
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/c440c66d0e8a2f04
vendored
Normal file
7
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4AudioLATM/c440c66d0e8a2f04
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("oc\x97\xf3V\x8e\xe0")
|
||||||
|
string("")
|
||||||
|
string("\x0f\x11")
|
||||||
|
string("0")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4VideoES/00e15d22123489fd
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4VideoES/00e15d22123489fd
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0")
|
||||||
|
string("0")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4VideoES/aa424148ecba23f1
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalMPEG4VideoES/aa424148ecba23f1
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("A")
|
||||||
|
string("")
|
2
pkg/formats/testdata/fuzz/FuzzUnmarshalOpus/771e938e4458e983
vendored
Normal file
2
pkg/formats/testdata/fuzz/FuzzUnmarshalOpus/771e938e4458e983
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0")
|
2
pkg/formats/testdata/fuzz/FuzzUnmarshalOpus/9cd9b70960b4a733
vendored
Normal file
2
pkg/formats/testdata/fuzz/FuzzUnmarshalOpus/9cd9b70960b4a733
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("/")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVP8/85649d45641911d0
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVP8/85649d45641911d0
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0")
|
||||||
|
string("")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVP8/aa424148ecba23f1
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVP8/aa424148ecba23f1
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("A")
|
||||||
|
string("")
|
4
pkg/formats/testdata/fuzz/FuzzUnmarshalVP9/4c51a06c202d48d0
vendored
Normal file
4
pkg/formats/testdata/fuzz/FuzzUnmarshalVP9/4c51a06c202d48d0
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("1")
|
||||||
|
string("")
|
||||||
|
string("#")
|
4
pkg/formats/testdata/fuzz/FuzzUnmarshalVP9/54e9dd922dda87eb
vendored
Normal file
4
pkg/formats/testdata/fuzz/FuzzUnmarshalVP9/54e9dd922dda87eb
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("1")
|
4
pkg/formats/testdata/fuzz/FuzzUnmarshalVP9/671f05b72e69d643
vendored
Normal file
4
pkg/formats/testdata/fuzz/FuzzUnmarshalVP9/671f05b72e69d643
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("")
|
||||||
|
string("")
|
||||||
|
string("0")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVorbis/199c2c84b007b8d1
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVorbis/199c2c84b007b8d1
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("/")
|
||||||
|
string("0")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVorbis/1e2e9f272753060b
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVorbis/1e2e9f272753060b
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0/0")
|
||||||
|
string("0")
|
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVorbis/70149aff1d6b6142
vendored
Normal file
3
pkg/formats/testdata/fuzz/FuzzUnmarshalVorbis/70149aff1d6b6142
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
go test fuzz v1
|
||||||
|
string("0/")
|
||||||
|
string("0")
|
@@ -57,7 +57,7 @@ func (f *Vorbis) unmarshal(payloadType uint8, clock string, codec string, rtpmap
|
|||||||
if key == "configuration" {
|
if key == "configuration" {
|
||||||
conf, err := base64.StdEncoding.DecodeString(val)
|
conf, err := base64.StdEncoding.DecodeString(val)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid AAC config (%v)", val)
|
return fmt.Errorf("invalid config: %v", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Configuration = conf
|
f.Configuration = conf
|
||||||
|
@@ -19,18 +19,3 @@ func TestVorbisAttributes(t *testing.T) {
|
|||||||
require.Equal(t, uint8(96), format.PayloadType())
|
require.Equal(t, uint8(96), format.PayloadType())
|
||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVorbisMediaDescription(t *testing.T) {
|
|
||||||
format := &Vorbis{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
SampleRate: 48000,
|
|
||||||
ChannelCount: 2,
|
|
||||||
Configuration: []byte{0x01, 0x02, 0x03, 0x04},
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "VORBIS/48000/2", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"configuration": "AQIDBA==",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
@@ -40,16 +40,18 @@ func (f *VP8) unmarshal(payloadType uint8, clock string, codec string, rtpmap st
|
|||||||
case "max-fr":
|
case "max-fr":
|
||||||
n, err := strconv.ParseUint(val, 10, 64)
|
n, err := strconv.ParseUint(val, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid max-fr (%v)", val)
|
return fmt.Errorf("invalid max-fr: %v", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 := int(n)
|
v2 := int(n)
|
||||||
f.MaxFR = &v2
|
f.MaxFR = &v2
|
||||||
|
|
||||||
case "max-fs":
|
case "max-fs":
|
||||||
n, err := strconv.ParseUint(val, 10, 64)
|
n, err := strconv.ParseUint(val, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid max-fs (%v)", val)
|
return fmt.Errorf("invalid max-fs: %v", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 := int(n)
|
v2 := int(n)
|
||||||
f.MaxFS = &v2
|
f.MaxFS = &v2
|
||||||
}
|
}
|
||||||
@@ -61,9 +63,11 @@ func (f *VP8) unmarshal(payloadType uint8, clock string, codec string, rtpmap st
|
|||||||
// Marshal implements Format.
|
// Marshal implements Format.
|
||||||
func (f *VP8) Marshal() (string, map[string]string) {
|
func (f *VP8) Marshal() (string, map[string]string) {
|
||||||
fmtp := make(map[string]string)
|
fmtp := make(map[string]string)
|
||||||
|
|
||||||
if f.MaxFR != nil {
|
if f.MaxFR != nil {
|
||||||
fmtp["max-fr"] = strconv.FormatInt(int64(*f.MaxFR), 10)
|
fmtp["max-fr"] = strconv.FormatInt(int64(*f.MaxFR), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.MaxFS != nil {
|
if f.MaxFS != nil {
|
||||||
fmtp["max-fs"] = strconv.FormatInt(int64(*f.MaxFS), 10)
|
fmtp["max-fs"] = strconv.FormatInt(int64(*f.MaxFS), 10)
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package formats
|
package formats //nolint:dupl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@@ -17,23 +17,6 @@ func TestVP8ttributes(t *testing.T) {
|
|||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVP8MediaDescription(t *testing.T) {
|
|
||||||
maxFR := 123
|
|
||||||
maxFS := 456
|
|
||||||
format := &VP8{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
MaxFR: &maxFR,
|
|
||||||
MaxFS: &maxFS,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "VP8/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"max-fr": "123",
|
|
||||||
"max-fs": "456",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVP8DecEncoder(t *testing.T) {
|
func TestVP8DecEncoder(t *testing.T) {
|
||||||
format := &VP8{}
|
format := &VP8{}
|
||||||
|
|
||||||
|
@@ -41,24 +41,27 @@ func (f *VP9) unmarshal(payloadType uint8, clock string, codec string, rtpmap st
|
|||||||
case "max-fr":
|
case "max-fr":
|
||||||
n, err := strconv.ParseUint(val, 10, 64)
|
n, err := strconv.ParseUint(val, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid max-fr (%v)", val)
|
return fmt.Errorf("invalid max-fr: %v", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 := int(n)
|
v2 := int(n)
|
||||||
f.MaxFR = &v2
|
f.MaxFR = &v2
|
||||||
|
|
||||||
case "max-fs":
|
case "max-fs":
|
||||||
n, err := strconv.ParseUint(val, 10, 64)
|
n, err := strconv.ParseUint(val, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid max-fs (%v)", val)
|
return fmt.Errorf("invalid max-fs: %v", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 := int(n)
|
v2 := int(n)
|
||||||
f.MaxFS = &v2
|
f.MaxFS = &v2
|
||||||
|
|
||||||
case "profile-id":
|
case "profile-id":
|
||||||
n, err := strconv.ParseUint(val, 10, 64)
|
n, err := strconv.ParseUint(val, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid profile-id (%v)", val)
|
return fmt.Errorf("invalid profile-id: %v", val)
|
||||||
}
|
}
|
||||||
|
|
||||||
v2 := int(n)
|
v2 := int(n)
|
||||||
f.ProfileID = &v2
|
f.ProfileID = &v2
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package formats
|
package formats //nolint:dupl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
@@ -17,26 +17,6 @@ func TestVP9Attributes(t *testing.T) {
|
|||||||
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVP9MediaDescription(t *testing.T) {
|
|
||||||
maxFR := 123
|
|
||||||
maxFS := 456
|
|
||||||
profileID := 789
|
|
||||||
format := &VP9{
|
|
||||||
PayloadTyp: 96,
|
|
||||||
MaxFR: &maxFR,
|
|
||||||
MaxFS: &maxFS,
|
|
||||||
ProfileID: &profileID,
|
|
||||||
}
|
|
||||||
|
|
||||||
rtpmap, fmtp := format.Marshal()
|
|
||||||
require.Equal(t, "VP9/90000", rtpmap)
|
|
||||||
require.Equal(t, map[string]string{
|
|
||||||
"max-fr": "123",
|
|
||||||
"max-fs": "456",
|
|
||||||
"profile-id": "789",
|
|
||||||
}, fmtp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVP9DecEncoder(t *testing.T) {
|
func TestVP9DecEncoder(t *testing.T) {
|
||||||
format := &VP9{}
|
format := &VP9{}
|
||||||
|
|
||||||
|
@@ -39,6 +39,45 @@ func getDirection(attributes []psdp.Attribute) Direction {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getFormatAttribute(attributes []psdp.Attribute, payloadType uint8, key string) string {
|
||||||
|
for _, attr := range attributes {
|
||||||
|
if attr.Key == key {
|
||||||
|
v := strings.TrimSpace(attr.Value)
|
||||||
|
if parts := strings.SplitN(v, " ", 2); len(parts) == 2 {
|
||||||
|
if tmp, err := strconv.ParseInt(parts[0], 10, 8); err == nil && uint8(tmp) == payloadType {
|
||||||
|
return parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeFMTP(enc string) map[string]string {
|
||||||
|
if enc == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := make(map[string]string)
|
||||||
|
|
||||||
|
for _, kv := range strings.Split(enc, ";") {
|
||||||
|
kv = strings.Trim(kv, " ")
|
||||||
|
|
||||||
|
if len(kv) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp := strings.SplitN(kv, "=", 2)
|
||||||
|
if len(tmp) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[strings.ToLower(tmp[0])] = tmp[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
// Direction is the direction of a media stream.
|
// Direction is the direction of a media stream.
|
||||||
type Direction string
|
type Direction string
|
||||||
|
|
||||||
@@ -82,7 +121,28 @@ func (m *Media) unmarshal(md *psdp.MediaDescription) error {
|
|||||||
|
|
||||||
m.Formats = nil
|
m.Formats = nil
|
||||||
for _, payloadType := range md.MediaName.Formats {
|
for _, payloadType := range md.MediaName.Formats {
|
||||||
format, err := formats.Unmarshal(md, payloadType)
|
if payloadType == "smart/1/90000" {
|
||||||
|
for _, attr := range md.Attributes {
|
||||||
|
if attr.Key == "rtpmap" {
|
||||||
|
i := strings.Index(attr.Value, " TP-LINK/90000")
|
||||||
|
if i >= 0 {
|
||||||
|
payloadType = attr.Value[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp, err := strconv.ParseInt(payloadType, 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
payloadTypeInt := uint8(tmp)
|
||||||
|
|
||||||
|
rtpMap := getFormatAttribute(md.Attributes, payloadTypeInt, "rtpmap")
|
||||||
|
fmtp := decodeFMTP(getFormatAttribute(md.Attributes, payloadTypeInt, "fmtp"))
|
||||||
|
|
||||||
|
format, err := formats.Unmarshal(string(m.Type), payloadTypeInt, rtpMap, fmtp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@@ -516,6 +516,63 @@ var casesMedias = []struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"tp-link",
|
||||||
|
"v=0\r\n" +
|
||||||
|
"o=- 4158123474391860926 2 IN IP4 127.0.0.1\r\n" +
|
||||||
|
"s=-\r\n" +
|
||||||
|
"t=0 0\r\n" +
|
||||||
|
"m=application 42504 RTP/AVP smart/1/90000\r\n" +
|
||||||
|
"a=rtpmap:95 TP-LINK/90000\r\n",
|
||||||
|
"v=0\r\n" +
|
||||||
|
"o=- 0 0 IN IP4 127.0.0.1\r\n" +
|
||||||
|
"s=Stream\r\n" +
|
||||||
|
"c=IN IP4 0.0.0.0\r\n" +
|
||||||
|
"t=0 0\r\n" +
|
||||||
|
"m=application 0 RTP/AVP 95\r\n" +
|
||||||
|
"a=control\r\n" +
|
||||||
|
"a=rtpmap:95 TP-LINK/90000\r\n",
|
||||||
|
Medias{
|
||||||
|
{
|
||||||
|
Type: "application",
|
||||||
|
Formats: []formats.Format{&formats.Generic{
|
||||||
|
PayloadTyp: 95,
|
||||||
|
RTPMap: "TP-LINK/90000",
|
||||||
|
ClockRat: 90000,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"h264 with space at end",
|
||||||
|
"v=0\r\n" +
|
||||||
|
"o=- 4158123474391860926 2 IN IP4 127.0.0.1\r\n" +
|
||||||
|
"s=-\r\n" +
|
||||||
|
"t=0 0\r\n" +
|
||||||
|
"m=video 42504 RTP/AVP 96\r\n" +
|
||||||
|
"a=rtpmap:96 H264/90000 \r\n" +
|
||||||
|
"a=fmtp:96 packetization-mode=1\r\n",
|
||||||
|
"v=0\r\n" +
|
||||||
|
"o=- 0 0 IN IP4 127.0.0.1\r\n" +
|
||||||
|
"s=Stream\r\n" +
|
||||||
|
"c=IN IP4 0.0.0.0\r\n" +
|
||||||
|
"t=0 0\r\n" +
|
||||||
|
"m=video 0 RTP/AVP 96\r\n" +
|
||||||
|
"a=control\r\n" +
|
||||||
|
"a=rtpmap:96 H264/90000\r\n" +
|
||||||
|
"a=fmtp:96 packetization-mode=1\r\n",
|
||||||
|
Medias{
|
||||||
|
{
|
||||||
|
Type: "video",
|
||||||
|
Formats: []formats.Format{
|
||||||
|
&formats.H264{
|
||||||
|
PayloadTyp: 96,
|
||||||
|
PacketizationMode: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMediasUnmarshal(t *testing.T) {
|
func TestMediasUnmarshal(t *testing.T) {
|
||||||
|
Reference in New Issue
Block a user