Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpproto.c @ da9e6c42

History | View | Annotate | Download (10.3 KB)

1 3b50d2ad Fabrice Bellard
/*
2
 * RTP network protocol
3 406792e7 Diego Biurrun
 * Copyright (c) 2002 Fabrice Bellard
4 3b50d2ad Fabrice Bellard
 *
5 b78e7197 Diego Biurrun
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8 3b50d2ad Fabrice Bellard
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10 b78e7197 Diego Biurrun
 * version 2.1 of the License, or (at your option) any later version.
11 3b50d2ad Fabrice Bellard
 *
12 b78e7197 Diego Biurrun
 * FFmpeg is distributed in the hope that it will be useful,
13 3b50d2ad Fabrice Bellard
 * 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 b78e7197 Diego Biurrun
 * License along with FFmpeg; if not, write to the Free Software
19 5509bffa Diego Biurrun
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 3b50d2ad Fabrice Bellard
 */
21 b4999290 Luca Barbato
22
/**
23 ba87f080 Diego Biurrun
 * @file
24 b4999290 Luca Barbato
 * RTP protocol
25
 */
26
27 245976da Diego Biurrun
#include "libavutil/avstring.h"
28 3b50d2ad Fabrice Bellard
#include "avformat.h"
29 1e6365b3 Carl Eugen Hoyos
#include "rtpdec.h"
30 3b50d2ad Fabrice Bellard
31
#include <unistd.h>
32 51885599 Fabrice Bellard
#include <stdarg.h>
33 e4a9e3cc Aurelien Jacobs
#include "internal.h"
34 42572ef5 Ramiro Polla
#include "network.h"
35 93115b82 Dave Yeo
#include "os_support.h"
36 3b50d2ad Fabrice Bellard
#include <fcntl.h>
37 b250f9c6 Aurelien Jacobs
#if HAVE_SYS_SELECT_H
38 0e55ba72 Michael Niedermayer
#include <sys/select.h>
39 7139bfa8 Kurtnoise
#endif
40 611b17d7 Dave Yeo
#include <sys/time.h>
41 3b50d2ad Fabrice Bellard
42
#define RTP_TX_BUF_SIZE  (64 * 1024)
43
#define RTP_RX_BUF_SIZE  (128 * 1024)
44
45
typedef 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 b4999290 Luca Barbato
60 3b50d2ad Fabrice Bellard
int rtp_set_remote_url(URLContext *h, const char *uri)
61
{
62
    RTPContext *s = h->priv_data;
63
    char hostname[256];
64
    int port;
65 51885599 Fabrice Bellard
66 3b50d2ad Fabrice Bellard
    char buf[1024];
67
    char path[1024];
68 115329f1 Diego Biurrun
69 c5c6e67c Martin Storsjö
    ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
70 f984dcf6 Martin Storsjö
                 path, sizeof(path), uri);
71 3b50d2ad Fabrice Bellard
72 57b5555c Martin Storsjö
    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
73 3b50d2ad Fabrice Bellard
    udp_set_remote_url(s->rtp_hd, buf);
74
75 57b5555c Martin Storsjö
    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
76 3b50d2ad Fabrice Bellard
    udp_set_remote_url(s->rtcp_hd, buf);
77
    return 0;
78
}
79
80
81 b4999290 Luca Barbato
/**
82
 * add option to url of the form:
83
 * "http://host:port/path?option1=val1&option2=val2...
84
 */
85
86 5c91a675 Zdenek Kabelac
static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
87 51885599 Fabrice Bellard
{
88
    char buf1[1024];
89
    va_list ap;
90
91
    va_start(ap, fmt);
92
    if (strchr(buf, '?'))
93 f7d78f36 Måns Rullgård
        av_strlcat(buf, "&", buf_size);
94 51885599 Fabrice Bellard
    else
95 f7d78f36 Måns Rullgård
        av_strlcat(buf, "?", buf_size);
96 51885599 Fabrice Bellard
    vsnprintf(buf1, sizeof(buf1), fmt, ap);
97 f7d78f36 Måns Rullgård
    av_strlcat(buf, buf1, buf_size);
98 51885599 Fabrice Bellard
    va_end(ap);
99
}
100
101 5c91a675 Zdenek Kabelac
static void build_udp_url(char *buf, int buf_size,
102 bb270c08 Diego Biurrun
                          const char *hostname, int port,
103 fc9b22dd Luca Barbato
                          int local_port, int ttl,
104
                          int max_packet_size)
