Browse code

rtsp: Support RFC4570 (source specific multicast) more properly.

Add support for domain names, for multiple source addresses,
for exclusions, and for session level specification of addresses.

Signed-off-by: Martin Storsjö <martin@martin.st>

Ed Torbett authored on 2013/07/26 19:38:00
Showing 2 changed files
... ...
@@ -286,8 +286,27 @@ typedef struct SDPParseState {
286 286
     struct sockaddr_storage default_ip;
287 287
     int            default_ttl;
288 288
     int            skip_media;  ///< set if an unknown m= line occurs
289
+    int nb_default_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */
290
+    struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */
291
+    int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */
292
+    struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */
289 293
 } SDPParseState;
290 294
 
295
+static void copy_default_source_addrs(struct RTSPSource **addrs, int count,
296
+                                      struct RTSPSource ***dest, int *dest_count)
297
+{
298
+    RTSPSource *rtsp_src, *rtsp_src2;
299
+    int i;
300
+    for (i = 0; i < count; i++) {
301
+        rtsp_src = addrs[i];
302
+        rtsp_src2 = av_malloc(sizeof(*rtsp_src2));
303
+        if (!rtsp_src2)
304
+            continue;
305
+        memcpy(rtsp_src2, rtsp_src, sizeof(*rtsp_src));
306
+        dynarray_add(dest, dest_count, rtsp_src2);
307
+    }
308
+}
309
+
291 310
 static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
292 311
                            int letter, const char *buf)
293 312
 {
... ...
@@ -298,6 +317,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
298 298
     int payload_type, i;
299 299
     AVStream *st;
300 300
     RTSPStream *rtsp_st;
301
+    RTSPSource *rtsp_src;
301 302
     struct sockaddr_storage sdp_ip;
302 303
     int ttl;
303 304
 
... ...
@@ -366,6 +386,15 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
366 366
         rtsp_st->sdp_ip = s1->default_ip;
367 367
         rtsp_st->sdp_ttl = s1->default_ttl;
368 368
 
369
+        copy_default_source_addrs(s1->default_include_source_addrs,
370
+                                  s1->nb_default_include_source_addrs,
371
+                                  &rtsp_st->include_source_addrs,
372
+                                  &rtsp_st->nb_include_source_addrs);
373
+        copy_default_source_addrs(s1->default_exclude_source_addrs,
374
+                                  s1->nb_default_exclude_source_addrs,
375
+                                  &rtsp_st->exclude_source_addrs,
376
+                                  &rtsp_st->nb_exclude_source_addrs);
377
+
369 378
         get_word(buf1, sizeof(buf1), &p); /* port */
370 379
         rtsp_st->sdp_port = atoi(buf1);
371 380
 
... ...
@@ -495,22 +524,43 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
495 495
             p += strspn(p, SPACE_CHARS);
496 496
             if (av_strstart(p, "inline:", &p))
497 497
                 get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p);
