]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtspdec.c
libavformat: Add av_pkt_dump{, _log}2, taking an AVStream parameter
[ffmpeg] / libavformat / rtspdec.c
index 13fa969dea85e697a631f6ba3de6d73d85b9de1d..95b8690f3ece1f434c986765b5fa463d63d2a137 100644 (file)
@@ -43,6 +43,19 @@ static int rtsp_read_play(AVFormatContext *s)
     rt->nb_byes = 0;
 
     if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
+        if (rt->transport == RTSP_TRANSPORT_RTP) {
+            for (i = 0; i < rt->nb_rtsp_streams; i++) {
+                RTSPStream *rtsp_st = rt->rtsp_streams[i];
+                RTPDemuxContext *rtpctx = rtsp_st->transport_priv;
+                if (!rtpctx)
+                    continue;
+                ff_rtp_reset_packet_queue(rtpctx);
+                rtpctx->last_rtcp_ntp_time  = AV_NOPTS_VALUE;
+                rtpctx->first_rtcp_ntp_time = AV_NOPTS_VALUE;
+                rtpctx->base_timestamp      = 0;
+                rtpctx->rtcp_ts_offset      = 0;
+            }
+        }
         if (rt->state == RTSP_STATE_PAUSED) {
             cmd[0] = 0;
         } else {
@@ -54,26 +67,18 @@ static int rtsp_read_play(AVFormatContext *s)
         if (reply->status_code != RTSP_STATUS_OK) {
             return -1;
         }
-        if (rt->transport == RTSP_TRANSPORT_RTP) {
+        if (rt->transport == RTSP_TRANSPORT_RTP &&
+            reply->range_start != AV_NOPTS_VALUE) {
             for (i = 0; i < rt->nb_rtsp_streams; i++) {
                 RTSPStream *rtsp_st = rt->rtsp_streams[i];
                 RTPDemuxContext *rtpctx = rtsp_st->transport_priv;
                 AVStream *st = NULL;
-                if (!rtpctx)
+                if (!rtpctx || rtsp_st->stream_index < 0)
                     continue;
-                if (rtsp_st->stream_index >= 0)
-                    st = s->streams[rtsp_st->stream_index];
-                ff_rtp_reset_packet_queue(rtpctx);
-                if (reply->range_start != AV_NOPTS_VALUE) {
-                    rtpctx->last_rtcp_ntp_time  = AV_NOPTS_VALUE;
-                    rtpctx->first_rtcp_ntp_time = AV_NOPTS_VALUE;
-                    rtpctx->base_timestamp      = 0;
-                    rtpctx->rtcp_ts_offset      = 0;
-                    if (st)
-                        rtpctx->range_start_offset =
-                            av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
-                                         st->time_base);
-                }
+                st = s->streams[rtsp_st->stream_index];
+                rtpctx->range_start_offset =
+                    av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
+                                 st->time_base);
             }
         }
     }
@@ -81,6 +86,24 @@ static int rtsp_read_play(AVFormatContext *s)
     return 0;
 }
 
+/* pause the stream */
+static int rtsp_read_pause(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    RTSPMessageHeader reply1, *reply = &reply1;
+
+    if (rt->state != RTSP_STATE_STREAMING)
+        return 0;
+    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;
+        }
+    }
+    rt->state = RTSP_STATE_PAUSED;
+    return 0;
+}
+
 int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
 {
     RTSPState *rt = s->priv_data;
@@ -113,7 +136,7 @@ int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
     ret = ff_sdp_parse(s, (const char *)content);
     av_freep(&content);
     if (ret < 0)
-        return AVERROR_INVALIDDATA;
+        return ret;
 
     return 0;
 }
@@ -161,7 +184,7 @@ int ff_rtsp_tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
     RTSPStream *rtsp_st;
 
 #ifdef DEBUG_RTP_TCP
