]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtsp.c
avutil/mem: Also poison new av_realloc-allocated blocks
[ffmpeg] / libavformat / rtsp.c
index 49c2d5237597c678124f5e88c8538c42bd0e27c4..3899c26fa4d896b73f1cf316a12abee5e306c484 100644 (file)
@@ -53,7 +53,6 @@
 
 /* Default timeout values for read packet in seconds  */
 #define READ_PACKET_TIMEOUT_S 10
-#define SDP_MAX_SIZE 16384
 #define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH
 #define DEFAULT_REORDERING_DELAY 100000
 
@@ -90,21 +89,14 @@ const AVOption ff_rtsp_options[] = {
     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 },
 };
 
@@ -253,6 +245,35 @@ static void finalize_rtp_handler_init(AVFormatContext *s, RTSPStream *rtsp_st,
     }
 }
 
+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,
@@ -542,7 +563,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
         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));
@@ -688,15 +709,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
 {
     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;
@@ -1034,7 +1047,7 @@ static void handle_rtp_info(RTSPState *rt, const char *url,
 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 (;;) {
@@ -1125,6 +1138,9 @@ void ff_rtsp_parse_line(AVFormatContext *s,
     } 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));
     }
 }
 
@@ -1133,7 +1149,7 @@ void ff_rtsp_skip_packet(AVFormatContext *s)
 {
     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)
@@ -1159,7 +1175,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
                        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;
@@ -1229,7 +1245,8 @@ start:
         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)
@@ -1238,7 +1255,7 @@ start:
         av_freep(&content);
 
     if (request) {
-        char buf[1024];
+        char buf[MAX_URL_SIZE];
         char base64buf[AV_BASE64_SIZE(sizeof(buf))];
         const char* ptr = buf;
 
@@ -1314,7 +1331,7 @@ static int rtsp_send_cmd_with_content_async(AVFormatContext *s,
                                             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)
@@ -1424,7 +1441,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
     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)
@@ -1445,7 +1462,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
     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
@@ -1503,8 +1520,10 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
         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),
@@ -1567,6 +1586,15 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
             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 ||
@@ -1594,7 +1622,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
             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)
@@ -1612,7 +1640,7 @@ int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
             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);
@@ -1674,7 +1702,7 @@ 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;
@@ -1718,6 +1746,9 @@ redirect:
         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) {
@@ -1865,7 +1896,9 @@ redirect:
 
     /* 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,
@@ -1900,9 +1933,15 @@ redirect:
         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);
@@ -1991,7 +2030,7 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
     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);
 
@@ -2049,7 +2088,7 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
                 }
             }
 #endif
-        } else if (n == 0 && --runs <= 0) {
+        } else if (n == 0 && rt->initial_timeout > 0 && --runs <= 0) {
             return AVERROR(ETIMEDOUT);
         } else if (n < 0 && errno != EINTR)
             return AVERROR(errno);
@@ -2255,9 +2294,7 @@ redo:
                     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);
                     }
                 }
             }
@@ -2334,7 +2371,7 @@ static int sdp_read_header(AVFormatContext *s)
     RTSPStream *rtsp_st;
     int size, i, err;
     char *content;
-    char url[1024];
+    char url[MAX_URL_SIZE];
 
     if (!ff_network_init())
         return AVERROR(EIO);
@@ -2347,11 +2384,14 @@ static int sdp_read_header(AVFormatContext *s)
     /* 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';
@@ -2424,7 +2464,7 @@ static const AVClass sdp_demuxer_class = {
     .version        = LIBAVUTIL_VERSION_INT,
 };
 
-AVInputFormat ff_sdp_demuxer = {
+const AVInputFormat ff_sdp_demuxer = {
     .name           = "sdp",
     .long_name      = NULL_IF_CONFIG_SMALL("SDP"),
     .priv_data_size = sizeof(RTSPState),
@@ -2458,12 +2498,15 @@ static int rtp_read_header(AVFormatContext *s)
     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;
 
@@ -2503,6 +2546,7 @@ static int rtp_read_header(AVFormatContext *s)
         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) {
@@ -2549,7 +2593,9 @@ static int rtp_read_header(AVFormatContext *s)
     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;
@@ -2577,7 +2623,7 @@ static const AVClass rtp_demuxer_class = {
     .version        = LIBAVUTIL_VERSION_INT,
 };
 
-AVInputFormat ff_rtp_demuxer = {
+const AVInputFormat ff_rtp_demuxer = {
     .name           = "rtp",
     .long_name      = NULL_IF_CONFIG_SMALL("RTP input"),
     .priv_data_size = sizeof(RTSPState),