• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/ffmpeg/libavformat/
1/*
2 * RTP network protocol
3 * Copyright (c) 2002 Fabrice Bellard
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * RTP protocol
25 */
26
27#include "libavutil/avstring.h"
28#include "avformat.h"
29#include "rtpdec.h"
30
31#include <unistd.h>
32#include <stdarg.h>
33#include "internal.h"
34#include "network.h"
35#include "os_support.h"
36#include <fcntl.h>
37#if HAVE_SYS_SELECT_H
38#include <sys/select.h>
39#endif
40#include <sys/time.h>
41
42#define RTP_TX_BUF_SIZE  (64 * 1024)
43#define RTP_RX_BUF_SIZE  (128 * 1024)
44
45typedef struct RTPContext {
46    URLContext *rtp_hd, *rtcp_hd;
47    int rtp_fd, rtcp_fd;
48} RTPContext;
49
50/**
51 * If no filename is given to av_open_input_file because you want to
52 * get the local port first, then you must call this function to set
53 * the remote server address.
54 *
55 * @param s1 media file context
56 * @param uri of the remote server
57 * @return zero if no error.
58 */
59
60int rtp_set_remote_url(URLContext *h, const char *uri)
61{
62    RTPContext *s = h->priv_data;
63    char hostname[256];
64    int port;
65
66    char buf[1024];
67    char path[1024];
68
69    ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
70                 path, sizeof(path), uri);
71
72    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
73    udp_set_remote_url(s->rtp_hd, buf);
74
75    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
76    udp_set_remote_url(s->rtcp_hd, buf);
77    return 0;
78}
79
80
81/**
82 * add option to url of the form:
83 * "http://host:port/path?option1=val1&option2=val2...
84 */
85
86static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
87{
88    char buf1[1024];
89    va_list ap;
90
91    va_start(ap, fmt);
92    if (strchr(buf, '?'))
93        av_strlcat(buf, "&", buf_size);
94    else
95        av_strlcat(buf, "?", buf_size);
96    vsnprintf(buf1, sizeof(buf1), fmt, ap);
97    av_strlcat(buf, buf1, buf_size);
98    va_end(ap);
99}
100
101static void build_udp_url(char *buf, int buf_size,
102                          const char *hostname, int port,
103                          int local_port, int ttl,
104                          int max_packet_size)
105{
106    ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
107    if (local_port >= 0)
108        url_add_option(buf, buf_size, "localport=%d", local_port);
109    if (ttl >= 0)
110        url_add_option(buf, buf_size, "ttl=%d", ttl);
111    if (max_packet_size >=0)
112        url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
113}
114
115/**
116 * url syntax: rtp://host:port[?option=val...]
117 * option: 'ttl=n'            : set the ttl value (for multicast only)
118 *         'rtcpport=n'       : set the remote rtcp port to n
119 *         'localrtpport=n'   : set the local rtp port to n
120 *         'localrtcpport=n'  : set the local rtcp port to n
121 *         'pkt_size=n'       : set max packet size
122 * deprecated option:
123 *         'localport=n'      : set the local port to n
124 *
125 * if rtcpport isn't set the rtcp port will be the rtp port + 1
126 * if local rtp port isn't set any available port will be used for the local
127 * rtp and rtcp ports
128 * if the local rtcp port is not set it will be the local rtp port + 1
129 */
130
131static int rtp_open(URLContext *h, const char *uri, int flags)
132{
133    RTPContext *s;
134    int rtp_port, rtcp_port,
135        is_output, ttl,
136        local_rtp_port, local_rtcp_port, max_packet_size;
137    char hostname[256];
138    char buf[1024];
139    char path[1024];
140    const char *p;
141
142    is_output = (flags & URL_WRONLY);
143
144    s = av_mallocz(sizeof(RTPContext));
145    if (!s)
146        return AVERROR(ENOMEM);
147    h->priv_data = s;
148
149    ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
150                 path, sizeof(path), uri);
151    /* extract parameters */
152    ttl = -1;
153    rtcp_port = rtp_port+1;
154    local_rtp_port = -1;
155    local_rtcp_port = -1;
156    max_packet_size = -1;
157
158    p = strchr(uri, '?');
159    if (p) {
160        if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
161            ttl = strtol(buf, NULL, 10);
162        }
163        if (find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
164            rtcp_port = strtol(buf, NULL, 10);
165        }
166        if (find_info_tag(buf, sizeof(buf), "localport", p)) {
167            local_rtp_port = strtol(buf, NULL, 10);
168        }
169        if (find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
170            local_rtp_port = strtol(buf, NULL, 10);
171        }
172        if (find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
173            local_rtcp_port = strtol(buf, NULL, 10);
174        }
175        if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
176            max_packet_size = strtol(buf, NULL, 10);
177        }
178    }
179
180    build_udp_url(buf, sizeof(buf),
181                  hostname, rtp_port, local_rtp_port, ttl, max_packet_size);
182    if (url_open(&s->rtp_hd, buf, flags) < 0)
183        goto fail;
184    if (local_rtp_port>=0 && local_rtcp_port<0)
185        local_rtcp_port = udp_get_local_port(s->rtp_hd) + 1;
186
187    build_udp_url(buf, sizeof(buf),
188                  hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size);
189    if (url_open(&s->rtcp_hd, buf, flags) < 0)
190        goto fail;
191
192    /* just to ease handle access. XXX: need to suppress direct handle
193       access */
194    s->rtp_fd = url_get_file_handle(s->rtp_hd);
195    s->rtcp_fd = url_get_file_handle(s->rtcp_hd);
196
197    h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
198    h->is_streamed = 1;
199    return 0;
200
201 fail:
202    if (s->rtp_hd)
203        url_close(s->rtp_hd);
204    if (s->rtcp_hd)
205        url_close(s->rtcp_hd);
206    av_free(s);
207    return AVERROR(EIO);
208}
209
210static int rtp_read(URLContext *h, uint8_t *buf, int size)
211{
212    RTPContext *s = h->priv_data;
213    struct sockaddr_in from;
214    socklen_t from_len;
215    int len, fd_max, n;
216    fd_set rfds;
217    struct timeval tv;
218#if 0
219    for(;;) {
220        from_len = sizeof(from);
221        len = recvfrom (s->rtp_fd, buf, size, 0,
222                        (struct sockaddr *)&from, &from_len);
223        if (len < 0) {
224            if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
225                ff_neterrno() == FF_NETERROR(EINTR))
226                continue;
227            return AVERROR(EIO);
228        }
229        break;
230    }
231#else
232    for(;;) {
233        if (url_interrupt_cb())
234            return AVERROR(EINTR);
235        /* build fdset to listen to RTP and RTCP packets */
236        FD_ZERO(&rfds);
237        fd_max = s->rtp_fd;
238        FD_SET(s->rtp_fd, &rfds);
239        if (s->rtcp_fd > fd_max)
240            fd_max = s->rtcp_fd;
241        FD_SET(s->rtcp_fd, &rfds);
242        tv.tv_sec = 0;
243        tv.tv_usec = 100 * 1000;
244        n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
245        if (n > 0) {
246            /* first try RTCP */
247            if (FD_ISSET(s->rtcp_fd, &rfds)) {
248                from_len = sizeof(from);
249                len = recvfrom (s->rtcp_fd, buf, size, 0,
250                                (struct sockaddr *)&from, &from_len);
251                if (len < 0) {
252                    if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
253                        ff_neterrno() == FF_NETERROR(EINTR))
254                        continue;
255                    return AVERROR(EIO);
256                }
257                break;
258            }
259            /* then RTP */
260            if (FD_ISSET(s->rtp_fd, &rfds)) {
261                from_len = sizeof(from);
262                len = recvfrom (s->rtp_fd, buf, size, 0,
263                                (struct sockaddr *)&from, &from_len);
264                if (len < 0) {
265                    if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
266                        ff_neterrno() == FF_NETERROR(EINTR))
267                        continue;
268                    return AVERROR(EIO);
269                }
270                break;
271            }
272        } else if (n < 0) {
273            if (ff_neterrno() == FF_NETERROR(EINTR))
274                continue;
275            return AVERROR(EIO);
276        }
277    }
278#endif
279    return len;
280}
281
282static int rtp_write(URLContext *h, uint8_t *buf, int size)
283{
284    RTPContext *s = h->priv_data;
285    int ret;
286    URLContext *hd;
287
288    if (buf[1] >= 200 && buf[1] <= 204) {
289        /* RTCP payload type */
290        hd = s->rtcp_hd;
291    } else {
292        /* RTP payload type */
293        hd = s->rtp_hd;
294    }
295
296    ret = url_write(hd, buf, size);
297#if 0
298    {
299        struct timespec ts;
300        ts.tv_sec = 0;
301        ts.tv_nsec = 10 * 1000000;
302        nanosleep(&ts, NULL);
303    }
304#endif
305    return ret;
306}
307
308static int rtp_close(URLContext *h)
309{
310    RTPContext *s = h->priv_data;
311
312    url_close(s->rtp_hd);
313    url_close(s->rtcp_hd);
314    av_free(s);
315    return 0;
316}
317
318/**
319 * Return the local rtp port used by the RTP connection
320 * @param s1 media file context
321 * @return the local port number
322 */
323
324int rtp_get_local_rtp_port(URLContext *h)
325{
326    RTPContext *s = h->priv_data;
327    return udp_get_local_port(s->rtp_hd);
328}
329
330/**
331 * Return the local rtp port used by the RTP connection
332 * @param s1 media file context
333 * @return the local port number
334 */
335
336int rtp_get_local_port(URLContext *h)
337{
338    RTPContext *s = h->priv_data;
339    return udp_get_local_port(s->rtp_hd);
340}
341
342/**
343 * Return the local rtcp port used by the RTP connection
344 * @param s1 media file context
345 * @return the local port number
346 */
347
348int rtp_get_local_rtcp_port(URLContext *h)
349{
350    RTPContext *s = h->priv_data;
351    return udp_get_local_port(s->rtcp_hd);
352}
353
354#if (LIBAVFORMAT_VERSION_MAJOR <= 52)
355/**
356 * Return the rtp and rtcp file handles for select() usage to wait for
357 * several RTP streams at the same time.
358 * @param h media file context
359 */
360
361void rtp_get_file_handles(URLContext *h, int *prtp_fd, int *prtcp_fd)
362{
363    RTPContext *s = h->priv_data;
364
365    *prtp_fd = s->rtp_fd;
366    *prtcp_fd = s->rtcp_fd;
367}
368#endif
369
370static int rtp_get_file_handle(URLContext *h)
371{
372    RTPContext *s = h->priv_data;
373    return s->rtp_fd;
374}
375
376URLProtocol rtp_protocol = {
377    "rtp",
378    rtp_open,
379    rtp_read,
380    rtp_write,
381    NULL, /* seek */
382    rtp_close,
383    .url_get_file_handle = rtp_get_file_handle,
384};
385