Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * RTP network protocol
  3.  * Copyright (c) 2002 Fabrice Bellard
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * RTP protocol
  25.  */
  26.  
  27. #include "libavutil/parseutils.h"
  28. #include "libavutil/avstring.h"
  29. #include "libavutil/opt.h"
  30. #include "avformat.h"
  31. #include "avio_internal.h"
  32. #include "rtp.h"
  33. #include "rtpproto.h"
  34. #include "url.h"
  35.  
  36. #include <stdarg.h>
  37. #include "internal.h"
  38. #include "network.h"
  39. #include "os_support.h"
  40. #include <fcntl.h>
  41. #if HAVE_POLL_H
  42. #include <sys/poll.h>
  43. #endif
  44.  
  45. typedef struct RTPContext {
  46.     const AVClass *class;
  47.     URLContext *rtp_hd, *rtcp_hd;
  48.     int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
  49.     struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
  50.     int write_to_source;
  51.     struct sockaddr_storage last_rtp_source, last_rtcp_source;
  52.     socklen_t last_rtp_source_len, last_rtcp_source_len;
  53.     int ttl;
  54.     int buffer_size;
  55.     int rtcp_port, local_rtpport, local_rtcpport;
  56.     int connect;
  57.     int pkt_size;
  58.     int dscp;
  59.     char *sources;
  60.     char *block;
  61. } RTPContext;
  62.  
  63. #define OFFSET(x) offsetof(RTPContext, x)
  64. #define D AV_OPT_FLAG_DECODING_PARAM
  65. #define E AV_OPT_FLAG_ENCODING_PARAM
  66. static const AVOption options[] = {
  67.     { "ttl",                "Time to live (in milliseconds, multicast only)",                   OFFSET(ttl),             AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
  68.     { "buffer_size",        "Send/Receive buffer size (in bytes)",                              OFFSET(buffer_size),     AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
  69.     { "rtcp_port",          "Custom rtcp port",                                                 OFFSET(rtcp_port),       AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
  70.     { "local_rtpport",      "Local rtp port",                                                   OFFSET(local_rtpport),   AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
  71.     { "local_rtcpport",     "Local rtcp port",                                                  OFFSET(local_rtcpport),  AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
  72.     { "connect",            "Connect socket",                                                   OFFSET(connect),         AV_OPT_TYPE_INT,    { .i64 =  0 },     0, 1,       .flags = D|E },
  73.     { "write_to_source",    "Send packets to the source address of the latest received packet", OFFSET(write_to_source), AV_OPT_TYPE_INT,    { .i64 =  0 },     0, 1,       .flags = D|E },
  74.     { "pkt_size",           "Maximum packet size",                                              OFFSET(pkt_size),        AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
  75.     { "dscp",               "DSCP class",                                                       OFFSET(dscp),            AV_OPT_TYPE_INT,    { .i64 = -1 },    -1, INT_MAX, .flags = D|E },
  76.     { "sources",            "Source list",                                                      OFFSET(sources),         AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
  77.     { "block",              "Block list",                                                       OFFSET(block),           AV_OPT_TYPE_STRING, { .str = NULL },               .flags = D|E },
  78.     { NULL }
  79. };
  80.  
  81. static const AVClass rtp_class = {
  82.     .class_name = "rtp",
  83.     .item_name  = av_default_item_name,
  84.     .option     = options,
  85.     .version    = LIBAVUTIL_VERSION_INT,
  86. };
  87.  
  88. /**
  89.  * If no filename is given to av_open_input_file because you want to
  90.  * get the local port first, then you must call this function to set
  91.  * the remote server address.
  92.  *
  93.  * @param h media file context
  94.  * @param uri of the remote server
  95.  * @return zero if no error.
  96.  */
  97.  
  98. int ff_rtp_set_remote_url(URLContext *h, const char *uri)
  99. {
  100.     RTPContext *s = h->priv_data;
  101.     char hostname[256];
  102.     int port, rtcp_port;
  103.     const char *p;
  104.  
  105.     char buf[1024];
  106.     char path[1024];
  107.  
  108.     av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
  109.                  path, sizeof(path), uri);
  110.     rtcp_port = port + 1;
  111.  
  112.     p = strchr(uri, '?');
  113.     if (p) {
  114.         if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
  115.             rtcp_port = strtol(buf, NULL, 10);
  116.         }
  117.     }
  118.  
  119.     ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
  120.     ff_udp_set_remote_url(s->rtp_hd, buf);
  121.  
  122.     ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, rtcp_port, "%s", path);
  123.     ff_udp_set_remote_url(s->rtcp_hd, buf);
  124.     return 0;
  125. }
  126.  
  127. static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
  128.                                          int type, int family, int flags)
  129. {
  130.     struct addrinfo hints = { 0 }, *res = 0;
  131.     int error;
  132.     char service[16];
  133.  
  134.     snprintf(service, sizeof(service), "%d", port);
  135.     hints.ai_socktype = type;
  136.     hints.ai_family   = family;
  137.     hints.ai_flags    = flags;
  138.     if ((error = getaddrinfo(hostname, service, &hints, &res))) {
  139.         res = NULL;
  140.         av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error));
  141.     }
  142.  
  143.     return res;
  144. }
  145.  
  146. static int compare_addr(const struct sockaddr_storage *a,
  147.                         const struct sockaddr_storage *b)
  148. {
  149.     if (a->ss_family != b->ss_family)
  150.         return 1;
  151.     if (a->ss_family == AF_INET) {
  152.         return (((const struct sockaddr_in *)a)->sin_addr.s_addr !=
  153.                 ((const struct sockaddr_in *)b)->sin_addr.s_addr);
  154.     }
  155.  
  156. #if HAVE_STRUCT_SOCKADDR_IN6
  157.     if (a->ss_family == AF_INET6) {
  158.         const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr;
  159.         const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr;
  160.         return memcmp(s6_addr_a, s6_addr_b, 16);
  161.     }
  162. #endif
  163.     return 1;
  164. }
  165.  
  166. static int get_port(const struct sockaddr_storage *ss)
  167. {
  168.     if (ss->ss_family == AF_INET)
  169.         return ntohs(((const struct sockaddr_in *)ss)->sin_port);
  170. #if HAVE_STRUCT_SOCKADDR_IN6
  171.     if (ss->ss_family == AF_INET6)
  172.         return ntohs(((const struct sockaddr_in6 *)ss)->sin6_port);
  173. #endif
  174.     return 0;
  175. }
  176.  
  177. static void set_port(struct sockaddr_storage *ss, int port)
  178. {
  179.     if (ss->ss_family == AF_INET)
  180.         ((struct sockaddr_in *)ss)->sin_port = htons(port);
  181. #if HAVE_STRUCT_SOCKADDR_IN6
  182.     else if (ss->ss_family == AF_INET6)
  183.         ((struct sockaddr_in6 *)ss)->sin6_port = htons(port);
  184. #endif
  185. }
  186.  
  187. static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr)
  188. {
  189.     int i;
  190.     if (s->nb_ssm_exclude_addrs) {
  191.         for (i = 0; i < s->nb_ssm_exclude_addrs; i++) {
  192.             if (!compare_addr(source_addr_ptr, s->ssm_exclude_addrs[i]))
  193.                 return 1;
  194.         }
  195.     }
  196.     if (s->nb_ssm_include_addrs) {
  197.         for (i = 0; i < s->nb_ssm_include_addrs; i++) {
  198.             if (!compare_addr(source_addr_ptr, s->ssm_include_addrs[i]))
  199.                 return 0;
  200.         }
  201.         return 1;
  202.     }
  203.     return 0;
  204. }
  205.  
  206. /**
  207.  * add option to url of the form:
  208.  * "http://host:port/path?option1=val1&option2=val2...
  209.  */
  210.  
  211. static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const char *fmt, ...)
  212. {
  213.     char buf1[1024];
  214.     va_list ap;
  215.  
  216.     va_start(ap, fmt);
  217.     if (strchr(buf, '?'))
  218.         av_strlcat(buf, "&", buf_size);
  219.     else
  220.         av_strlcat(buf, "?", buf_size);
  221.     vsnprintf(buf1, sizeof(buf1), fmt, ap);
  222.     av_strlcat(buf, buf1, buf_size);
  223.     va_end(ap);
  224. }
  225.  
  226. static void build_udp_url(RTPContext *s,
  227.                           char *buf, int buf_size,
  228.                           const char *hostname,
  229.                           int port, int local_port,
  230.                           const char *include_sources,
  231.                           const char *exclude_sources)
  232. {
  233.     ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
  234.     if (local_port >= 0)
  235.         url_add_option(buf, buf_size, "localport=%d", local_port);
  236.     if (s->ttl >= 0)
  237.         url_add_option(buf, buf_size, "ttl=%d", s->ttl);
  238.     if (s->buffer_size >= 0)
  239.         url_add_option(buf, buf_size, "buffer_size=%d", s->buffer_size);
  240.     if (s->pkt_size >= 0)
  241.         url_add_option(buf, buf_size, "pkt_size=%d", s->pkt_size);
  242.     if (s->connect)
  243.         url_add_option(buf, buf_size, "connect=1");
  244.     if (s->dscp >= 0)
  245.         url_add_option(buf, buf_size, "dscp=%d", s->dscp);
  246.     url_add_option(buf, buf_size, "fifo_size=0");
  247.     if (include_sources && include_sources[0])
  248.         url_add_option(buf, buf_size, "sources=%s", include_sources);
  249.     if (exclude_sources && exclude_sources[0])
  250.         url_add_option(buf, buf_size, "block=%s", exclude_sources);
  251. }
  252.  
  253. static void rtp_parse_addr_list(URLContext *h, char *buf,
  254.                                 struct sockaddr_storage ***address_list_ptr,
  255.                                 int *address_list_size_ptr)
  256. {
  257.     struct addrinfo *ai = NULL;
  258.     struct sockaddr_storage *source_addr;
  259.     char tmp = '\0', *p = buf, *next;
  260.  
  261.     /* Resolve all of the IPs */
  262.  
  263.     while (p && p[0]) {
  264.         next = strchr(p, ',');
  265.  
  266.         if (next) {
  267.             tmp = *next;
  268.             *next = '\0';
  269.         }
  270.  
  271.         ai = rtp_resolve_host(p, 0, SOCK_DGRAM, AF_UNSPEC, 0);
  272.         if (ai) {
  273.             source_addr = av_mallocz(sizeof(struct sockaddr_storage));
  274.             if (!source_addr) {
  275.                 freeaddrinfo(ai);
  276.                 break;
  277.             }
  278.  
  279.             memcpy(source_addr, ai->ai_addr, ai->ai_addrlen);
  280.             freeaddrinfo(ai);
  281.             dynarray_add(address_list_ptr, address_list_size_ptr, source_addr);
  282.         } else {
  283.             av_log(h, AV_LOG_WARNING, "Unable to resolve %s\n", p);
  284.         }
  285.  
  286.         if (next) {
  287.             *next = tmp;
  288.             p = next + 1;
  289.         } else {
  290.             p = NULL;
  291.         }
  292.     }
  293. }
  294.  
  295. /**
  296.  * url syntax: rtp://host:port[?option=val...]
  297.  * option: 'ttl=n'            : set the ttl value (for multicast only)
  298.  *         'rtcpport=n'       : set the remote rtcp port to n
  299.  *         'localrtpport=n'   : set the local rtp port to n
  300.  *         'localrtcpport=n'  : set the local rtcp port to n
  301.  *         'pkt_size=n'       : set max packet size
  302.  *         'connect=0/1'      : do a connect() on the UDP socket
  303.  *         'sources=ip[,ip]'  : list allowed source IP addresses
  304.  *         'block=ip[,ip]'    : list disallowed source IP addresses
  305.  *         'write_to_source=0/1' : send packets to the source address of the latest received packet
  306.  *         'dscp=n'           : set DSCP value to n (QoS)
  307.  * deprecated option:
  308.  *         'localport=n'      : set the local port to n
  309.  *
  310.  * if rtcpport isn't set the rtcp port will be the rtp port + 1
  311.  * if local rtp port isn't set any available port will be used for the local
  312.  * rtp and rtcp ports
  313.  * if the local rtcp port is not set it will be the local rtp port + 1
  314.  */
  315.  
  316. static int rtp_open(URLContext *h, const char *uri, int flags)
  317. {
  318.     RTPContext *s = h->priv_data;
  319.     int rtp_port;
  320.     char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
  321.     char *sources = include_sources, *block = exclude_sources;
  322.     char buf[1024];
  323.     char path[1024];
  324.     const char *p;
  325.     int i, max_retry_count = 3;
  326.  
  327.     av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
  328.                  path, sizeof(path), uri);
  329.     /* extract parameters */
  330.     if (s->rtcp_port < 0)
  331.         s->rtcp_port = rtp_port + 1;
  332.  
  333.     p = strchr(uri, '?');
  334.     if (p) {
  335.         if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
  336.             s->ttl = strtol(buf, NULL, 10);
  337.         }
  338.         if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
  339.             s->rtcp_port = strtol(buf, NULL, 10);
  340.         }
  341.         if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
  342.             s->local_rtpport = strtol(buf, NULL, 10);
  343.         }
  344.         if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
  345.             s->local_rtpport = strtol(buf, NULL, 10);
  346.         }
  347.         if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
  348.             s->local_rtcpport = strtol(buf, NULL, 10);
  349.         }
  350.         if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
  351.             s->pkt_size = strtol(buf, NULL, 10);
  352.         }
  353.         if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
  354.             s->connect = strtol(buf, NULL, 10);
  355.         }
  356.         if (av_find_info_tag(buf, sizeof(buf), "write_to_source", p)) {
  357.             s->write_to_source = strtol(buf, NULL, 10);
  358.         }
  359.         if (av_find_info_tag(buf, sizeof(buf), "dscp", p)) {
  360.             s->dscp = strtol(buf, NULL, 10);
  361.         }
  362.         if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
  363.             av_strlcpy(include_sources, buf, sizeof(include_sources));
  364.  
  365.             rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
  366.         } else {
  367.             rtp_parse_addr_list(h, s->sources, &s->ssm_include_addrs, &s->nb_ssm_include_addrs);
  368.             sources = s->sources;
  369.         }
  370.         if (av_find_info_tag(buf, sizeof(buf), "block", p)) {
  371.             av_strlcpy(exclude_sources, buf, sizeof(exclude_sources));
  372.             rtp_parse_addr_list(h, buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
  373.         } else {
  374.             rtp_parse_addr_list(h, s->block, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs);
  375.             block = s->block;
  376.         }
  377.     }
  378.  
  379.     for (i = 0; i < max_retry_count; i++) {
  380.         build_udp_url(s, buf, sizeof(buf),
  381.                       hostname, rtp_port, s->local_rtpport,
  382.                       sources, block);
  383.         if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
  384.             goto fail;
  385.         s->local_rtpport = ff_udp_get_local_port(s->rtp_hd);
  386.         if(s->local_rtpport == 65535) {
  387.             s->local_rtpport = -1;
  388.             continue;
  389.         }
  390.         if (s->local_rtcpport < 0) {
  391.             s->local_rtcpport = s->local_rtpport + 1;
  392.             build_udp_url(s, buf, sizeof(buf),
  393.                           hostname, s->rtcp_port, s->local_rtcpport,
  394.                           sources, block);
  395.             if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0) {
  396.                 s->local_rtpport = s->local_rtcpport = -1;
  397.                 continue;
  398.             }
  399.             break;
  400.         }
  401.         build_udp_url(s, buf, sizeof(buf),
  402.                       hostname, s->rtcp_port, s->local_rtcpport,
  403.                       sources, block);
  404.         if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
  405.             goto fail;
  406.         break;
  407.     }
  408.  
  409.     /* just to ease handle access. XXX: need to suppress direct handle
  410.        access */
  411.     s->rtp_fd = ffurl_get_file_handle(s->rtp_hd);
  412.     s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd);
  413.  
  414.     h->max_packet_size = s->rtp_hd->max_packet_size;
  415.     h->is_streamed = 1;
  416.     return 0;
  417.  
  418.  fail:
  419.     if (s->rtp_hd)
  420.         ffurl_close(s->rtp_hd);
  421.     if (s->rtcp_hd)
  422.         ffurl_close(s->rtcp_hd);
  423.     return AVERROR(EIO);
  424. }
  425.  
  426. static int rtp_read(URLContext *h, uint8_t *buf, int size)
  427. {
  428.     RTPContext *s = h->priv_data;
  429.     int len, n, i;
  430.     struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
  431.     int poll_delay = h->flags & AVIO_FLAG_NONBLOCK ? 0 : 100;
  432.     struct sockaddr_storage *addrs[2] = { &s->last_rtp_source, &s->last_rtcp_source };
  433.     socklen_t *addr_lens[2] = { &s->last_rtp_source_len, &s->last_rtcp_source_len };
  434.  
  435.     for(;;) {
  436.         if (ff_check_interrupt(&h->interrupt_callback))
  437.             return AVERROR_EXIT;
  438.         n = poll(p, 2, poll_delay);
  439.         if (n > 0) {
  440.             /* first try RTCP, then RTP */
  441.             for (i = 1; i >= 0; i--) {
  442.                 if (!(p[i].revents & POLLIN))
  443.                     continue;
  444.                 *addr_lens[i] = sizeof(*addrs[i]);
  445.                 len = recvfrom(p[i].fd, buf, size, 0,
  446.                                 (struct sockaddr *)addrs[i], addr_lens[i]);
  447.                 if (len < 0) {
  448.                     if (ff_neterrno() == AVERROR(EAGAIN) ||
  449.                         ff_neterrno() == AVERROR(EINTR))
  450.                         continue;
  451.                     return AVERROR(EIO);
  452.                 }
  453.                 if (rtp_check_source_lists(s, addrs[i]))
  454.                     continue;
  455.                 return len;
  456.             }
  457.         } else if (n < 0) {
  458.             if (ff_neterrno() == AVERROR(EINTR))
  459.                 continue;
  460.             return AVERROR(EIO);
  461.         }
  462.         if (h->flags & AVIO_FLAG_NONBLOCK)
  463.             return AVERROR(EAGAIN);
  464.     }
  465.     return len;
  466. }
  467.  
  468. static int rtp_write(URLContext *h, const uint8_t *buf, int size)
  469. {
  470.     RTPContext *s = h->priv_data;
  471.     int ret;
  472.     URLContext *hd;
  473.  
  474.     if (size < 2)
  475.         return AVERROR(EINVAL);
  476.  
  477.     if ((buf[0] & 0xc0) != (RTP_VERSION << 6))
  478.         av_log(h, AV_LOG_WARNING, "Data doesn't look like RTP packets, "
  479.                                   "make sure the RTP muxer is used\n");
  480.  
  481.     if (s->write_to_source) {
  482.         int fd;
  483.         struct sockaddr_storage *source, temp_source;
  484.         socklen_t *source_len, temp_len;
  485.         if (!s->last_rtp_source.ss_family && !s->last_rtcp_source.ss_family) {
  486.             av_log(h, AV_LOG_ERROR,
  487.                    "Unable to send packet to source, no packets received yet\n");
  488.             // Intentionally not returning an error here
  489.             return size;
  490.         }
  491.  
  492.         if (RTP_PT_IS_RTCP(buf[1])) {
  493.             fd = s->rtcp_fd;
  494.             source     = &s->last_rtcp_source;
  495.             source_len = &s->last_rtcp_source_len;
  496.         } else {
  497.             fd = s->rtp_fd;
  498.             source     = &s->last_rtp_source;
  499.             source_len = &s->last_rtp_source_len;
  500.         }
  501.         if (!source->ss_family) {
  502.             source      = &temp_source;
  503.             source_len  = &temp_len;
  504.             if (RTP_PT_IS_RTCP(buf[1])) {
  505.                 temp_source = s->last_rtp_source;
  506.                 temp_len    = s->last_rtp_source_len;
  507.                 set_port(source, get_port(source) + 1);
  508.                 av_log(h, AV_LOG_INFO,
  509.                        "Not received any RTCP packets yet, inferring peer port "
  510.                        "from the RTP port\n");
  511.             } else {
  512.                 temp_source = s->last_rtcp_source;
  513.                 temp_len    = s->last_rtcp_source_len;
  514.                 set_port(source, get_port(source) - 1);
  515.                 av_log(h, AV_LOG_INFO,
  516.                        "Not received any RTP packets yet, inferring peer port "
  517.                        "from the RTCP port\n");
  518.             }
  519.         }
  520.  
  521.         if (!(h->flags & AVIO_FLAG_NONBLOCK)) {
  522.             ret = ff_network_wait_fd(fd, 1);
  523.             if (ret < 0)
  524.                 return ret;
  525.         }
  526.         ret = sendto(fd, buf, size, 0, (struct sockaddr *) source,
  527.                      *source_len);
  528.  
  529.         return ret < 0 ? ff_neterrno() : ret;
  530.     }
  531.  
  532.     if (RTP_PT_IS_RTCP(buf[1])) {
  533.         /* RTCP payload type */
  534.         hd = s->rtcp_hd;
  535.     } else {
  536.         /* RTP payload type */
  537.         hd = s->rtp_hd;
  538.     }
  539.  
  540.     ret = ffurl_write(hd, buf, size);
  541.     return ret;
  542. }
  543.  
  544. static int rtp_close(URLContext *h)
  545. {
  546.     RTPContext *s = h->priv_data;
  547.     int i;
  548.  
  549.     for (i = 0; i < s->nb_ssm_include_addrs; i++)
  550.         av_freep(&s->ssm_include_addrs[i]);
  551.     av_freep(&s->ssm_include_addrs);
  552.     for (i = 0; i < s->nb_ssm_exclude_addrs; i++)
  553.         av_freep(&s->ssm_exclude_addrs[i]);
  554.     av_freep(&s->ssm_exclude_addrs);
  555.  
  556.     ffurl_close(s->rtp_hd);
  557.     ffurl_close(s->rtcp_hd);
  558.     return 0;
  559. }
  560.  
  561. /**
  562.  * Return the local rtp port used by the RTP connection
  563.  * @param h media file context
  564.  * @return the local port number
  565.  */
  566.  
  567. int ff_rtp_get_local_rtp_port(URLContext *h)
  568. {
  569.     RTPContext *s = h->priv_data;
  570.     return ff_udp_get_local_port(s->rtp_hd);
  571. }
  572.  
  573. /**
  574.  * Return the local rtcp port used by the RTP connection
  575.  * @param h media file context
  576.  * @return the local port number
  577.  */
  578.  
  579. int ff_rtp_get_local_rtcp_port(URLContext *h)
  580. {
  581.     RTPContext *s = h->priv_data;
  582.     return ff_udp_get_local_port(s->rtcp_hd);
  583. }
  584.  
  585. static int rtp_get_file_handle(URLContext *h)
  586. {
  587.     RTPContext *s = h->priv_data;
  588.     return s->rtp_fd;
  589. }
  590.  
  591. static int rtp_get_multi_file_handle(URLContext *h, int **handles,
  592.                                      int *numhandles)
  593. {
  594.     RTPContext *s = h->priv_data;
  595.     int *hs       = *handles = av_malloc(sizeof(**handles) * 2);
  596.     if (!hs)
  597.         return AVERROR(ENOMEM);
  598.     hs[0] = s->rtp_fd;
  599.     hs[1] = s->rtcp_fd;
  600.     *numhandles = 2;
  601.     return 0;
  602. }
  603.  
  604. URLProtocol ff_rtp_protocol = {
  605.     .name                      = "rtp",
  606.     .url_open                  = rtp_open,
  607.     .url_read                  = rtp_read,
  608.     .url_write                 = rtp_write,
  609.     .url_close                 = rtp_close,
  610.     .url_get_file_handle       = rtp_get_file_handle,
  611.     .url_get_multi_file_handle = rtp_get_multi_file_handle,
  612.     .priv_data_size            = sizeof(RTPContext),
  613.     .flags                     = URL_PROTOCOL_FLAG_NETWORK,
  614.     .priv_data_class           = &rtp_class,
  615. };
  616.