#include "libavutil/avassert.h"
#include "libavutil/base64.h"
+#include "libavutil/bprint.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "rtpenc.h"
#include "mpegts.h"
-/* Timeout values for socket poll, in ms,
- * and read_packet(), in seconds */
-#define POLL_TIMEOUT_MS 100
+/* Default timeout values for read packet in seconds */
#define READ_PACKET_TIMEOUT_S 10
-#define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / POLL_TIMEOUT_MS
-#define SDP_MAX_SIZE 16384
#define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH
#define DEFAULT_REORDERING_DELAY 100000
#define COMMON_OPTS() \
{ "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \
- { "buffer_size", "Underlying protocol send/receive buffer size", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC } \
+ { "buffer_size", "Underlying protocol send/receive buffer size", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC }, \
+ { "pkt_size", "Underlying protocol send packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ENC } \
const AVOption ff_rtsp_options[] = {
{ "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
{ "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" },
+ { "https", "HTTPS tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTPS )}, 0, 0, DEC, "rtsp_transport" },
RTSP_FLAG_OPTS("rtsp_flags", "set RTSP flags"),
{ "listen", "wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" },
{ "prefer_tcp", "try RTP via TCP first, if available", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_PREFER_TCP}, 0, 0, DEC|ENC, "rtsp_flags" },
+ { "satip_raw", "export raw MPEG-TS stream instead of demuxing", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_SATIP_RAW}, 0, 0, DEC, "rtsp_flags" },
RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
{ "min_port", "set minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
{ "max_port", "set maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
{ "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
-#if FF_API_OLD_RTSP_OPTIONS
- { "timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen) (deprecated, use listen_timeout)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
- { "stimeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
-#else
{ "timeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
-#endif
COMMON_OPTS(),
{ "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
-#if FF_API_OLD_RTSP_OPTIONS
- { "user-agent", "override User-Agent header (deprecated, use user_agent)", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
-#endif
{ NULL },
};
RTSP_FLAG_OPTS("sdp_flags", "SDP flags"),
{ "custom_io", "use custom I/O", 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" },
+ { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = READ_PACKET_TIMEOUT_S}, INT_MIN, INT_MAX, DEC },
RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
COMMON_OPTS(),
{ NULL },
static const AVOption rtp_options[] = {
RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"),
+ { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = READ_PACKET_TIMEOUT_S}, INT_MIN, INT_MAX, DEC },
+ RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
COMMON_OPTS(),
{ NULL },
};
snprintf(buf, sizeof(buf), "%d", rt->buffer_size);
av_dict_set(&opts, "buffer_size", buf, 0);
+ snprintf(buf, sizeof(buf), "%d", rt->pkt_size);
+ av_dict_set(&opts, "pkt_size", buf, 0);
return opts;
}
}
}
+static int init_satip_stream(AVFormatContext *s)
+{
+ RTSPState *rt = s->priv_data;
+ RTSPStream *rtsp_st = av_mallocz(sizeof(RTSPStream));
+ if (!rtsp_st)
+ return AVERROR(ENOMEM);
+ dynarray_add(&rt->rtsp_streams,
+ &rt->nb_rtsp_streams, rtsp_st);
+
+ rtsp_st->sdp_payload_type = 33; // MP2T
+ av_strlcpy(rtsp_st->control_url,
+ rt->control_uri, sizeof(rtsp_st->control_url));
+
+ if (rt->rtsp_flags & RTSP_FLAG_SATIP_RAW) {
+ AVStream *st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+ st->id = rt->nb_rtsp_streams - 1;
+ rtsp_st->stream_index = st->index;
+ st->codecpar->codec_type = AVMEDIA_TYPE_DATA;
+ st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS;
+ } else {
+ rtsp_st->stream_index = -1;
+ init_rtp_handler(&ff_mpegts_dynamic_handler, rtsp_st, NULL);
+ finalize_rtp_handler_init(s, rtsp_st, NULL);
+ }
+ return 0;
+}
+
/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */
static int sdp_parse_rtpmap(AVFormatContext *s,
AVStream *st, RTSPStream *rtsp_st,
break;
case 'a':
if (av_strstart(p, "control:", &p)) {
- if (s->nb_streams == 0) {
+ if (rt->nb_rtsp_streams == 0) {
if (!strncmp(p, "rtsp://", 7))
av_strlcpy(rt->control_uri, p,
sizeof(rt->control_uri));
{
const char *p;
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
- * "rulebooks" describing their properties. Therefore, the SDP line
- * buffer is large.
- *
- * The Vorbis FMTP line can be up to 16KB - see xiph_parse_sdp_line
- * in rtpdec_xiph.c. */
- char buf[16384], *q;
+ char buf[SDP_MAX_SIZE], *q;
SDPParseState sdp_parse_state = { { 0 } }, *s1 = &sdp_parse_state;
p = content;
ff_rtp_parse_close(rtsp_st->transport_priv);
}
rtsp_st->transport_priv = NULL;
- if (rtsp_st->rtp_handle)
- ffurl_close(rtsp_st->rtp_handle);
- rtsp_st->rtp_handle = NULL;
+ ffurl_closep(&rtsp_st->rtp_handle);
}
}
static void rtsp_parse_rtp_info(RTSPState *rt, const char *p)
{
int read = 0;
- char key[20], value[1024], url[1024] = "";
+ char key[20], value[MAX_URL_SIZE], url[MAX_URL_SIZE] = "";
uint32_t seq = 0, rtptime = 0;
for (;;) {
} else if (av_stristart(p, "Content-Type:", &p)) {
p += strspn(p, SPACE_CHARS);
av_strlcpy(reply->content_type, p, sizeof(reply->content_type));
+ } else if (av_stristart(p, "com.ses.streamID:", &p)) {
+ p += strspn(p, SPACE_CHARS);
+ av_strlcpy(reply->stream_id, p, sizeof(reply->stream_id));
}
}
{
RTSPState *rt = s->priv_data;
int ret, len, len1;
- uint8_t buf[1024];
+ uint8_t buf[MAX_URL_SIZE];
ret = ffurl_read_complete(rt->rtsp_hd, buf, 3);
if (ret != 3)
int return_on_interleaved_data, const char *method)
{
RTSPState *rt = s->priv_data;
- char buf[4096], buf1[1024], *q;
+ char buf[MAX_URL_SIZE], buf1[MAX_URL_SIZE], *q;
unsigned char ch;
const char *p;
int ret, content_length, line_count = 0, request = 0;
content = av_malloc(content_length + 1);
if (!content)
return AVERROR(ENOMEM);
- ffurl_read_complete(rt->rtsp_hd, content, content_length);
+ if (ffurl_read_complete(rt->rtsp_hd, content, content_length) != content_length)
+ return AVERROR(EIO);
content[content_length] = '\0';
}
if (content_ptr)
av_freep(&content);
if (request) {
- char buf[1024];
+ char buf[MAX_URL_SIZE];
char base64buf[AV_BASE64_SIZE(sizeof(buf))];
const char* ptr = buf;
int send_content_length)
{
RTSPState *rt = s->priv_data;
- char buf[4096], *out_buf;
+ char buf[MAX_URL_SIZE], *out_buf;
char base64buf[AV_BASE64_SIZE(sizeof(buf))];
+ if (!rt->rtsp_hd_out)
+ return AVERROR(ENOTCONN);
+
/* Add in RTSP headers */
out_buf = buf;
rt->seq++;
int rtx = 0, j, i, err, interleave = 0, port_off;
RTSPStream *rtsp_st;
RTSPMessageHeader reply1, *reply = &reply1;
- char cmd[2048];
+ char cmd[MAX_URL_SIZE];
const char *trans_pref;
if (rt->transport == RTSP_TRANSPORT_RDT)
port_off -= port_off & 0x01;
for (j = rt->rtp_port_min + port_off, i = 0; i < rt->nb_rtsp_streams; ++i) {
- char transport[2048];
+ char transport[MAX_URL_SIZE];
/*
* WMS serves all UDP data over a single connection, the RTX, which
rtp_opened:
port = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle);
have_port:
- snprintf(transport, sizeof(transport) - 1,
- "%s/UDP;", trans_pref);
+ av_strlcpy(transport, trans_pref, sizeof(transport));
+ av_strlcat(transport,
+ rt->server_type == RTSP_SERVER_SATIP ? ";" : "/UDP;",
+ sizeof(transport));
if (rt->server_type != RTSP_SERVER_REAL)
av_strlcat(transport, "unicast;", sizeof(transport));
av_strlcatf(transport, sizeof(transport),
goto fail;
}
+ if (rt->server_type == RTSP_SERVER_SATIP && reply->stream_id[0]) {
+ char proto[128], host[128], path[512], auth[128];
+ int port;
+ av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host),
+ &port, path, sizeof(path), rt->control_uri);
+ ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, host,
+ port, "/stream=%s", reply->stream_id);
+ }
+
/* XXX: same protocol for all streams is required */
if (i > 0) {
if (reply->transports[0].lower_transport != rt->lower_transport ||
break;
case RTSP_LOWER_TRANSPORT_UDP: {
- char url[1024], options[30] = "";
+ char url[MAX_URL_SIZE], options[30] = "";
const char *peer = host;
if (rt->rtsp_flags & RTSP_FLAG_FILTER_SRC)
break;
}
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {
- char url[1024], namebuf[50], optbuf[20] = "";
+ char url[MAX_URL_SIZE], namebuf[50], optbuf[20] = "";
struct sockaddr_storage addr;
int port, ttl;
+ AVDictionary *opts = map_to_opts(rt);
if (reply->transports[0].destination.ss_family) {
addr = reply->transports[0].destination;
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
ff_url_join(url, sizeof(url), "rtp", NULL, namebuf,
port, "%s", optbuf);
- if (ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
- &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL) < 0) {
+ err = ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
+ &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
+ av_dict_free(&opts);
+
+ if (err < 0) {
err = AVERROR_INVALIDDATA;
goto fail;
}
void ff_rtsp_close_connections(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- if (rt->rtsp_hd_out != rt->rtsp_hd) ffurl_close(rt->rtsp_hd_out);
- ffurl_close(rt->rtsp_hd);
- rt->rtsp_hd = rt->rtsp_hd_out = NULL;
+ if (rt->rtsp_hd_out != rt->rtsp_hd)
+ ffurl_closep(&rt->rtsp_hd_out);
+ rt->rtsp_hd_out = NULL;
+ ffurl_closep(&rt->rtsp_hd);
}
int ff_rtsp_connect(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
char proto[128], host[1024], path[1024];
- char tcpname[1024], cmd[2048], auth[128];
+ char tcpname[1024], cmd[MAX_URL_SIZE], auth[128];
const char *lower_rtsp_proto = "tcp";
int port, err, tcp_fd;
RTSPMessageHeader reply1, *reply = &reply1;
int lower_transport_mask = 0;
int default_port = RTSP_DEFAULT_PORT;
+ int https_tunnel = 0;
char real_challenge[64] = "";
struct sockaddr_storage peer;
socklen_t peer_len = sizeof(peer);
s->max_delay = s->iformat ? DEFAULT_REORDERING_DELAY : 0;
rt->control_transport = RTSP_MODE_PLAIN;
- if (rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_HTTP)) {
+ if (rt->lower_transport_mask & ((1 << RTSP_LOWER_TRANSPORT_HTTP) |
+ (1 << RTSP_LOWER_TRANSPORT_HTTPS))) {
+ https_tunnel = !!(rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_HTTPS));
rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP;
rt->control_transport = RTSP_MODE_TUNNEL;
}
lower_rtsp_proto = "tls";
default_port = RTSPS_DEFAULT_PORT;
rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP;
+ } else if (!strcmp(proto, "satip")) {
+ av_strlcpy(proto, "rtsp", sizeof(proto));
+ rt->server_type = RTSP_SERVER_SATIP;
}
if (*auth) {
char httpname[1024];
char sessioncookie[17];
char headers[1024];
+ AVDictionary *options = NULL;
+
+ av_dict_set_int(&options, "timeout", rt->stimeout, 0);
- ff_url_join(httpname, sizeof(httpname), "http", auth, host, port, "%s", path);
+ ff_url_join(httpname, sizeof(httpname), https_tunnel ? "https" : "http", auth, host, port, "%s", path);
snprintf(sessioncookie, sizeof(sessioncookie), "%08x%08x",
av_get_random_seed(), av_get_random_seed());
}
/* complete the connection */
- if (ffurl_connect(rt->rtsp_hd, NULL)) {
+ if (ffurl_connect(rt->rtsp_hd, &options)) {
+ av_dict_free(&options);
err = AVERROR(EIO);
goto fail;
}
sessioncookie);
av_opt_set(rt->rtsp_hd_out->priv_data, "headers", headers, 0);
av_opt_set(rt->rtsp_hd_out->priv_data, "chunked_post", "0", 0);
+ av_opt_set(rt->rtsp_hd_out->priv_data, "send_expect_100", "0", 0);
/* Initialize the authentication state for the POST session. The HTTP
* protocol implementation doesn't properly handle multi-pass
ff_http_init_auth_state(rt->rtsp_hd_out, rt->rtsp_hd);
/* complete the connection */
- if (ffurl_connect(rt->rtsp_hd_out, NULL)) {
+ if (ffurl_connect(rt->rtsp_hd_out, &options)) {
+ av_dict_free(&options);
err = AVERROR(EIO);
goto fail;
}
+ av_dict_free(&options);
} else {
int ret;
/* open the tcp connection */
/* request options supported by the server; this also detects server
* type */
- for (rt->server_type = RTSP_SERVER_RTP;;) {
+ if (rt->server_type != RTSP_SERVER_SATIP)
+ rt->server_type = RTSP_SERVER_RTP;
+ for (;;) {
cmd[0] = 0;
if (rt->server_type == RTSP_SERVER_REAL)
av_strlcat(cmd,
break;
}
- if (CONFIG_RTSP_DEMUXER && s->iformat)
- err = ff_rtsp_setup_input_streams(s, reply);
- else if (CONFIG_RTSP_MUXER)
+#if CONFIG_RTSP_DEMUXER
+ if (s->iformat) {
+ if (rt->server_type == RTSP_SERVER_SATIP)
+ err = init_satip_stream(s);
+ else
+ err = ff_rtsp_setup_input_streams(s, reply);
+ } else
+#endif
+ if (CONFIG_RTSP_MUXER)
err = ff_rtsp_setup_output_streams(s, host);
else
av_assert0(0);
if (rt->rtsp_flags & RTSP_FLAG_LISTEN) {
if (rt->state == RTSP_STATE_STREAMING) {
- if (!ff_rtsp_parse_streaming_commands(s))
- return AVERROR_EOF;
- else
- av_log(s, AV_LOG_WARNING,
- "Unable to answer to TEARDOWN\n");
+ return ff_rtsp_parse_streaming_commands(s);
} else
- return 0;
+ return AVERROR_EOF;
} else {
RTSPMessageHeader reply;
ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL);
{
RTSPState *rt = s->priv_data;
RTSPStream *rtsp_st;
- int n, i, ret, timeout_cnt = 0;
+ int n, i, ret;
struct pollfd *p = rt->p;
int *fds = NULL, fdsnum, fdsidx;
+ int runs = rt->initial_timeout * 1000LL / POLLING_TIME;
if (!p) {
- p = rt->p = av_malloc_array(2 * (rt->nb_rtsp_streams + 1), sizeof(struct pollfd));
+ p = rt->p = av_malloc_array(2 * rt->nb_rtsp_streams + 1, sizeof(*p));
if (!p)
return AVERROR(ENOMEM);
return AVERROR_EXIT;
if (wait_end && wait_end - av_gettime_relative() < 0)
return AVERROR(EAGAIN);
- n = poll(p, rt->max_p, POLL_TIMEOUT_MS);
+ n = poll(p, rt->max_p, POLLING_TIME);
if (n > 0) {
int j = rt->rtsp_hd ? 1 : 0;
- timeout_cnt = 0;
for (i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
if (rtsp_st->rtp_handle) {
}
}
#endif
- } else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) {
+ } else if (n == 0 && rt->initial_timeout > 0 && --runs <= 0) {
return AVERROR(ETIMEDOUT);
} else if (n < 0 && errno != EINTR)
return AVERROR(errno);
s->start_time_realtime = av_rescale (rtpctx->first_rtcp_ntp_time - (NTP_OFFSET << 32), 1000000, 1LL << 32);
if (rtpctx->st) {
s->start_time_realtime -=
- av_rescale (rtpctx->rtcp_ts_offset,
- (uint64_t) rtpctx->st->time_base.num * 1000000,
- rtpctx->st->time_base.den);
+ av_rescale_q (rtpctx->rtcp_ts_offset, rtpctx->st->time_base, AV_TIME_BASE_Q);
}
}
}
#endif /* CONFIG_RTPDEC */
#if CONFIG_SDP_DEMUXER
-static int sdp_probe(AVProbeData *p1)
+static int sdp_probe(const AVProbeData *p1)
{
const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
RTSPStream *rtsp_st;
int size, i, err;
char *content;
- char url[1024];
+ char url[MAX_URL_SIZE];
if (!ff_network_init())
return AVERROR(EIO);
/* read the whole sdp file */
/* XXX: better loading */
content = av_malloc(SDP_MAX_SIZE);
- if (!content)
+ if (!content) {
+ ff_network_close();
return AVERROR(ENOMEM);
+ }
size = avio_read(s->pb, content, SDP_MAX_SIZE - 1);
if (size <= 0) {
av_free(content);
+ ff_network_close();
return AVERROR_INVALIDDATA;
}
content[size] ='\0';
#endif /* CONFIG_SDP_DEMUXER */
#if CONFIG_RTP_DEMUXER
-static int rtp_probe(AVProbeData *p)
+static int rtp_probe(const AVProbeData *p)
{
if (av_strstart(p->filename, "rtp:", NULL))
return AVPROBE_SCORE_MAX;
static int rtp_read_header(AVFormatContext *s)
{
uint8_t recvbuf[RTP_MAX_PACKET_LENGTH];
- char host[500], sdp[500];
+ char host[500], filters_buf[1000];
int ret, port;
URLContext* in = NULL;
int payload_type;
AVIOContext pb;
socklen_t addrlen = sizeof(addr);
RTSPState *rt = s->priv_data;
+ const char *p;
+ AVBPrint sdp;
+ AVDictionary *opts = NULL;
if (!ff_network_init())
return AVERROR(EIO);
+ opts = map_to_opts(rt);
ret = ffurl_open_whitelist(&in, s->url, AVIO_FLAG_READ,
- &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL);
+ &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL);
+ av_dict_free(&opts);
if (ret)
goto fail;
break;
}
getsockname(ffurl_get_file_handle(in), (struct sockaddr*) &addr, &addrlen);
- ffurl_close(in);
- in = NULL;
+ ffurl_closep(&in);
par = avcodec_parameters_alloc();
if (!par) {
av_log(s, AV_LOG_ERROR, "Unable to receive RTP payload type %d "
"without an SDP file describing it\n",
payload_type);
+ ret = AVERROR_INVALIDDATA;
goto fail;
}
if (par->codec_type != AVMEDIA_TYPE_DATA) {
av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port,
NULL, 0, s->url);
- snprintf(sdp, sizeof(sdp),
- "v=0\r\nc=IN IP%d %s\r\nm=%s %d RTP/AVP %d\r\n",
- addr.ss_family == AF_INET ? 4 : 6, host,
- par->codec_type == AVMEDIA_TYPE_DATA ? "application" :
- par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio",
- port, payload_type);
- av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp);
+ av_bprint_init(&sdp, 0, AV_BPRINT_SIZE_UNLIMITED);
+ av_bprintf(&sdp, "v=0\r\nc=IN IP%d %s\r\n",
+ addr.ss_family == AF_INET ? 4 : 6, host);
+
+ p = strchr(s->url, '?');
+ if (p) {
+ static const char filters[][2][8] = { { "sources", "incl" },
+ { "block", "excl" } };
+ int i;
+ char *q;
+ for (i = 0; i < FF_ARRAY_ELEMS(filters); i++) {
+ if (av_find_info_tag(filters_buf, sizeof(filters_buf), filters[i][0], p)) {
+ q = filters_buf;
+ while ((q = strchr(q, ',')) != NULL)
+ *q = ' ';
+ av_bprintf(&sdp, "a=source-filter:%s IN IP%d %s %s\r\n",
+ filters[i][1],
+ addr.ss_family == AF_INET ? 4 : 6, host,
+ filters_buf);
+ }
+ }
+ }
+
+ av_bprintf(&sdp, "m=%s %d RTP/AVP %d\r\n",
+ par->codec_type == AVMEDIA_TYPE_DATA ? "application" :
+ par->codec_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio",
+ port, payload_type);
+ av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp.str);
+ if (!av_bprint_is_complete(&sdp))
+ goto fail_nobuf;
avcodec_parameters_free(&par);
- ffio_init_context(&pb, sdp, strlen(sdp), 0, NULL, NULL, NULL, NULL);
+ ffio_init_context(&pb, sdp.str, sdp.len, 0, NULL, NULL, NULL, NULL);
s->pb = &pb;
- /* sdp_read_header initializes this again */
+ /* if sdp_read_header() fails then following ff_network_close() cancels out */
+ /* ff_network_init() at the start of this function. Otherwise it cancels out */
+ /* ff_network_init() inside sdp_read_header() */
ff_network_close();
rt->media_type_mask = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1;
ret = sdp_read_header(s);
s->pb = NULL;
+ av_bprint_finalize(&sdp, NULL);
return ret;
+fail_nobuf:
+ ret = AVERROR(ENOMEM);
+ av_log(s, AV_LOG_ERROR, "rtp_read_header(): not enough buffer space for sdp-headers\n");
+ av_bprint_finalize(&sdp, NULL);
fail:
avcodec_parameters_free(&par);
- if (in)
- ffurl_close(in);
+ ffurl_closep(&in);
ff_network_close();
return ret;
}