]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtsp.c
Remove forward declarations.
[ffmpeg] / libavformat / rtsp.c
index c366ff1faae39b9d48f393c986373476d5403f02..b882c1f280c0094837089237bf3531d27f80f868 100644 (file)
 //#define DEBUG
 //#define DEBUG_RTP_TCP
 
-static int rtsp_read_play(AVFormatContext *s);
-
 #if LIBAVFORMAT_VERSION_INT < (53 << 16)
 int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP);
 #endif
 
-static int rtsp_probe(AVProbeData *p)
-{
-    if (av_strstart(p->filename, "rtsp:", NULL))
-        return AVPROBE_SCORE_MAX;
-    return 0;
-}
-
 #define SPACE_CHARS " \t\r\n"
 /* we use memchr() instead of strchr() here because strchr() will return
  * the terminating '\0' of SPACE_CHARS instead of NULL if c is '\0'. */
@@ -294,7 +285,7 @@ static void sdp_parse_fmtp(AVStream *st, const char *p)
     }
 }
 
-/** Parse a string \p in the form of Range:npt=xx-xx, and determine the start
+/** Parse a string p in the form of Range:npt=xx-xx, and determine the start
  *  and end time.
  *  Used for seeking in the rtp stream.
  */
@@ -554,6 +545,77 @@ static int sdp_parse(AVFormatContext *s, const char *content)
     return 0;
 }
 
+/* close and free RTSP streams */
+static void rtsp_close_streams(RTSPState *rt)
+{
+    int i;
+    RTSPStream *rtsp_st;
+
+    for(i=0;i<rt->nb_rtsp_streams;i++) {
+        rtsp_st = rt->rtsp_streams[i];
+        if (rtsp_st) {
+            if (rtsp_st->transport_priv) {
+                if (rt->transport == RTSP_TRANSPORT_RDT)
+                    ff_rdt_parse_close(rtsp_st->transport_priv);
+                else
+                    rtp_parse_close(rtsp_st->transport_priv);
+            }
+            if (rtsp_st->rtp_handle)
+                url_close(rtsp_st->rtp_handle);
+            if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
+                rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context);
+        }
+    }
+    av_free(rt->rtsp_streams);
+    if (rt->asf_ctx) {
+        av_close_input_stream (rt->asf_ctx);
+        rt->asf_ctx = NULL;
+    }
+    av_freep(&rt->auth_b64);
+}
+
+static int
+rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
+{
+    RTSPState *rt = s->priv_data;
+    AVStream *st = NULL;
+
+    /* open the RTP context */
+    if (rtsp_st->stream_index >= 0)
+        st = s->streams[rtsp_st->stream_index];
+    if (!st)
+        s->ctx_flags |= AVFMTCTX_NOHEADER;
+
+    if (rt->transport == RTSP_TRANSPORT_RDT)
+        rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
+                                            rtsp_st->dynamic_protocol_context,
+                                            rtsp_st->dynamic_handler);
+    else
+        rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle,
+                                         rtsp_st->sdp_payload_type,
+                                         &rtsp_st->rtp_payload_data);
+
+    if (!rtsp_st->transport_priv) {
+         return AVERROR(ENOMEM);
+    } else if (rt->transport != RTSP_TRANSPORT_RDT) {
+        if(rtsp_st->dynamic_handler) {
+            rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
+                                           rtsp_st->dynamic_protocol_context,
+                                           rtsp_st->dynamic_handler);
+        }
+    }
+
+    return 0;
+}
+
+#if CONFIG_RTSP_DEMUXER
+static int rtsp_probe(AVProbeData *p)
+{
+    if (av_strstart(p->filename, "rtsp:", NULL))
+        return AVPROBE_SCORE_MAX;
+    return 0;
+}
+
 static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp)
 {
     const char *p;
@@ -704,6 +766,9 @@ void rtsp_parse_line(RTSPMessageHeader *reply, const char *buf)
     } else if (av_stristart(p, "Notice:", &p) ||
                av_stristart(p, "X-Notice:", &p)) {
         reply->notice = strtol(p, NULL, 10);
+    } else if (av_stristart(p, "Location:", &p)) {
+        skip_spaces(&p);
+        av_strlcpy(reply->location, p , sizeof(reply->location));
     }
 }
 
