Merge commit '2c17fb61ced2059034856a6c6cd303014aed01fe'
authorHendrik Leppkes <h.leppkes@gmail.com>
Sun, 29 Nov 2015 15:13:24 +0000 (16:13 +0100)
committerHendrik Leppkes <h.leppkes@gmail.com>
Sun, 29 Nov 2015 15:13:24 +0000 (16:13 +0100)
* commit '2c17fb61ced2059034856a6c6cd303014aed01fe':
  rtsp: Log getaddrinfo failures

Merged-by: Hendrik Leppkes <h.leppkes@gmail.com>
1  2 
libavformat/rtsp.c
libavformat/rtsp.h
libavformat/rtspdec.c

diff --combined libavformat/rtsp.c
@@@ -2,24 -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"
  
  #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_INT, {.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 },
  };
@@@ -179,17 -174,23 +179,24 @@@ static void rtsp_parse_range_npt(const 
      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);
      }
  }
  
- static int get_sockaddr(const char *buf, struct sockaddr_storage *sock)
+ static int get_sockaddr(AVFormatContext *s,
+                         const char *buf, struct sockaddr_storage *sock)
  {
      struct addrinfo hints = { 0 }, *ai = NULL;
+     int ret;
      hints.ai_flags = AI_NUMERICHOST;
-     if (getaddrinfo(buf, NULL, &hints, &ai))
+     if ((ret = getaddrinfo(buf, NULL, &hints, &ai))) {
+         av_log(s, AV_LOG_ERROR, "getaddrinfo(%s): %s\n",
+                buf,
+                gai_strerror(ret));
          return -1;
+     }
      memcpy(sock, ai->ai_addr, FFMIN(sizeof(*sock), ai->ai_addrlen));
      freeaddrinfo(ai);
      return 0;
@@@ -397,7 -398,7 +404,7 @@@ static void sdp_parse_line(AVFormatCont
          if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6"))
              return;
          get_word_sep(buf1, sizeof(buf1), "/", &p);
-         if (get_sockaddr(buf1, &sdp_ip))
+         if (get_sockaddr(s, buf1, &sdp_ip))
              return;
          ttl = 16;
          if (*p == '/') {
              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;
              /* 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(
@@@ -700,13 -699,13 +707,13 @@@ int ff_sdp_parse(AVFormatContext *s, co
      }
  
      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);
  
 -    rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
 +    rt->p = av_malloc_array(rt->nb_rtsp_streams + 1, sizeof(struct pollfd) * 2);
      if (!rt->p) return AVERROR(ENOMEM);
      return 0;
  }
@@@ -730,7 -729,7 +737,7 @@@ void ff_rtsp_undo_setup(AVFormatContex
                          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,23 -762,23 +770,23 @@@ void ff_rtsp_close_streams(AVFormatCont
                  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_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)
      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,
          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);
@@@ -861,7 -860,8 +868,8 @@@ static void rtsp_parse_range(int *min_p
  }
  
  /* XXX: only one transport specification is parsed */
- static void rtsp_parse_transport(RTSPMessageHeader *reply, const char *p)
+ static void rtsp_parse_transport(AVFormatContext *s,
+                                  RTSPMessageHeader *reply, const char *p)
  {
      char transport_protocol[16];
      char profile[16];
                  if (*p == '=') {
                      p++;
                      get_word_sep(buf, sizeof(buf), ";,", &p);
-                     get_sockaddr(buf, &th->destination);
+                     get_sockaddr(s, buf, &th->destination);
                  }
              } else if (!strcmp(parameter, "source")) {
                  if (*p == '=') {
@@@ -1040,7 -1040,8 +1048,8 @@@ static void rtsp_parse_rtp_info(RTSPSta
          handle_rtp_info(rt, url, seq, rtptime);
  }
  
- void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf,
+ void ff_rtsp_parse_line(AVFormatContext *s,
+                         RTSPMessageHeader *reply, const char *buf,
                          RTSPState *rt, const char *method)
  {
      const char *p;
      } else if (av_stristart(p, "Content-Length:", &p)) {
          reply->content_length = strtol(p, NULL, 10);
      } else if (av_stristart(p, "Transport:", &p)) {
-         rtsp_parse_transport(reply, p);
+         rtsp_parse_transport(s, reply, p);
      } else if (av_stristart(p, "CSeq:", &p)) {
          reply->seq = strtol(p, NULL, 10);
      } else if (av_stristart(p, "Range:", &p)) {
@@@ -1186,7 -1187,7 +1195,7 @@@ start
                  request = 1;
              }
          } else {
-             ff_rtsp_parse_line(reply, p, rt, method);
+             ff_rtsp_parse_line(s, reply, p, rt, method);
              av_strlcat(rt->last_reply, p,    sizeof(rt->last_reply));
              av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply));
          }
      if (content_ptr)
          *content_ptr = content;
      else
 -        av_free(content);
 +        av_freep(&content);
  
      if (request) {
          char buf[1024];
@@@ -1297,7 -1298,7 +1306,7 @@@ static int rtsp_send_cmd_with_content_a
      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);
@@@ -1408,6 -1409,10 +1417,6 @@@ int ff_rtsp_make_setup_request(AVFormat
      /* 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. */
                  if (!err)
                      goto rtp_opened;
              }
 -
              av_log(s, AV_LOG_ERROR, "Unable to open an input RTP port\n");
              err = AVERROR(EIO);
              goto fail;
              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;
          }
  
@@@ -1786,14 -1792,12 +1795,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) < 0) {
 -            err = AVERROR(EIO);
 +                    host, port,
 +                    "?timeout=%d", rt->stimeout);
 +        if ((ret = ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
 +                       &s->interrupt_callback, NULL)) < 0) {
 +            err = ret;
              goto fail;
          }
          rt->rtsp_hd_out = rt->rtsp_hd;
                         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;
          }
  
          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;
  
          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);
