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 }
00119
00137 static int rtp_open(URLContext *h, const char *uri, int flags)
00138 {
00139 RTPContext *s = h->priv_data;
00140 int rtp_port, rtcp_port,
00141 ttl, connect,
00142 local_rtp_port, local_rtcp_port, max_packet_size;
00143 char hostname[256];
00144 char buf[1024];
00145 char path[1024];
00146 const char *p;
00147
00148 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
00149 path, sizeof(path), uri);
00150
00151 ttl = -1;
00152 rtcp_port = rtp_port+1;
00153 local_rtp_port = -1;
00154 local_rtcp_port = -1;
00155 max_packet_size = -1;
00156 connect = 0;
00157
00158 p = strchr(uri, '?');
00159 if (p) {
00160 if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
00161 ttl = strtol(buf, NULL, 10);
00162 }
00163 if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
00164 rtcp_port = strtol(buf, NULL, 10);
00165 }
00166 if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
00167 local_rtp_port = strtol(buf, NULL, 10);
00168 }
00169 if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
00170 local_rtp_port = strtol(buf, NULL, 10);
00171 }
00172 if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
00173 local_rtcp_port = strtol(buf, NULL, 10);
00174 }
00175 if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00176 max_packet_size = strtol(buf, NULL, 10);
00177 }
00178 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
00179 connect = strtol(buf, NULL, 10);
00180 }
00181 }
00182
00183 build_udp_url(buf, sizeof(buf),
00184 hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
00185 connect);
00186 if (ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
00187 goto fail;
00188 if (local_rtp_port>=0 && local_rtcp_port<0)
00189 local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1;
00190
00191 build_udp_url(buf, sizeof(buf),
00192 hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
00193 connect);
00194 if (ffurl_open(&s->rtcp_hd, buf, flags, &h->interrupt_callback, NULL) < 0)
00195 goto fail;
00196
00197
00198
00199 s->rtp_fd = ffurl_get_file_handle(s->rtp_hd);
00200 s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd);
00201
00202 h->max_packet_size = s->rtp_hd->max_packet_size;
00203 h->is_streamed = 1;
00204 return 0;
00205
00206 fail:
00207 if (s->rtp_hd)
00208 ffurl_close(s->rtp_hd);
00209 if (s->rtcp_hd)
00210 ffurl_close(s->rtcp_hd);
00211 return AVERROR(EIO);
00212 }
00213
00214 static int rtp_read(URLContext *h, uint8_t *buf, int size)
00215 {
00216 RTPContext *s = h->priv_data;
00217 struct sockaddr_storage from;
00218 socklen_t from_len;
00219 int len, n;
00220 struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
00221
00222 for(;;) {
00223 if (ff_check_interrupt(&h->interrupt_callback))
00224 return AVERROR_EXIT;
00225
00226 n = poll(p, 2, 100);
00227 if (n > 0) {
00228
00229 if (p[1].revents & POLLIN) {
00230 from_len = sizeof(from);
00231 len = recvfrom (s->rtcp_fd, buf, size, 0,
00232 (struct sockaddr *)&from, &from_len);
00233 if (len < 0) {
00234 if (ff_neterrno() == AVERROR(EAGAIN) ||
00235 ff_neterrno() == AVERROR(EINTR))
00236 continue;
00237 return AVERROR(EIO);
00238 }
00239 break;
00240 }
00241
00242 if (p[0].revents & POLLIN) {
00243 from_len = sizeof(from);
00244 len = recvfrom (s->rtp_fd, buf, size, 0,
00245 (struct sockaddr *)&from, &from_len);
00246 if (len < 0) {
00247 if (ff_neterrno() == AVERROR(EAGAIN) ||
00248 ff_neterrno() == AVERROR(EINTR))
00249 continue;
00250 return AVERROR(EIO);
00251 }
00252 break;
00253 }
00254 } else if (n < 0) {
00255 if (ff_neterrno() == AVERROR(EINTR))
00256 continue;
00257 return AVERROR(EIO);
00258 }
00259 }
00260 return len;
00261 }
00262
00263 static int rtp_write(URLContext *h, const uint8_t *buf, int size)
00264 {
00265 RTPContext *s = h->priv_data;
00266 int ret;
00267 URLContext *hd;
00268
00269 if (buf[1] >= RTCP_SR && buf[1] <= RTCP_APP) {
00270
00271 hd = s->rtcp_hd;
00272 } else {
00273
00274 hd = s->rtp_hd;
00275 }
00276
00277 ret = ffurl_write(hd, buf, size);
00278 return ret;
00279 }
00280
00281 static int rtp_close(URLContext *h)
00282 {
00283 RTPContext *s = h->priv_data;
00284
00285 ffurl_close(s->rtp_hd);
00286 ffurl_close(s->rtcp_hd);
00287 return 0;
00288 }
00289
00296 int ff_rtp_get_local_rtp_port(URLContext *h)
00297 {
00298 RTPContext *s = h->priv_data;
00299 return ff_udp_get_local_port(s->rtp_hd);
00300 }
00301
00308 int ff_rtp_get_local_rtcp_port(URLContext *h)
00309 {
00310 RTPContext *s = h->priv_data;
00311 return ff_udp_get_local_port(s->rtcp_hd);
00312 }
00313
00314 static int rtp_get_file_handle(URLContext *h)
00315 {
00316 RTPContext *s = h->priv_data;
00317 return s->rtp_fd;
00318 }
00319
00320 int ff_rtp_get_rtcp_file_handle(URLContext *h) {
00321 RTPContext *s = h->priv_data;
00322 return s->rtcp_fd;
00323 }
00324
00325 URLProtocol ff_rtp_protocol = {
00326 .name = "rtp",
00327 .url_open = rtp_open,
00328 .url_read = rtp_read,
00329 .url_write = rtp_write,
00330 .url_close = rtp_close,
00331 .url_get_file_handle = rtp_get_file_handle,
00332 .priv_data_size = sizeof(RTPContext),
00333 .flags = URL_PROTOCOL_FLAG_NETWORK,
00334 };