@@ -741,7 +806,7 @@ static void rtsp_skip_packet(AVFormatContext *s)
  * @param s RTSP demuxer context
  * @param reply pointer where the RTSP message header will be stored
  * @param content_ptr pointer where the RTSP message body, if any, will
- *                    be stored (length is in \p reply)
+ *                    be stored (length is in reply)
  * @param return_on_interleaved_data whether the function may return if we
  *                   encounter a data marker ('$'), which precedes data
  *                   packets over interleaved TCP/RTSP connections. If this
@@ -877,70 +942,6 @@ static void rtsp_send_cmd (AVFormatContext *s,
     rtsp_read_reply(s, reply, content_ptr, 0);
 }
 
-
-/* close and free RTSP streams */
-static void rtsp_close_streams(RTSPState *rt)
-{
-    int i;
-    RTSPStream *rtsp_st;
-
-    for(i=0;i<rt->nb_rtsp_streams;i++) {
-        rtsp_st = rt->rtsp_streams[i];
-        if (rtsp_st) {
-            if (rtsp_st->transport_priv) {
-                if (rt->transport == RTSP_TRANSPORT_RDT)
-                    ff_rdt_parse_close(rtsp_st->transport_priv);
-                else
-                    rtp_parse_close(rtsp_st->transport_priv);
-            }
-            if (rtsp_st->rtp_handle)
-                url_close(rtsp_st->rtp_handle);
-            if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
-                rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context);
-        }
-    }
-    av_free(rt->rtsp_streams);
-    if (rt->asf_ctx) {
-        av_close_input_stream (rt->asf_ctx);
-        rt->asf_ctx = NULL;
-    }
-    av_freep(&rt->auth_b64);
-}
-
-static int
-rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
-{
-    RTSPState *rt = s->priv_data;
-    AVStream *st = NULL;
-
-    /* open the RTP context */
-    if (rtsp_st->stream_index >= 0)
-        st = s->streams[rtsp_st->stream_index];
-    if (!st)
-        s->ctx_flags |= AVFMTCTX_NOHEADER;
-
-    if (rt->transport == RTSP_TRANSPORT_RDT)
-        rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
-                                            rtsp_st->dynamic_protocol_context,
-                                            rtsp_st->dynamic_handler);
-    else
-        rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle,
-                                         rtsp_st->sdp_payload_type,
-                                         &rtsp_st->rtp_payload_data);
-
-    if (!rtsp_st->transport_priv) {
-         return AVERROR(ENOMEM);
-    } else if (rt->transport != RTSP_TRANSPORT_RDT) {
-        if(rtsp_st->dynamic_handler) {
-            rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
-                                           rtsp_st->dynamic_protocol_context,
-                                           rtsp_st->dynamic_handler);
-        }
-    }
-
-    return 0;
-}
-
 /**
  * @returns 0 on success, <0 on error, 1 if protocol is unavailable.
  */
@@ -1168,6 +1169,35 @@ fail:
     return err;
 }
 
