00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/parseutils.h"
00028 #include "libavutil/avstring.h"
00029 #include "avformat.h"
00030 #include "avio_internal.h"
00031 #include "rtpdec.h"
00032 #include "url.h"
00033
00034 #include <unistd.h>
00035 #include <stdarg.h>
00036 #include "internal.h"
00037 #include "network.h"
00038 #include "os_support.h"
00039 #include <fcntl.h>
00040 #if HAVE_POLL_H
00041 #include <sys/poll.h>
00042 #endif
00043 #include <sys/time.h>
00044
00045 #define RTP_TX_BUF_SIZE (64 * 1024)
00046 #define RTP_RX_BUF_SIZE (128 * 1024)
00047
00048 typedef struct RTPContext {
00049 URLContext *rtp_hd, *rtcp_hd;
00050 int rtp_fd, rtcp_fd;
00051 } RTPContext;
00052
00063 int ff_rtp_set_remote_url(URLContext *h, const char *uri)
00064 {
00065 RTPContext *s = h->priv_data;
00066 char hostname[256];
00067 int port;
00068
00069 char buf[1024];
00070 char path[1024];
00071
00072 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
00073 path, sizeof(path), uri);
00074
00075 ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
00076 ff_udp_set_remote_url(s->rtp_hd, buf);
00077
00078 ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
00079 ff_udp_set_remote_url(s->rtcp_hd, buf);
00080 return 0;
00081 }
00082
00083
00089 static av_printf_format(3, 4) void url_add_option(char *buf, int buf_size, const char *fmt, ...)
00090 {
00091 char buf1[1024];
00092 va_list ap;
00093
00094 va_start(ap, fmt);
00095 if (strchr(buf, '?'))
00096 av_strlcat(buf, "&", buf_size);
00097 else
00098 av_strlcat(buf, "?", buf_size);
00099 vsnprintf(buf1, sizeof(buf1), fmt, ap);
00100 av_strlcat(buf, buf1, buf_size);
00101 va_end(ap);
00102 }
00103
00104 static void build_udp_url(char *buf, int buf_size,
00105 const char *hostname, int port,
00106 int local_port, int ttl,
00107 int max_packet_size, int connect)
00108 {
00109 ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
00110 if (local_port >= 0)
00111 url_add_option(buf, buf_size, "localport=%d", local_port);
00112 if (ttl >= 0)
00113 url_add_option(buf, buf_size, "ttl=%d", ttl);
00114 if (max_packet_size >=0)
00115 url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
00116 if (connect)
00117 url_add_option(buf, buf_size, "connect=1");
00118 url_add_option(buf, buf_size, "fifo_size=0");
00119 }
00120
00138 static int rtp_open(URLContext *h, const char *uri, int flags)
00139 {
00140 RTPContext *s = h->priv_data;
00141 int rtp_port, rtcp_port,
00142 ttl, connect,
00143 local_rtp_port, local_rtcp_port, max_packet_size;
00144 char hostname[256];
00145 char buf[1024];
00146 char path[1024];
00147 const char *p;
00148
00149 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
00150 path, sizeof(path), uri);
00151
00152 ttl = -1;
00153 rtcp_port = rtp_port+1;
00154 local_rtp_port = -1;
00155 local_rtcp_port = -1;
00156 max_packet_size = -1;
00157 connect = 0;
00158
00159 p = strchr(uri, '?');
00160 if (p) {
00161 if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
00162 ttl = strtol(buf, NULL, 10);
00163 }
00164 if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
00165 rtcp_port = strtol(buf, NULL, 10);
00166 }
00167 if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
00168 local_rtp_port = strtol(buf, NULL, 10);
00169 }
00170 if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
00171 local_rtp_port = strtol(buf, NULL, 10);
00172 }
00173 if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
00174 local_rtcp_port = strtol(buf, NULL, 10);
00175 }
00176 if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00177 max_packet_size = strtol(buf, NULL, 10);
00178 }
00179 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
00180 connect = strtol(buf, NULL, 10);
00181 }
00182 }
00183
00184 build_udp_url(buf, sizeof(buf),
00185 hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
00186 connect);
00187 if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
00188 goto fail;
00189 if (local_rtp_port>=0 && local_rtcp_port<0)
00190 local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1;
00191
00192 build_udp_url(buf, sizeof(buf),
00193 hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
00194 connect);
00195 if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
00196 goto fail;
00197
00198
00199
00200 s->rtp_fd = ffurl_get_file_handle(s->rtp_hd);
00201 s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd);
00202
00203 h->max_packet_size = s->rtp_hd->max_packet_size;
00204 h->is_streamed = 1;
00205 return 0;
00206
00207 fail:
00208 if (s->rtp_hd)
00209 ffurl_close(s->rtp_hd);
00210 if (s->rtcp_hd)
00211 ffurl_close(s->rtcp_hd);
00212 return AVERROR(EIO);
00213 }
00214
00215 static int rtp_read(URLContext *h, uint8_t *buf, int size)
00216 {
00217 RTPContext *s = h->priv_data;
00218 struct sockaddr_storage from;
00219 socklen_t from_len;
00220 int len, n;
00221 struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
00222
00223 for(;;) {
00224 if (ff_check_interrupt(&h->interrupt_callback))
00225 return AVERROR_EXIT;
00226
00227 n = poll(p, 2, 100);
00228 if (n > 0) {
00229
00230 if (p[1].revents & POLLIN) {
00231 from_len = sizeof(from);
00232 len = recvfrom (s->rtcp_fd, buf, size, 0,
00233 (struct sockaddr *)&from, &from_len);
00234 if (len < 0) {
00235 if (ff_neterrno() == AVERROR(EAGAIN) ||
00236 ff_neterrno() == AVERROR(EINTR))
00237 continue;
00238 return AVERROR(EIO);
00239 }
00240 break;
00241 }
00242
00243 if (p[0].revents & POLLIN) {
00244 from_len = sizeof(from);
00245 len = recvfrom (s->rtp_fd, buf, size, 0,
00246 (struct sockaddr *)&from, &from_len);
00247 if (len < 0) {
00248 if (ff_neterrno() == AVERROR(EAGAIN) ||
00249 ff_neterrno() == AVERROR(EINTR))
00250 continue;
00251 return AVERROR(EIO);
00252 }
00253 break;
00254 }
00255 } else if (n < 0) {
00256 if (ff_neterrno() == AVERROR(EINTR))
00257 continue;
00258 return AVERROR(EIO);
00259 }
00260 }
00261 return len;
00262 }
00263
00264 static int rtp_write(URLContext *h, const uint8_t *buf, int size)
00265 {
00266 RTPContext *s = h->priv_data;
00267 int ret;
00268 URLContext *hd;
00269
00270 if (RTP_PT_IS_RTCP(buf[1])) {
00271
00272 hd = s->rtcp_hd;
00273 } else {
00274
00275 hd = s->rtp_hd;
00276 }
00277
00278 ret = ffurl_write(hd, buf, size);
00279 return ret;
00280 }
00281
00282 static int rtp_close(URLContext *h)
00283 {
00284 RTPContext *s = h->priv_data;
00285
00286 ffurl_close(s->rtp_hd);
00287 ffurl_close(s->rtcp_hd);
00288 return 0;
00289 }
00290
00297 int ff_rtp_get_local_rtp_port(URLContext *h)
00298 {
00299 RTPContext *s = h->priv_data;
00300 return ff_udp_get_local_port(s->rtp_hd);
00301 }
00302
00309 int ff_rtp_get_local_rtcp_port(URLContext *h)
00310 {
00311 RTPContext *s = h->priv_data;
00312 return ff_udp_get_local_port(s->rtcp_hd);
00313 }
00314
00315 static int rtp_get_file_handle(URLContext *h)
00316 {
00317 RTPContext *s = h->priv_data;
00318 return s->rtp_fd;
00319 }
00320
00321 int ff_rtp_get_rtcp_file_handle(URLContext *h) {
00322 RTPContext *s = h->priv_data;
00323 return s->rtcp_fd;
00324 }
00325
00326 URLProtocol ff_rtp_protocol = {
00327 .name = "rtp",
00328 .url_open = rtp_open,
00329 .url_read = rtp_read,
00330 .url_write = rtp_write,
00331 .url_close = rtp_close,
00332 .url_get_file_handle = rtp_get_file_handle,
00333 .priv_data_size = sizeof(RTPContext),
00334 .flags = URL_PROTOCOL_FLAG_NETWORK,
00335 };