Allow subscription to any of the streams, not just the first, available in
[libav.git] / libavformat / rtsp.c
index 1e874ed..f0c6e1b 100644 (file)
@@ -75,6 +75,8 @@ typedef struct RTSPState {
     char last_reply[2048]; /* XXX: allocate ? */
     void *cur_tx;
     int need_subscription;
+    enum AVDiscard real_setup_cache[MAX_STREAMS];
+    char last_subscription[1024];
 } RTSPState;
 
 typedef struct RTSPStream {
@@ -1352,27 +1354,66 @@ static int rtsp_read_packet(AVFormatContext *s,
     int ret, len;
     uint8_t buf[RTP_MAX_PACKET_LENGTH];
 
-    if (rt->server_type == RTSP_SERVER_REAL && rt->need_subscription) {
+    if (rt->server_type == RTSP_SERVER_REAL) {
         int i;
         RTSPHeader reply1, *reply = &reply1;
+        enum AVDiscard cache[MAX_STREAMS];
         char cmd[1024];
 
-        snprintf(cmd, sizeof(cmd),
-                 "SET_PARAMETER %s RTSP/1.0\r\n"
-                 "Subscribe: ",
-                 s->filename);
-        for (i = 0; i < rt->nb_rtsp_streams; i++) {
-            if (i != 0) av_strlcat(cmd, ",", sizeof(cmd));
-            ff_rdt_subscribe_rule(cmd, sizeof(cmd), i, 0);
+        for (i = 0; i < s->nb_streams; i++)
+            cache[i] = s->streams[i]->discard;
+
+        if (!rt->need_subscription) {
+            if (memcmp (cache, rt->real_setup_cache,
+                        sizeof(enum AVDiscard) * s->nb_streams)) {
+                av_strlcatf(cmd, sizeof(cmd),
+                            "SET_PARAMETER %s RTSP/1.0\r\n"
+                            "Unsubscribe: %s\r\n",
+                            s->filename, rt->last_subscription);
+                rtsp_send_cmd(s, cmd, reply, NULL);
+                if (reply->status_code != RTSP_STATUS_OK)
+                    return AVERROR_INVALIDDATA;
+                rt->need_subscription = 1;
+            }
         }
-        av_strlcat(cmd, "\r\n", sizeof(cmd));
-        rtsp_send_cmd(s, cmd, reply, NULL);
-        if (reply->status_code != RTSP_STATUS_OK)
-            return AVERROR_INVALIDDATA;
-        rt->need_subscription = 0;
 
-        if (rt->state == RTSP_STATE_PLAYING)
-            rtsp_read_play (s);
+        if (rt->need_subscription) {
+            int r, rule_nr, first = 1;
+
+            memcpy(rt->real_setup_cache, cache,
+                   sizeof(enum AVDiscard) * s->nb_streams);
+            rt->last_subscription[0] = 0;
+
+            snprintf(cmd, sizeof(cmd),
+                     "SET_PARAMETER %s RTSP/1.0\r\n"
+                     "Subscribe: ",
+                     s->filename);
+            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]->discard != AVDISCARD_ALL) {
+                            if (!first)
+                                av_strlcat(rt->last_subscription, ",",
+                                           sizeof(rt->last_subscription));
+                            ff_rdt_subscribe_rule(
+                                rt->last_subscription,
+                                sizeof(rt->last_subscription), i, rule_nr);
+                            first = 0;
+                        }
+                        rule_nr++;
+                    }
+                }
+            }
+            av_strlcatf(cmd, sizeof(cmd), "%s\r\n", rt->last_subscription);
+            rtsp_send_cmd(s, cmd, reply, NULL);
+            if (reply->status_code != RTSP_STATUS_OK)
+                return AVERROR_INVALIDDATA;
+            rt->need_subscription = 0;
+
+            if (rt->state == RTSP_STATE_PLAYING)
+                rtsp_read_play (s);
+        }
     }
 
     /* get next frames from the same RTP packet */