105 51885599 Fabrice Bellard
{
106 57b5555c Martin Storsjö
    ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
107 51885599 Fabrice Bellard
    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 fc9b22dd Luca Barbato
    if (max_packet_size >=0)
112
        url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
113 51885599 Fabrice Bellard
}
114
115 b4999290 Luca Barbato
/**
116 51885599 Fabrice Bellard
 * url syntax: rtp://host:port[?option=val...]
117 9094d867 Luca Barbato
 * 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 51885599 Fabrice Bellard
 *
125 9094d867 Luca Barbato
 * 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 51885599 Fabrice Bellard
 */
130 b4999290 Luca Barbato
131 3b50d2ad Fabrice Bellard
static int rtp_open(URLContext *h, const char *uri, int flags)
132
{
133
    RTPContext *s;
134 9094d867 Luca Barbato
    int rtp_port, rtcp_port,
135
        is_output, ttl,
136
        local_rtp_port, local_rtcp_port, max_packet_size;
137 3b50d2ad Fabrice Bellard
    char hostname[256];
138
    char buf[1024];
139
    char path[1024];
140 51885599 Fabrice Bellard
    const char *p;
141 115329f1 Diego Biurrun
142 3b50d2ad Fabrice Bellard
    is_output = (flags & URL_WRONLY);
143
144
    s = av_mallocz(sizeof(RTPContext));
145
    if (!s)
146 8fa36ae0 François Revol
        return AVERROR(ENOMEM);
147 3b50d2ad Fabrice Bellard
    h->priv_data = s;
148 115329f1 Diego Biurrun
149 9094d867 Luca Barbato
    ff_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
150 f984dcf6 Martin Storsjö
                 path, sizeof(path), uri);
151 51885599 Fabrice Bellard
    /* extract parameters */
152
    ttl = -1;
153 9094d867 Luca Barbato
    rtcp_port = rtp_port+1;
154
    local_rtp_port = -1;
155
    local_rtcp_port = -1;
156 fc9b22dd Luca Barbato
    max_packet_size = -1;
157
158 51885599 Fabrice Bellard
    p = strchr(uri, '?');
159
    if (p) {
160
        if (find_info_tag(buf, sizeof(buf), "ttl", p)) {
161
            ttl = strtol(buf, NULL, 10);
162
        }
163 9094d867 Luca Barbato
        if (find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
164
            rtcp_port = strtol(buf, NULL, 10);
165
        }
166 51885599 Fabrice Bellard
        if (find_info_tag(buf, sizeof(buf), "localport", p)) {
167 9094d867 Luca Barbato
            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 51885599 Fabrice Bellard
        }
175 fc9b22dd Luca Barbato
        if (find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
176
            max_packet_size = strtol(buf, NULL, 10);
177
        }
178 51885599 Fabrice Bellard
    }
179 3b50d2ad Fabrice Bellard
180 51885599 Fabrice Bellard
    build_udp_url(buf, sizeof(buf),
181 9094d867 Luca Barbato
                  hostname, rtp_port, local_rtp_port, ttl, max_packet_size);
182 3b50d2ad Fabrice Bellard
    if (url_open(&s->rtp_hd, buf, flags) < 0)
183
        goto fail;
184 9094d867 Luca Barbato
    if (local_rtp_port>=0 && local_rtcp_port<0)
185
        local_rtcp_port = udp_get_local_port(s->rtp_hd) + 1;
186 115329f1 Diego Biurrun
187 51885599 Fabrice Bellard
    build_udp_url(buf, sizeof(buf),
188 9094d867 Luca Barbato
                  hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size);
189 3b50d2ad Fabrice Bellard
    if (url_open(&s->rtcp_hd, buf, flags) < 0)
190
        goto fail;
191 115329f1 Diego Biurrun
192 3b50d2ad Fabrice Bellard
    /* just to ease handle access. XXX: need to suppress direct handle
193
       access */
194 f0a80394 Ronald S. Bultje
    s->rtp_fd = url_get_file_handle(s->rtp_hd);
195
    s->rtcp_fd = url_get_file_handle(s->rtcp_hd);
196 3b50d2ad Fabrice Bellard
197 115329f1 Diego Biurrun
    h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
198 3b50d2ad Fabrice Bellard
    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 6f3e0b21 Panagiotis Issaris
    return AVERROR(EIO);
