Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpproto.c @ c76374c6

History | View | Annotate | Download (9.94 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 ab0287fc Anton Khirnov
#include "libavutil/parseutils.h"
28 245976da Diego Biurrun
#include "libavutil/avstring.h"
29 3b50d2ad Fabrice Bellard
#include "avformat.h"
30 1e6365b3 Carl Eugen Hoyos
#include "rtpdec.h"
31 3b50d2ad Fabrice Bellard
32
#include <unistd.h>
33 51885599 Fabrice Bellard
#include <stdarg.h>
34 e4a9e3cc Aurelien Jacobs
#include "internal.h"
35 42572ef5 Ramiro Polla
#include "network.h"
36 93115b82 Dave Yeo
#include "os_support.h"
37 3b50d2ad Fabrice Bellard
#include <fcntl.h>
38 a8475bbd Luca Barbato
#if HAVE_POLL_H
39
#include <sys/poll.h>
40 7139bfa8 Kurtnoise
#endif
41 611b17d7 Dave Yeo
#include <sys/time.h>
42 3b50d2ad Fabrice Bellard
43
#define RTP_TX_BUF_SIZE  (64 * 1024)
44
#define RTP_RX_BUF_SIZE  (128 * 1024)
45
46
typedef struct RTPContext {
47
    URLContext *rtp_hd, *rtcp_hd;
48
    int rtp_fd, rtcp_fd;
49
} RTPContext;
50
51
/**
52
 * If no filename is given to av_open_input_file because you want to
53
 * get the local port first, then you must call this function to set
54
 * the remote server address.
55
 *
56 9a58234f Diego Biurrun
 * @param h media file context
57 3b50d2ad Fabrice Bellard
 * @param uri of the remote server
58
 * @return zero if no error.
59
 */
60 b4999290 Luca Barbato
61 3b50d2ad Fabrice Bellard
int rtp_set_remote_url(URLContext *h, const char *uri)
62
{
63
    RTPContext *s = h->priv_data;
64
    char hostname[256];
65
    int port;
66 51885599 Fabrice Bellard
67 3b50d2ad Fabrice Bellard
    char buf[1024];
68
    char path[1024];
69 115329f1 Diego Biurrun
70 f3bfe388 Måns Rullgård
    av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
71 f984dcf6 Martin Storsjö
                 path, sizeof(path), uri);
72 3b50d2ad Fabrice Bellard
73 57b5555c Martin Storsjö
    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
74 3b50d2ad Fabrice Bellard
    udp_set_remote_url(s->rtp_hd, buf);
75
76 57b5555c Martin Storsjö
    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
77 3b50d2ad Fabrice Bellard
    udp_set_remote_url(s->rtcp_hd, buf);
78
    return 0;
79
}
80
81
82 b4999290 Luca Barbato
/**
83
 * add option to url of the form:
84
 * "http://host:port/path?option1=val1&option2=val2...
85
 */
86
87 5c91a675 Zdenek Kabelac
static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
88 51885599 Fabrice Bellard
{
89
    char buf1[1024];
90
    va_list ap;
91
92
    va_start(ap, fmt);
93
    if (strchr(buf, '?'))
94 f7d78f36 Måns Rullgård
        av_strlcat(buf, "&", buf_size);
95 51885599 Fabrice Bellard
    else
96 f7d78f36 Måns Rullgård
        av_strlcat(buf, "?", buf_size);
97 51885599 Fabrice Bellard
    vsnprintf(buf1, sizeof(buf1), fmt, ap);
98 f7d78f36 Måns Rullgård
    av_strlcat(buf, buf1, buf_size);
99 51885599 Fabrice Bellard
    va_end(ap);
100
}
101
102 5c91a675 Zdenek Kabelac
static void build_udp_url(char *buf, int buf_size,
103 bb270c08 Diego Biurrun
                          const char *hostname, int port,
104 fc9b22dd Luca Barbato
                          int local_port, int ttl,
105 babd19ce Martin Storsjö
                          int max_packet_size, int connect)
