summaryrefslogtreecommitdiff
path: root/ffmpeg/libavformat/rtsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavformat/rtsp.c')
-rw-r--r--ffmpeg/libavformat/rtsp.c171
1 files changed, 137 insertions, 34 deletions
diff --git a/ffmpeg/libavformat/rtsp.c b/ffmpeg/libavformat/rtsp.c
index 317893c..9ee016c 100644
--- a/ffmpeg/libavformat/rtsp.c
+++ b/ffmpeg/libavformat/rtsp.c
@@ -42,6 +42,7 @@
#include "rtsp.h"
#include "rtpdec.h"
+#include "rtpproto.h"
#include "rdt.h"
#include "rtpdec_formats.h"
#include "rtpenc_chain.h"
@@ -49,8 +50,6 @@
#include "rtpenc.h"
#include "mpegts.h"
-//#define DEBUG
-
/* Timeout values for socket poll, in ms,
* and read_packet(), in seconds */
#define POLL_TIMEOUT_MS 100
@@ -66,8 +65,7 @@
#define RTSP_FLAG_OPTS(name, longname) \
{ name, longname, OFFSET(rtsp_flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtsp_flags" }, \
- { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }, \
- { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" }
+ { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }
#define RTSP_MEDIATYPE_OPTS(name, longname) \
{ name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_DATA+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \
@@ -87,17 +85,21 @@ const AVOption ff_rtsp_options[] = {
{ "udp_multicast", "UDP multicast", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP_MULTICAST}, 0, 0, DEC, "rtsp_transport" },
{ "http", "HTTP tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTP)}, 0, 0, DEC, "rtsp_transport" },
RTSP_FLAG_OPTS("rtsp_flags", "RTSP flags"),
+ { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" },
RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
{ "min_port", "Minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
{ "max_port", "Maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
{ "timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies flag listen", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
+ { "stimeout", "timeout (in micro seconds) of socket i/o operations.", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
RTSP_REORDERING_OPTS(),
+ { "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
{ NULL },
};
static const AVOption sdp_options[] = {
RTSP_FLAG_OPTS("sdp_flags", "SDP flags"),
{ "custom_io", "Use custom IO", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" },
+ { "rtcp_to_source", "Send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" },
RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
RTSP_REORDERING_OPTS(),
{ NULL },
@@ -289,8 +291,27 @@ typedef struct SDPParseState {
struct sockaddr_storage default_ip;
int default_ttl;
int skip_media; ///< set if an unknown m= line occurs
+ int nb_default_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */
+ struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */
+ int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */
+ struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */
} SDPParseState;
+static void copy_default_source_addrs(struct RTSPSource **addrs, int count,
+ struct RTSPSource ***dest, int *dest_count)
+{
+ RTSPSource *rtsp_src, *rtsp_src2;
+ int i;
+ for (i = 0; i < count; i++) {
+ rtsp_src = addrs[i];
+ rtsp_src2 = av_malloc(sizeof(*rtsp_src2));
+ if (!rtsp_src2)
+ continue;
+ memcpy(rtsp_src2, rtsp_src, sizeof(*rtsp_src));
+ dynarray_add(dest, dest_count, rtsp_src2);
+ }
+}
+
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
int letter, const char *buf)
{
@@ -301,6 +322,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
int payload_type, i;
AVStream *st;
RTSPStream *rtsp_st;
+ RTSPSource *rtsp_src;
struct sockaddr_storage sdp_ip;
int ttl;
@@ -369,6 +391,15 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
rtsp_st->sdp_ip = s1->default_ip;
rtsp_st->sdp_ttl = s1->default_ttl;
+ copy_default_source_addrs(s1->default_include_source_addrs,
+ s1->nb_default_include_source_addrs,
+ &rtsp_st->include_source_addrs,
+ &rtsp_st->nb_include_source_addrs);
+ copy_default_source_addrs(s1->default_exclude_source_addrs,
+ s1->nb_default_exclude_source_addrs,
+ &rtsp_st->exclude_source_addrs,
+ &rtsp_st->nb_exclude_source_addrs);
+
get_word(buf1, sizeof(buf1), &p); /* port */
rtsp_st->sdp_port = atoi(buf1);
@@ -498,6 +529,43 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
p += strspn(p, SPACE_CHARS);
if (av_strstart(p, "inline:", &p))
get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p);
+ } else if (av_strstart(p, "source-filter:", &p)) {
+ int exclude = 0;
+ get_word(buf1, sizeof(buf1), &p);
+ if (strcmp(buf1, "incl") && strcmp(buf1, "excl"))
+ return;
+ exclude = !strcmp(buf1, "excl");
+
+ get_word(buf1, sizeof(buf1), &p);
+ if (strcmp(buf1, "IN") != 0)
+ return;
+ get_word(buf1, sizeof(buf1), &p);
+ if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*"))
+ return;
+ // not checking that the destination address actually matches or is wildcard
+ get_word(buf1, sizeof(buf1), &p);
+
+ while (*p != '\0') {
+ rtsp_src = av_mallocz(sizeof(*rtsp_src));
+ if (!rtsp_src)
+ return;
+ get_word(rtsp_src->addr, sizeof(rtsp_src->addr), &p);
+ if (exclude) {
+ if (s->nb_streams == 0) {
+ dynarray_add(&s1->default_exclude_source_addrs, &s1->nb_default_exclude_source_addrs, rtsp_src);
+ } else {
+ rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
+ dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src);
+ }
+ } else {
+ if (s->nb_streams == 0) {
+ dynarray_add(&s1->default_include_source_addrs, &s1->nb_default_include_source_addrs, rtsp_src);
+ } else {
+ rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
+ dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src);
+ }
+ }
+ }
} else {
if (rt->server_type == RTSP_SERVER_WMS)
ff_wms_parse_sdp_a_line(s, p);
@@ -522,7 +590,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
{
RTSPState *rt = s->priv_data;
const char *p;
- int letter;
+ int letter, i;
/* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
* contain long SDP lines containing complete ASF Headers (several
* kB) or arrays of MDPR (RM stream descriptor) headers plus
@@ -559,13 +627,21 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
if (*p == '\n')
p++;
}
+
+ for (i = 0; i < s1->nb_default_include_source_addrs; i++)
+ av_free(s1->default_include_source_addrs[i]);
+ av_freep(&s1->default_include_source_addrs);
+ for (i = 0; i < s1->nb_default_exclude_source_addrs; i++)
+ av_free(s1->default_exclude_source_addrs[i]);
+ av_freep(&s1->default_exclude_source_addrs);
+
rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
if (!rt->p) return AVERROR(ENOMEM);
return 0;
}
#endif /* CONFIG_RTPDEC */
-void ff_rtsp_undo_setup(AVFormatContext *s)
+void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets)
{
RTSPState *rt = s->priv_data;
int i;
@@ -580,6 +656,8 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
av_write_trailer(rtpctx);
if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
uint8_t *ptr;
+ if (CONFIG_RTSP_MUXER && rtpctx->pb && send_packets)
+ ff_rtsp_tcp_write_packet(s, rtsp_st);
avio_close_dyn_buf(rtpctx->pb, &ptr);
av_free(ptr);
} else {
@@ -602,16 +680,23 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
void ff_rtsp_close_streams(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- int i;
+ int i, j;
RTSPStream *rtsp_st;
- ff_rtsp_undo_setup(s);
+ ff_rtsp_undo_setup(s, 0);
for (i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
if (rtsp_st) {
if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
rtsp_st->dynamic_handler->free(
rtsp_st->dynamic_protocol_context);
+ for (j = 0; j < rtsp_st->nb_include_source_addrs; j++)
+ av_free(rtsp_st->include_source_addrs[j]);
+ av_freep(&rtsp_st->include_source_addrs);
+ for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++)
+ av_free(rtsp_st->exclude_source_addrs[j]);
+ av_freep(&rtsp_st->exclude_source_addrs);
+
av_free(rtsp_st);
}
}
@@ -644,8 +729,8 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
s->ctx_flags |= AVFMTCTX_NOHEADER;
if (s->oformat && CONFIG_RTSP_MUXER) {
- int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, s, st,
- rtsp_st->rtp_handle,
+ int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv,
+ s, st, rtsp_st->rtp_handle,
RTSP_TCP_MAX_PACKET_SIZE,
rtsp_st->stream_index);
/* Ownership of rtp_handle is passed to the rtp mux context */
@@ -1119,11 +1204,11 @@ start:
*
* @return zero if success, nonzero otherwise
*/
-static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
- const char *method, const char *url,
- const char *headers,
- const unsigned char *send_content,
- int send_content_length)
+static int rtsp_send_cmd_with_content_async(AVFormatContext *s,
+ const char *method, const char *url,
+ const char *headers,
+ const unsigned char *send_content,
+ int send_content_length)
{
RTSPState *rt = s->priv_data;
char buf[4096], *out_buf;
@@ -1136,6 +1221,7 @@ static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
if (headers)
av_strlcat(buf, headers, sizeof(buf));
av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", rt->seq);
+ av_strlcatf(buf, sizeof(buf), "User-Agent: %s\r\n", rt->user_agent);
if (rt->session_id[0] != '\0' && (!headers ||
!strstr(headers, "\nIf-Match:"))) {
av_strlcatf(buf, sizeof(buf), "Session: %s\r\n", rt->session_id);
@@ -1176,7 +1262,7 @@ static int ff_rtsp_send_cmd_with_content_async(AVFormatContext *s,
int ff_rtsp_send_cmd_async(AVFormatContext *s, const char *method,
const char *url, const char *headers)
{
- return ff_rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0);
+ return rtsp_send_cmd_with_content_async(s, method, url, headers, NULL, 0);
}
int ff_rtsp_send_cmd(AVFormatContext *s, const char *method, const char *url,
@@ -1201,9 +1287,9 @@ int ff_rtsp_send_cmd_with_content(AVFormatContext *s,
retry:
cur_auth_type = rt->auth_state.auth_type;
- if ((ret = ff_rtsp_send_cmd_with_content_async(s, method, url, header,
- send_content,
- send_content_length)))
+ if ((ret = rtsp_send_cmd_with_content_async(s, method, url, header,
+ send_content,
+ send_content_length)))
return ret;
if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0)
@@ -1398,18 +1484,15 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
case RTSP_LOWER_TRANSPORT_UDP: {
char url[1024], options[30] = "";
+ const char *peer = host;
if (rt->rtsp_flags & RTSP_FLAG_FILTER_SRC)
av_strlcpy(options, "?connect=1", sizeof(options));
/* Use source address if specified */
- if (reply->transports[0].source[0]) {
- ff_url_join(url, sizeof(url), "rtp", NULL,
- reply->transports[0].source,
- reply->transports[0].server_port_min, "%s", options);
- } else {
- ff_url_join(url, sizeof(url), "rtp", NULL, host,
- reply->transports[0].server_port_min, "%s", options);
- }
+ if (reply->transports[0].source[0])
+ peer = reply->transports[0].source;
+ ff_url_join(url, sizeof(url), "rtp", NULL, peer,
+ reply->transports[0].server_port_min, "%s", options);
if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) &&
ff_rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
err = AVERROR_INVALIDDATA;
@@ -1466,7 +1549,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
return 0;
fail:
- ff_rtsp_undo_setup(s);
+ ff_rtsp_undo_setup(s, 0);
return err;
}
@@ -1618,7 +1701,8 @@ redirect:
}
} else {
/* open the tcp connection */
- ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);
+ ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port,
+ "?timeout=%d", rt->stimeout);
if (ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR(EIO);
@@ -2028,7 +2112,7 @@ static int sdp_probe(AVProbeData *p1)
while (p < p_end && *p != '\0') {
if (p + sizeof("c=IN IP") - 1 < p_end &&
av_strstart(p, "c=IN IP", NULL))
- return AVPROBE_SCORE_MAX / 2;
+ return AVPROBE_SCORE_EXTENSION;
while (p < p_end - 1 && *p != '\n') p++;
if (++p >= p_end)
@@ -2039,6 +2123,17 @@ static int sdp_probe(AVProbeData *p1)
return 0;
}
+static void append_source_addrs(char *buf, int size, const char *name,
+ int count, struct RTSPSource **addrs)
+{
+ int i;
+ if (!count)
+ return;
+ av_strlcatf(buf, size, "&%s=%s", name, addrs[0]->addr);
+ for (i = 1; i < count; i++)
+ av_strlcatf(buf, size, ",%s", addrs[i]->addr);
+}
+
static int sdp_read_header(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
@@ -2079,9 +2174,17 @@ static int sdp_read_header(AVFormatContext *s)
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
ff_url_join(url, sizeof(url), "rtp", NULL,
namebuf, rtsp_st->sdp_port,
- "?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
- rtsp_st->sdp_ttl,
- rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0);
+ "?localport=%d&ttl=%d&connect=%d&write_to_source=%d",
+ rtsp_st->sdp_port, rtsp_st->sdp_ttl,
+ rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0,
+ rt->rtsp_flags & RTSP_FLAG_RTCP_TO_SOURCE ? 1 : 0);
+
+ append_source_addrs(url, sizeof(url), "sources",
+ rtsp_st->nb_include_source_addrs,
+ rtsp_st->include_source_addrs);
+ append_source_addrs(url, sizeof(url), "block",
+ rtsp_st->nb_exclude_source_addrs,
+ rtsp_st->exclude_source_addrs);
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR_INVALIDDATA;
@@ -2134,7 +2237,7 @@ static int rtp_probe(AVProbeData *p)
static int rtp_read_header(AVFormatContext *s)
{
- uint8_t recvbuf[1500];
+ uint8_t recvbuf[RTP_MAX_PACKET_LENGTH];
char host[500], sdp[500];
int ret, port;
URLContext* in = NULL;