498
-        } else if (av_strstart(p, "source-filter:", &p) && s->nb_streams > 0) {
498
+        } else if (av_strstart(p, "source-filter:", &p)) {
499
+            int exclude = 0;
499 500
             get_word(buf1, sizeof(buf1), &p);
500
-            if (strcmp(buf1, "incl"))
501
+            if (strcmp(buf1, "incl") && strcmp(buf1, "excl"))
501 502
                 return;
503
+            exclude = !strcmp(buf1, "excl");
502 504
 
503 505
             get_word(buf1, sizeof(buf1), &p);
504 506
             if (strcmp(buf1, "IN") != 0)
505 507
                 return;
506 508
             get_word(buf1, sizeof(buf1), &p);
507
-            if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6"))
509
+            if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*"))
508 510
                 return;
509
-            // not checking that the destination address actually matches
511
+            // not checking that the destination address actually matches or is wildcard
510 512
             get_word(buf1, sizeof(buf1), &p);
511 513
 
512
-            rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
513
-            get_word(rtsp_st->source_addr, sizeof(rtsp_st->source_addr), &p);
514
+            while (*p != '\0') {
515
+                rtsp_src = av_mallocz(sizeof(*rtsp_src));
516
+                if (!rtsp_src)
517
+                    return;
518
+                get_word(rtsp_src->addr, sizeof(rtsp_src->addr), &p);
519
+                if (exclude) {
520
+                    if (s->nb_streams == 0) {
521
+                        dynarray_add(&s1->default_exclude_source_addrs, &s1->nb_default_exclude_source_addrs, rtsp_src);
522
+                    } else {
523
+                        rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
524
+                        dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src);
525
+                    }
526
+                } else {
527
+                    if (s->nb_streams == 0) {
528
+                        dynarray_add(&s1->default_include_source_addrs, &s1->nb_default_include_source_addrs, rtsp_src);
529
+                    } else {
530
+                        rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
531
+                        dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src);
532
+                    }
533
+                }
534
+            }
514 535
         } else {
515 536
             if (rt->server_type == RTSP_SERVER_WMS)
516 537
                 ff_wms_parse_sdp_a_line(s, p);
... ...
@@ -535,7 +585,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
535 535
 {
536 536
     RTSPState *rt = s->priv_data;
537 537
     const char *p;
538
-    int letter;
538
+    int letter, i;
539 539
     /* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
540 540
      * contain long SDP lines containing complete ASF Headers (several
541 541
      * kB) or arrays of MDPR (RM stream descriptor) headers plus
... ...
@@ -572,6 +622,14 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
572 572
         if (*p == '\n')
573 573
             p++;
574 574
     }
575
+
576
+    for (i = 0; i < s1->nb_default_include_source_addrs; i++)
577
+        av_free(s1->default_include_source_addrs[i]);
578
+    av_freep(&s1->default_include_source_addrs);
579
+    for (i = 0; i < s1->nb_default_exclude_source_addrs; i++)
580
+        av_free(s1->default_exclude_source_addrs[i]);
581
+    av_freep(&s1->default_exclude_source_addrs);
582
+
575 583
     rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
576 584
     if (!rt->p) return AVERROR(ENOMEM);
577 585
     return 0;
... ...
@@ -615,7 +673,7 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
615 615
 void ff_rtsp_close_streams(AVFormatContext *s)
616 616
 {
617 617
     RTSPState *rt = s->priv_data;
618
-    int i;
618
+    int i, j;
619 619
     RTSPStream *rtsp_st;
620 620
 
621 621
     ff_rtsp_undo_setup(s);
... ...
@@ -625,6 +683,13 @@ void ff_rtsp_close_streams(AVFormatContext *s)
625 625
             if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
626 626
                 rtsp_st->dynamic_handler->free(
627 627
                     rtsp_st->dynamic_protocol_context);
628
+            for (j = 0; j < rtsp_st->nb_include_source_addrs; j++)
629
+                av_free(rtsp_st->include_source_addrs[j]);
630
+            av_freep(&rtsp_st->include_source_addrs);
631
+            for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++)
632
+                av_free(rtsp_st->exclude_source_addrs[j]);
633
+            av_freep(&rtsp_st->exclude_source_addrs);
634
+
628 635
             av_free(rtsp_st);
629 636
         }
630 637
     }
... ...
@@ -2058,6 +2123,17 @@ static int sdp_probe(AVProbeData *p1)
2058 2058
     return 0;
2059 2059
 }
2060 2060
 
2061
+static void append_source_addrs(char *buf, int size, const char *name,
2062
+                                int count, struct RTSPSource **addrs)
2063
+{
2064
+    int i;
2065
+    if (!count)
2066
+        return;
2067
+    av_strlcatf(buf, size, "&%s=%s", name, addrs[0]->addr);
2068
+    for (i = 1; i < count; i++)
2069
+        av_strlcatf(buf, size, ",%s", addrs[i]->addr);
2070
+}
2071
+
2061 2072
 static int sdp_read_header(AVFormatContext *s)
2062 2073
 {
2063 2074
     RTSPState *rt = s->priv_data;
... ...
@@ -2101,8 +2177,13 @@ static int sdp_read_header(AVFormatContext *s)
2101 2101
                         "?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
2102 2102
                         rtsp_st->sdp_ttl,
2103 2103
                         rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0);
2104
-            if (rtsp_st->source_addr[0])
2105
-                av_strlcatf(url, sizeof(url), "&sources=%s", rtsp_st->source_addr);
2104
+
2105
+            append_source_addrs(url, sizeof(url), "sources",
2106
+                                rtsp_st->nb_include_source_addrs,
2107
+                                rtsp_st->include_source_addrs);
2108
+            append_source_addrs(url, sizeof(url), "block",
2109
+                                rtsp_st->nb_exclude_source_addrs,
2110
+                                rtsp_st->exclude_source_addrs);
2106 2111
             if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
2107 2112
                            &s->interrupt_callback, NULL) < 0) {
2108 2113
                 err = AVERROR_INVALIDDATA;
... ...
@@ -402,6 +402,10 @@ typedef struct RTSPState {
402 402
 #define RTSP_FLAG_LISTEN      0x2    /**< Wait for incoming connections. */
403 403
 #define RTSP_FLAG_CUSTOM_IO   0x4    /**< Do all IO via the AVIOContext. */
404 404
 
405
+typedef struct RTSPSource {
406
+    char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */
407
+} RTSPSource;
408
+
405 409
 /**
406 410
  * Describe a single stream, as identified by a single m= line block in the
407 411
  * SDP content. In the case of RDT, one RTSPStream can represent multiple
... ...
@@ -425,7 +429,10 @@ typedef struct RTSPStream {
425 425
     //@{
426 426
     int sdp_port;             /**< port (from SDP content) */
427 427
     struct sockaddr_storage sdp_ip; /**< IP address (from SDP content) */
428
-    char source_addr[100];    /**< Source-specific multicast source IP address (from SDP content) */
428
+    int nb_include_source_addrs; /**< Number of source-specific multicast include source IP addresses (from SDP content) */
429
+    struct RTSPSource **include_source_addrs; /**< Source-specific multicast include source IP addresses (from SDP content) */
430
+    int nb_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP addresses (from SDP content) */
431
+    struct RTSPSource **exclude_source_addrs; /**< Source-specific multicast exclude source IP addresses (from SDP content) */
429 432
     int sdp_ttl;              /**< IP Time-To-Live (from SDP content) */
430 433
     int sdp_payload_type;     /**< payload type */
431 434
     //@}