00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/avstring.h"
00028 #include "avformat.h"
00029 #include "rtpdec.h"
00030
00031 #include <unistd.h>
00032 #include <stdarg.h>
00033 #include "internal.h"
00034 #include "network.h"
00035 #include "os_support.h"
00036 #include <fcntl.h>
00037 #if HAVE_SYS_SELECT_H
00038 #include <sys/select.h>
00039 #endif
00040 #include <sys/time.h>
00041
00042 #define RTP_TX_BUF_SIZE (64 * 1024)
00043 #define RTP_RX_BUF_SIZE (128 * 1024)
00044
00045 typedef struct RTPContext {
00046 URLContext *rtp_hd, *rtcp_hd;
00047 int rtp_fd, rtcp_fd;
00048 } RTPContext;
00049
00060 int rtp_set_remote_url(URLContext *h, const char *uri)
00061 {
00062 RTPContext *s = h->priv_data;
00063 char hostname[256];
00064 int port;
00065
00066 char buf[1024];
00067 char path[1024];
00068
00069 ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
00070 path, sizeof(path), uri);
00071
00072 ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
00073 udp_set_remote_url(s->rtp_hd, buf);
00074
00075 ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
00076 udp_set_remote_url(s->rtcp_hd, buf);
00077 return 0;
00078 }
00079
00080
00086 static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
00087 {
00088 char buf1[1024];
00089 va_list ap;
00090
00091 va_start(ap, fmt);
00092 if (strchr(buf, '?'))
00093 av_strlcat(buf, "&", buf_size);
00094 else
00095 av_strlcat(buf, "?", buf_size);
00096 vsnprintf(buf1, sizeof(buf1), fmt, ap);
00097 av_strlcat(buf, buf1, buf_size);
00098 va_end(ap);
00099 }
00100
00101 static void build_udp_url(char *buf, int buf_size,
00102 const char *hostname, int port,
00103 int local_port, int ttl,
00104 int max_packet_size)
00105 {
00106 ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
00107 if (local_port >= 0)
00108 url_add_option(buf, buf_size, "localport=%d", local_port);
00109 if (ttl >= 0)
00110 url_add_option(buf, buf_size, "ttl=%d", ttl);
00111 if (max_packet_size >=0)
00112 url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
00113 }
00114
00131 static int rtp_open(URLContext *h, const char *uri, int flags)
00132 {
00133 RTPContext *s;
00134 int rtp_port, rtcp_port,
00135 is_output, ttl,
00136 local_rtp_port, local_rtcp_port, max_packet_size;
00137 char hostname[256];
00138 char buf[1024];
00139 char path[1024];
00140 const char *p;
00141
00142 is_output = (flags & URL_WRONLY);
00143
00144 s = av_mallocz(sizeof(RTPContext));
00145 if (!s)
00146 return AVERROR(ENOMEM);
00147 h->priv_data = s;
00148
00149 ff_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
00158 p = strchr(uri, '?');
00159 if (p) {
00160 if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
00161 ttl = strtol(buf, NULL, 10);
00162 }
00163 if (find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
00164 rtcp_port = strtol(buf, NULL, 10);
00165 }
00166 if (find_info_tag(buf, sizeof(buf), "localport", p)) {
00167 local_rtp_port = strtol(buf, NULL, 10);
00168 }
00169 if (find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
00170 local_rtp_port = strtol(buf, NULL, 10);
00171 }
00172 if (find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
00173 local_rtcp_port = strtol(buf, NULL, 10);
00174 }
00175 if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00176 max_packet_size = strtol(buf, NULL, 10);
00177 }
00178 }
00179
00180 build_udp_url(buf, sizeof(buf),
00181 hostname, rtp_port, local_rtp_port, ttl, max_packet_size);
00182 if (url_open(&s->rtp_hd, buf, flags) < 0)
00183 goto fail;
00184 if (local_rtp_port>=0 && local_rtcp_port<0)
00185 local_rtcp_port = udp_get_local_port(s->rtp_hd) + 1;
00186
00187 build_udp_url(buf, sizeof(buf),
00188 hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size);
00189 if (url_open(&s->rtcp_hd, buf, flags) < 0)
00190 goto fail;
00191
00192
00193
00194 s->rtp_fd = url_get_file_handle(s->rtp_hd);
00195 s->rtcp_fd = url_get_file_handle(s->rtcp_hd);
00196
00197 h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
00198 h->is_streamed = 1;
00199 return 0;
00200
00201 fail:
00202 if (s->rtp_hd)
00203 url_close(s->rtp_hd);
00204 if (s->rtcp_hd)
00205 url_close(s->rtcp_hd);
00206 av_free(s);
00207 return AVERROR(EIO);
00208 }
00209
00210 static int rtp_read(URLContext *h, uint8_t *buf, int size)
00211 {
00212 RTPContext *s = h->priv_data;
00213 struct sockaddr_in from;
00214 socklen_t from_len;
00215 int len, fd_max, n;
00216 fd_set rfds;
00217 struct timeval tv;
00218 #if 0
00219 for(;;) {
00220 from_len = sizeof(from);
00221 len = recvfrom (s->rtp_fd, buf, size, 0,
00222 (struct sockaddr *)&from, &from_len);
00223 if (len < 0) {
00224 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00225 ff_neterrno() == FF_NETERROR(EINTR))
00226 continue;
00227 return AVERROR(EIO);
00228 }
00229 break;
00230 }
00231 #else
00232 for(;;) {
00233 if (url_interrupt_cb())
00234 return AVERROR(EINTR);
00235
00236 FD_ZERO(&rfds);
00237 fd_max = s->rtp_fd;
00238 FD_SET(s->rtp_fd, &rfds);
00239 if (s->rtcp_fd > fd_max)
00240 fd_max = s->rtcp_fd;
00241 FD_SET(s->rtcp_fd, &rfds);
00242 tv.tv_sec = 0;
00243 tv.tv_usec = 100 * 1000;
00244 n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
00245 if (n > 0) {
00246
00247 if (FD_ISSET(s->rtcp_fd, &rfds)) {
00248 from_len = sizeof(from);
00249 len = recvfrom (s->rtcp_fd, buf, size, 0,
00250 (struct sockaddr *)&from, &from_len);
00251 if (len < 0) {
00252 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00253 ff_neterrno() == FF_NETERROR(EINTR))
00254 continue;
00255 return AVERROR(EIO);
00256 }
00257 break;
00258 }
00259
00260 if (FD_ISSET(s->rtp_fd, &rfds)) {
00261 from_len = sizeof(from);
00262 len = recvfrom (s->rtp_fd, buf, size, 0,
00263 (struct sockaddr *)&from, &from_len);
00264 if (len < 0) {
00265 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00266 ff_neterrno() == FF_NETERROR(EINTR))
00267 continue;
00268 return AVERROR(EIO);
00269 }
00270 break;
00271 }
00272 } else if (n < 0) {
00273 if (ff_neterrno() == FF_NETERROR(EINTR))
00274 continue;
00275 return AVERROR(EIO);
00276 }
00277 }
00278 #endif
00279 return len;
00280 }
00281
00282 static int rtp_write(URLContext *h, uint8_t *buf, int size)
00283 {
00284 RTPContext *s = h->priv_data;
00285 int ret;
00286 URLContext *hd;
00287
00288 if (buf[1] >= 200 && buf[1] <= 204) {
00289
00290 hd = s->rtcp_hd;
00291 } else {
00292
00293 hd = s->rtp_hd;
00294 }
00295
00296 ret = url_write(hd, buf, size);
00297 #if 0
00298 {
00299 struct timespec ts;
00300 ts.tv_sec = 0;
00301 ts.tv_nsec = 10 * 1000000;
00302 nanosleep(&ts, NULL);
00303 }
00304 #endif
00305 return ret;
00306 }
00307
00308 static int rtp_close(URLContext *h)
00309 {
00310 RTPContext *s = h->priv_data;
00311
00312 url_close(s->rtp_hd);
00313 url_close(s->rtcp_hd);
00314 av_free(s);
00315 return 0;
00316 }
00317
00324 int rtp_get_local_rtp_port(URLContext *h)
00325 {
00326 RTPContext *s = h->priv_data;
00327 return udp_get_local_port(s->rtp_hd);
00328 }
00329
00336 int rtp_get_local_port(URLContext *h)
00337 {
00338 RTPContext *s = h->priv_data;
00339 return udp_get_local_port(s->rtp_hd);
00340 }
00341
00348 int rtp_get_local_rtcp_port(URLContext *h)
00349 {
00350 RTPContext *s = h->priv_data;
00351 return udp_get_local_port(s->rtcp_hd);
00352 }
00353
00354 #if (LIBAVFORMAT_VERSION_MAJOR <= 52)
00355
00361 void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
00362 {
00363 RTPContext *s = h->priv_data;
00364
00365 *prtp_fd = s->rtp_fd;
00366 *prtcp_fd = s->rtcp_fd;
00367 }
00368 #endif
00369
00370 static int rtp_get_file_handle(URLContext *h)
00371 {
00372 RTPContext *s = h->priv_data;
00373 return s->rtp_fd;
00374 }
00375
00376 URLProtocol rtp_protocol = {
00377 "rtp",
00378 rtp_open,
00379 rtp_read,
00380 rtp_write,
00381 NULL,
00382 rtp_close,
00383 .url_get_file_handle = rtp_get_file_handle,
00384 };