Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpproto.c @ 4ec153bb

History | View | Annotate | Download (9.97 KB)

1
/*
2
 * RTP network protocol
3
 * Copyright (c) 2002 Fabrice Bellard
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav 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
 * Libav 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 Libav; 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 "avio_internal.h"
31
#include "rtpdec.h"
32

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

    
44
#define RTP_TX_BUF_SIZE  (64 * 1024)
45
#define RTP_RX_BUF_SIZE  (128 * 1024)
46

    
47
typedef struct RTPContext {
48
    URLContext *rtp_hd, *rtcp_hd;
49
    int rtp_fd, rtcp_fd;
50
} RTPContext;
51

    
52
/**
53
 * If no filename is given to av_open_input_file because you want to
54
 * get the local port first, then you must call this function to set
55
 * the remote server address.
56
 *
57
 * @param h media file context
58
 * @param uri of the remote server
59
 * @return zero if no error.
60
 */
61

    
62
int rtp_set_remote_url(URLContext *h, const char *uri)
63
{
64
    RTPContext *s = h->priv_data;
65
    char hostname[256];
66
    int port;
67

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

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

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

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

    
82

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

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

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

    
103
static void build_udp_url(char *buf, int buf_size,
104
                          const char *hostname, int port,
105
                          int local_port, int ttl,
106
                          int max_packet_size, int connect)
107
{
108
    ff_url_join(buf, buf_size, "udp", NULL, hostname, port, NULL);
109
    if (local_port >= 0)
110
        url_add_option(buf, buf_size, "localport=%d", local_port);
111
    if (ttl >= 0)
112
        url_add_option(buf, buf_size, "ttl=%d", ttl);
113
    if (max_packet_size >=0)
114
        url_add_option(buf, buf_size, "pkt_size=%d", max_packet_size);
115
    if (connect)
116
        url_add_option(buf, buf_size, "connect=1");
117
}
118

    
119
/**
120
 * url syntax: rtp://host:port[?option=val...]
121
 * option: 'ttl=n'            : set the ttl value (for multicast only)
122
 *         'rtcpport=n'       : set the remote rtcp port to n
123
 *         'localrtpport=n'   : set the local rtp port to n
124
 *         'localrtcpport=n'  : set the local rtcp port to n
125
 *         'pkt_size=n'       : set max packet size
126
 *         'connect=0/1'      : do a connect() on the UDP socket
127
 * deprecated option:
128
 *         'localport=n'      : set the local port to n
129
 *
130
 * if rtcpport isn't set the rtcp port will be the rtp port + 1
131
 * if local rtp port isn't set any available port will be used for the local
132
 * rtp and rtcp ports
133
 * if the local rtcp port is not set it will be the local rtp port + 1
134
 */
135

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

    
147
    is_output = (flags & URL_WRONLY);
148

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

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

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

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

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

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

    
208
    h->max_packet_size = url_get_max_packet_size(s->rtp_hd);
209
    h->is_streamed = 1;
210
    return 0;
211

    
212
 fail:
213
    if (s->rtp_hd)
214
        url_close(s->rtp_hd);
215
    if (s->rtcp_hd)
216
        url_close(s->rtcp_hd);
217
    av_free(s);
218
    return AVERROR(EIO);
219
}
220

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

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

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

    
291
    if (buf[1] >= RTCP_SR && buf[1] <= RTCP_APP) {
292
        /* RTCP payload type */
293
        hd = s->rtcp_hd;
294
    } else {
295
        /* RTP payload type */
296
        hd = s->rtp_hd;
297
    }
298

    
299
    ret = url_write(hd, buf, size);
300
#if 0
301
    {
302
        struct timespec ts;
303
        ts.tv_sec = 0;
304
        ts.tv_nsec = 10 * 1000000;
305
        nanosleep(&ts, NULL);
306
    }
307
#endif
308
    return ret;
309
}
310

    
311
static int rtp_close(URLContext *h)
312
{
313
    RTPContext *s = h->priv_data;
314

    
315
    url_close(s->rtp_hd);
316
    url_close(s->rtcp_hd);
317
    av_free(s);
318
    return 0;
319
}
320

    
321
/**
322
 * Return the local rtp port used by the RTP connection
323
 * @param h media file context
324
 * @return the local port number
325
 */
326

    
327
int rtp_get_local_rtp_port(URLContext *h)
328
{
329
    RTPContext *s = h->priv_data;
330
    return ff_udp_get_local_port(s->rtp_hd);
331
}
332

    
333
/**
334
 * Return the local rtcp port used by the RTP connection
335
 * @param h media file context
336
 * @return the local port number
337
 */
338

    
339
int rtp_get_local_rtcp_port(URLContext *h)
340
{
341
    RTPContext *s = h->priv_data;
342
    return ff_udp_get_local_port(s->rtcp_hd);
343
}
344

    
345
static int rtp_get_file_handle(URLContext *h)
346
{
347
    RTPContext *s = h->priv_data;
348
    return s->rtp_fd;
349
}
350

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

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