-    dprintf(s, "tcp_read_packet:\n");
+    av_dlog(s, "tcp_read_packet:\n");
 #endif
 redo:
     for (;;) {
@@ -182,7 +205,7 @@ redo:
     id  = buf[0];
     len = AV_RB16(buf + 1);
 #ifdef DEBUG_RTP_TCP
-    dprintf(s, "id=%d len=%d\n", id, len);
+    av_dlog(s, "id=%d len=%d\n", id, len);
 #endif
     if (len > buf_size || len < 12)
         goto redo;
@@ -206,6 +229,20 @@ found:
     *prtsp_st = rtsp_st;
     return len;
 }
+
+static int resetup_tcp(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    char host[1024];
+    int port;
+
+    av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0,
+                 s->filename);
+    ff_rtsp_undo_setup(s);
+    return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP,
+                                      rt->real_challenge);
+}
+
 static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     RTSPState *rt = s->priv_data;
@@ -213,6 +250,7 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
     RTSPMessageHeader reply1, *reply = &reply1;
     char cmd[1024];
 
+retry:
     if (rt->server_type == RTSP_SERVER_REAL) {
         int i;
 
@@ -245,7 +283,7 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
             for (i = 0; i < rt->nb_rtsp_streams; i++) {
                 rule_nr = 0;
                 for (r = 0; r < s->nb_streams; r++) {
-                    if (s->streams[r]->priv_data == rt->rtsp_streams[i]) {
+                    if (s->streams[r]->id == i) {
                         if (s->streams[r]->discard != AVDISCARD_ALL) {
                             if (!first)
                                 av_strlcat(rt->last_subscription, ",",
@@ -272,8 +310,32 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
     }
 
     ret = ff_rtsp_fetch_packet(s, pkt);
-    if (ret < 0)
+    if (ret < 0) {
+        if (ret == AVERROR(ETIMEDOUT) && !rt->packets) {
+            if (rt->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
+                rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) {
+                RTSPMessageHeader reply1, *reply = &reply1;
+                av_log(s, AV_LOG_WARNING, "UDP timeout, retrying with TCP\n");
+                if (rtsp_read_pause(s) != 0)
+                    return -1;
+                // TEARDOWN is required on Real-RTSP, but might make
+                // other servers close the connection.
+                if (rt->server_type == RTSP_SERVER_REAL)
+                    ff_rtsp_send_cmd(s, "TEARDOWN", rt->control_uri, NULL,
+                                     reply, NULL);
+                rt->session_id[0] = '\0';
+                if (resetup_tcp(s) == 0) {
+                    rt->state = RTSP_STATE_IDLE;
+                    rt->need_subscription = 1;
+                    if (rtsp_read_play(s) != 0)
+                        return -1;
+                    goto retry;
+                }
+            }
+        }
         return ret;
+    }
+    rt->packets++;
 
     /* send dummy request to keep TCP connection alive */
     if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) {
@@ -287,24 +349,6 @@ static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
     return 0;
 }
 
-/* pause the stream */
-static int rtsp_read_pause(AVFormatContext *s)
-{
-    RTSPState *rt = s->priv_data;
-    RTSPMessageHeader reply1, *reply = &reply1;
-
-    if (rt->state != RTSP_STATE_STREAMING)
-        return 0;
-    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;
-        }
-    }
-    rt->state = RTSP_STATE_PAUSED;
-    return 0;
-}
-
 static int rtsp_read_seek(AVFormatContext *s, int stream_index,
                           int64_t timestamp, int flags)
 {
@@ -338,7 +382,7 @@ static int rtsp_read_close(AVFormatContext *s)
 #if 0
     /* NOTE: it is valid to flush the buffer here */
     if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
-        url_fclose(&rt->rtsp_gb);
+        avio_close(&rt->rtsp_gb);
     }
 #endif
     ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
@@ -351,7 +395,7 @@ static int rtsp_read_close(AVFormatContext *s)
     return 0;
 }
 
-AVInputFormat rtsp_demuxer = {
+AVInputFormat ff_rtsp_demuxer = {
     "rtsp",
     NULL_IF_CONFIG_SMALL("RTSP input format"),
     sizeof(RTSPState),