106 51885599 Fabrice Bellard
{
107 57b5555c Martin Storsjö
    ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
108 51885599 Fabrice Bellard
    if (local_port >= 0)
109
        url_add_option(buf, buf_size, "localport=%d", local_port);
110
    if (ttl >= 0)
111
        url_add_option(buf, buf_size, "ttl=%d", ttl);
112 fc9b22dd Luca Barbato
    if (max_packet_size >=0)
113
        url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
114 babd19ce Martin Storsjö
    if (connect)
115
        url_add_option(buf, buf_size, "connect=1");
116 51885599 Fabrice Bellard
}
117
118 b4999290 Luca Barbato
/**
119 51885599 Fabrice Bellard
 * url syntax: rtp://host:port[?option=val...]
120 9094d867 Luca Barbato
 * option: 'ttl=n'            : set the ttl value (for multicast only)
121
 *         'rtcpport=n'       : set the remote rtcp port to n
122
 *         'localrtpport=n'   : set the local rtp port to n
123
 *         'localrtcpport=n'  : set the local rtcp port to n
124
 *         'pkt_size=n'       : set max packet size
125 babd19ce Martin Storsjö
 *         'connect=0/1'      : do a connect() on the UDP socket
126 9094d867 Luca Barbato
 * deprecated option:
127
 *         'localport=n'      : set the local port to n
128 51885599 Fabrice Bellard
 *
129 9094d867 Luca Barbato
 * if rtcpport isn't set the rtcp port will be the rtp port + 1
130
 * if local rtp port isn't set any available port will be used for the local
131
 * rtp and rtcp ports
132
 * if the local rtcp port is not set it will be the local rtp port + 1
133 51885599 Fabrice Bellard
 */
134 b4999290 Luca Barbato
135 3b50d2ad Fabrice Bellard
static int rtp_open(URLContext *h, const char *uri, int flags)
136
{
137
    RTPContext *s;
138 9094d867 Luca Barbato
    int rtp_port, rtcp_port,
139 babd19ce Martin Storsjö
        is_output, ttl, connect,
140 9094d867 Luca Barbato
        local_rtp_port, local_rtcp_port, max_packet_size;
141 3b50d2ad Fabrice Bellard
    char hostname[256];
142
    char buf[1024];
143
    char path[1024];
144 51885599 Fabrice Bellard
    const char *p;
145 115329f1 Diego Biurrun
146 3b50d2ad Fabrice Bellard
    is_output = (flags & URL_WRONLY);
147
148
    s = av_mallocz(sizeof(RTPContext));
149
    if (!s)
150 8fa36ae0 François Revol
        return AVERROR(ENOMEM);
151 3b50d2ad Fabrice Bellard
    h->priv_data = s;
152 115329f1 Diego Biurrun
153 f3bfe388 Måns Rullgård
    av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
154 f984dcf6 Martin Storsjö
                 path, sizeof(path), uri);
155 51885599 Fabrice Bellard
    /* extract parameters */
156
    ttl = -1;
157 9094d867 Luca Barbato
    rtcp_port = rtp_port+1;
158
    local_rtp_port = -1;
159
    local_rtcp_port = -1;
160 fc9b22dd Luca Barbato
    max_packet_size = -1;
161 babd19ce Martin Storsjö
    connect = 0;
162 fc9b22dd Luca Barbato
163 51885599 Fabrice Bellard
    p = strchr(uri, '?');
164
    if (p) {
165 ab0287fc Anton Khirnov
        if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
166 51885599 Fabrice Bellard
            ttl = strtol(buf, NULL, 10);
167
        }
168 ab0287fc Anton Khirnov
        if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
169 9094d867 Luca Barbato
            rtcp_port = strtol(buf, NULL, 10);
170
        }
171 ab0287fc Anton Khirnov
        if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
172 9094d867 Luca Barbato
            local_rtp_port = strtol(buf, NULL, 10);
173
        }
174 ab0287fc Anton Khirnov
        if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
175 9094d867 Luca Barbato
            local_rtp_port = strtol(buf, NULL, 10);
176
        }
177 ab0287fc Anton Khirnov
        if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
178 9094d867 Luca Barbato
            local_rtcp_port = strtol(buf, NULL, 10);
179 51885599 Fabrice Bellard
        }
180 ab0287fc Anton Khirnov
        if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
181 fc9b22dd Luca Barbato
            max_packet_size = strtol(buf, NULL, 10);
182
        }
183 ab0287fc Anton Khirnov
        if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
184 babd19ce Martin Storsjö
            connect = strtol(buf, NULL, 10);
