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