• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/rtpproto.c

Go to the documentation of this file.
00001 /*
00002  * RTP network protocol
00003  * Copyright (c) 2002 Fabrice Bellard
00004  *
00005  * This file is part of FFmpeg.
00006  *
00007  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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/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     /* extract parameters */
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     /* just to ease handle access. XXX: need to suppress direct handle
00193        access */
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         /* build fdset to listen to RTP and RTCP packets */
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             /* first try RTCP */
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             /* then RTP */
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         /* RTCP payload type */
00290         hd = s->rtcp_hd;
00291     } else {
00292         /* RTP payload type */
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, /* seek */
00382     rtp_close,
00383     .url_get_file_handle = rtp_get_file_handle,
00384 };

Generated on Fri Sep 16 2011 17:17:50 for FFmpeg by  doxygen 1.7.1