+static int rtsp_read_play(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    RTSPMessageHeader reply1, *reply = &reply1;
+    char cmd[1024];
+
+    av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
+
+    if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
+        if (rt->state == RTSP_STATE_PAUSED) {
+            snprintf(cmd, sizeof(cmd),
+                     "PLAY %s RTSP/1.0\r\n",
+                     s->filename);
+        } else {
+            snprintf(cmd, sizeof(cmd),
+                     "PLAY %s RTSP/1.0\r\n"
+                     "Range: npt=%0.3f-\r\n",
+                     s->filename,
+                     (double)rt->seek_timestamp / AV_TIME_BASE);
+        }
+        rtsp_send_cmd(s, cmd, reply, NULL);
+        if (reply->status_code != RTSP_STATUS_OK) {
+            return -1;
+        }
+    }
+    rt->state = RTSP_STATE_PLAYING;
+    return 0;
+}
+
 static int rtsp_read_header(AVFormatContext *s,
                             AVFormatParameters *ap)
 {
@@ -1180,7 +1210,7 @@ static int rtsp_read_header(AVFormatContext *s,
     unsigned char *content = NULL;
     int lower_transport_mask = 0;
     char real_challenge[64];
-
+  redirect:
     /* extract hostname and port */
     url_split(NULL, 0, auth, sizeof(auth),
               host, sizeof(host), &port, path, sizeof(path), s->filename);
@@ -1337,10 +1367,78 @@ static int rtsp_read_header(AVFormatContext *s,
     rtsp_close_streams(rt);
     av_freep(&content);
     url_close(rt->rtsp_hd);
-    av_freep(&rt->auth_b64);
+    if (reply->status_code >=300 && reply->status_code < 400) {
+        av_strlcpy(s->filename, reply->location, sizeof(s->filename));
+        av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n",
+               reply->status_code,
+               s->filename);
+        goto redirect;
+    }
     return err;
 }
 
+static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
+                           uint8_t *buf, int buf_size)
+{
+    RTSPState *rt = s->priv_data;
+    RTSPStream *rtsp_st;
+    fd_set rfds;
+    int fd, fd_max, n, i, ret, tcp_fd;
+    struct timeval tv;
+
+    for(;;) {
+        if (url_interrupt_cb())
+            return AVERROR(EINTR);
+        FD_ZERO(&rfds);
+        if (rt->rtsp_hd) {
+            tcp_fd = fd_max = url_get_file_handle(rt->rtsp_hd);
+            FD_SET(tcp_fd, &rfds);
+        } else {
+            fd_max = 0;
+            tcp_fd = -1;
+        }
+        for(i = 0; i < rt->nb_rtsp_streams; i++) {
+            rtsp_st = rt->rtsp_streams[i];
+            if (rtsp_st->rtp_handle) {
+                /* currently, we cannot probe RTCP handle because of
+                 * blocking restrictions */
+                fd = url_get_file_handle(rtsp_st->rtp_handle);
+                if (fd > fd_max)
+                    fd_max = fd;
+                FD_SET(fd, &rfds);
+            }
+        }
+        tv.tv_sec = 0;
+        tv.tv_usec = 100 * 1000;
+        n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
+        if (n > 0) {
+            for(i = 0; i < rt->nb_rtsp_streams; i++) {
+                rtsp_st = rt->rtsp_streams[i];
+                if (rtsp_st->rtp_handle) {
+                    fd = url_get_file_handle(rtsp_st->rtp_handle);
+                    if (FD_ISSET(fd, &rfds)) {
+                        ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
+                        if (ret > 0) {
+                            *prtsp_st = rtsp_st;
+                            return ret;
+                        }
+                    }
+                }
+            }
+#if CONFIG_RTSP_DEMUXER
+            if (FD_ISSET(tcp_fd, &rfds)) {
+                RTSPMessageHeader reply;
+
+                rtsp_read_reply(s, &reply, NULL, 0);
+                /* XXX: parse message */
+                if (rt->state != RTSP_STATE_PLAYING)
+                    return 0;
+            }
+#endif
+        }
+    }
+}
+
 static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
                            uint8_t *buf, int buf_size)
 {
@@ -1395,73 +1493,68 @@ static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
     return len;
 }
 
