mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2024-12-25 16:52:31 +00:00
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;
|
struct sockaddr_storage default_ip;
|
||||||
int default_ttl;
|
int default_ttl;
|
||||||
int skip_media; ///< set if an unknown m= line occurs
|
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;
|
} 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,
|
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
||||||
int letter, const char *buf)
|
int letter, const char *buf)
|
||||||
{
|
{
|
||||||
@ -298,6 +317,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
|||||||
int payload_type, i;
|
int payload_type, i;
|
||||||
AVStream *st;
|
AVStream *st;
|
||||||
RTSPStream *rtsp_st;
|
RTSPStream *rtsp_st;
|
||||||
|
RTSPSource *rtsp_src;
|
||||||
struct sockaddr_storage sdp_ip;
|
struct sockaddr_storage sdp_ip;
|
||||||
int ttl;
|
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_ip = s1->default_ip;
|
||||||
rtsp_st->sdp_ttl = s1->default_ttl;
|
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 */
|
get_word(buf1, sizeof(buf1), &p); /* port */
|
||||||
rtsp_st->sdp_port = atoi(buf1);
|
rtsp_st->sdp_port = atoi(buf1);
|
||||||
|
|
||||||
@ -495,22 +524,43 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
|
|||||||
p += strspn(p, SPACE_CHARS);
|
p += strspn(p, SPACE_CHARS);
|
||||||
if (av_strstart(p, "inline:", &p))
|
if (av_strstart(p, "inline:", &p))
|
||||||
get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &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);
|
get_word(buf1, sizeof(buf1), &p);
|
||||||
if (strcmp(buf1, "incl"))
|
if (strcmp(buf1, "incl") && strcmp(buf1, "excl"))
|
||||||
return;
|
return;
|
||||||
|
exclude = !strcmp(buf1, "excl");
|
||||||
|
|
||||||
get_word(buf1, sizeof(buf1), &p);
|
get_word(buf1, sizeof(buf1), &p);
|
||||||
if (strcmp(buf1, "IN") != 0)
|
if (strcmp(buf1, "IN") != 0)
|
||||||
return;
|
return;
|
||||||
get_word(buf1, sizeof(buf1), &p);
|
get_word(buf1, sizeof(buf1), &p);
|
||||||
if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6"))
|
if (strcmp(buf1, "IP4") && strcmp(buf1, "IP6") && strcmp(buf1, "*"))
|
||||||
return;
|
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);
|
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];
|
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 {
|
} else {
|
||||||
if (rt->server_type == RTSP_SERVER_WMS)
|
if (rt->server_type == RTSP_SERVER_WMS)
|
||||||
ff_wms_parse_sdp_a_line(s, p);
|
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;
|
RTSPState *rt = s->priv_data;
|
||||||
const char *p;
|
const char *p;
|
||||||
int letter;
|
int letter, i;
|
||||||
/* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
|
/* Some SDP lines, particularly for Realmedia or ASF RTSP streams,
|
||||||
* contain long SDP lines containing complete ASF Headers (several
|
* contain long SDP lines containing complete ASF Headers (several
|
||||||
* kB) or arrays of MDPR (RM stream descriptor) headers plus
|
* 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')
|
if (*p == '\n')
|
||||||
p++;
|
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));
|
rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
|
||||||
if (!rt->p) return AVERROR(ENOMEM);
|
if (!rt->p) return AVERROR(ENOMEM);
|
||||||
return 0;
|
return 0;
|
||||||
@ -615,7 +673,7 @@ void ff_rtsp_undo_setup(AVFormatContext *s)
|
|||||||
void ff_rtsp_close_streams(AVFormatContext *s)
|
void ff_rtsp_close_streams(AVFormatContext *s)
|
||||||
{
|
{
|
||||||
RTSPState *rt = s->priv_data;
|
RTSPState *rt = s->priv_data;
|
||||||
int i;
|
int i, j;
|
||||||
RTSPStream *rtsp_st;
|
RTSPStream *rtsp_st;
|
||||||
|
|
||||||
ff_rtsp_undo_setup(s);
|
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)
|
if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
|
||||||
rtsp_st->dynamic_handler->free(
|
rtsp_st->dynamic_handler->free(
|
||||||
rtsp_st->dynamic_protocol_context);
|
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);
|
av_free(rtsp_st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2058,6 +2123,17 @@ static int sdp_probe(AVProbeData *p1)
|
|||||||
return 0;
|
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)
|
static int sdp_read_header(AVFormatContext *s)
|
||||||
{
|
{
|
||||||
RTSPState *rt = s->priv_data;
|
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,
|
"?localport=%d&ttl=%d&connect=%d", rtsp_st->sdp_port,
|
||||||
rtsp_st->sdp_ttl,
|
rtsp_st->sdp_ttl,
|
||||||
rt->rtsp_flags & RTSP_FLAG_FILTER_SRC ? 1 : 0);
|
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,
|
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
|
||||||
&s->interrupt_callback, NULL) < 0) {
|
&s->interrupt_callback, NULL) < 0) {
|
||||||
err = AVERROR_INVALIDDATA;
|
err = AVERROR_INVALIDDATA;
|
||||||
|
@ -402,6 +402,10 @@ typedef struct RTSPState {
|
|||||||
#define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */
|
#define RTSP_FLAG_LISTEN 0x2 /**< Wait for incoming connections. */
|
||||||
#define RTSP_FLAG_CUSTOM_IO 0x4 /**< Do all IO via the AVIOContext. */
|
#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
|
* 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
|
* 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) */
|
int sdp_port; /**< port (from SDP content) */
|
||||||
struct sockaddr_storage sdp_ip; /**< IP address (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_ttl; /**< IP Time-To-Live (from SDP content) */
|
||||||
int sdp_payload_type; /**< payload type */
|
int sdp_payload_type; /**< payload type */
|
||||||
//@}
|
//@}
|
||||||
|
Loading…
Reference in New Issue
Block a user