185
        }
186 51885599 Fabrice Bellard
    }
187 3b50d2ad Fabrice Bellard
188 51885599 Fabrice Bellard
    build_udp_url(buf, sizeof(buf),
189 babd19ce Martin Storsjö
                  hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
190
                  connect);
191 3b50d2ad Fabrice Bellard
    if (url_open(&s->rtp_hd, buf, flags) < 0)
192
        goto fail;
193 9094d867 Luca Barbato
    if (local_rtp_port>=0 && local_rtcp_port<0)
194
        local_rtcp_port = udp_get_local_port(s->rtp_hd) + 1;
195 115329f1 Diego Biurrun
196 51885599 Fabrice Bellard
    build_udp_url(buf, sizeof(buf),
197 babd19ce Martin Storsjö
                  hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
198
                  connect);
199 3b50d2ad Fabrice Bellard
    if (url_open(&s->rtcp_hd, buf, flags) < 0)
200
        goto fail;
201 115329f1 Diego Biurrun
202 3b50d2ad Fabrice Bellard
    /* just to ease handle access. XXX: need to suppress direct handle
203
       access */
204 f0a80394 Ronald S. Bultje
    s->rtp_fd = url_get_file_handle(s->rtp_hd);
205
    s->rtcp_fd = url_get_file_handle(s->rtcp_hd);
206 3b50d2ad Fabrice Bellard
207 115329f1 Diego Biurrun
    h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
208 3b50d2ad Fabrice Bellard
    h->is_streamed = 1;
209
    return 0;
210
211
 fail:
212
    if (s->rtp_hd)
213
        url_close(s->rtp_hd);
214
    if (s->rtcp_hd)
215
        url_close(s->rtcp_hd);
216
    av_free(s);
217 6f3e0b21 Panagiotis Issaris
    return AVERROR(EIO);