-static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
-                           uint8_t *buf, int buf_size)
+static int rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
 {
     RTSPState *rt = s->priv_data;
+    int ret, len;
+    uint8_t buf[10 * RTP_MAX_PACKET_LENGTH];
     RTSPStream *rtsp_st;
-    fd_set rfds;
-    int fd, fd_max, n, i, ret, tcp_fd;
-    struct timeval tv;
 
-    for(;;) {
-        if (url_interrupt_cb())
-            return AVERROR(EINTR);
-        FD_ZERO(&rfds);
-        if (rt->rtsp_hd) {
-            tcp_fd = fd_max = url_get_file_handle(rt->rtsp_hd);
-            FD_SET(tcp_fd, &rfds);
+    /* get next frames from the same RTP packet */
+    if (rt->cur_transport_priv) {
+        if (rt->transport == RTSP_TRANSPORT_RDT)
+            ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
+        else
+            ret = rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
+        if (ret == 0) {
+            rt->cur_transport_priv = NULL;
+            return 0;
+        } else if (ret == 1) {
+            return 0;
         } else {
-            fd_max = 0;
-            tcp_fd = -1;
-        }
-        for(i = 0; i < rt->nb_rtsp_streams; i++) {
-            rtsp_st = rt->rtsp_streams[i];
-            if (rtsp_st->rtp_handle) {
-                /* currently, we cannot probe RTCP handle because of
-                 * blocking restrictions */
-                fd = url_get_file_handle(rtsp_st->rtp_handle);
-                if (fd > fd_max)
-                    fd_max = fd;
-                FD_SET(fd, &rfds);
-            }
+            rt->cur_transport_priv = NULL;
         }
-        tv.tv_sec = 0;
-        tv.tv_usec = 100 * 1000;
-        n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
-        if (n > 0) {
-            for(i = 0; i < rt->nb_rtsp_streams; i++) {
-                rtsp_st = rt->rtsp_streams[i];
-                if (rtsp_st->rtp_handle) {
-                    fd = url_get_file_handle(rtsp_st->rtp_handle);
-                    if (FD_ISSET(fd, &rfds)) {
-                        ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
-                        if (ret > 0) {
-                            *prtsp_st = rtsp_st;
-                            return ret;
-                        }
-                    }
-                }
-            }
-            if (FD_ISSET(tcp_fd, &rfds)) {
-                RTSPMessageHeader reply;
+    }
 
-                rtsp_read_reply(s, &reply, NULL, 0);
-                /* XXX: parse message */
-                if (rt->state != RTSP_STATE_PLAYING)
-                    return 0;
-            }
-        }
+    /* read next RTP packet */
+ redo:
+    switch(rt->lower_transport) {
+    default:
+#if CONFIG_RTSP_DEMUXER
+    case RTSP_LOWER_TRANSPORT_TCP:
+        len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf));
+        break;
+#endif
+    case RTSP_LOWER_TRANSPORT_UDP:
+    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
+        len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
+        if (len >=0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP)
+            rtp_check_and_send_back_rr(rtsp_st->transport_priv, len);
+        break;
+    }
+    if (len < 0)
+        return len;
+    if (len == 0)
+        return AVERROR_EOF;
+    if (rt->transport == RTSP_TRANSPORT_RDT)
+        ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
+    else
+        ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
+    if (ret < 0)
+        goto redo;
+    if (ret == 1) {
+        /* more packets may follow, so we save the RTP context */
+        rt->cur_transport_priv = rtsp_st->transport_priv;
     }
+
+    return ret;
 }
 
 static int rtsp_read_packet(AVFormatContext *s,
                             AVPacket *pkt)
 {
     RTSPState *rt = s->priv_data;
-    RTSPStream *rtsp_st;
-    int ret, len;
-    uint8_t buf[10 * RTP_MAX_PACKET_LENGTH];
+    int ret;
     RTSPMessageHeader reply1, *reply = &reply1;
     char cmd[1024];
 
@@ -1525,49 +1618,9 @@ static int rtsp_read_packet(AVFormatContext *s,
         }
     }
 