@@@ -1938,7 -1936,7 +1947,7 @@@ static int udp_read_packet(AVFormatCont
                      p[max_p].fd       = fds[fdsidx];
                      p[max_p++].events = POLLIN;
                  }
 -                av_free(fds);
 +                av_freep(&fds);
              }
          }
          n = poll(p, max_p, POLL_TIMEOUT_MS);
@@@ -2048,7 -2046,7 +2057,7 @@@ int ff_rtsp_fetch_packet(AVFormatContex
          } 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;
@@@ -2167,16 -2165,6 +2176,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++;
              }
          }
      } 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;
@@@ -2221,7 -2209,7 +2230,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,7 -2262,7 +2283,7 @@@ static int sdp_read_header(AVFormatCont
      content[size] ='\0';
  
      err = ff_sdp_parse(s, content);
 -    av_free(content);
 +    av_freep(&content);
      if (err) goto fail;
  
      /* open each RTP stream */
@@@ -2437,7 -2425,7 +2446,7 @@@ static int rtp_read_header(AVFormatCont
      /* 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;
diff --combined libavformat/rtsp.h
@@@ -2,20 -2,20 +2,20 @@@
   * RTSP definitions
   * 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
   */
  #ifndef AVFORMAT_RTSP_H
@@@ -76,7 -76,7 +76,7 @@@ enum RTSPControlTransport 
  #define RTSP_DEFAULT_NB_AUDIO_CHANNELS 1
  #define RTSP_DEFAULT_AUDIO_SAMPLERATE 44100
  #define RTSP_RTP_PORT_MIN 5000
 -#define RTSP_RTP_PORT_MAX 10000
 +#define RTSP_RTP_PORT_MAX 65000
  
  /**
   * This describes a single item in the "Transport:" line of one stream as
@@@ -392,20 -392,10 +392,20 @@@ typedef struct RTSPState 
      int initial_timeout;
  
      /**
 +     * timeout of socket i/o operations.
 +     */
 +    int stimeout;
 +
 +    /**
       * Size of RTP packet reordering queue.
       */
      int reordering_queue_size;
  
 +    /**
 +     * User-Agent string
 +     */
 +    char *user_agent;
 +
      char default_lang[4];
      int buffer_size;
  } RTSPState;
  #define RTSP_FLAG_CUSTOM_IO   0x4    /**< Do all IO via the AVIOContext. */
  #define RTSP_FLAG_RTCP_TO_SOURCE 0x8 /**< Send RTCP packets to the source
                                            address of received packets. */
 +#define RTSP_FLAG_PREFER_TCP  0x10   /**< Try RTP via TCP first if possible. */
  
  typedef struct RTSPSource {
      char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */
@@@ -470,7 -459,8 +470,8 @@@ typedef struct RTSPStream 
      char crypto_params[100];
  } RTSPStream;
  
- void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf,
+ void ff_rtsp_parse_line(AVFormatContext *s,
+                         RTSPMessageHeader *reply, const char *buf,
                          RTSPState *rt, const char *method);
  
  /**
diff --combined libavformat/rtspdec.c
@@@ -2,20 -2,20 +2,20 @@@
   * RTSP demuxer
   * 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
   */
  
@@@ -151,7 -151,7 +151,7 @@@ static inline int rtsp_read_request(AVF
              return ret;
          if (rbuflen > 1) {
              av_log(s, AV_LOG_TRACE, "Parsing[%d]: %s\n", rbuflen, rbuf);
-             ff_rtsp_parse_line(request, rbuf, rt, method);
+             ff_rtsp_parse_line(s, request, rbuf, rt, method);
          }
      } while (rbuflen > 0);
      if (request->seq != rt->seq + 1) {
@@@ -367,10 -367,8 +367,10 @@@ static inline int parse_command_line(AV
      const char *linept, *searchlinept;
      linept = strchr(line, ' ');
  
 -    if (!linept)
 +    if (!linept) {
 +        av_log(s, AV_LOG_ERROR, "Error parsing method string\n");
          return AVERROR_INVALIDDATA;
 +    }
  
      if (linept - line > methodsize - 1) {
          av_log(s, AV_LOG_ERROR, "Method string too long\n");
@@@ -550,7 -548,7 +550,7 @@@ static int rtsp_read_play(AVFormatConte
          }
          ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);
          if (reply->status_code != RTSP_STATUS_OK) {
 -            return -1;
 +            return ff_rtsp_averror(reply->status_code, -1);
          }
          if (rt->transport == RTSP_TRANSPORT_RTP &&
              reply->range_start != AV_NOPTS_VALUE) {
                  AVStream *st = NULL;
                  if (!rtpctx || rtsp_st->stream_index < 0)
                      continue;
 +
                  st = s->streams[rtsp_st->stream_index];
                  rtpctx->range_start_offset =
                      av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
@@@ -583,7 -580,7 +583,7 @@@ static int rtsp_read_pause(AVFormatCont
      else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
          ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL);
          if (reply->status_code != RTSP_STATUS_OK) {
 -            return -1;
 +            return ff_rtsp_averror(reply->status_code, -1);
          }
      }
      rt->state = RTSP_STATE_PAUSED;
@@@ -610,12 -607,12 +610,12 @@@ int ff_rtsp_setup_input_streams(AVForma
                     sizeof(cmd));
      }
      ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content);
 -    if (!content)
 -        return AVERROR_INVALIDDATA;
      if (reply->status_code != RTSP_STATUS_OK) {
          av_freep(&content);
 -        return AVERROR_INVALIDDATA;
 +        return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
      }
 +    if (!content)
 +        return AVERROR_INVALIDDATA;
  
      av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content);
      /* now we got the SDP description, we parse it */
