diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2013-08-14 14:36:07 +0400 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2013-08-14 14:38:11 +0400 |
commit | 2425be894a527640c98b8c30f3bbecce77e730f1 (patch) | |
tree | f2c0e5f8739d1521dc53c2acf065786b647a29cb /libavformat | |
parent | 1a01f367a40f8df03282f66dc77e63f7fa8491f5 (diff) | |
parent | 6b58e11a8331690ec32e9869db89ae10c54614e9 (diff) |
Merge commit '6b58e11a8331690ec32e9869db89ae10c54614e9'
* commit '6b58e11a8331690ec32e9869db89ae10c54614e9':
rtpproto: Add an option for writing return packets to the address of the last received packets
Merged-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/rtpproto.c | 89 |
1 files changed, 84 insertions, 5 deletions
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index 2dc381a25f..85300a6eb7 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -45,6 +45,9 @@ typedef struct RTPContext { URLContext *rtp_hd, *rtcp_hd; int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs; struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs; + int write_to_source; + struct sockaddr_storage last_rtp_source, last_rtcp_source; + socklen_t last_rtp_source_len, last_rtcp_source_len; } RTPContext; /** @@ -125,6 +128,27 @@ static int compare_addr(const struct sockaddr_storage *a, return 1; } +static int get_port(const struct sockaddr_storage *ss) +{ + if (ss->ss_family == AF_INET) + return ntohs(((const struct sockaddr_in *)ss)->sin_port); +#ifdef AF_INET6 + if (ss->ss_family == AF_INET6) + return ntohs(((const struct sockaddr_in6 *)ss)->sin6_port); +#endif + return 0; +} + +static void set_port(struct sockaddr_storage *ss, int port) +{ + if (ss->ss_family == AF_INET) + ((struct sockaddr_in *)ss)->sin_port = htons(port); +#ifdef AF_INET6 + else if (ss->ss_family == AF_INET6) + ((struct sockaddr_in6 *)ss)->sin6_port = htons(port); +#endif +} + static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr) { int i; @@ -237,6 +261,7 @@ static void rtp_parse_addr_list(URLContext *h, char *buf, * 'connect=0/1' : do a connect() on the UDP socket * 'sources=ip[,ip]' : list allowed source IP addresses * 'block=ip[,ip]' : list disallowed source IP addresses + * 'write_to_source=0/1' : send packets to the source address of the latest received packet * deprecated option: * 'localport=n' : set the local port to n * @@ -290,6 +315,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { connect = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) { + s->write_to_source = strtol(buf, NULL, 10); + } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { av_strlcpy(include_sources, buf, sizeof(include_sources)); rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs); @@ -334,11 +362,11 @@ static int rtp_open(URLContext *h, const char *uri, int flags) static int rtp_read(URLContext *h, uint8_t *buf, int size) { RTPContext *s = h->priv_data; - struct sockaddr_storage from; - socklen_t from_len; int len, n, i; struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}}; int poll_delay = h->flags & AVIO_FLAG_NONBLOCK ? 0 : 100; + struct sockaddr_storage *addrs[2] = { &s->last_rtp_source, &s->last_rtcp_source }; + socklen_t *addr_lens[2] = { &s->last_rtp_source_len, &s->last_rtcp_source_len }; for(;;) { if (ff_check_interrupt(&h->interrupt_callback)) @@ -349,16 +377,16 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) for (i = 1; i >= 0; i--) { if (!(p[i].revents & POLLIN)) continue; - from_len = sizeof(from); + *addr_lens[i] = sizeof(*addrs[i]); len = recvfrom(p[i].fd, buf, size, 0, - (struct sockaddr *)&from, &from_len); + (struct sockaddr *)addrs[i], addr_lens[i]); if (len < 0) { if (ff_neterrno() == AVERROR(EAGAIN) || ff_neterrno() == AVERROR(EINTR)) continue; return AVERROR(EIO); } - if (rtp_check_source_lists(s, &from)) + if (rtp_check_source_lists(s, addrs[i])) continue; return len; } @@ -382,6 +410,57 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size) if (size < 2) return AVERROR(EINVAL); + if (s->write_to_source) { + int fd; + struct sockaddr_storage *source, temp_source; + socklen_t *source_len, temp_len; + if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) { + av_log(h, AV_LOG_ERROR, + "Unable to send packet to source, no packets received yet\n"); + // Intentionally not returning an error here + return size; + } + + if (RTP_PT_IS_RTCP(buf[1])) { + fd = s->rtcp_fd; + source = &s->last_rtcp_source; + source_len = &s->last_rtcp_source_len; + } else { + fd = s->rtp_fd; + source = &s->last_rtp_source; + source_len = &s->last_rtp_source_len; + } + if (!source->ss_family) { + source = &temp_source; + source_len = &temp_len; + if (RTP_PT_IS_RTCP(buf[1])) { + temp_source = s->last_rtp_source; + temp_len = s->last_rtp_source_len; + set_port(source, get_port(source) + 1); + av_log(h, AV_LOG_INFO, + "Not received any RTCP packets yet, inferring peer port " + "from the RTP port\n"); + } else { + temp_source = s->last_rtcp_source; + temp_len = s->last_rtcp_source_len; + set_port(source, get_port(source) - 1); + av_log(h, AV_LOG_INFO, + "Not received any RTP packets yet, inferring peer port " + "from the RTCP port\n"); + } + } + + if (!(h->flags & AVIO_FLAG_NONBLOCK)) { + ret = ff_network_wait_fd(fd, 1); + if (ret < 0) + return ret; + } + ret = sendto(fd, buf, size, 0, (struct sockaddr *) source, + *source_len); + + return ret < 0 ? ff_neterrno() : ret; + } + if (RTP_PT_IS_RTCP(buf[1])) { /* RTCP payload type */ hd = s->rtcp_hd; |