mirror of
https://github.com/aler9/gortsplib
synced 2025-10-04 23:02:45 +08:00
client: parse incoming RTP/H264 packets; fix RTCP receiver jitter
This commit is contained in:
109
client.go
109
client.go
@@ -25,12 +25,14 @@ import (
|
|||||||
|
|
||||||
"github.com/aler9/gortsplib/pkg/auth"
|
"github.com/aler9/gortsplib/pkg/auth"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
|
"github.com/aler9/gortsplib/pkg/h264"
|
||||||
"github.com/aler9/gortsplib/pkg/headers"
|
"github.com/aler9/gortsplib/pkg/headers"
|
||||||
"github.com/aler9/gortsplib/pkg/liberrors"
|
"github.com/aler9/gortsplib/pkg/liberrors"
|
||||||
"github.com/aler9/gortsplib/pkg/multibuffer"
|
"github.com/aler9/gortsplib/pkg/multibuffer"
|
||||||
"github.com/aler9/gortsplib/pkg/ringbuffer"
|
"github.com/aler9/gortsplib/pkg/ringbuffer"
|
||||||
"github.com/aler9/gortsplib/pkg/rtcpreceiver"
|
"github.com/aler9/gortsplib/pkg/rtcpreceiver"
|
||||||
"github.com/aler9/gortsplib/pkg/rtcpsender"
|
"github.com/aler9/gortsplib/pkg/rtcpsender"
|
||||||
|
"github.com/aler9/gortsplib/pkg/rtph264"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -59,6 +61,7 @@ type clientTrack struct {
|
|||||||
tcpChannel int
|
tcpChannel int
|
||||||
rtcpReceiver *rtcpreceiver.RTCPReceiver
|
rtcpReceiver *rtcpreceiver.RTCPReceiver
|
||||||
rtcpSender *rtcpsender.RTCPSender
|
rtcpSender *rtcpsender.RTCPSender
|
||||||
|
h264Decoder *rtph264.Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s clientState) String() string {
|
func (s clientState) String() string {
|
||||||
@@ -122,6 +125,21 @@ type clientRes struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClientOnPacketRTPCtx is the context of a RTP packet.
|
||||||
|
type ClientOnPacketRTPCtx struct {
|
||||||
|
TrackID int
|
||||||
|
Packet *rtp.Packet
|
||||||
|
PTSEqualsDTS bool
|
||||||
|
H264NALUs [][]byte
|
||||||
|
H264PTS time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientOnPacketRTCPCtx is the context of a RTCP packet.
|
||||||
|
type ClientOnPacketRTCPCtx struct {
|
||||||
|
TrackID int
|
||||||
|
Packet rtcp.Packet
|
||||||
|
}
|
||||||
|
|
||||||
// Client is a RTSP client.
|
// Client is a RTSP client.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
//
|
//
|
||||||
@@ -132,9 +150,9 @@ type Client struct {
|
|||||||
// called after every response.
|
// called after every response.
|
||||||
OnResponse func(*base.Response)
|
OnResponse func(*base.Response)
|
||||||
// called when a RTP packet arrives.
|
// called when a RTP packet arrives.
|
||||||
OnPacketRTP func(int, *rtp.Packet)
|
OnPacketRTP func(*ClientOnPacketRTPCtx)
|
||||||
// called when a RTCP packet arrives.
|
// called when a RTCP packet arrives.
|
||||||
OnPacketRTCP func(int, rtcp.Packet)
|
OnPacketRTCP func(*ClientOnPacketRTCPCtx)
|
||||||
|
|
||||||
//
|
//
|
||||||
// RTSP parameters
|
// RTSP parameters
|
||||||
@@ -252,11 +270,11 @@ type Client struct {
|
|||||||
func (c *Client) Start(scheme string, host string) error {
|
func (c *Client) Start(scheme string, host string) error {
|
||||||
// callbacks
|
// callbacks
|
||||||
if c.OnPacketRTP == nil {
|
if c.OnPacketRTP == nil {
|
||||||
c.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
c.OnPacketRTP = func(ctx *ClientOnPacketRTPCtx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.OnPacketRTCP == nil {
|
if c.OnPacketRTCP == nil {
|
||||||
c.OnPacketRTCP = func(trackID int, pkt rtcp.Packet) {
|
c.OnPacketRTCP = func(ctx *ClientOnPacketRTCPCtx) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -698,7 +716,15 @@ func (c *Client) playRecordStart() {
|
|||||||
v := time.Now().Unix()
|
v := time.Now().Unix()
|
||||||
c.tcpLastFrameTime = &v
|
c.tcpLastFrameTime = &v
|
||||||
}
|
}
|
||||||
} else if *c.effectiveTransport == TransportUDP {
|
} else {
|
||||||
|
for _, ct := range c.tracks {
|
||||||
|
if _, ok := ct.track.(*TrackH264); ok {
|
||||||
|
ct.h264Decoder = &rtph264.Decoder{}
|
||||||
|
ct.h264Decoder.Init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if *c.effectiveTransport == TransportUDP {
|
||||||
for trackID, cct := range c.tracks {
|
for trackID, cct := range c.tracks {
|
||||||
ctrackID := trackID
|
ctrackID := trackID
|
||||||
|
|
||||||
@@ -713,6 +739,7 @@ func (c *Client) playRecordStart() {
|
|||||||
cct.udpRTCPListener.start(false)
|
cct.udpRTCPListener.start(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// for some reason, SetReadDeadline() must always be called in the same
|
// for some reason, SetReadDeadline() must always be called in the same
|
||||||
// goroutine, otherwise Read() freezes.
|
// goroutine, otherwise Read() freezes.
|
||||||
@@ -753,11 +780,7 @@ func (c *Client) runReader() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove padding
|
c.onPacketRTP(trackID, pkt)
|
||||||
pkt.Header.Padding = false
|
|
||||||
pkt.PaddingSize = 0
|
|
||||||
|
|
||||||
c.OnPacketRTP(trackID, pkt)
|
|
||||||
} else {
|
} else {
|
||||||
packets, err := rtcp.Unmarshal(payload)
|
packets, err := rtcp.Unmarshal(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -765,7 +788,7 @@ func (c *Client) runReader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, pkt := range packets {
|
for _, pkt := range packets {
|
||||||
c.OnPacketRTCP(trackID, pkt)
|
c.onPacketRTCP(trackID, pkt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -783,7 +806,7 @@ func (c *Client) runReader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, pkt := range packets {
|
for _, pkt := range packets {
|
||||||
c.OnPacketRTCP(trackID, pkt)
|
c.onPacketRTCP(trackID, pkt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -851,6 +874,10 @@ func (c *Client) playRecordStop(isClosing bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, ct := range c.tracks {
|
||||||
|
ct.h264Decoder = nil
|
||||||
|
}
|
||||||
|
|
||||||
// stop timers
|
// stop timers
|
||||||
c.checkStreamTimer = emptyTimer()
|
c.checkStreamTimer = emptyTimer()
|
||||||
c.keepaliveTimer = emptyTimer()
|
c.keepaliveTimer = emptyTimer()
|
||||||
@@ -1822,6 +1849,64 @@ func (c *Client) runWriter() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) onPacketRTP(trackID int, pkt *rtp.Packet) {
|
||||||
|
// remove padding
|
||||||
|
pkt.Header.Padding = false
|
||||||
|
pkt.PaddingSize = 0
|
||||||
|
|
||||||
|
ct := c.tracks[trackID]
|
||||||
|
|
||||||
|
if ct.h264Decoder != nil {
|
||||||
|
nalus, pts, err := ct.h264Decoder.DecodeUntilMarker(pkt)
|
||||||
|
if err == nil {
|
||||||
|
ptsEqualsDTS := h264.IDRPresent(nalus)
|
||||||
|
|
||||||
|
rr := ct.rtcpReceiver
|
||||||
|
if rr != nil {
|
||||||
|
rr.ProcessPacketRTP(time.Now(), pkt, ptsEqualsDTS)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.OnPacketRTP(&ClientOnPacketRTPCtx{
|
||||||
|
TrackID: trackID,
|
||||||
|
Packet: pkt,
|
||||||
|
PTSEqualsDTS: ptsEqualsDTS,
|
||||||
|
H264NALUs: append([][]byte(nil), nalus...),
|
||||||
|
H264PTS: pts,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
rr := ct.rtcpReceiver
|
||||||
|
if rr != nil {
|
||||||
|
rr.ProcessPacketRTP(time.Now(), pkt, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.OnPacketRTP(&ClientOnPacketRTPCtx{
|
||||||
|
TrackID: trackID,
|
||||||
|
Packet: pkt,
|
||||||
|
PTSEqualsDTS: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rr := ct.rtcpReceiver
|
||||||
|
if rr != nil {
|
||||||
|
rr.ProcessPacketRTP(time.Now(), pkt, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.OnPacketRTP(&ClientOnPacketRTPCtx{
|
||||||
|
TrackID: trackID,
|
||||||
|
Packet: pkt,
|
||||||
|
PTSEqualsDTS: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) onPacketRTCP(trackID int, pkt rtcp.Packet) {
|
||||||
|
c.OnPacketRTCP(&ClientOnPacketRTCPCtx{
|
||||||
|
TrackID: trackID,
|
||||||
|
Packet: pkt,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// WritePacketRTP writes a RTP packet.
|
// WritePacketRTP writes a RTP packet.
|
||||||
func (c *Client) WritePacketRTP(trackID int, pkt *rtp.Packet, ptsEqualsDTS bool) error {
|
func (c *Client) WritePacketRTP(trackID int, pkt *rtp.Packet, ptsEqualsDTS bool) error {
|
||||||
c.writeMutex.RLock()
|
c.writeMutex.RLock()
|
||||||
|
@@ -233,9 +233,9 @@ func TestClientPublishSerial(t *testing.T) {
|
|||||||
v := TransportTCP
|
v := TransportTCP
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
OnPacketRTCP: func(trackID int, pkt rtcp.Packet) {
|
OnPacketRTCP: func(ctx *ClientOnPacketRTCPCtx) {
|
||||||
require.Equal(t, 0, trackID)
|
require.Equal(t, 0, ctx.TrackID)
|
||||||
require.Equal(t, &testRTCPPacket, pkt)
|
require.Equal(t, &testRTCPPacket, ctx.Packet)
|
||||||
close(recvDone)
|
close(recvDone)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1119,10 +1119,10 @@ func TestClientPublishIgnoreTCPRTPPackets(t *testing.T) {
|
|||||||
v := TransportTCP
|
v := TransportTCP
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
t.Errorf("should not happen")
|
t.Errorf("should not happen")
|
||||||
},
|
},
|
||||||
OnPacketRTCP: func(trackID int, pkt rtcp.Packet) {
|
OnPacketRTCP: func(ctx *ClientOnPacketRTCPCtx) {
|
||||||
close(rtcpReceived)
|
close(rtcpReceived)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -404,7 +404,7 @@ func TestClientRead(t *testing.T) {
|
|||||||
}(),
|
}(),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
c.OnPacketRTP = func(ctx *ClientOnPacketRTPCtx) {
|
||||||
// ignore multicast loopback
|
// ignore multicast loopback
|
||||||
if transport == "multicast" {
|
if transport == "multicast" {
|
||||||
counter++
|
counter++
|
||||||
@@ -413,8 +413,8 @@ func TestClientRead(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
require.Equal(t, 0, trackID)
|
require.Equal(t, 0, ctx.TrackID)
|
||||||
require.Equal(t, &testRTPPacket, pkt)
|
require.Equal(t, &testRTPPacket, ctx.Packet)
|
||||||
|
|
||||||
err := c.WritePacketRTCP(0, &testRTCPPacket)
|
err := c.WritePacketRTCP(0, &testRTCPPacket)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -546,9 +546,9 @@ func TestClientReadNonStandardFrameSize(t *testing.T) {
|
|||||||
v := TransportTCP
|
v := TransportTCP
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
require.Equal(t, 0, trackID)
|
require.Equal(t, 0, ctx.TrackID)
|
||||||
require.Equal(t, &refRTPPacket, pkt)
|
require.Equal(t, &refRTPPacket, ctx.Packet)
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -684,9 +684,9 @@ func TestClientReadPartial(t *testing.T) {
|
|||||||
v := TransportTCP
|
v := TransportTCP
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
require.Equal(t, 0, trackID)
|
require.Equal(t, 0, ctx.TrackID)
|
||||||
require.Equal(t, &testRTPPacket, pkt)
|
require.Equal(t, &testRTPPacket, ctx.Packet)
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -970,8 +970,8 @@ func TestClientReadAnyPort(t *testing.T) {
|
|||||||
|
|
||||||
c := &Client{
|
c := &Client{
|
||||||
AnyPortEnable: true,
|
AnyPortEnable: true,
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
require.Equal(t, &testRTPPacket, pkt)
|
require.Equal(t, &testRTPPacket, ctx.Packet)
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1101,7 +1101,7 @@ func TestClientReadAutomaticProtocol(t *testing.T) {
|
|||||||
packetRecv := make(chan struct{})
|
packetRecv := make(chan struct{})
|
||||||
|
|
||||||
c := Client{
|
c := Client{
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1349,7 +1349,7 @@ func TestClientReadAutomaticProtocol(t *testing.T) {
|
|||||||
|
|
||||||
c := &Client{
|
c := &Client{
|
||||||
ReadTimeout: 1 * time.Second,
|
ReadTimeout: 1 * time.Second,
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1481,8 +1481,8 @@ func TestClientReadDifferentInterleavedIDs(t *testing.T) {
|
|||||||
v := TransportTCP
|
v := TransportTCP
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
require.Equal(t, 0, trackID)
|
require.Equal(t, 0, ctx.TrackID)
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1634,7 +1634,7 @@ func TestClientReadRedirect(t *testing.T) {
|
|||||||
packetRecv := make(chan struct{})
|
packetRecv := make(chan struct{})
|
||||||
|
|
||||||
c := Client{
|
c := Client{
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -1845,7 +1845,7 @@ func TestClientReadPause(t *testing.T) {
|
|||||||
v := TransportTCP
|
v := TransportTCP
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
if atomic.SwapInt32(&firstFrame, 1) == 0 {
|
if atomic.SwapInt32(&firstFrame, 1) == 0 {
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
}
|
}
|
||||||
@@ -1911,7 +1911,8 @@ func TestClientReadRTCPReport(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, base.Describe, req.Method)
|
require.Equal(t, base.Describe, req.Method)
|
||||||
|
|
||||||
track, err := NewTrackH264(96, []byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}, nil)
|
track, err := NewTrackH264(96, []byte{0x01, 0x02, 0x03, 0x04},
|
||||||
|
[]byte{0x01, 0x02, 0x03, 0x04}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tracks := Tracks{track}
|
tracks := Tracks{track}
|
||||||
@@ -1985,7 +1986,7 @@ func TestClientReadRTCPReport(t *testing.T) {
|
|||||||
Timestamp: 54352,
|
Timestamp: 54352,
|
||||||
SSRC: 753621,
|
SSRC: 753621,
|
||||||
},
|
},
|
||||||
Payload: []byte{0x01, 0x02, 0x03, 0x04},
|
Payload: []byte{0x05, 0x02, 0x03, 0x04},
|
||||||
}
|
}
|
||||||
byts, _ := pkt.Marshal()
|
byts, _ := pkt.Marshal()
|
||||||
_, err = l1.WriteTo(byts, &net.UDPAddr{
|
_, err = l1.WriteTo(byts, &net.UDPAddr{
|
||||||
@@ -1998,8 +1999,8 @@ func TestClientReadRTCPReport(t *testing.T) {
|
|||||||
SSRC: 753621,
|
SSRC: 753621,
|
||||||
NTPTime: 0,
|
NTPTime: 0,
|
||||||
RTPTime: 0,
|
RTPTime: 0,
|
||||||
PacketCount: 0,
|
PacketCount: 1,
|
||||||
OctetCount: 0,
|
OctetCount: 4,
|
||||||
}
|
}
|
||||||
byts, _ = sr.Marshal()
|
byts, _ = sr.Marshal()
|
||||||
_, err = l2.WriteTo(byts, &net.UDPAddr{
|
_, err = l2.WriteTo(byts, &net.UDPAddr{
|
||||||
@@ -2335,7 +2336,7 @@ func TestClientReadIgnoreTCPInvalidTrack(t *testing.T) {
|
|||||||
v := TransportTCP
|
v := TransportTCP
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *ClientOnPacketRTPCtx) {
|
||||||
close(recv)
|
close(recv)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -2791,9 +2792,9 @@ func TestClientReadDifferentSource(t *testing.T) {
|
|||||||
}(),
|
}(),
|
||||||
}
|
}
|
||||||
|
|
||||||
c.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
c.OnPacketRTP = func(ctx *ClientOnPacketRTPCtx) {
|
||||||
require.Equal(t, 0, trackID)
|
require.Equal(t, 0, ctx.TrackID)
|
||||||
require.Equal(t, &testRTPPacket, pkt)
|
require.Equal(t, &testRTPPacket, ctx.Packet)
|
||||||
close(packetRecv)
|
close(packetRecv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -182,13 +182,7 @@ func (u *clientUDPListener) processPlayRTP(now time.Time, payload []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
u.c.tracks[u.trackID].rtcpReceiver.ProcessPacketRTP(now, pkt, true)
|
u.c.onPacketRTP(u.trackID, pkt)
|
||||||
|
|
||||||
// remove padding
|
|
||||||
pkt.Header.Padding = false
|
|
||||||
pkt.PaddingSize = 0
|
|
||||||
|
|
||||||
u.c.OnPacketRTP(u.trackID, pkt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *clientUDPListener) processPlayRTCP(now time.Time, payload []byte) {
|
func (u *clientUDPListener) processPlayRTCP(now time.Time, payload []byte) {
|
||||||
@@ -199,7 +193,7 @@ func (u *clientUDPListener) processPlayRTCP(now time.Time, payload []byte) {
|
|||||||
|
|
||||||
for _, pkt := range packets {
|
for _, pkt := range packets {
|
||||||
u.c.tracks[u.trackID].rtcpReceiver.ProcessPacketRTCP(now, pkt)
|
u.c.tracks[u.trackID].rtcpReceiver.ProcessPacketRTCP(now, pkt)
|
||||||
u.c.OnPacketRTCP(u.trackID, pkt)
|
u.c.onPacketRTCP(u.trackID, pkt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +204,7 @@ func (u *clientUDPListener) processRecordRTCP(now time.Time, payload []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, pkt := range packets {
|
for _, pkt := range packets {
|
||||||
u.c.OnPacketRTCP(u.trackID, pkt)
|
u.c.onPacketRTCP(u.trackID, pkt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
"github.com/aler9/gortsplib/pkg/rtpaac"
|
"github.com/aler9/gortsplib/pkg/rtpaac"
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -58,13 +57,13 @@ func main() {
|
|||||||
dec.Init()
|
dec.Init()
|
||||||
|
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
c.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
if trackID != aacTrack {
|
if ctx.TrackID != aacTrack {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode AAC AUs from the RTP packet
|
// decode AAC AUs from the RTP packet
|
||||||
aus, _, err := dec.Decode(pkt)
|
aus, _, err := dec.Decode(ctx.Packet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -10,8 +10,6 @@ import (
|
|||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
"github.com/aler9/gortsplib/pkg/rtph264"
|
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -75,10 +73,6 @@ func main() {
|
|||||||
panic("H264 track not found")
|
panic("H264 track not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup RTP->H264 decoder
|
|
||||||
rtpDec := &rtph264.Decoder{}
|
|
||||||
rtpDec.Init()
|
|
||||||
|
|
||||||
// setup H264->raw frames decoder
|
// setup H264->raw frames decoder
|
||||||
h264dec, err := newH264Decoder()
|
h264dec, err := newH264Decoder()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -96,18 +90,16 @@ func main() {
|
|||||||
|
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
saveCount := 0
|
saveCount := 0
|
||||||
c.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
if trackID != h264TrackID {
|
if ctx.TrackID != h264TrackID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert RTP packet to H264 NALUs
|
if ctx.H264NALUs == nil {
|
||||||
nalus, _, err := rtpDec.Decode(pkt)
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, nalu := range nalus {
|
for _, nalu := range ctx.H264NALUs {
|
||||||
// convert H264 NALUs to RGBA frames
|
// convert H264 NALUs to RGBA frames
|
||||||
img, err := h264dec.decode(nalu)
|
img, err := h264dec.decode(nalu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -3,8 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
"github.com/aler9/gortsplib/pkg/rtph264"
|
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -47,10 +45,6 @@ func main() {
|
|||||||
panic("H264 track not found")
|
panic("H264 track not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup RTP->H264 decoder
|
|
||||||
rtpDec := &rtph264.Decoder{}
|
|
||||||
rtpDec.Init()
|
|
||||||
|
|
||||||
// setup H264->MPEGTS encoder
|
// setup H264->MPEGTS encoder
|
||||||
enc, err := newMPEGTSEncoder(h264track.SPS(), h264track.PPS())
|
enc, err := newMPEGTSEncoder(h264track.SPS(), h264track.PPS())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -58,19 +52,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
c.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
if trackID != h264TrackID {
|
if ctx.TrackID != h264TrackID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert RTP packet to H264 NALUs
|
if ctx.H264NALUs == nil {
|
||||||
nalus, pts, err := rtpDec.DecodeUntilMarker(pkt)
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode H264 NALUs into MPEG-TS
|
// encode H264 NALUs into MPEG-TS
|
||||||
err = enc.encode(nalus, pts)
|
err = enc.encode(ctx.H264NALUs, ctx.H264PTS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -5,8 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
"github.com/aler9/gortsplib/pkg/rtph264"
|
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -52,10 +50,6 @@ func main() {
|
|||||||
panic("H264 track not found")
|
panic("H264 track not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup RTP->H264 decoder
|
|
||||||
rtpDec := &rtph264.Decoder{}
|
|
||||||
rtpDec.Init()
|
|
||||||
|
|
||||||
// setup H264->raw frames decoder
|
// setup H264->raw frames decoder
|
||||||
h264dec, err := newH264Decoder()
|
h264dec, err := newH264Decoder()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -72,18 +66,16 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
c.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
c.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
if trackID != h264TrackID {
|
if ctx.TrackID != h264TrackID {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert RTP packet to H264 NALUs
|
if ctx.H264NALUs == nil {
|
||||||
nalus, _, err := rtpDec.Decode(pkt)
|
|
||||||
if err != nil {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, nalu := range nalus {
|
for _, nalu := range ctx.H264NALUs {
|
||||||
// convert H264 NALUs to RGBA frames
|
// convert H264 NALUs to RGBA frames
|
||||||
img, err := h264dec.decode(nalu)
|
img, err := h264dec.decode(nalu)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -5,8 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/pion/rtcp"
|
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -23,12 +21,12 @@ func main() {
|
|||||||
// timeout of write operations
|
// timeout of write operations
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
log.Printf("RTP packet from track %d, payload type %d\n", trackID, pkt.Header.PayloadType)
|
log.Printf("RTP packet from track %d, payload type %d\n", ctx.TrackID, ctx.Packet.Header.PayloadType)
|
||||||
},
|
},
|
||||||
// called when a RTCP packet arrives
|
// called when a RTCP packet arrives
|
||||||
OnPacketRTCP: func(trackID int, pkt rtcp.Packet) {
|
OnPacketRTCP: func(ctx *gortsplib.ClientOnPacketRTCPCtx) {
|
||||||
log.Printf("RTCP packet from track %d, type %T\n", trackID, pkt)
|
log.Printf("RTCP packet from track %d, type %T\n", ctx.TrackID, ctx.Packet)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,8 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
"github.com/pion/rtcp"
|
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -17,12 +15,12 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
c := gortsplib.Client{
|
c := gortsplib.Client{
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
log.Printf("RTP packet from track %d, payload type %d\n", trackID, pkt.Header.PayloadType)
|
log.Printf("RTP packet from track %d, payload type %d\n", ctx.TrackID, ctx.Packet.Header.PayloadType)
|
||||||
},
|
},
|
||||||
// called when a RTCP packet arrives
|
// called when a RTCP packet arrives
|
||||||
OnPacketRTCP: func(trackID int, pkt rtcp.Packet) {
|
OnPacketRTCP: func(ctx *gortsplib.ClientOnPacketRTCPCtx) {
|
||||||
log.Printf("RTCP packet from track %d, type %T\n", trackID, pkt)
|
log.Printf("RTCP packet from track %d, type %T\n", ctx.TrackID, ctx.Packet)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,8 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/pion/rtcp"
|
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -18,12 +16,12 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
c := gortsplib.Client{
|
c := gortsplib.Client{
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
log.Printf("RTP packet from track %d, payload type %d\n", trackID, pkt.Header.PayloadType)
|
log.Printf("RTP packet from track %d, payload type %d\n", ctx.TrackID, ctx.Packet.Header.PayloadType)
|
||||||
},
|
},
|
||||||
// called when a RTCP packet arrives
|
// called when a RTCP packet arrives
|
||||||
OnPacketRTCP: func(trackID int, pkt rtcp.Packet) {
|
OnPacketRTCP: func(ctx *gortsplib.ClientOnPacketRTCPCtx) {
|
||||||
log.Printf("RTCP packet from track %d, type %T\n", trackID, pkt)
|
log.Printf("RTCP packet from track %d, type %T\n", ctx.TrackID, ctx.Packet)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
"github.com/aler9/gortsplib/pkg/base"
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to
|
// This example shows how to
|
||||||
@@ -46,8 +45,8 @@ func main() {
|
|||||||
defer publisher.Close()
|
defer publisher.Close()
|
||||||
|
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
reader.OnPacketRTP = func(trackID int, pkt *rtp.Packet) {
|
reader.OnPacketRTP = func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
publisher.WritePacketRTP(trackID, pkt, true)
|
publisher.WritePacketRTP(ctx.TrackID, ctx.Packet, ctx.PTSEqualsDTS)
|
||||||
}
|
}
|
||||||
|
|
||||||
// start reading tracks
|
// start reading tracks
|
||||||
|
@@ -4,8 +4,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib"
|
"github.com/aler9/gortsplib"
|
||||||
"github.com/pion/rtcp"
|
|
||||||
"github.com/pion/rtp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example shows how to connect to a RTSP server
|
// This example shows how to connect to a RTSP server
|
||||||
@@ -14,12 +12,12 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
c := gortsplib.Client{
|
c := gortsplib.Client{
|
||||||
// called when a RTP packet arrives
|
// called when a RTP packet arrives
|
||||||
OnPacketRTP: func(trackID int, pkt *rtp.Packet) {
|
OnPacketRTP: func(ctx *gortsplib.ClientOnPacketRTPCtx) {
|
||||||
log.Printf("RTP packet from track %d, payload type %d\n", trackID, pkt.Header.PayloadType)
|
log.Printf("RTP packet from track %d, payload type %d\n", ctx.TrackID, ctx.Packet.Header.PayloadType)
|
||||||
},
|
},
|
||||||
// called when a RTCP packet arrives
|
// called when a RTCP packet arrives
|
||||||
OnPacketRTCP: func(trackID int, pkt rtcp.Packet) {
|
OnPacketRTCP: func(ctx *gortsplib.ClientOnPacketRTCPCtx) {
|
||||||
log.Printf("RTCP packet from track %d, type %T\n", trackID, pkt)
|
log.Printf("RTCP packet from track %d, type %T\n", ctx.TrackID, ctx.Packet)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user