Skip to content

Commit

Permalink
fix compatibility with Mercury cameras (#271) (#275)
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed May 8, 2023
1 parent a54a594 commit 49d0d56
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 13 deletions.
4 changes: 4 additions & 0 deletions pkg/auth/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func sha256Base64(in string) string {
}

// Validator allows to validate credentials generated by a Sender.
//
// Deprecated: Validator{} has been replaced by Validate()
type Validator struct {
user string
Expand All @@ -40,6 +41,7 @@ type Validator struct {

// NewValidator allocates a Validator.
// If methods is nil, the Basic and Digest methods are used.
//
// Deprecated: Validator{} has been replaced by Validate()
func NewValidator(user string, pass string, methods []headers.AuthMethod) *Validator {
if methods == nil {
Expand Down Expand Up @@ -80,6 +82,7 @@ func NewValidator(user string, pass string, methods []headers.AuthMethod) *Valid

// Header generates the WWW-Authenticate header needed by a client to
// authenticate.
//
// Deprecated: Validator{} has been replaced by Validate()
func (va *Validator) Header() base.HeaderValue {
var ret base.HeaderValue
Expand All @@ -103,6 +106,7 @@ func (va *Validator) Header() base.HeaderValue {
}

// ValidateRequest validates a request sent by a client.
//
// Deprecated: Validator{} has been replaced by Validate()
func (va *Validator) ValidateRequest(req *base.Request, baseURL *url.URL) error {
var auth headers.Authorization
Expand Down
9 changes: 6 additions & 3 deletions pkg/media/media.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package media
import (
"fmt"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
Expand All @@ -14,6 +15,8 @@ import (
"github.com/bluenviron/gortsplib/v3/pkg/url"
)

var smartRegexp = regexp.MustCompile("^([0-9]+) (.*?)/90000")

func getControlAttribute(attributes []psdp.Attribute) string {
for _, attr := range attributes {
if attr.Key == "control" {
Expand Down Expand Up @@ -135,9 +138,9 @@ func (m *Media) unmarshal(md *psdp.MediaDescription) error {
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]
sm := smartRegexp.FindStringSubmatch(attr.Value)
if sm != nil {
payloadType = sm[1]
break
}
}
Expand Down
34 changes: 31 additions & 3 deletions pkg/media/medias_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,19 +522,19 @@ var casesMedias = []struct {
"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" +
"m=application/TP-LINK 0 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" +
"m=application/TP-LINK 0 RTP/AVP 95\r\n" +
"a=control\r\n" +
"a=rtpmap:95 TP-LINK/90000\r\n",
Medias{
{
Type: "application",
Type: "application/TP-LINK",
Formats: []formats.Format{&formats.Generic{
PayloadTyp: 95,
RTPMa: "TP-LINK/90000",
Expand All @@ -543,6 +543,34 @@ var casesMedias = []struct {
},
},
},
{
"mercury",
"v=0\n" +
"o=- 14665860 31787219 1 IN IP4 192.168.0.60\n" +
"s=Session streamed by \"MERCURY RTSP Server\"\n" +
"t=0 0\n" +
"a=smart_encoder:virtualIFrame=1\n" +
"m=application/MERCURY 0 RTP/AVP smart/1/90000\n" +
"a=rtpmap:95 MERCURY/90000\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/MERCURY 0 RTP/AVP 95\r\n" +
"a=control\r\n" +
"a=rtpmap:95 MERCURY/90000\r\n",
Medias{
{
Type: "application/MERCURY",
Formats: []formats.Format{&formats.Generic{
PayloadTyp: 95,
RTPMa: "MERCURY/90000",
ClockRat: 90000,
}},
},
},
},
{
"h264 with space at end",
"v=0\r\n" +
Expand Down
9 changes: 4 additions & 5 deletions pkg/sdp/sdp.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,14 +406,13 @@ func (s *SessionDescription) unmarshalMediaDescription(value string) error {

newMediaDesc := &psdp.MediaDescription{}

if fields[0] == "application/TP-LINK" {
fields[0] = "application"
}

// <media>
// Set according to currently registered with IANA
// https://tools.ietf.org/html/rfc4566#section-5.14
if i := indexOf(fields[0], []string{"audio", "video", "text", "application", "message"}); i == -1 {
if fields[0] != "video" &&
fields[0] != "audio" &&
fields[0] != "application" &&
!strings.HasPrefix(fields[0], "application/") {
return fmt.Errorf("%w `%v`", errSDPInvalidValue, fields[0])
}
newMediaDesc.MediaName.Media = fields[0]
Expand Down
136 changes: 134 additions & 2 deletions pkg/sdp/sdp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1876,7 +1876,7 @@ var cases = []struct {
"m=audio 0 RTP/AVP 8\r\n" +
"a=rtpmap:8 PCMA/8000\r\n" +
"a=control:track2\r\n" +
"m=application 0 RTP/AVP smart/1/90000\r\n" +
"m=application/TP-LINK 0 RTP/AVP smart/1/90000\r\n" +
"a=rtpmap:95 TP-LINK/90000\r\n" +
"a=control:track3\r\n"),
SessionDescription{
Expand Down Expand Up @@ -1945,7 +1945,7 @@ var cases = []struct {
},
{
MediaName: psdp.MediaName{
Media: "application",
Media: "application/TP-LINK",
Protos: []string{"RTP", "AVP"},
Formats: []string{"smart/1/90000"},
},
Expand Down Expand Up @@ -2215,6 +2215,138 @@ var cases = []struct {
},
},
},
{
"mercury",
[]byte("v=0\n" +
"o=- 14665860 31787219 1 IN IP4 192.168.0.60\n" +
"s=Session streamed by \"MERCURY RTSP Server\"\n" +
"t=0 0\n" +
"a=smart_encoder:virtualIFrame=1\n" +
"m=video 0 RTP/AVP 96\n" +
"c=IN IP4 0.0.0.0\n" +
"b=AS:4096\n" +
"a=range:npt=0-\n" +
"a=control:track1\n" +
"a=rtpmap:96 H264/90000\n" +
"a=fmtp:96 packetization-mode=1; profile-level-id=4D001F;" +
" sprop-parameter-sets=J00AH+dAKALdgKUFBQXwAAADABAAAAMCi2gD6AXf//wK,KO48gA==\n" +
"m=audio 0 RTP/AVP 8\n" +
"a=rtpmap:8 PCMA/8000\n" +
"a=control:track2\n" +
"m=application/MERCURY 0 RTP/AVP smart/1/90000\n" +
"a=rtpmap:95 MERCURY/90000\n" +
"a=control:track3\n"),
[]byte("v=0\r\n" +
"o=- 14665860 31787219 1 IN IP4 192.168.0.60\r\n" +
"s=Session streamed by \"MERCURY RTSP Server\"\r\n" +
"t=0 0\r\n" +
"a=smart_encoder:virtualIFrame=1\r\n" +
"m=video 0 RTP/AVP 96\r\n" +
"c=IN IP4 0.0.0.0\r\n" +
"b=AS:4096\r\n" +
"a=range:npt=0-\r\n" +
"a=control:track1\r\n" +
"a=rtpmap:96 H264/90000\r\n" +
"a=fmtp:96 packetization-mode=1; profile-level-id=4D001F;" +
" sprop-parameter-sets=J00AH+dAKALdgKUFBQXwAAADABAAAAMCi2gD6AXf//wK,KO48gA==\r\n" +
"m=audio 0 RTP/AVP 8\r\n" +
"a=rtpmap:8 PCMA/8000\r\n" +
"a=control:track2\r\n" +
"m=application/MERCURY 0 RTP/AVP smart/1/90000\r\n" +
"a=rtpmap:95 MERCURY/90000\r\n" +
"a=control:track3\r\n"),
SessionDescription{
Origin: psdp.Origin{
Username: "- 14665860",
SessionID: 31787219,
SessionVersion: 1,
NetworkType: "IN",
AddressType: "IP4",
UnicastAddress: "192.168.0.60",
},
SessionName: "Session streamed by \"MERCURY RTSP Server\"",
TimeDescriptions: []psdp.TimeDescription{{}},
Attributes: []psdp.Attribute{
{
Key: "smart_encoder",
Value: "virtualIFrame=1",
},
},
MediaDescriptions: []*psdp.MediaDescription{
{
MediaName: psdp.MediaName{
Media: "video",
Protos: []string{"RTP", "AVP"},
Formats: []string{"96"},
},
ConnectionInformation: &psdp.ConnectionInformation{
NetworkType: "IN",
AddressType: "IP4",
Address: &psdp.Address{
Address: "0.0.0.0",
},
},
Bandwidth: []psdp.Bandwidth{{
Type: "AS",
Bandwidth: 4096,
}},
Attributes: []psdp.Attribute{
{
Key: "range",
Value: "npt=0-",
},
{
Key: "control",
Value: "track1",
},
{
Key: "rtpmap",
Value: "96 H264/90000",
},
{
Key: "fmtp",
Value: "96 packetization-mode=1; profile-level-id=4D001F;" +
" sprop-parameter-sets=J00AH+dAKALdgKUFBQXwAAADABAAAAMCi2gD6AXf//wK,KO48gA==",
},
},
},
{
MediaName: psdp.MediaName{
Media: "audio",
Protos: []string{"RTP", "AVP"},
Formats: []string{"8"},
},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "8 PCMA/8000",
},
{
Key: "control",
Value: "track2",
},
},
},
{
MediaName: psdp.MediaName{
Media: "application/MERCURY",
Protos: []string{"RTP", "AVP"},
Formats: []string{"smart/1/90000"},
},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "95 MERCURY/90000",
},
{
Key: "control",
Value: "track3",
},
},
},
},
},
},
}

func TestUnmarshal(t *testing.T) {
Expand Down

0 comments on commit 49d0d56

Please sign in to comment.