[FFmpeg-devel] [PATCH] rtsp.c: read TCP server notifications/messages

Ronald S. Bultje rsbultje
Sun Mar 15 02:52:09 CET 2009


Hi Luca,

On Sat, Mar 14, 2009 at 9:15 PM, Luca Barbato <lu_zero at gentoo.org> wrote:
> Ronald S. Bultje wrote:
>> as per $subj, this patch allows us to parse messages from RTSP servers
>> over the RTSP/TCP connection, either interleaved with the TCP data
>> packets or in addition to the UDP data packets. This eventually (next
>> patch) allows us to read things like interrupt, EOS etc. notifications
>> from the RTSP server.
>
> There are some typos in the comment
>
> data_is_ok doesn't sound right, it's more return_on_interleave,

Fixed.

> I'm not sure this patch is ok please tell me more.

OK, so the top 4 hunks add a feature to rtsp_read_reply() to return
when a data marker is encountered ('$'), similar to what was
previously done in tcp_read_packet(). Hunk 5 removes this code from
tcp_read_packet() and uses rtsp_read_reply() instead for the same
purpose. Hunk 6-7 add the TCP socket to the set that we select() on in
udp_read_packet(), so that if data is available, it is read (these are
normally RTSP messages).

The purpose of this patch is to allow RTSP messages to be read from
the TCP connection (regardless of whether the transport is UDP or
TCP). I reuse rtsp_read_reply() for this purpose to prevent any
duplicate code. The purpose of reading messages interleaved with TCP
data or while UDP data is being sent is because they could contain
server notifications, e.g. an eos notice (WMS doesn't use RTCP bye)
[1].

Ronald

[1] http://msdn.microsoft.com/en-us/library/cc245302(PROT.10).aspx
-------------- next part --------------
Index: ffmpeg-svn/libavformat/rtsp.c
===================================================================
--- ffmpeg-svn.orig/libavformat/rtsp.c	2009-03-14 21:33:04.000000000 -0400
+++ ffmpeg-svn/libavformat/rtsp.c	2009-03-14 21:38:40.000000000 -0400
@@ -743,15 +743,36 @@
     }
 }
 
-static void
+/**
+ * Read a RTSP message from the server, or prepare to read data
+ * packets if we're reading data interleaved over the TCP/RTSP
+ * connection as well.
+ *
+ * @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)
+ * @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
+ *                   is set, this function will return 1 after encountering
+ *                   a '$'. If it is not set, the function will skip any
+ *                   data packets (if they are encountered), until a reply
+ *                   has been fully parsed. If no more data is available
+ *                   without parsing a reply, it will return an error.
+ *
+ * @returns 1 if a data packets is ready to be received, -1 on error,
+ *          and 0 on success.
+ */
+static int
 rtsp_read_reply (AVFormatContext *s, RTSPMessageHeader *reply,
-                 unsigned char **content_ptr)
+                 unsigned char **content_ptr, int return_on_interleaved_data)
 {
     RTSPState *rt = s->priv_data;
     char buf[4096], buf1[1024], *q;
     unsigned char ch;
     const char *p;
-    int content_length, line_count = 0;
+    int ret, content_length, line_count = 0;
     unsigned char *content = NULL;
 
     memset(reply, 0, sizeof(*reply));
@@ -761,12 +782,19 @@
     for(;;) {
         q = buf;
         for(;;) {
-            if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1)
-                break;
+            ret = url_readbuf(rt->rtsp_hd, &ch, 1);
+#ifdef DEBUG_RTP_TCP
+            printf("ret=%d c=%02x [%c]\n", ret, ch, ch);
+#endif
+            if (ret != 1)
+                return -1;
             if (ch == '\n')
                 break;
             if (ch == '$') {
                 /* XXX: only parse it if first char on line ? */
+                if (return_on_interleaved_data) {
+                    return 1;
+                } else
                 rtsp_skip_packet(s);
             } else if (ch != '\r') {
                 if ((q - buf) < sizeof(buf) - 1)
@@ -808,6 +836,8 @@
         *content_ptr = content;
     else
         av_free(content);
+
+    return 0;
 }
 
 static void rtsp_send_cmd(AVFormatContext *s,
@@ -831,7 +861,7 @@
 #endif
     url_write(rt->rtsp_hd, buf, strlen(buf));
 
-    rtsp_read_reply(s, reply, content_ptr);
+    rtsp_read_reply(s, reply, content_ptr, 0);
 }
 
 
@@ -1273,14 +1303,14 @@
 #endif
  redo:
     for(;;) {
-        ret = url_readbuf(rt->rtsp_hd, buf, 1);
-#ifdef DEBUG_RTP_TCP
-        printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]);
-#endif
-        if (ret != 1)
+        RTSPMessageHeader reply;
+
+        ret = rtsp_read_reply(s, &reply, NULL, 1);
+        if (ret == -1)
             return -1;
-        if (buf[0] == '$')
+        if (ret == 1) /* received '$' */
             break;
+        /* XXX: parse message */
     }
     ret = url_readbuf(rt->rtsp_hd, buf, 3);
     if (ret != 3)
@@ -1319,14 +1349,15 @@
     RTSPState *rt = s->priv_data;
     RTSPStream *rtsp_st;
     fd_set rfds;
-    int fd, fd_max, n, i, ret;
+    int fd, fd_max, n, i, ret, tcp_fd;
     struct timeval tv;
 
     for(;;) {
         if (url_interrupt_cb())
             return AVERROR(EINTR);
         FD_ZERO(&rfds);
-        fd_max = -1;
+        tcp_fd = fd_max = url_get_file_handle(rt->rtsp_hd);
+        FD_SET(tcp_fd, &rfds);
         for(i = 0; i < rt->nb_rtsp_streams; i++) {
             rtsp_st = rt->rtsp_streams[i];
             if (rtsp_st->rtp_handle) {
@@ -1355,6 +1386,12 @@
                     }
                 }
             }
+            if (FD_ISSET(tcp_fd, &rfds)) {
+                RTSPMessageHeader reply;
+
+                rtsp_read_reply(s, &reply, NULL, 0);
+                /* XXX: parse message */
+            }
         }
     }
 }



More information about the ffmpeg-devel mailing list