Libav 0.7.1
|
00001 /* 00002 * RTP network protocol 00003 * Copyright (c) 2002 Fabrice Bellard 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 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 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; 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 s = av_mallocz(sizeof(RTPContext)); 00149 if (!s) 00150 return AVERROR(ENOMEM); 00151 h->priv_data = s; 00152 00153 av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, 00154 path, sizeof(path), uri); 00155 /* extract parameters */ 00156 ttl = -1; 00157 rtcp_port = rtp_port+1; 00158 local_rtp_port = -1; 00159 local_rtcp_port = -1; 00160 max_packet_size = -1; 00161 connect = 0; 00162 00163 p = strchr(uri, '?'); 00164 if (p) { 00165 if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) { 00166 ttl = strtol(buf, NULL, 10); 00167 } 00168 if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) { 00169 rtcp_port = strtol(buf, NULL, 10); 00170 } 00171 if (av_find_info_tag(buf, sizeof(buf), "localport", p)) { 00172 local_rtp_port = strtol(buf, NULL, 10); 00173 } 00174 if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) { 00175 local_rtp_port = strtol(buf, NULL, 10); 00176 } 00177 if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) { 00178 local_rtcp_port = strtol(buf, NULL, 10); 00179 } 00180 if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { 00181 max_packet_size = strtol(buf, NULL, 10); 00182 } 00183 if (av_find_info_tag(buf, sizeof(buf), "connect", p)) { 00184 connect = strtol(buf, NULL, 10); 00185 } 00186 } 00187 00188 build_udp_url(buf, sizeof(buf), 00189 hostname, rtp_port, local_rtp_port, ttl, max_packet_size, 00190 connect); 00191 if (ffurl_open(&s->rtp_hd, buf, flags) < 0) 00192 goto fail; 00193 if (local_rtp_port>=0 && local_rtcp_port<0) 00194 local_rtcp_port = ff_udp_get_local_port(s->rtp_hd) + 1; 00195 00196 build_udp_url(buf, sizeof(buf), 00197 hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size, 00198 connect); 00199 if (ffurl_open(&s->rtcp_hd, buf, flags) < 0) 00200 goto fail; 00201 00202 /* just to ease handle access. XXX: need to suppress direct handle 00203 access */ 00204 s->rtp_fd = ffurl_get_file_handle(s->rtp_hd); 00205 s->rtcp_fd = ffurl_get_file_handle(s->rtcp_hd); 00206 00207 h->max_packet_size = s->rtp_hd->max_packet_size; 00208 h->is_streamed = 1; 00209 return 0; 00210 00211 fail: 00212 if (s->rtp_hd) 00213 ffurl_close(s->rtp_hd); 00214 if (s->rtcp_hd) 00215 ffurl_close(s->rtcp_hd); 00216 av_free(s); 00217 return AVERROR(EIO); 00218 } 00219 00220 static int rtp_read(URLContext *h, uint8_t *buf, int size) 00221 { 00222 RTPContext *s = h->priv_data; 00223 struct sockaddr_storage from; 00224 socklen_t from_len; 00225 int len, n; 00226 struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}}; 00227 00228 #if 0 00229 for(;;) { 00230 from_len = sizeof(from); 00231 len = recvfrom (s->rtp_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 #else 00242 for(;;) { 00243 if (url_interrupt_cb()) 00244 return AVERROR_EXIT; 00245 /* build fdset to listen to RTP and RTCP packets */ 00246 n = poll(p, 2, 100); 00247 if (n > 0) { 00248 /* first try RTCP */ 00249 if (p[1].revents & POLLIN) { 00250 from_len = sizeof(from); 00251 len = recvfrom (s->rtcp_fd, buf, size, 0, 00252 (struct sockaddr *)&from, &from_len); 00253 if (len < 0) { 00254 if (ff_neterrno() == AVERROR(EAGAIN) || 00255 ff_neterrno() == AVERROR(EINTR)) 00256 continue; 00257 return AVERROR(EIO); 00258 } 00259 break; 00260 } 00261 /* then RTP */ 00262 if (p[0].revents & POLLIN) { 00263 from_len = sizeof(from); 00264 len = recvfrom (s->rtp_fd, buf, size, 0, 00265 (struct sockaddr *)&from, &from_len); 00266 if (len < 0) { 00267 if (ff_neterrno() == AVERROR(EAGAIN) || 00268 ff_neterrno() == AVERROR(EINTR)) 00269 continue; 00270 return AVERROR(EIO); 00271 } 00272 break; 00273 } 00274 } else if (n < 0) { 00275 if (ff_neterrno() == AVERROR(EINTR)) 00276 continue; 00277 return AVERROR(EIO); 00278 } 00279 } 00280 #endif 00281 return len; 00282 } 00283 00284 static int rtp_write(URLContext *h, const uint8_t *buf, int size) 00285 { 00286 RTPContext *s = h->priv_data; 00287 int ret; 00288 URLContext *hd; 00289 00290 if (buf[1] >= RTCP_SR && buf[1] <= RTCP_APP) { 00291 /* RTCP payload type */ 00292 hd = s->rtcp_hd; 00293 } else { 00294 /* RTP payload type */ 00295 hd = s->rtp_hd; 00296 } 00297 00298 ret = ffurl_write(hd, buf, size); 00299 #if 0 00300 { 00301 struct timespec ts; 00302 ts.tv_sec = 0; 00303 ts.tv_nsec = 10 * 1000000; 00304 nanosleep(&ts, NULL); 00305 } 00306 #endif 00307 return ret; 00308 } 00309 00310 static int rtp_close(URLContext *h) 00311 { 00312 RTPContext *s = h->priv_data; 00313 00314 ffurl_close(s->rtp_hd); 00315 ffurl_close(s->rtcp_hd); 00316 av_free(s); 00317 return 0; 00318 } 00319 00326 int rtp_get_local_rtp_port(URLContext *h) 00327 { 00328 RTPContext *s = h->priv_data; 00329 return ff_udp_get_local_port(s->rtp_hd); 00330 } 00331 00338 int rtp_get_local_rtcp_port(URLContext *h) 00339 { 00340 RTPContext *s = h->priv_data; 00341 return ff_udp_get_local_port(s->rtcp_hd); 00342 } 00343 00344 static int rtp_get_file_handle(URLContext *h) 00345 { 00346 RTPContext *s = h->priv_data; 00347 return s->rtp_fd; 00348 } 00349 00350 int rtp_get_rtcp_file_handle(URLContext *h) { 00351 RTPContext *s = h->priv_data; 00352 return s->rtcp_fd; 00353 } 00354 00355 URLProtocol ff_rtp_protocol = { 00356 .name = "rtp", 00357 .url_open = rtp_open, 00358 .url_read = rtp_read, 00359 .url_write = rtp_write, 00360 .url_close = rtp_close, 00361 .url_get_file_handle = rtp_get_file_handle, 00362 };