@@@ -728,7 -725,7 +728,7 @@@ static int rtsp_read_header(AVFormatCon
              return ret;
  
          rt->real_setup_cache = !s->nb_streams ? NULL :
 -            av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache));
 +            av_mallocz_array(s->nb_streams, 2 * sizeof(*rt->real_setup_cache));
          if (!rt->real_setup_cache && s->nb_streams)
              return AVERROR(ENOMEM);
          rt->real_setup = rt->real_setup_cache + s->nb_streams;
          if (rt->initial_pause) {
              /* do not start immediately */
          } else {
 -            if (rtsp_read_play(s) < 0) {
 +            if ((ret = rtsp_read_play(s)) < 0) {
                  ff_rtsp_close_streams(s);
                  ff_rtsp_close_connections(s);
 -                return AVERROR_INVALIDDATA;
 +                return ret;
              }
          }
      }
@@@ -774,7 -771,7 +774,7 @@@ redo
      id  = buf[0];
      len = AV_RB16(buf + 1);
      av_log(s, AV_LOG_TRACE, "id=%d len=%d\n", id, len);
 -    if (len > buf_size || len < 12)
 +    if (len > buf_size || len < 8)
          goto redo;
      /* get the data */
      ret = ffurl_read_complete(rt->rtsp_hd, buf, len);
@@@ -833,7 -830,7 +833,7 @@@ retry
                  ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
                                   cmd, reply, NULL);
                  if (reply->status_code != RTSP_STATUS_OK)
 -                    return AVERROR_INVALIDDATA;
 +                    return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
                  rt->need_subscription = 1;
              }
          }
              ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
                               cmd, reply, NULL);
              if (reply->status_code != RTSP_STATUS_OK)
 -                return AVERROR_INVALIDDATA;
 +                return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
              rt->need_subscription = 0;
  
              if (rt->state == RTSP_STATE_STREAMING)
@@@ -929,7 -926,6 +929,7 @@@ static int rtsp_read_seek(AVFormatConte
                            int64_t timestamp, int flags)
  {
      RTSPState *rt = s->priv_data;
 +    int ret;
  
      rt->seek_timestamp = av_rescale_q(timestamp,
                                        s->streams[stream_index]->time_base,
      case RTSP_STATE_IDLE:
          break;
      case RTSP_STATE_STREAMING:
 -        if (rtsp_read_pause(s) != 0)
 -            return -1;
 +        if ((ret = rtsp_read_pause(s)) != 0)
 +            return ret;
          rt->state = RTSP_STATE_SEEKING;
 -        if (rtsp_read_play(s) != 0)
 -            return -1;
 +        if ((ret = rtsp_read_play(s)) != 0)
 +            return ret;
          break;
      case RTSP_STATE_PAUSED:
          rt->state = RTSP_STATE_IDLE;