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>
This commit is contained in:
parent
7497222090
commit
1f57d60129
@ -286,8 +286,27 @@ typedef struct SDPParseState {
|
||||
struct sockaddr_storage default_ip;
|
||||
int default_ttl;
|
||||
int skip_media; ///< set if an unknown m= line occurs
|
||||
int nb_default_include_source_addrs; /**< Number of source-specific multicast include source IP address (from SDP content) */
|
||||
struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */
|
||||
int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */
|
||||
struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */
|
||||
} SDPParseState;
|
||||
|
||||
static void copy_default_source_addrs(struct RTSPSource **addrs, int count,
|
||||
struct RTSPSource ***dest, int *dest_count)
|
||||
{
|
||||
RTSPSource *rtsp_src, *rtsp_src2;
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
rtsp_src = addrs[i];
|
||||
rtsp_src2 = av_malloc(sizeof(*rtsp_src2));
|
||||
if (!rtsp_src2)
|
||||
continue;
|
||||
memcpy(rtsp_src2, rtsp_src, sizeof(*rtsp_src));
|
||||
dynarray_add(dest, dest_count, rtsp_src2);
|
||||
}
|
||||
}
|
||||
|
||||
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
||||
int letter, const char *buf)
|
||||
{
|
||||
@ -298,6 +317,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
||||
int payload_type, i;
|
||||
AVStream *st;
|
||||
RTSPStream *rtsp_st;
|
||||
RTSPSource *rtsp_src;
|
||||
struct sockaddr_storage sdp_ip;
|
||||
int ttl;
|
||||
|
||||
@ -366,6 +386,15 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
||||
rtsp_st->sdp_ip = s1->default_ip;
|
||||
rtsp_st->sdp_ttl = s1->default_ttl;
|
||||
|
||||
copy_default_source_addrs(s1->default_include_source_addrs,
|
||||
s1->nb_default_include_source_addrs,
|
||||
&rtsp_st->include_source_addrs,
|
||||
&rtsp_st->nb_include_source_addrs);
|
||||
copy_default_source_addrs(s1->default_exclude_source_addrs,
|
||||
s1->nb_default_exclude_source_addrs,
|
||||
&rtsp_st->exclude_source_addrs,
|
||||
&rtsp_st->nb_exclude_source_addrs);
|
||||
|
||||
get_word(buf1, sizeof(buf1), &p); /* port */
|
||||
rtsp_st->sdp_port = atoi(buf1);
|
||||
|
||||
@ -495,22 +524,43 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
||||
p += strspn(p, SPACE_CHARS);
|
||||
if (av_strstart(p, "inline:", &p))
|
||||
get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p);
|
||||
} else if (av_strstart(p, "source-filter:", &p) && s->nb_streams > 0) {
|
||||
} else if (av_strstart(p, "source-filter:", &p)) {
|
||||
int exclude = 0;
|
||||
get_word(buf1, sizeof(buf1), &p);
|
||||
if (strcmp(buf1, "incl"))
|
||||
if (strcmp(buf1, "incl") && strcmp(buf1, "excl"))
|
||||
return;
|
||||
exclude = !strcmp(buf1, "excl");
|
||||
|
||||
get_word(buf1, sizeof(buf1), &p);
|
||||
if (strcmp(buf1, "IN") != 0)
|
||||
return;
|
||||
get_word(buf1, sizeof(buf1), &p);
|
||||
if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6"))
|
||||
if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*"))
|
||||
return;
|
||||
// not checking that the destination address actually matches
|
||||
// not checking that the destination address actually matches or is wildcard
|
||||
get_word(buf1, sizeof(buf1), &p);
|
||||
|
||||
while (*p != '\0') {
|
||||
rtsp_src = av_mallocz(sizeof(*rtsp_src));
|
||||
if (!rtsp_src)
|
||||
return;
|
||||
get_word(rtsp_src->addr, sizeof(rtsp_src->addr), &p);
|
||||
if (exclude) {
|
||||
if (s->nb_streams == 0) {
|
||||
dynarray_add(&s1->default_exclude_source_addrs, &s1->nb_default_exclude_source_addrs, rtsp_src);
|
||||
} else {
|
||||
rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
|
||||
get_word(rtsp_st->source_addr, sizeof(rtsp_st->source_addr), &p);
|
||||
dynarray_add(&rtsp_st->exclude_source_addrs, &rtsp_st->nb_exclude_source_addrs, rtsp_src);
|
||||
}
|
||||
} else {
|
||||
if (s->nb_streams == 0) {
|
||||
dynarray_add(&s1->default_include_source_addrs, &s1->nb_default_include_source_addrs, rtsp_src);
|
||||
} else {
|
||||
rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
|
||||
dynarray_add(&rtsp_st->include_source_addrs, &rtsp_st->nb_include_source_addrs, rtsp_src);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (rt->server_type == RTSP_SERVER_WMS)
|
||||
ff_wms_parse_sdp_a_line(s, p);
|
||||
@ -535,7 +585,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
|
||||
{
|
||||
RTSPState *rt = s->priv_data;
|
||||
const char *p;
|
||||
int letter;
|
||||
int letter, i;
|
||||
/* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
|
||||
* contain long SDP lines containing complete ASF Headers (several
|
||||
* kB) or arrays of MDPR (RM stream descriptor) headers plus
|
||||
@ -572,6 +622,14 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
|
||||
if (*p == '\n')
|
||||
p++;
|
||||
}
|
||||
|
||||
for (i = 0; i < s1->nb_default_include_source_addrs; i++)
|
||||
av_free(s1->default_include_source_addrs[i]);
|
||||
av_freep(&s1->default_include_source_addrs);
|
||||
for (i = 0; i < s1->nb_default_exclude_source_addrs; i++)
|
||||
av_free(s1->default_exclude_source_addrs[i]);
|
||||
av_freep(&s1->default_exclude_source_addrs);
|
||||
|
||||
rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
|
||||
if (!rt->p) return AVERROR(ENOMEM);
|
||||
return 0;
|
||||
@ -615,7 +673,7 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
|
||||
void ff_rtsp_close_streams(AVFormatContext *s)
|
||||
{
|
||||
RTSPState *rt = s->priv_data;
|
||||
int i;
|
||||
int i, j;
|
||||
RTSPStream *rtsp_st;
|
||||
|
||||
ff_rtsp_undo_setup(s);
|
||||
@ -625,6 +683,13 @@ void ff_rtsp_close_streams(AVFormatContext *s)
|
||||
if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
|
||||
rtsp_st->dynamic_handler->free(
|
||||
rtsp_st->dynamic_protocol_context);
|
||||
for (j = 0; j < rtsp_st->nb_include_source_addrs; j++)
|
||||
av_free(rtsp_st->include_source_addrs[j]);
|
||||
av_freep(&rtsp_st->include_source_addrs);
|
||||
for (j = 0; j < rtsp_st->nb_exclude_source_addrs; j++)
|
||||
av_free(rtsp_st->exclude_source_addrs[j]);
|
||||
av_freep(&rtsp_st->exclude_source_addrs);
|
||||
|
||||
av_free(rtsp_st);
|
||||
}
|
||||
}
|
||||
@ -2058,6 +2123,17 @@ static int sdp_probe(AVProbeData *p1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void append_source_addrs(char *buf, int size, const char *name,
|
||||
int count, struct RTSPSource **addrs)
|
||||
{
|
||||
int i;
|
||||
if (!count)
|
||||
return;
|
||||
av_strlcatf(buf, size, "&%s=%s", name, addrs[0]->addr);
|
||||
for (i = 1; i < count; i++)
|
||||
av_strlcatf(buf, size, ",%s", addrs[i]->addr);
|
||||
}
|
||||
|
||||
static int sdp_read_header(AVFormatContext *s)
|
||||
{
|
||||
RTSPState *rt = s->priv_data;
|
||||
@ -2101,8 +2177,13 @@ static int sdp_read_header(AVFormatContext *s)
|
||||
"?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
|
||||
rtsp_st->sdp_ttl,
|
||||
rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0);
|
||||
if (rtsp_st->source_addr[0])
|
||||
av_strlcatf(url, sizeof(url), "&sources=%s", rtsp_st->source_addr);
|
||||
|
||||
append_source_addrs(url, sizeof(url), "sources",
|
||||
rtsp_st->nb_include_source_addrs,
|
||||
rtsp_st->include_source_addrs);
|
||||
append_source_addrs(url, sizeof(url), "block",
|
||||
rtsp_st->nb_exclude_source_addrs,
|
||||
rtsp_st->exclude_source_addrs);
|
||||
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
|
||||
&s->interrupt_callback, NULL) < 0) {
|
||||
err = AVERROR_INVALIDDATA;
|
||||
|
@ -402,6 +402,10 @@ typedef struct RTSPState {
|
||||
#define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */
|
||||
#define RTSP_FLAG_CUSTOM_IO 0x4 /**< Do all IO via the AVIOContext. */
|
||||
|
||||
typedef struct RTSPSource {
|
||||
char addr[128]; /**< Source-specific multicast include source IP address (from SDP content) */
|
||||
} RTSPSource;
|
||||
|
||||
/**
|
||||
* Describe a single stream, as identified by a single m= line block in the
|
||||
* SDP content. In the case of RDT, one RTSPStream can represent multiple
|
||||
@ -425,7 +429,10 @@ typedef struct RTSPStream {
|
||||
//@{
|
||||
int sdp_port; /**< port (from SDP content) */
|
||||
struct sockaddr_storage sdp_ip; /**< IP address (from SDP content) */
|
||||
char source_addr[100]; /**< Source-specific multicast source IP address (from SDP content) */
|
||||
int nb_include_source_addrs; /**< Number of source-specific multicast include source IP addresses (from SDP content) */
|
||||
struct RTSPSource **include_source_addrs; /**< Source-specific multicast include source IP addresses (from SDP content) */
|
||||
int nb_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP addresses (from SDP content) */
|
||||
struct RTSPSource **exclude_source_addrs; /**< Source-specific multicast exclude source IP addresses (from SDP content) */
|
||||
int sdp_ttl; /**< IP Time-To-Live (from SDP content) */
|
||||
int sdp_payload_type; /**< payload type */
|
||||
//@}
|
||||
|
Loading…
Reference in New Issue
Block a user