Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpproto.c @ c24a4034

History | View | Annotate | Download (9.94 KB)

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/parseutils.h"
28
#include "libavutil/avstring.h"
29
#include "avformat.h"
30
#include "rtpdec.h"
31

    
32
#include <unistd.h>
33
#include <stdarg.h>
34
#include "internal.h"
35
#include "network.h"
36
#include "os_support.h"
37
#include <fcntl.h>
38
#if HAVE_POLL_H
39
#include <sys/poll.h>
40
#endif
41
#include <sys/time.h>
42

    
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
 * @param h media file context
57
 * @param uri of the remote server
58
 * @return zero if no error.
59
 */
60

    
61
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

    
67
    char buf[1024];
68
    char path[1024];
69

    
70
    av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &port,
71
                 path, sizeof(path), uri);
72

    
73
    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port, "%s", path);
74
    udp_set_remote_url(s->rtp_hd, buf);
75

    
76
    ff_url_join(buf, sizeof(buf), "udp", NULL, hostname, port + 1, "%s", path);
77
    udp_set_remote_url(s->rtcp_hd, buf);
78
    return 0;
79
}
80

    
81

    
82
/**
83
 * add option to url of the form:
84
 * "http://host:port/path?option1=val1&option2=val2...
85
 */
86

    
87
static void url_add_option(char *buf, int buf_size, const char *fmt, ...)
88
{
89
    char buf1[1024];
90
    va_list ap;
91

    
92
    va_start(ap, fmt);
93
    if (strchr(buf, '?'))
94
        av_strlcat(buf, "&", buf_size);
95
    else
96
        av_strlcat(buf, "?", buf_size);
97
    vsnprintf(buf1, sizeof(buf1), fmt, ap);
98
    av_strlcat(buf, buf1, buf_size);
99
    va_end(ap);
100
}
101

    
102
static void build_udp_url(char *buf, int buf_size,
103
                          const char *hostname, int port,
104
                          int local_port, int ttl,
105
                          int max_packet_size, int connect)
106
{
107
    ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
108
    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
    if (max_packet_size >=0)
113
        url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
114
    if (connect)
115
        url_add_option(buf, buf_size, "connect=1");
116
}
117

    
118
/**
119
 * url syntax: rtp://host:port[?option=val...]
120
 * 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
 *         'connect=0/1'      : do a connect() on the UDP socket
126
 * deprecated option:
127
 *         'localport=n'      : set the local port to n
128
 *
129
 * 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
 */
134

    
135
static int rtp_open(URLContext *h, const char *uri, int flags)
136
{
137
    RTPContext *s;
138
    int rtp_port, rtcp_port,
139
        is_output, ttl, connect,
140
        local_rtp_port, local_rtcp_port, max_packet_size;
141
    char hostname[256];
142
    char buf[1024];
143
    char path[1024];
144
    const char *p;
145

    
146
    is_output = (flags & URL_WRONLY);
147

    
148
    s = av_mallocz(sizeof(RTPContext));
149
    if (!s)
150
        return AVERROR(ENOMEM);
151
    h->priv_data = s;
152

    
153
    av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
154
                 path, sizeof(path), uri);
155
    /* extract parameters */
156
    ttl = -1;
157
    rtcp_port = rtp_port+1;
158
    local_rtp_port = -1;
159
    local_rtcp_port = -1;
160
    max_packet_size = -1;
161
    connect = 0;
162

    
163
    p = strchr(uri, '?');
164
    if (p) {
165
        if (av_find_info_tag(buf, sizeof(buf), "ttl", p)) {
166
            ttl = strtol(buf, NULL, 10);
167
        }
168
        if (av_find_info_tag(buf, sizeof(buf), "rtcpport", p)) {
169
            rtcp_port = strtol(buf, NULL, 10);
170
        }
171
        if (av_find_info_tag(buf, sizeof(buf), "localport", p)) {
172
            local_rtp_port = strtol(buf, NULL, 10);
173
        }
174
        if (av_find_info_tag(buf, sizeof(buf), "localrtpport", p)) {
175
            local_rtp_port = strtol(buf, NULL, 10);
176
        }
177
        if (av_find_info_tag(buf, sizeof(buf), "localrtcpport", p)) {
178
            local_rtcp_port = strtol(buf, NULL, 10);
179
        }
180
        if (av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) {
181
            max_packet_size = strtol(buf, NULL, 10);
182
        }
183
        if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
184
            connect = strtol(buf, NULL, 10);
185
        }
