]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtsp.c
xdcam hd422 720p24 fourcc in mov
[ffmpeg] / libavformat / rtsp.c
index 16997e32450d9f13a7263ae424f363795b774389..877b38d2316c0afacb4814a58d008587a430cd7f 100644 (file)
@@ -53,6 +53,7 @@ int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP);
 #define READ_PACKET_TIMEOUT_S 10
 #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / SELECT_TIMEOUT_MS
 #define SDP_MAX_SIZE 16384
+#define RECVBUF_SIZE 10 * RTP_MAX_PACKET_LENGTH
 
 static void get_word_until_chars(char *buf, int buf_size,
                                  const char *sep, const char **pp)
@@ -114,6 +115,12 @@ static int sdp_parse_rtpmap(AVFormatContext *s,
                 break;
             }
         }
+        /* If no dynamic handler was found, check with the list of standard
+         * allocated types, if such a stream for some reason happens to
+         * use a private payload type. This isn't handled in rtpdec.c, since
+         * the format name from the rtpmap line never is passed into rtpdec. */
+        if (!rtsp_st->dynamic_handler)
+            codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type);
     } else {
         /* We are in a standard case
          * (from http://www.iana.org/assignments/rtp-parameters). */
@@ -492,6 +499,7 @@ void ff_rtsp_close_streams(AVFormatContext *s)
         av_close_input_stream (rt->asf_ctx);
         rt->asf_ctx = NULL;
     }
+    av_free(rt->recvbuf);
 }
 
 static void *rtsp_rtp_mux_open(AVFormatContext *s, AVStream *st,
@@ -574,7 +582,9 @@ static int rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
                                             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->sdp_payload_type,
+            (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP || !s->max_delay)
+            ? 0 : RTP_REORDER_QUEUE_DEFAULT_SIZE);
 
     if (!rtsp_st->transport_priv) {
          return AVERROR(ENOMEM);
@@ -701,7 +711,14 @@ static void rtsp_parse_transport(RTSPMessageHeader *reply, const char *p)
                     get_word_sep(buf, sizeof(buf), ";,", &p);
                     get_sockaddr(buf, &th->destination);
                 }
+            } else if (!strcmp(parameter, "source")) {
+                if (*p == '=') {
+                    p++;
+                    get_word_sep(buf, sizeof(buf), ";,", &p);
+                    av_strlcpy(th->source, buf, sizeof(th->source));
+                }
             }
+
             while (*p != ';' && *p != '\0' && *p != ',')
                 p++;
             if (*p == ';')
@@ -1154,9 +1171,15 @@ static int make_setup_request(AVFormatContext *s, const char *host, int port,
         case RTSP_LOWER_TRANSPORT_UDP: {
             char url[1024];
 
-            /* XXX: also use address if specified */
-            ff_url_join(url, sizeof(url), "rtp", NULL, host,
-                        reply->transports[0].server_port_min, NULL);
+            /* Use source address if specified */
+            if (reply->transports[0].source[0]) {
+                ff_url_join(url, sizeof(url), "rtp", NULL,
+                            reply->transports[0].source,
+                            reply->transports[0].server_port_min, NULL);
+            } else {
+                ff_url_join(url, sizeof(url), "rtp", NULL, host,
+                            reply->transports[0].server_port_min, NULL);
+            }
             if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) &&
                 rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
                 err = AVERROR_INVALIDDATA;
@@ -1226,6 +1249,7 @@ static int rtsp_read_play(AVFormatContext *s)
     char cmd[1024];
 
     av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
+    rt->nb_byes = 0;
 
     if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
         if (rt->state == RTSP_STATE_PAUSED) {
@@ -1239,8 +1263,7 @@ static int rtsp_read_play(AVFormatContext *s)
         if (reply->status_code != RTSP_STATUS_OK) {
             return -1;
         }
-        if (reply->range_start != AV_NOPTS_VALUE &&
-            rt->transport == RTSP_TRANSPORT_RTP) {
+        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;
@@ -1249,12 +1272,15 @@ static int rtsp_read_play(AVFormatContext *s)
                     continue;
                 if (rtsp_st->stream_index >= 0)
                     st = s->streams[rtsp_st->stream_index];
-                rtpctx->last_rtcp_ntp_time  = AV_NOPTS_VALUE;
-                rtpctx->first_rtcp_ntp_time = AV_NOPTS_VALUE;
-                if (st)
-                    rtpctx->range_start_offset = av_rescale_q(reply->range_start,
-                                                              AV_TIME_BASE_Q,
-                                                              st->time_base);
+                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;
+                    if (st)
+                        rtpctx->range_start_offset =
+                            av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
+                                         st->time_base);
+                }
             }
         }
     }
@@ -1289,6 +1315,7 @@ static int rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply
         return AVERROR_INVALIDDATA;
     }
 
