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 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 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;
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 s = av_mallocz(sizeof(RTPContext));
00150 if (!s)
00151 return AVERROR(ENOMEM);
00152 h->priv_data = s;
00153
00154 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
00155 path, sizeof(path), uri);
00156
00157 ttl = -1;
00158 rtcp_port = rtp_port+1;
00159 local_rtp_port = -1;
00160 local_rtcp_port = -1;
00161 max_packet_size = -1;
00162 connect = 0;
00163
00164 p = strchr(uri, '?');
00165 if (p) {
00166 if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
00167 ttl = strtol(buf, NULL, 10);
00168 }
00169 if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
00170 rtcp_port = strtol(buf, NULL, 10);
00171 }
00172 if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
00173 local_rtp_port = strtol(buf, NULL, 10);
00174 }
00175 if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
00176 local_rtp_port = strtol(buf, NULL, 10);
00177 }
00178 if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
00179 local_rtcp_port = strtol(buf, NULL, 10);
00180 }
00181 if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00182 max_packet_size = strtol(buf, NULL, 10);
00183 }
00184 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
00185 connect = strtol(buf, NULL, 10);
00186 }
00187 }
00188
00189 build_udp_url(buf, sizeof(buf),
00190 hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
00191 connect);
00192 if (ffurl_open(&s->rtp_hd, buf, flags) < 0)
00193 goto fail;
00194 if (local_rtp_port>=0 && local_rtcp_port<0)
00195 local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1;
00196
00197 build_udp_url(buf, sizeof(buf),
00198 hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
00199 connect);
00200 if (ffurl_open(&s->rtcp_hd, buf, flags) < 0)
00201 goto fail;
00202
00203
00204
00205 s->rtp_fd = ffurl_get_file_handle(s->rtp_hd);
00206 s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd);
00207
00208 h->max_packet_size = s->rtp_hd->max_packet_size;
00209 h->is_streamed = 1;
00210 return 0;
00211
00212 fail:
00213 if (s->rtp_hd)
00214 ffurl_close(s->rtp_hd);
00215 if (s->rtcp_hd)
00216 ffurl_close(s->rtcp_hd);
00217 av_free(s);
00218 return AVERROR(EIO);
00219 }
00220
00221 static int rtp_read(URLContext *h, uint8_t *buf, int size)
00222 {
00223 RTPContext *s = h->priv_data;
00224 struct sockaddr_storage from;
00225 socklen_t from_len;
00226 int len, n;
00227 struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
00228
00229 #if 0
00230 for(;;) {
00231 from_len = sizeof(from);
00232 len = recvfrom (s->rtp_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 #else
00243 for(;;) {
00244 if (url_interrupt_cb())
00245 return AVERROR_EXIT;
00246
00247 n = poll(p, 2, 100);
00248 if (n > 0) {
00249
00250 if (p[1].revents & POLLIN) {
00251 from_len = sizeof(from);
00252 len = recvfrom (s->rtcp_fd, buf, size, 0,
00253 (struct sockaddr *)&from, &from_len);
00254 if (len < 0) {
00255 if (ff_neterrno() == AVERROR(EAGAIN) ||
00256 ff_neterrno() == AVERROR(EINTR))
00257 continue;
00258 return AVERROR(EIO);
00259 }
00260 break;
00261 }
00262
00263 if (p[0].revents & POLLIN) {
00264 from_len = sizeof(from);
00265 len = recvfrom (s->rtp_fd, buf, size, 0,
00266 (struct sockaddr *)&from, &from_len);
00267 if (len < 0) {
00268 if (ff_neterrno() == AVERROR(EAGAIN) ||
00269 ff_neterrno() == AVERROR(EINTR))
00270 continue;
00271 return AVERROR(EIO);
00272 }
00273 break;
00274 }
00275 } else if (n < 0) {
00276 if (ff_neterrno() == AVERROR(EINTR))
00277 continue;
00278 return AVERROR(EIO);
00279 }
00280 }
00281 #endif
00282 return len;
00283 }
00284
00285 static int rtp_write(URLContext *h, const uint8_t *buf, int size)
00286 {
00287 RTPContext *s = h->priv_data;
00288 int ret;
00289 URLContext *hd;
00290
00291 if (buf[1] >= RTCP_SR && buf[1] <= RTCP_APP) {
00292
00293 hd = s->rtcp_hd;
00294 } else {
00295
00296 hd = s->rtp_hd;
00297 }
00298
00299 ret = ffurl_write(hd, buf, size);
00300 #if 0
00301 {
00302 struct timespec ts;
00303 ts.tv_sec = 0;
00304 ts.tv_nsec = 10 * 1000000;
00305 nanosleep(&ts, NULL);
00306 }
00307 #endif
00308 return ret;
00309 }
00310
00311 static int rtp_close(URLContext *h)
00312 {
00313 RTPContext *s = h->priv_data;
00314
00315 ffurl_close(s->rtp_hd);
00316 ffurl_close(s->rtcp_hd);
00317 av_free(s);
00318 return 0;
00319 }
00320
00327 int rtp_get_local_rtp_port(URLContext *h)
00328 {
00329 RTPContext *s = h->priv_data;
00330 return ff_udp_get_local_port(s->rtp_hd);
00331 }
00332
00339 int rtp_get_local_rtcp_port(URLContext *h)
00340 {
00341 RTPContext *s = h->priv_data;
00342 return ff_udp_get_local_port(s->rtcp_hd);
00343 }
00344
00345 static int rtp_get_file_handle(URLContext *h)
00346 {
00347 RTPContext *s = h->priv_data;
00348 return s->rtp_fd;
00349 }
00350
00351 int rtp_get_rtcp_file_handle(URLContext *h) {
00352 RTPContext *s = h->priv_data;
00353 return s->rtcp_fd;
00354 }
00355
00356 URLProtocol ff_rtp_protocol = {
00357 .name = "rtp",
00358 .url_open = rtp_open,
00359 .url_read = rtp_read,
00360 .url_write = rtp_write,
00361 .url_close = rtp_close,
00362 .url_get_file_handle = rtp_get_file_handle,
00363 };