diff options
Diffstat (limited to 'libavformat/rtsp.c')
-rw-r--r-- | libavformat/rtsp.c | 238 |
1 files changed, 126 insertions, 112 deletions
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 141477b..b6da61b 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -2,23 +2,24 @@ * RTSP/SDP client * Copyright (c) 2002 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/base64.h" #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" @@ -64,48 +65,52 @@ #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" } + { "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" }, \ + { name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \ { "video", "Video", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_VIDEO}, 0, 0, DEC, "allowed_media_types" }, \ { "audio", "Audio", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_AUDIO}, 0, 0, DEC, "allowed_media_types" }, \ - { "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" } + { "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" }, \ + { "subtitle", "Subtitle", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_SUBTITLE}, 0, 0, DEC, "allowed_media_types" } #define COMMON_OPTS() \ - { "reorder_queue_size", "Number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \ + { "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 } \ const AVOption ff_rtsp_options[] = { - { "initial_pause", "Don't start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC }, + { "initial_pause", "do not start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC }, FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags), - { "rtsp_transport", "RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \ + { "rtsp_transport", "set RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \ { "udp", "UDP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP}, 0, 0, DEC|ENC, "rtsp_transport" }, \ { "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" }, - 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 }, + 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" }, + 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 }, + { "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 }, + { "stimeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC }, COMMON_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"), + { "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" }, + 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", "RTP flags"), + RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"), COMMON_OPTS(), { NULL }, }; @@ -174,7 +179,8 @@ static void rtsp_parse_range_npt(const char *p, int64_t *start, int64_t *end) if (*p == '-') { p++; get_word_sep(buf, sizeof(buf), "-", &p); - av_parse_time(end, buf, 1); + if (av_parse_time(end, buf, 1) < 0) + av_log(NULL, AV_LOG_DEBUG, "Failed to parse interval end specification '%s'\n", buf); } } @@ -435,8 +441,10 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, codec_type = AVMEDIA_TYPE_AUDIO; } else if (!strcmp(st_type, "video")) { codec_type = AVMEDIA_TYPE_VIDEO; - } else if (!strcmp(st_type, "application") || !strcmp(st_type, "text")) { + } else if (!strcmp(st_type, "application")) { codec_type = AVMEDIA_TYPE_DATA; + } else if (!strcmp(st_type, "text")) { + codec_type = AVMEDIA_TYPE_SUBTITLE; } if (codec_type == AVMEDIA_TYPE_UNKNOWN || !(rt->media_type_mask & (1 << codec_type))) { s1->skip_media = 1; @@ -477,7 +485,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, /* no corresponding stream */ if (rt->transport == RTSP_TRANSPORT_RAW) { if (CONFIG_RTPDEC && !rt->ts) - rt->ts = ff_mpegts_parse_open(s); + rt->ts = avpriv_mpegts_parse_open(s); } else { RTPDynamicProtocolHandler *handler; handler = ff_rtp_handler_find_by_id( @@ -702,10 +710,10 @@ int ff_sdp_parse(AVFormatContext *s, const char *content) } 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[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[i]); av_freep(&s1->default_exclude_source_addrs); return 0; @@ -730,7 +738,7 @@ void ff_rtsp_undo_setup(AVFormatContext *s, int send_packets) ff_rtsp_tcp_write_packet(s, rtsp_st); ffio_free_dyn_buf(&rtpctx->pb); } else { - avio_close(rtpctx->pb); + avio_closep(&rtpctx->pb); } avformat_free_context(rtpctx); } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT) @@ -763,24 +771,23 @@ void ff_rtsp_close_streams(AVFormatContext *s) av_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[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[j]); av_freep(&rtsp_st->exclude_source_addrs); - av_free(rtsp_st); + av_freep(&rtsp_st); } } - av_free(rt->rtsp_streams); + av_freep(&rt->rtsp_streams); if (rt->asf_ctx) { avformat_close_input(&rt->asf_ctx); } if (CONFIG_RTPDEC && rt->ts) - ff_mpegts_parse_close(rt->ts); - av_freep(&rt->protocols); - av_free(rt->p); - av_free(rt->recvbuf); + avpriv_mpegts_parse_close(rt->ts); + av_freep(&rt->p); + av_freep(&rt->recvbuf); } int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) @@ -801,7 +808,7 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) if (!st) s->ctx_flags |= AVFMTCTX_NOHEADER; - if (CONFIG_RTSP_MUXER && s->oformat) { + if (CONFIG_RTSP_MUXER && s->oformat && st) { int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, s, st, rtsp_st->rtp_handle, RTSP_TCP_MAX_PACKET_SIZE, @@ -813,7 +820,7 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) st->time_base = ((AVFormatContext*)rtsp_st->transport_priv)->streams[0]->time_base; } else if (rt->transport == RTSP_TRANSPORT_RAW) { return 0; // Don't need to open any parser here - } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT) + } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT && st) rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index, rtsp_st->dynamic_protocol_context, rtsp_st->dynamic_handler); @@ -1214,7 +1221,7 @@ start: if (content_ptr) *content_ptr = content; else - av_free(content); + av_freep(&content); if (request) { char buf[1024]; @@ -1303,7 +1310,7 @@ static int 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", LIBAVFORMAT_IDENT); + 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); @@ -1413,10 +1420,6 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, /* default timeout: 1 minute */ rt->timeout = 60; - /* for each stream, make the setup request */ - /* XXX: we assume the same server is used for the control of each - * RTSP stream */ - /* Choose a random starting offset within the first half of the * port range, to allow for a number of ports to try even if the offset * happens to be at the end of the random range. */ @@ -1468,15 +1471,14 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, "?localport=%d", j); /* we will use two ports per rtp stream (rtp and rtcp) */ j += 2; - err = ffurl_open(&rtsp_st->rtp_handle, buf, AVIO_FLAG_READ_WRITE, - &s->interrupt_callback, &opts, rt->protocols, NULL); + err = ffurl_open_whitelist(&rtsp_st->rtp_handle, buf, AVIO_FLAG_READ_WRITE, + &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); av_dict_free(&opts); if (!err) goto rtp_opened; } - av_log(s, AV_LOG_ERROR, "Unable to open an input RTP port\n"); err = AVERROR(EIO); goto fail; @@ -1544,7 +1546,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, goto fail; } else if (reply->status_code != RTSP_STATUS_OK || reply->nb_transports != 1) { - err = AVERROR_INVALIDDATA; + err = ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA); goto fail; } @@ -1612,8 +1614,8 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port, namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST); ff_url_join(url, sizeof(url), "rtp", NULL, namebuf, port, "%s", optbuf); - if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, - &s->interrupt_callback, NULL, rt->protocols, NULL) < 0) { + 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 = AVERROR_INVALIDDATA; goto fail; } @@ -1670,13 +1672,6 @@ int ff_rtsp_connect(AVFormatContext *s) if (!ff_network_init()) return AVERROR(EIO); - if (!rt->protocols) { - rt->protocols = ffurl_get_protocols(s->protocol_whitelist, - s->protocol_blacklist); - if (!rt->protocols) - return AVERROR(ENOMEM); - } - if (s->max_delay < 0) /* Not set by the caller */ s->max_delay = s->iformat ? DEFAULT_REORDERING_DELAY : 0; @@ -1740,7 +1735,7 @@ redirect: /* GET requests */ if (ffurl_alloc(&rt->rtsp_hd, httpname, AVIO_FLAG_READ, - &s->interrupt_callback, rt->protocols) < 0) { + &s->interrupt_callback) < 0) { err = AVERROR(EIO); goto fail; } @@ -1754,6 +1749,14 @@ redirect: sessioncookie); av_opt_set(rt->rtsp_hd->priv_data, "headers", headers, 0); + if (!rt->rtsp_hd->protocol_whitelist && s->protocol_whitelist) { + rt->rtsp_hd->protocol_whitelist = av_strdup(s->protocol_whitelist); + if (!rt->rtsp_hd->protocol_whitelist) { + err = AVERROR(ENOMEM); + goto fail; + } + } + /* complete the connection */ if (ffurl_connect(rt->rtsp_hd, NULL)) { err = AVERROR(EIO); @@ -1762,7 +1765,7 @@ redirect: /* POST requests */ if (ffurl_alloc(&rt->rtsp_hd_out, httpname, AVIO_FLAG_WRITE, - &s->interrupt_callback, rt->protocols) < 0 ) { + &s->interrupt_callback) < 0 ) { err = AVERROR(EIO); goto fail; } @@ -1803,12 +1806,14 @@ redirect: goto fail; } } else { + int ret; /* open the tcp connection */ ff_url_join(tcpname, sizeof(tcpname), lower_rtsp_proto, NULL, - host, port, NULL); - if (ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE, - &s->interrupt_callback, NULL, rt->protocols, NULL) < 0) { - err = AVERROR(EIO); + host, port, + "?timeout=%d", rt->stimeout); + if ((ret = ffurl_open_whitelist(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE, + &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL)) < 0) { + err = ret; goto fail; } rt->rtsp_hd_out = rt->rtsp_hd; @@ -1847,7 +1852,7 @@ redirect: sizeof(cmd)); ff_rtsp_send_cmd(s, "OPTIONS", rt->control_uri, cmd, reply, NULL); if (reply->status_code != RTSP_STATUS_OK) { - err = AVERROR_INVALIDDATA; + err = ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA); goto fail; } @@ -1866,6 +1871,8 @@ redirect: err = ff_rtsp_setup_input_streams(s, reply); else if (CONFIG_RTSP_MUXER) err = ff_rtsp_setup_output_streams(s, host); + else + av_assert0(0); if (err) goto fail; @@ -1873,6 +1880,10 @@ redirect: int lower_transport = ff_log2_tab[lower_transport_mask & ~(lower_transport_mask - 1)]; + if ((lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) + && (rt->rtsp_flags & RTSP_FLAG_PREFER_TCP)) + lower_transport = RTSP_LOWER_TRANSPORT_TCP; + err = ff_rtsp_make_setup_request(s, host, port, lower_transport, rt->server_type == RTSP_SERVER_REAL ? real_challenge : NULL); @@ -1907,12 +1918,39 @@ redirect: #endif /* CONFIG_RTSP_DEMUXER || CONFIG_RTSP_MUXER */ #if CONFIG_RTPDEC +static int parse_rtsp_message(AVFormatContext *s) +{ + RTSPState *rt = s->priv_data; + int ret; + + 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"); + } else + return 0; + } else { + RTSPMessageHeader reply; + ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL); + if (ret < 0) + return ret; + /* XXX: parse message */ + if (rt->state != RTSP_STATE_STREAMING) + return 0; + } + + return 0; +} + static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, uint8_t *buf, int buf_size, int64_t wait_end) { RTSPState *rt = s->priv_data; RTSPStream *rtsp_st; - int n, i, ret, tcp_fd, timeout_cnt = 0; + int n, i, ret, timeout_cnt = 0; struct pollfd *p = rt->p; int *fds = NULL, fdsnum, fdsidx; @@ -1922,11 +1960,8 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, return AVERROR(ENOMEM); if (rt->rtsp_hd) { - tcp_fd = ffurl_get_file_handle(rt->rtsp_hd); - p[rt->max_p].fd = tcp_fd; + p[rt->max_p].fd = ffurl_get_file_handle(rt->rtsp_hd); p[rt->max_p++].events = POLLIN; - } else { - tcp_fd = -1; } for (i = 0; i < rt->nb_rtsp_streams; i++) { rtsp_st = rt->rtsp_streams[i]; @@ -1945,7 +1980,7 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, p[rt->max_p].fd = fds[fdsidx]; p[rt->max_p++].events = POLLIN; } - av_free(fds); + av_freep(&fds); } } } @@ -1957,7 +1992,7 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, return AVERROR(EAGAIN); n = poll(p, rt->max_p, POLL_TIMEOUT_MS); if (n > 0) { - int j = 1 - (tcp_fd == -1); + 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]; @@ -1973,25 +2008,8 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, } } #if CONFIG_RTSP_DEMUXER - if (tcp_fd != -1 && p[0].revents & POLLIN) { - 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"); - } else - return 0; - } else { - RTSPMessageHeader reply; - ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL); - if (ret < 0) - return ret; - /* XXX: parse message */ - if (rt->state != RTSP_STATE_STREAMING) - return 0; - } + if (rt->rtsp_hd && p[0].revents & POLLIN) { + return parse_rtsp_message(s); } #endif } else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) { @@ -2070,7 +2088,7 @@ static int read_packet(AVFormatContext *s, wait_end && wait_end < av_gettime_relative()) len = AVERROR(EAGAIN); else - len = ffio_read_partial(s->pb, rt->recvbuf, RECVBUF_SIZE); + len = avio_read_partial(s->pb, rt->recvbuf, RECVBUF_SIZE); len = pick_stream(s, rtsp_st, rt->recvbuf, len); if (len > 0 && (*rtsp_st)->transport_priv && rt->transport == RTSP_TRANSPORT_RTP) ff_rtp_check_and_send_back_rr((*rtsp_st)->transport_priv, NULL, s->pb, len); @@ -2100,7 +2118,7 @@ int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt) } else if (rt->transport == RTSP_TRANSPORT_RTP) { ret = ff_rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0); } else if (CONFIG_RTPDEC && rt->ts) { - ret = ff_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf + rt->recvbuf_pos, rt->recvbuf_len - rt->recvbuf_pos); + ret = avpriv_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf + rt->recvbuf_pos, rt->recvbuf_len - rt->recvbuf_pos); if (ret >= 0) { rt->recvbuf_pos += ret; ret = rt->recvbuf_pos < rt->recvbuf_len; @@ -2195,6 +2213,16 @@ redo: st2->time_base); } } + // Make real NTP start time available in AVFormatContext + if (s->start_time_realtime == AV_NOPTS_VALUE) { + 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); + } + } } if (ret == -RTCP_BYE) { rt->nb_byes++; @@ -2207,7 +2235,7 @@ redo: } } } else if (CONFIG_RTPDEC && rt->ts) { - ret = ff_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf, len); + ret = avpriv_mpegts_parse_packet(rt->ts, pkt, rt->recvbuf, len); if (ret >= 0) { if (ret < len) { rt->recvbuf_len = len; @@ -2239,7 +2267,7 @@ static int sdp_probe(AVProbeData *p1) /* we look for a line beginning "c=IN IP" */ while (p < p_end && *p != '\0') { - if (p + sizeof("c=IN IP") - 1 < p_end && + if (sizeof("c=IN IP") - 1 < p_end - p && av_strstart(p, "c=IN IP", NULL)) return AVPROBE_SCORE_EXTENSION; @@ -2274,13 +2302,6 @@ static int sdp_read_header(AVFormatContext *s) if (!ff_network_init()) return AVERROR(EIO); - if (!rt->protocols) { - rt->protocols = ffurl_get_protocols(s->protocol_whitelist, - s->protocol_blacklist); - if (!rt->protocols) - return AVERROR(ENOMEM); - } - if (s->max_delay < 0) /* Not set by the caller */ s->max_delay = DEFAULT_REORDERING_DELAY; if (rt->rtsp_flags & RTSP_FLAG_CUSTOM_IO) @@ -2299,7 +2320,7 @@ static int sdp_read_header(AVFormatContext *s) content[size] ='\0'; err = ff_sdp_parse(s, content); - av_free(content); + av_freep(&content); if (err) goto fail; /* open each RTP stream */ @@ -2332,8 +2353,8 @@ static int sdp_read_header(AVFormatContext *s) append_source_addrs(url, sizeof(url), "block", rtsp_st->nb_exclude_source_addrs, rtsp_st->exclude_source_addrs); - err = ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE, - &s->interrupt_callback, &opts, rt->protocols, NULL); + err = ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ, + &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); av_dict_free(&opts); @@ -2402,15 +2423,8 @@ static int rtp_read_header(AVFormatContext *s) if (!ff_network_init()) return AVERROR(EIO); - if (!rt->protocols) { - rt->protocols = ffurl_get_protocols(s->protocol_whitelist, - s->protocol_blacklist); - if (!rt->protocols) - return AVERROR(ENOMEM); - } - - ret = ffurl_open(&in, s->filename, AVIO_FLAG_READ, - &s->interrupt_callback, NULL, rt->protocols, NULL); + ret = ffurl_open_whitelist(&in, s->filename, AVIO_FLAG_READ, + &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL); if (ret) goto fail; @@ -2477,7 +2491,7 @@ static int rtp_read_header(AVFormatContext *s) /* sdp_read_header initializes this again */ ff_network_close(); - rt->media_type_mask = (1 << (AVMEDIA_TYPE_DATA+1)) - 1; + rt->media_type_mask = (1 << (AVMEDIA_TYPE_SUBTITLE+1)) - 1; ret = sdp_read_header(s); s->pb = NULL; |