186
    }
187

    
188
    build_udp_url(buf, sizeof(buf),
189
                  hostname, rtp_port, local_rtp_port, ttl, max_packet_size,
190
                  connect);
191
    if (url_open(&s->rtp_hd, buf, flags) < 0)
192
        goto fail;
193
    if (local_rtp_port>=0 && local_rtcp_port<0)
194
        local_rtcp_port = udp_get_local_port(s->rtp_hd) + 1;
195

    
196
    build_udp_url(buf, sizeof(buf),
197
                  hostname, rtcp_port, local_rtcp_port, ttl, max_packet_size,
198
                  connect);
199
    if (url_open(&s->rtcp_hd, buf, flags) < 0)
200
        goto fail;
201

    
202
    /* just to ease handle access. XXX: need to suppress direct handle
203
       access */
204
    s->rtp_fd = url_get_file_handle(s->rtp_hd);
205
    s->rtcp_fd = url_get_file_handle(s->rtcp_hd);
206

    
207
    h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
208
    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
    return AVERROR(EIO);
218
}
219

    
220
static int rtp_read(URLContext *h, uint8_t *buf, int size)
221
{
222
    RTPContext *s = h->priv_data;
223
    struct sockaddr_storage from;
224
    socklen_t from_len;
225
    int len, n;
226
    struct pollfd p[2] = {{s->rtp_fd, POLLIN, 0}, {s->rtcp_fd, POLLIN, 0}};
227

    
228
#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
            if (ff_neterrno() == AVERROR(EAGAIN) ||
235
                ff_neterrno() == AVERROR(EINTR))
236
                continue;
237
            return AVERROR(EIO);
238
        }
239
        break;
240
    }
241
#else
242
    for(;;) {
243
        if (url_interrupt_cb())
244
            return AVERROR(EINTR);
245
        /* build fdset to listen to RTP and RTCP packets */
246
        n = poll(p, 2, 100);
247
        if (n > 0) {
248
            /* first try RTCP */
249
            if (p[1].revents & POLLIN) {
250
                from_len = sizeof(from);
251
                len = recvfrom (s->rtcp_fd, buf, size, 0,
252
                                (struct sockaddr *)&from, &from_len);
253
                if (len < 0) {
254
                    if (ff_neterrno() == AVERROR(EAGAIN) ||
255
                        ff_neterrno() == AVERROR(EINTR))
256
                        continue;
257
                    return AVERROR(EIO);
258
                }
259
                break;
260
            }
261
            /* then RTP */
262
            if (p[0].revents & POLLIN) {
263
                from_len = sizeof(from);
264
                len = recvfrom (s->rtp_fd, buf, size, 0,
265
                                (struct sockaddr *)&from, &from_len);
266
                if (len < 0) {
267
                    if (ff_neterrno() == AVERROR(EAGAIN) ||
268
                        ff_neterrno() == AVERROR(EINTR))
269
                        continue;
270
                    return AVERROR(EIO);
271
                }
272
                break;
273
            }
274
        } else if (n < 0) {
275
            if (ff_neterrno() == AVERROR(EINTR))
276
                continue;
277
            return AVERROR(EIO);
278
        }
279
    }
280
#endif
281
    return len;
282
}
283

    
284
static int rtp_write(URLContext *h, const uint8_t *buf, int size)
285
{
286
    RTPContext *s = h->priv_data;
287
    int ret;
288
    URLContext *hd;
289

    
290
    if (buf[1] >= RTCP_SR && buf[1] <= RTCP_APP) {
291
        /* 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
 * Return the local rtp port used by the RTP connection
322
 * @param h media file context
323
 * @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
}
331

    
332
/**
333
 * Return the local rtcp port used by the RTP connection
334
 * @param h media file context
335
 * @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
static int rtp_get_file_handle(URLContext *h)
345
{
346
    RTPContext *s = h->priv_data;
347
    return s->rtp_fd;
348
}
349

    
350
int rtp_get_rtcp_file_handle(URLContext *h) {
351
    RTPContext *s = h->priv_data;
352
    return s->rtcp_fd;
353
}
354

    
355
URLProtocol ff_rtp_protocol = {
356
    "rtp",
357
    rtp_open,
358
    rtp_read,
359
    rtp_write,
360
    NULL, /* seek */
361
    rtp_close,
362
    .url_get_file_handle = rtp_get_file_handle,
363
};