218 3b50d2ad Fabrice Bellard
}
219
220 0c1a9eda Zdenek Kabelac
static int rtp_read(URLContext *h, uint8_t *buf, int size)
221 3b50d2ad Fabrice Bellard
{
222
    RTPContext *s = h->priv_data;
223 4a94cfea Martin Storsjö
    struct sockaddr_storage from;
224 191e8ca7 Måns Rullgård
    socklen_t from_len;
225 a8475bbd Luca Barbato
    int len, n;
226
    struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
227
228 3b50d2ad Fabrice Bellard
#if 0
229
    for(;;) {
230
        from_len = sizeof(from);
231
        len = recvfrom (s->rtp_fd, buf, size, 0,
232
                        (struct sockaddr *)&from, &from_len);
233
        if (len < 0) {
234 28c4741a Martin Storsjö
            if (ff_neterrno() == AVERROR(EAGAIN) ||
235
                ff_neterrno() == AVERROR(EINTR))
236 3b50d2ad Fabrice Bellard
                continue;
237 6f3e0b21 Panagiotis Issaris
            return AVERROR(EIO);
238 3b50d2ad Fabrice Bellard
        }
239
        break;
240
    }
241
#else
242
    for(;;) {
243 c2b40ac2 Martin Storsjö
        if (url_interrupt_cb())
244 c76374c6 Nicolas George
            return AVERROR_EXIT;
245 3b50d2ad Fabrice Bellard
        /* build fdset to listen to RTP and RTCP packets */
246 a8475bbd Luca Barbato
        n = poll(p, 2, 100);
247 3b50d2ad Fabrice Bellard
        if (n > 0) {
248
            /* first try RTCP */
249 a8475bbd Luca Barbato
            if (p[1].revents & POLLIN) {
250 3b50d2ad Fabrice Bellard
                from_len = sizeof(from);
251
                len = recvfrom (s->rtcp_fd, buf, size, 0,
252
                                (struct sockaddr *)&from, &from_len);
253
                if (len < 0) {
254 28c4741a Martin Storsjö
                    if (ff_neterrno() == AVERROR(EAGAIN) ||
255
                        ff_neterrno() == AVERROR(EINTR))
256 3b50d2ad Fabrice Bellard
                        continue;
257 6f3e0b21 Panagiotis Issaris
                    return AVERROR(EIO);
258 3b50d2ad Fabrice Bellard
                }
259
                break;
260
            }
261
            /* then RTP */
262 a8475bbd Luca Barbato
            if (p[0].revents & POLLIN) {
263 3b50d2ad Fabrice Bellard
                from_len = sizeof(from);
264
                len = recvfrom (s->rtp_fd, buf, size, 0,
265
                                (struct sockaddr *)&from, &from_len);
266
                if (len < 0) {
267 28c4741a Martin Storsjö
                    if (ff_neterrno() == AVERROR(EAGAIN) ||
268
                        ff_neterrno() == AVERROR(EINTR))
269 3b50d2ad Fabrice Bellard
                        continue;
270 6f3e0b21 Panagiotis Issaris
                    return AVERROR(EIO);
271 3b50d2ad Fabrice Bellard
                }
272
                break;
273
            }
274 886f3f2f Martin Storsjö
        } else if (n < 0) {
275 28c4741a Martin Storsjö
            if (ff_neterrno() == AVERROR(EINTR))
276 cae9a15c Martin Storsjö
                continue;
277 886f3f2f Martin Storsjö
            return AVERROR(EIO);
278 3b50d2ad Fabrice Bellard
        }
279
    }
280
#endif
281
    return len;
282
}
283
284 27241cbf Martin Storsjö
static int rtp_write(URLContext *h, const uint8_t *buf, int size)
285 3b50d2ad Fabrice Bellard
{
286
    RTPContext *s = h->priv_data;
287 51885599 Fabrice Bellard
    int ret;
288 3b50d2ad Fabrice Bellard
    URLContext *hd;
289 115329f1 Diego Biurrun
290 7f3468d3 Josh Allmann
    if (buf[1] >= RTCP_SR && buf[1] <= RTCP_APP) {
291 3b50d2ad Fabrice Bellard
        /* RTCP payload type */
292
        hd = s->rtcp_hd;
293
    } else {
294
        /* RTP payload type */
295
        hd = s->rtp_hd;
296
    }
297
298
    ret = url_write(hd, buf, size);
299
#if 0
300
    {
301
        struct timespec ts;
302
        ts.tv_sec = 0;
303
        ts.tv_nsec = 10 * 1000000;
304
        nanosleep(&ts, NULL);
305
    }
306
#endif
307
    return ret;
308
}
309
310
static int rtp_close(URLContext *h)
311
{
312
    RTPContext *s = h->priv_data;
313
314
    url_close(s->rtp_hd);
315
    url_close(s->rtcp_hd);
316
    av_free(s);
317
    return 0;
318
}
319
320
/**
321 9094d867 Luca Barbato
 * Return the local rtp port used by the RTP connection
322 9a58234f Diego Biurrun
 * @param h media file context
323 9094d867 Luca Barbato
 * @return the local port number
324
 */
325
326
int rtp_get_local_rtp_port(URLContext *h)
327
{
328
    RTPContext *s = h->priv_data;
329
    return udp_get_local_port(s->rtp_hd);
330 3b50d2ad Fabrice Bellard
}
331
332 9094d867 Luca Barbato
/**
333
 * Return the local rtcp port used by the RTP connection
334 9a58234f Diego Biurrun
 * @param h media file context
335 9094d867 Luca Barbato
 * @return the local port number
336
 */
337
338
int rtp_get_local_rtcp_port(URLContext *h)
339
{
340
    RTPContext *s = h->priv_data;
341
    return udp_get_local_port(s->rtcp_hd);
342
}
343
344 f0a80394 Ronald S. Bultje
static int rtp_get_file_handle(URLContext *h)
345
{
346
    RTPContext *s = h->priv_data;
347
    return s->rtp_fd;
348
}
349 3b50d2ad Fabrice Bellard
350 186f1ec5 Josh Allmann
int rtp_get_rtcp_file_handle(URLContext *h) {
351
    RTPContext *s = h->priv_data;
352
    return s->rtcp_fd;
353
}
354
355 c6610a21 Diego Elio Pettenò
URLProtocol ff_rtp_protocol = {
356 3b50d2ad Fabrice Bellard
    "rtp",
357
    rtp_open,
358
    rtp_read,
359
    rtp_write,
360
    NULL, /* seek */
361
    rtp_close,
362 f0a80394 Ronald S. Bultje
    .url_get_file_handle = rtp_get_file_handle,
363 3b50d2ad Fabrice Bellard
};