Skip to content

Commit

Permalink
support tracks without clock rate
Browse files Browse the repository at this point in the history
  • Loading branch information
aler9 committed Nov 27, 2022
1 parent f16cb17 commit d521a78
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 118 deletions.
2 changes: 1 addition & 1 deletion client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@ func (c *Client) doDescribe(u *url.URL) (Tracks, *url.URL, *base.Response, error
}

var tracks Tracks
sd, err := tracks.Unmarshal(res.Body, true)
sd, err := tracks.Unmarshal(res.Body)
if err != nil {
return nil, nil, nil, err
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/rtcpreceiver/rtcpreceiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func (rr *RTCPReceiver) report(ts time.Time) rtcp.Packet {
return nil
}

if rr.clockRate == 0 {
return nil
}

report := &rtcp.ReceiverReport{
SSRC: rr.receiverSSRC,
Reports: []rtcp.ReceptionReport{
Expand Down
4 changes: 4 additions & 0 deletions pkg/rtcpsender/rtcpsender.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ func (rs *RTCPSender) report(ts time.Time) rtcp.Packet {
return nil
}

if rs.clockRate == 0 {
return nil
}

return &rtcp.SenderReport{
SSRC: *rs.senderSSRC,
NTPTime: func() uint64 {
Expand Down
2 changes: 1 addition & 1 deletion serversession.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ func (ss *ServerSession) handleRequest(sc *ServerConn, req *base.Request) (*base
}

var tracks Tracks
_, err = tracks.Unmarshal(req.Body, false)
_, err = tracks.Unmarshal(req.Body)
if err != nil {
return &base.Response{
StatusCode: base.StatusBadRequest,
Expand Down
10 changes: 7 additions & 3 deletions serverstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,20 @@ func (st *ServerStream) rtpInfo(trackID int, now time.Time) (uint16, uint32, boo
return 0, 0, false
}

clockRate := st.tracks[trackID].ClockRate()
if clockRate == 0 {
return 0, 0, false
}

// sequence number of the first packet of the stream
seq := track.lastSequenceNumber + 1

// RTP timestamp corresponding to the time value in
// the Range response header.
// remove a small quantity in order to avoid DTS > PTS
cr := st.tracks[trackID].ClockRate()
ts := uint32(uint64(track.lastTimeRTP) +
uint64(now.Sub(track.lastTimeNTP).Seconds()*float64(cr)) -
uint64(cr)/10)
uint64(now.Sub(track.lastTimeNTP).Seconds()*float64(clockRate)) -
uint64(clockRate)/10)

return seq, ts, true
}
Expand Down
7 changes: 1 addition & 6 deletions track_generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,7 @@ func newTrackGenericFromMediaDescription(

// Init initializes a TrackGeneric
func (t *TrackGeneric) Init() error {
var err error
t.clockRate, err = findClockRate(t)
if err != nil {
return fmt.Errorf("unable to get clock rate: %s", err)
}

t.clockRate, _ = findClockRate(t)
return nil
}

Expand Down
64 changes: 1 addition & 63 deletions track_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,68 +599,6 @@ func TestTrackNewFromMediaDescriptionErrors(t *testing.T) {
},
"no media formats found",
},
{
"no rtpmap",
&psdp.MediaDescription{
MediaName: psdp.MediaName{
Media: "video",
Protos: []string{"RTP", "AVP"},
Formats: []string{"90"},
},
},
"unable to get clock rate: attribute 'rtpmap' not found",
},
{
"invalid clockrate 1",
&psdp.MediaDescription{
MediaName: psdp.MediaName{
Media: "video",
Protos: []string{"RTP", "AVP"},
Formats: []string{"96"},
},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "97 mpeg4-generic/48000/2",
},
},
},
"unable to get clock rate: attribute 'rtpmap' not found",
},
{
"invalid clockrate 2",
&psdp.MediaDescription{
MediaName: psdp.MediaName{
Media: "video",
Protos: []string{"RTP", "AVP"},
Formats: []string{"96"},
},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "96 mpeg4-generic",
},
},
},
"unable to get clock rate: invalid rtpmap (mpeg4-generic)",
},
{
"invalid clockrate 3",
&psdp.MediaDescription{
MediaName: psdp.MediaName{
Media: "video",
Protos: []string{"RTP", "AVP"},
Formats: []string{"96"},
},
Attributes: []psdp.Attribute{
{
Key: "rtpmap",
Value: "96 mpeg4-generic/aa",
},
},
},
"unable to get clock rate: strconv.ParseInt: parsing \"aa\": invalid syntax",
},
{
"aac missing fmtp",
&psdp.MediaDescription{
Expand Down Expand Up @@ -966,7 +904,7 @@ func TestTrackURL(t *testing.T) {
} {
t.Run(ca.name, func(t *testing.T) {
var tracks Tracks
_, err := tracks.Unmarshal(ca.sdp, false)
_, err := tracks.Unmarshal(ca.sdp)
require.NoError(t, err)
ur, err := tracks[0].url(ca.baseURL)
require.NoError(t, err)
Expand Down
7 changes: 1 addition & 6 deletions tracks.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package gortsplib
import (
"fmt"
"strconv"
"strings"

psdp "github.com/pion/sdp/v3"

Expand All @@ -14,7 +13,7 @@ import (
type Tracks []Track

// Unmarshal decodes tracks from the SDP format. It returns the decoded SDP.
func (ts *Tracks) Unmarshal(byts []byte, skipGenericTracksWithoutClockRate bool) (*sdp.SessionDescription, error) {
func (ts *Tracks) Unmarshal(byts []byte) (*sdp.SessionDescription, error) {
var sd sdp.SessionDescription
err := sd.Unmarshal(byts)
if err != nil {
Expand All @@ -26,10 +25,6 @@ func (ts *Tracks) Unmarshal(byts []byte, skipGenericTracksWithoutClockRate bool)
for i, md := range sd.MediaDescriptions {
t, err := newTrackFromMediaDescription(md)
if err != nil {
if skipGenericTracksWithoutClockRate &&
strings.HasPrefix(err.Error(), "unable to get clock rate") {
continue
}
return nil, fmt.Errorf("unable to parse track %d: %s", i+1, err)
}

Expand Down
82 changes: 44 additions & 38 deletions tracks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestTracksReadErrors(t *testing.T) {
for _, ca := range []struct {
name string
sdp []byte
err string
}{
{
"invalid SDP",
[]byte{0x00, 0x01},
"invalid line: (\x00\x01)",
},
{
"invalid track",
[]byte("v=0\r\n" +
"o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" +
"s=SDP Seminar\r\n" +
"m=video 0 RTP/AVP/TCP 96\r\n" +
"a=rtpmap:96 H265/90000\r\n" +
"a=fmtp:96 sprop-vps=QAEMAf//AWAAAAMAsAAAAwAAAwB4FwJA; " +
"sprop-sps=QgEBAWAAAAMAsAAAAwAAAwB4oAKggC8c1YgXuRZFL/y5/E/qbgQEBAE=; sprop-pps=RAHAcvBTJA==;\r\n" +
"a=control:streamid=0\r\n" +
"m=audio 0 RTP/AVP/TCP 97\r\n" +
"a=rtpmap:97 mpeg4-generic/44100/2\r\n" +
"a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=zzz1210\r\n" +
"a=control:streamid=1\r\n"),
"unable to parse track 2: invalid AAC config (zzz1210)",
},
} {
t.Run(ca.name, func(t *testing.T) {
var tracks Tracks
_, err := tracks.Unmarshal(ca.sdp, false)
require.EqualError(t, err, ca.err)
})
}
}

func TestTracksReadSkipGenericTracksWithoutClockRate(t *testing.T) {
func TestTracksRead(t *testing.T) {
sdp := []byte("v=0\r\n" +
"o=- 0 0 IN IP4 10.0.0.131\r\n" +
"s=Media Presentation\r\n" +
Expand All @@ -69,7 +33,7 @@ func TestTracksReadSkipGenericTracksWithoutClockRate(t *testing.T) {
"b=AS:8\r\n")

var tracks Tracks
_, err := tracks.Unmarshal(sdp, true)
_, err := tracks.Unmarshal(sdp)
require.NoError(t, err)
require.Equal(t, Tracks{
&TrackH264{
Expand All @@ -87,5 +51,47 @@ func TestTracksReadSkipGenericTracksWithoutClockRate(t *testing.T) {
control: "rtsp://10.0.100.50/profile5/media.smp/trackID=a",
},
},
&TrackGeneric{
Media: "application",
Payloads: []TrackGenericPayload{{
Type: 107,
}},
},
}, tracks)
}

func TestTracksReadErrors(t *testing.T) {
for _, ca := range []struct {
name string
sdp []byte
err string
}{
{
"invalid SDP",
[]byte{0x00, 0x01},
"invalid line: (\x00\x01)",
},
{
"invalid track",
[]byte("v=0\r\n" +
"o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" +
"s=SDP Seminar\r\n" +
"m=video 0 RTP/AVP/TCP 96\r\n" +
"a=rtpmap:96 H265/90000\r\n" +
"a=fmtp:96 sprop-vps=QAEMAf//AWAAAAMAsAAAAwAAAwB4FwJA; " +
"sprop-sps=QgEBAWAAAAMAsAAAAwAAAwB4oAKggC8c1YgXuRZFL/y5/E/qbgQEBAE=; sprop-pps=RAHAcvBTJA==;\r\n" +
"a=control:streamid=0\r\n" +
"m=audio 0 RTP/AVP/TCP 97\r\n" +
"a=rtpmap:97 mpeg4-generic/44100/2\r\n" +
"a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=zzz1210\r\n" +
"a=control:streamid=1\r\n"),
"unable to parse track 2: invalid AAC config (zzz1210)",
},
} {
t.Run(ca.name, func(t *testing.T) {
var tracks Tracks
_, err := tracks.Unmarshal(ca.sdp)
require.EqualError(t, err, ca.err)
})
}
}

0 comments on commit d521a78

Please sign in to comment.