208 3b50d2ad Fabrice Bellard
}
209
210 0c1a9eda Zdenek Kabelac
static int rtp_read(URLContext *h, uint8_t *buf, int size)
211 3b50d2ad Fabrice Bellard
{
212
    RTPContext *s = h->priv_data;
213
    struct sockaddr_in from;
214 191e8ca7 Måns Rullgård
    socklen_t from_len;
215
    int len, fd_max, n;
216 3b50d2ad Fabrice Bellard
    fd_set rfds;
217 c2b40ac2 Martin Storsjö
    struct timeval tv;
218 3b50d2ad Fabrice Bellard
#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 8da4034f Alex Beregszaszi
            if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
225
                ff_neterrno() == FF_NETERROR(EINTR))
226 3b50d2ad Fabrice Bellard
                continue;
227 6f3e0b21 Panagiotis Issaris
            return AVERROR(EIO);
228 3b50d2ad Fabrice Bellard
        }
229
        break;
230
    }
231
#else
232
    for(;;) {
233 c2b40ac2 Martin Storsjö
        if (url_interrupt_cb())
234
            return AVERROR(EINTR);
235 3b50d2ad Fabrice Bellard
        /* 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 c2b40ac2 Martin Storsjö
        tv.tv_sec = 0;
243
        tv.tv_usec = 100 * 1000;
244
        n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
245 3b50d2ad Fabrice Bellard
        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 8da4034f Alex Beregszaszi
                    if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
253
                        ff_neterrno() == FF_NETERROR(EINTR))
254 3b50d2ad Fabrice Bellard
                        continue;
255 6f3e0b21 Panagiotis Issaris
                    return AVERROR(EIO);
256 3b50d2ad Fabrice Bellard
                }
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 8da4034f Alex Beregszaszi
                    if (ff_neterrno() == FF_NETERROR(EAGAIN) ||
266
                        ff_neterrno() == FF_NETERROR(EINTR))
267 3b50d2ad Fabrice Bellard
                        continue;
268 6f3e0b21 Panagiotis Issaris
                    return AVERROR(EIO);
269 3b50d2ad Fabrice Bellard
                }
270
                break;
271
            }
272 886f3f2f Martin Storsjö
        } else if (n < 0) {
273 cae9a15c Martin Storsjö
            if (ff_neterrno() == FF_NETERROR(EINTR))
274
                continue;
275 886f3f2f Martin Storsjö
            return AVERROR(EIO);
276 3b50d2ad Fabrice Bellard
        }
277
    }
278
#endif
279
    return len;
280
}
281
282 27241cbf Martin Storsjö
static int rtp_write(URLContext *h, const uint8_t *buf, int size)
283 3b50d2ad Fabrice Bellard
{
284
    RTPContext *s = h->priv_data;
285 51885599 Fabrice Bellard
    int ret;
286 3b50d2ad Fabrice Bellard
    URLContext *hd;
287 115329f1 Diego Biurrun
288 3b50d2ad Fabrice Bellard
    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
308
static 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 9094d867 Luca Barbato
 * Return the local rtp port used by the RTP connection
320
 * @param s1 media file context
321
 * @return the local port number
322
 */
323
324
int 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 3b50d2ad Fabrice Bellard
 * @param s1 media file context
333
 * @return the local port number
334
 */
335 b4999290 Luca Barbato
336 3b50d2ad Fabrice Bellard
int 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 9094d867 Luca Barbato
/**
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
348
int 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 f0a80394 Ronald S. Bultje
#if (LIBAVFORMAT_VERSION_MAJOR <= 52)
355 3b50d2ad Fabrice Bellard
/**
356 b4999290 Luca Barbato
 * Return the rtp and rtcp file handles for select() usage to wait for
357
 * several RTP streams at the same time.
358 3b50d2ad Fabrice Bellard
 * @param h media file context
359
 */
360 b4999290 Luca Barbato
361 3b50d2ad Fabrice Bellard
void 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 f0a80394 Ronald S. Bultje
#endif
369
370
static int rtp_get_file_handle(URLContext *h)
371
{
372
    RTPContext *s = h->priv_data;
373
    return s->rtp_fd;
374
}
375 3b50d2ad Fabrice Bellard
376
URLProtocol rtp_protocol = {
377
    "rtp",
378
    rtp_open,
379
    rtp_read,
380
    rtp_write,
381
    NULL, /* seek */
382
    rtp_close,
383 f0a80394 Ronald S. Bultje
    .url_get_file_handle = rtp_get_file_handle,
384 3b50d2ad Fabrice Bellard
};