00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avformat.h"
00022 #include "avstring.h"
00023
00024 #include <unistd.h>
00025 #include <stdarg.h>
00026 #include "network.h"
00027 #include <fcntl.h>
00028
00029 #define RTP_TX_BUF_SIZE (64 * 1024)
00030 #define RTP_RX_BUF_SIZE (128 * 1024)
00031
00032 typedef struct RTPContext {
00033 URLContext *rtp_hd, *rtcp_hd;
00034 int rtp_fd, rtcp_fd;
00035 } RTPContext;
00036
00046 int rtp_set_remote_url(URLContext *h, const char *uri)
00047 {
00048 RTPContext *s = h->priv_data;
00049 char hostname[256];
00050 int port;
00051
00052 char buf[1024];
00053 char path[1024];
00054
00055 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
00056 path, sizeof(path), uri);
00057
00058 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path);
00059 udp_set_remote_url(s->rtp_hd, buf);
00060
00061 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path);
00062 udp_set_remote_url(s->rtcp_hd, buf);
00063 return 0;
00064 }
00065
00066
00067
00068
00069 static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
00070 {
00071 char buf1[1024];
00072 va_list ap;
00073
00074 va_start(ap, fmt);
00075 if (strchr(buf, '?'))
00076 av_strlcat(buf, "&", buf_size);
00077 else
00078 av_strlcat(buf, "?", buf_size);
00079 vsnprintf(buf1, sizeof(buf1), fmt, ap);
00080 av_strlcat(buf, buf1, buf_size);
00081 va_end(ap);
00082 }
00083
00084 static void build_udp_url(char *buf, int buf_size,
00085 const char *hostname, int port,
00086 int local_port, int multicast, int ttl)
00087 {
00088 snprintf(buf, buf_size, "udp://%s:%d", hostname, port);
00089 if (local_port >= 0)
00090 url_add_option(buf, buf_size, "localport=%d", local_port);
00091 if (multicast)
00092 url_add_option(buf, buf_size, "multicast=1");
00093 if (ttl >= 0)
00094 url_add_option(buf, buf_size, "ttl=%d", ttl);
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104 static int rtp_open(URLContext *h, const char *uri, int flags)
00105 {
00106 RTPContext *s;
00107 int port, is_output, is_multicast, ttl, local_port;
00108 char hostname[256];
00109 char buf[1024];
00110 char path[1024];
00111 const char *p;
00112
00113 is_output = (flags & URL_WRONLY);
00114
00115 s = av_mallocz(sizeof(RTPContext));
00116 if (!s)
00117 return AVERROR(ENOMEM);
00118 h->priv_data = s;
00119
00120 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
00121 path, sizeof(path), uri);
00122
00123 is_multicast = 0;
00124 ttl = -1;
00125 local_port = -1;
00126 p = strchr(uri, '?');
00127 if (p) {
00128 is_multicast = find_info_tag(buf, sizeof(buf), "multicast", p);
00129 if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
00130 ttl = strtol(buf, NULL, 10);
00131 }
00132 if (find_info_tag(buf, sizeof(buf), "localport", p)) {
00133 local_port = strtol(buf, NULL, 10);
00134 }
00135 }
00136
00137 build_udp_url(buf, sizeof(buf),
00138 hostname, port, local_port, is_multicast, ttl);
00139 if (url_open(&s->rtp_hd, buf, flags) < 0)
00140 goto fail;
00141 local_port = udp_get_local_port(s->rtp_hd);
00142
00143
00144
00145
00146 build_udp_url(buf, sizeof(buf),
00147 hostname, port + 1, local_port + 1, is_multicast, ttl);
00148 if (url_open(&s->rtcp_hd, buf, flags) < 0)
00149 goto fail;
00150
00151
00152
00153 s->rtp_fd = udp_get_file_handle(s->rtp_hd);
00154 s->rtcp_fd = udp_get_file_handle(s->rtcp_hd);
00155
00156 h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
00157 h->is_streamed = 1;
00158 return 0;
00159
00160 fail:
00161 if (s->rtp_hd)
00162 url_close(s->rtp_hd);
00163 if (s->rtcp_hd)
00164 url_close(s->rtcp_hd);
00165 av_free(s);
00166 return AVERROR(EIO);
00167 }
00168
00169 static int rtp_read(URLContext *h, uint8_t *buf, int size)
00170 {
00171 RTPContext *s = h->priv_data;
00172 struct sockaddr_in from;
00173 socklen_t from_len;
00174 int len, fd_max, n;
00175 fd_set rfds;
00176 #if 0
00177 for(;;) {
00178 from_len = sizeof(from);
00179 len = recvfrom (s->rtp_fd, buf, size, 0,
00180 (struct sockaddr *)&from, &from_len);
00181 if (len < 0) {
00182 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00183 ff_neterrno() == FF_NETERROR(EINTR))
00184 continue;
00185 return AVERROR(EIO);
00186 }
00187 break;
00188 }
00189 #else
00190 for(;;) {
00191
00192 FD_ZERO(&rfds);
00193 fd_max = s->rtp_fd;
00194 FD_SET(s->rtp_fd, &rfds);
00195 if (s->rtcp_fd > fd_max)
00196 fd_max = s->rtcp_fd;
00197 FD_SET(s->rtcp_fd, &rfds);
00198 n = select(fd_max + 1, &rfds, NULL, NULL, NULL);
00199 if (n > 0) {
00200
00201 if (FD_ISSET(s->rtcp_fd, &rfds)) {
00202 from_len = sizeof(from);
00203 len = recvfrom (s->rtcp_fd, buf, size, 0,
00204 (struct sockaddr *)&from, &from_len);
00205 if (len < 0) {
00206 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00207 ff_neterrno() == FF_NETERROR(EINTR))
00208 continue;
00209 return AVERROR(EIO);
00210 }
00211 break;
00212 }
00213
00214 if (FD_ISSET(s->rtp_fd, &rfds)) {
00215 from_len = sizeof(from);
00216 len = recvfrom (s->rtp_fd, buf, size, 0,
00217 (struct sockaddr *)&from, &from_len);
00218 if (len < 0) {
00219 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00220 ff_neterrno() == FF_NETERROR(EINTR))
00221 continue;
00222 return AVERROR(EIO);
00223 }
00224 break;
00225 }
00226 }
00227 }
00228 #endif
00229 return len;
00230 }
00231
00232 static int rtp_write(URLContext *h, uint8_t *buf, int size)
00233 {
00234 RTPContext *s = h->priv_data;
00235 int ret;
00236 URLContext *hd;
00237
00238 if (buf[1] >= 200 && buf[1] <= 204) {
00239
00240 hd = s->rtcp_hd;
00241 } else {
00242
00243 hd = s->rtp_hd;
00244 }
00245
00246 ret = url_write(hd, buf, size);
00247 #if 0
00248 {
00249 struct timespec ts;
00250 ts.tv_sec = 0;
00251 ts.tv_nsec = 10 * 1000000;
00252 nanosleep(&ts, NULL);
00253 }
00254 #endif
00255 return ret;
00256 }
00257
00258 static int rtp_close(URLContext *h)
00259 {
00260 RTPContext *s = h->priv_data;
00261
00262 url_close(s->rtp_hd);
00263 url_close(s->rtcp_hd);
00264 av_free(s);
00265 return 0;
00266 }
00267
00273 int rtp_get_local_port(URLContext *h)
00274 {
00275 RTPContext *s = h->priv_data;
00276 return udp_get_local_port(s->rtp_hd);
00277 }
00278
00284 void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
00285 {
00286 RTPContext *s = h->priv_data;
00287
00288 *prtp_fd = s->rtp_fd;
00289 *prtcp_fd = s->rtcp_fd;
00290 }
00291
00292 URLProtocol rtp_protocol = {
00293 "rtp",
00294 rtp_open,
00295 rtp_read,
00296 rtp_write,
00297 NULL,
00298 rtp_close,
00299 };