-    /* get next frames from the same RTP packet */
-    if (rt->cur_transport_priv) {
-        if (rt->transport == RTSP_TRANSPORT_RDT)
-            ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
-        else
-            ret = rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
-        if (ret == 0) {
-            rt->cur_transport_priv = NULL;
-            return 0;
-        } else if (ret == 1) {
-            return 0;
-        } else {
-            rt->cur_transport_priv = NULL;
-        }
-    }
-
-    /* read next RTP packet */
- redo:
-    switch(rt->lower_transport) {
-    default:
-    case RTSP_LOWER_TRANSPORT_TCP:
-        len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf));
-        break;
-    case RTSP_LOWER_TRANSPORT_UDP:
-    case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
-        len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
-        if (len >=0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP)
-            rtp_check_and_send_back_rr(rtsp_st->transport_priv, len);
-        break;
-    }
-    if (len < 0)
-        return len;
-    if (len == 0)
-        return AVERROR_EOF;
-    if (rt->transport == RTSP_TRANSPORT_RDT)
-        ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
-    else
-        ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
-    if (ret < 0)
-        goto redo;
-    if (ret == 1) {
-        /* more packets may follow, so we save the RTP context */
-        rt->cur_transport_priv = rtsp_st->transport_priv;
+    ret = rtsp_fetch_packet(s, pkt);
+    if (ret < 0) {
+        return ret;
     }
 
     /* send dummy request to keep TCP connection alive */
@@ -1588,35 +1641,6 @@ static int rtsp_read_packet(AVFormatContext *s,
     return 0;
 }
 
-static int rtsp_read_play(AVFormatContext *s)
-{
-    RTSPState *rt = s->priv_data;
-    RTSPMessageHeader reply1, *reply = &reply1;
-    char cmd[1024];
-
-    av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
-
-    if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
-        if (rt->state == RTSP_STATE_PAUSED) {
-            snprintf(cmd, sizeof(cmd),
-                     "PLAY %s RTSP/1.0\r\n",
-                     s->filename);
-        } else {
-            snprintf(cmd, sizeof(cmd),
-                     "PLAY %s RTSP/1.0\r\n"
-                     "Range: npt=%0.3f-\r\n",
-                     s->filename,
-                     (double)rt->seek_timestamp / AV_TIME_BASE);
-        }
-        rtsp_send_cmd(s, cmd, reply, NULL);
-        if (reply->status_code != RTSP_STATUS_OK) {
-            return -1;
-        }
-    }
-    rt->state = RTSP_STATE_PLAYING;
-    return 0;
-}
-
 /* pause the stream */
 static int rtsp_read_pause(AVFormatContext *s)
 {
@@ -1687,7 +1711,6 @@ static int rtsp_read_close(AVFormatContext *s)
     return 0;
 }
 
-#if CONFIG_RTSP_DEMUXER
 AVInputFormat rtsp_demuxer = {
     "rtsp",
     NULL_IF_CONFIG_SMALL("RTSP input format"),
@@ -1767,12 +1790,6 @@ static int sdp_read_header(AVFormatContext *s,
     return err;
 }
 
-static int sdp_read_packet(AVFormatContext *s,
-                            AVPacket *pkt)
-{
-    return rtsp_read_packet(s, pkt);
-}
-
 static int sdp_read_close(AVFormatContext *s)
 {
     RTSPState *rt = s->priv_data;
@@ -1780,14 +1797,12 @@ static int sdp_read_close(AVFormatContext *s)
     return 0;
 }
 
-#if CONFIG_SDP_DEMUXER
 AVInputFormat sdp_demuxer = {
     "sdp",
     NULL_IF_CONFIG_SMALL("SDP"),
     sizeof(RTSPState),
     sdp_probe,
     sdp_read_header,
-    sdp_read_packet,
+    rtsp_fetch_packet,
     sdp_read_close,
 };
-#endif