summaryrefslogtreecommitdiff
path: root/libavformat
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat')
-rw-r--r--libavformat/rtpdec.c39
-rw-r--r--libavformat/rtpdec.h13
-rw-r--r--libavformat/rtsp.c6
3 files changed, 58 insertions, 0 deletions
diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c
index 80b576c28a..dfc5b0b482 100644
--- a/libavformat/rtpdec.c
+++ b/libavformat/rtpdec.c
@@ -273,6 +273,45 @@ int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count)
return 0;
}
+void rtp_send_punch_packets(URLContext* rtp_handle)
+{
+ ByteIOContext *pb;
+ uint8_t *buf;
+ int len;
+
+ /* Send a small RTP packet */
+ if (url_open_dyn_buf(&pb) < 0)
+ return;
+
+ put_byte(pb, (RTP_VERSION << 6));
+ put_byte(pb, 0); /* Payload type */
+ put_be16(pb, 0); /* Seq */
+ put_be32(pb, 0); /* Timestamp */
+ put_be32(pb, 0); /* SSRC */
+
+ put_flush_packet(pb);
+ len = url_close_dyn_buf(pb, &buf);
+ if ((len > 0) && buf)
+ url_write(rtp_handle, buf, len);
+ av_free(buf);
+
+ /* Send a minimal RTCP RR */
+ if (url_open_dyn_buf(&pb) < 0)
+ return;
+
+ put_byte(pb, (RTP_VERSION << 6));
+ put_byte(pb, 201); /* receiver report */
+ put_be16(pb, 1); /* length in words - 1 */
+ put_be32(pb, 0); /* our own SSRC */
+
+ put_flush_packet(pb);
+ len = url_close_dyn_buf(pb, &buf);
+ if ((len > 0) && buf)
+ url_write(rtp_handle, buf, len);
+ av_free(buf);
+}
+
+
/**
* open a new RTP parse context for stream 'st'. 'st' can be NULL for
* MPEG2TS streams to indicate that they should be demuxed inside the
diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h
index 1a243f89c8..92d519684f 100644
--- a/libavformat/rtpdec.h
+++ b/libavformat/rtpdec.h
@@ -74,6 +74,19 @@ void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd);
#endif
/**
+ * Send a dummy packet on both port pairs to set up the connection
+ * state in potential NAT routers, so that we're able to receive
+ * packets.
+ *
+ * Note, this only works if the NAT router doesn't remap ports. This
+ * isn't a standardized procedure, but it works in many cases in practice.
+ *
+ * The same routine is used with RDT too, even if RDT doesn't use normal
+ * RTP packets otherwise.
+ */
+void rtp_send_punch_packets(URLContext* rtp_handle);
+
+/**
* some rtp servers assume client is dead if they don't hear from them...
* so we send a Receiver Report to the provided ByteIO context
* (we don't have access to the rtcp handle from here)
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 8bc940dd92..f379b781b0 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -1146,6 +1146,12 @@ static int make_setup_request(AVFormatContext *s, const char *host, int port,
err = AVERROR_INVALIDDATA;
goto fail;
}
+ /* Try to initialize the connection state in a
+ * potential NAT router by sending dummy packets.
+ * RTP/RTCP dummy packets are used for RDT, too.
+ */
+ if (!(rt->server_type == RTSP_SERVER_WMS && i > 1))
+ rtp_send_punch_packets(rtsp_st->rtp_handle);
break;
}
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {