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
00030 #include <unistd.h>
00031 #include <stdarg.h>
00032 #include "network.h"
00033 #include "os_support.h"
00034 #include <fcntl.h>
00035 #if HAVE_SYS_SELECT_H
00036 #include <sys/select.h>
00037 #endif
00038
00039 #define RTP_TX_BUF_SIZE (64 * 1024)
00040 #define RTP_RX_BUF_SIZE (128 * 1024)
00041
00042 typedef struct RTPContext {
00043 URLContext *rtp_hd, *rtcp_hd;
00044 int rtp_fd, rtcp_fd;
00045 } RTPContext;
00046
00057 int rtp_set_remote_url(URLContext *h, const char *uri)
00058 {
00059 RTPContext *s = h->priv_data;
00060 char hostname[256];
00061 int port;
00062
00063 char buf[1024];
00064 char path[1024];
00065
00066 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
00067 path, sizeof(path), uri);
00068
00069 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port, path);
00070 udp_set_remote_url(s->rtp_hd, buf);
00071
00072 snprintf(buf, sizeof(buf), "udp://%s:%d%s", hostname, port + 1, path);
00073 udp_set_remote_url(s->rtcp_hd, buf);
00074 return 0;
00075 }
00076
00077
00083 static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
00084 {
00085 char buf1[1024];
00086 va_list ap;
00087
00088 va_start(ap, fmt);
00089 if (strchr(buf, '?'))
00090 av_strlcat(buf, "&", buf_size);
00091 else
00092 av_strlcat(buf, "?", buf_size);
00093 vsnprintf(buf1, sizeof(buf1), fmt, ap);
00094 av_strlcat(buf, buf1, buf_size);
00095 va_end(ap);
00096 }
00097
00098 static void build_udp_url(char *buf, int buf_size,
00099 const char *hostname, int port,
00100 int local_port, int ttl,
00101 int max_packet_size)
00102 {
00103 snprintf(buf, buf_size, "udp://%s:%d", hostname, port);
00104 if (local_port >= 0)
00105 url_add_option(buf, buf_size, "localport=%d", local_port);
00106 if (ttl >= 0)
00107 url_add_option(buf, buf_size, "ttl=%d", ttl);
00108 if (max_packet_size >=0)
00109 url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
00110 }
00111
00120 static int rtp_open(URLContext *h, const char *uri, int flags)
00121 {
00122 RTPContext *s;
00123 int port, is_output, ttl, local_port, max_packet_size;
00124 char hostname[256];
00125 char buf[1024];
00126 char path[1024];
00127 const char *p;
00128
00129 is_output = (flags & URL_WRONLY);
00130
00131 s = av_mallocz(sizeof(RTPContext));
00132 if (!s)
00133 return AVERROR(ENOMEM);
00134 h->priv_data = s;
00135
00136 url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
00137 path, sizeof(path), uri);
00138
00139 ttl = -1;
00140 local_port = -1;
00141 max_packet_size = -1;
00142
00143 p = strchr(uri, '?');
00144 if (p) {
00145 if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
00146 ttl = strtol(buf, NULL, 10);
00147 }
00148 if (find_info_tag(buf, sizeof(buf), "localport", p)) {
00149 local_port = strtol(buf, NULL, 10);
00150 }
00151 if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
00152 max_packet_size = strtol(buf, NULL, 10);
00153 }
00154 }
00155
00156 build_udp_url(buf, sizeof(buf),
00157 hostname, port, local_port, ttl, max_packet_size);
00158 if (url_open(&s->rtp_hd, buf, flags) < 0)
00159 goto fail;
00160 local_port = udp_get_local_port(s->rtp_hd);
00161
00162
00163
00164
00165 build_udp_url(buf, sizeof(buf),
00166 hostname, port + 1, local_port + 1, ttl, max_packet_size);
00167 if (url_open(&s->rtcp_hd, buf, flags) < 0)
00168 goto fail;
00169
00170
00171
00172 s->rtp_fd = udp_get_file_handle(s->rtp_hd);
00173 s->rtcp_fd = udp_get_file_handle(s->rtcp_hd);
00174
00175 h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
00176 h->is_streamed = 1;
00177 return 0;
00178
00179 fail:
00180 if (s->rtp_hd)
00181 url_close(s->rtp_hd);
00182 if (s->rtcp_hd)
00183 url_close(s->rtcp_hd);
00184 av_free(s);
00185 return AVERROR(EIO);
00186 }
00187
00188 static int rtp_read(URLContext *h, uint8_t *buf, int size)
00189 {
00190 RTPContext *s = h->priv_data;
00191 struct sockaddr_in from;
00192 socklen_t from_len;
00193 int len, fd_max, n;
00194 fd_set rfds;
00195 #if 0
00196 for(;;) {
00197 from_len = sizeof(from);
00198 len = recvfrom (s->rtp_fd, buf, size, 0,
00199 (struct sockaddr *)&from, &from_len);
00200 if (len < 0) {
00201 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00202 ff_neterrno() == FF_NETERROR(EINTR))
00203 continue;
00204 return AVERROR(EIO);
00205 }
00206 break;
00207 }
00208 #else
00209 for(;;) {
00210
00211 FD_ZERO(&rfds);
00212 fd_max = s->rtp_fd;
00213 FD_SET(s->rtp_fd, &rfds);
00214 if (s->rtcp_fd > fd_max)
00215 fd_max = s->rtcp_fd;
00216 FD_SET(s->rtcp_fd, &rfds);
00217 n = select(fd_max + 1, &rfds, NULL, NULL, NULL);
00218 if (n > 0) {
00219
00220 if (FD_ISSET(s->rtcp_fd, &rfds)) {
00221 from_len = sizeof(from);
00222 len = recvfrom (s->rtcp_fd, buf, size, 0,
00223 (struct sockaddr *)&from, &from_len);
00224 if (len < 0) {
00225 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00226 ff_neterrno() == FF_NETERROR(EINTR))
00227 continue;
00228 return AVERROR(EIO);
00229 }
00230 break;
00231 }
00232
00233 if (FD_ISSET(s->rtp_fd, &rfds)) {
00234 from_len = sizeof(from);
00235 len = recvfrom (s->rtp_fd, buf, size, 0,
00236 (struct sockaddr *)&from, &from_len);
00237 if (len < 0) {
00238 if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
00239 ff_neterrno() == FF_NETERROR(EINTR))
00240 continue;
00241 return AVERROR(EIO);
00242 }
00243 break;
00244 }
00245 }
00246 }
00247 #endif
00248 return len;
00249 }
00250
00251 static int rtp_write(URLContext *h, uint8_t *buf, int size)
00252 {
00253 RTPContext *s = h->priv_data;
00254 int ret;
00255 URLContext *hd;
00256
00257 if (buf[1] >= 200 && buf[1] <= 204) {
00258
00259 hd = s->rtcp_hd;
00260 } else {
00261
00262 hd = s->rtp_hd;
00263 }
00264
00265 ret = url_write(hd, buf, size);
00266 #if 0
00267 {
00268 struct timespec ts;
00269 ts.tv_sec = 0;
00270 ts.tv_nsec = 10 * 1000000;
00271 nanosleep(&ts, NULL);
00272 }
00273 #endif
00274 return ret;
00275 }
00276
00277 static int rtp_close(URLContext *h)
00278 {
00279 RTPContext *s = h->priv_data;
00280
00281 url_close(s->rtp_hd);
00282 url_close(s->rtcp_hd);
00283 av_free(s);
00284 return 0;
00285 }
00286
00293 int rtp_get_local_port(URLContext *h)
00294 {
00295 RTPContext *s = h->priv_data;
00296 return udp_get_local_port(s->rtp_hd);
00297 }
00298
00305 void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
00306 {
00307 RTPContext *s = h->priv_data;
00308
00309 *prtp_fd = s->rtp_fd;
00310 *prtcp_fd = s->rtcp_fd;
00311 }
00312
00313 URLProtocol rtp_protocol = {
00314 "rtp",
00315 rtp_open,
00316 rtp_read,
00317 rtp_write,
00318 NULL,
00319 rtp_close,
00320 };