+    av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content);
     /* now we got the SDP description, we parse it */
     ret = sdp_parse(s, (const char *)content);
     av_freep(&content);
@@ -1332,7 +1359,7 @@ static int rtsp_setup_output_streams(AVFormatContext *s, const char *addr)
         av_free(sdp);
         return AVERROR_INVALIDDATA;
     }
-    av_log(s, AV_LOG_INFO, "SDP:\n%s\n", sdp);
+    av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", sdp);
     ff_rtsp_send_cmd_with_content(s, "ANNOUNCE", rt->control_uri,
                                   "Content-Type: application/sdp\r\n",
                                   reply, NULL, sdp, strlen(sdp));
@@ -1648,7 +1675,7 @@ static int rtsp_read_header(AVFormatContext *s,
 }
 
 static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
-                           uint8_t *buf, int buf_size)
+                           uint8_t *buf, int buf_size, int64_t wait_end)
 {
     RTSPState *rt = s->priv_data;
     RTSPStream *rtsp_st;
@@ -1659,6 +1686,8 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
     for (;;) {
         if (url_interrupt_cb())
             return AVERROR(EINTR);
+        if (wait_end && wait_end - av_gettime() < 0)
+            return AVERROR(EAGAIN);
         FD_ZERO(&rfds);
         if (rt->rtsp_hd) {
             tcp_fd = fd_max = url_get_file_handle(rt->rtsp_hd);
@@ -1774,8 +1803,11 @@ 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;
+    RTSPStream *rtsp_st, *first_queue_st = NULL;
+    int64_t wait_end = 0;
+
+    if (rt->nb_byes == rt->nb_rtsp_streams)
+        return AVERROR_EOF;
 
     /* get next frames from the same RTP packet */
     if (rt->cur_transport_priv) {
@@ -1792,30 +1824,58 @@ static int rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
             rt->cur_transport_priv = NULL;
     }
 
+    if (rt->transport == RTSP_TRANSPORT_RTP) {
+        int i;
+        int64_t first_queue_time = 0;
+        for (i = 0; i < rt->nb_rtsp_streams; i++) {
+            RTPDemuxContext *rtpctx = rt->rtsp_streams[i]->transport_priv;
+            int64_t queue_time = ff_rtp_queued_packet_time(rtpctx);
+            if (queue_time && (queue_time - first_queue_time < 0 ||
+                               !first_queue_time)) {
+                first_queue_time = queue_time;
+                first_queue_st   = rt->rtsp_streams[i];
+            }
+        }
+        if (first_queue_time)
+            wait_end = first_queue_time + s->max_delay;
+    }
+
     /* read next RTP packet */
  redo:
+    if (!rt->recvbuf) {
+        rt->recvbuf = av_malloc(RECVBUF_SIZE);
+        if (!rt->recvbuf)
+            return AVERROR(ENOMEM);
+    }
+
     switch(rt->lower_transport) {
     default:
 #if CONFIG_RTSP_DEMUXER
     case RTSP_LOWER_TRANSPORT_TCP:
-        len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf));
+        len = tcp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE);
         break;
 #endif
     case RTSP_LOWER_TRANSPORT_UDP:
     case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
-        len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
+        len = udp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE, wait_end);
         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 == AVERROR(EAGAIN) && first_queue_st &&
+        rt->transport == RTSP_TRANSPORT_RTP) {
+        rtsp_st = first_queue_st;
+        ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, NULL, 0);
+        goto end;
+    }
     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);
+        ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
     } else {
-        ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
+        ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, &rt->recvbuf, len);
         if (ret < 0) {
             /* Either bad packet, or a RTCP packet. Check if the
              * first_rtcp_ntp_time field was initialized. */
@@ -1827,14 +1887,24 @@ static int rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
                  * as this one. */
                 int i;
                 for (i = 0; i < rt->nb_rtsp_streams; i++) {
-                    RTPDemuxContext *rtpctx2 = rtsp_st->transport_priv;
+                    RTPDemuxContext *rtpctx2 = rt->rtsp_streams[i]->transport_priv;
                     if (rtpctx2 &&
                         rtpctx2->first_rtcp_ntp_time == AV_NOPTS_VALUE)
                         rtpctx2->first_rtcp_ntp_time = rtpctx->first_rtcp_ntp_time;
                 }
             }
+            if (ret == -RTCP_BYE) {
+                rt->nb_byes++;
+
+                av_log(s, AV_LOG_DEBUG, "Received BYE for stream %d (%d/%d)\n",
+                       rtsp_st->stream_index, rt->nb_byes, rt->nb_rtsp_streams);
+
+                if (rt->nb_byes == rt->nb_rtsp_streams)
+                    return AVERROR_EOF;
+            }
         }
     }
+end:
     if (ret < 0)
         goto redo;
     if (ret == 1)